1 /*-------------------------------------------------------------------------------
2
3 BARONY
4 File: init_game.cpp
5 Desc: contains game specific initialization code that shouldn't be
6 seen in the editor.
7
8 Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
9 See LICENSE for details.
10
11 -------------------------------------------------------------------------------*/
12
13 #include "main.hpp"
14 #include "draw.hpp"
15 #include "files.hpp"
16 #include "game.hpp"
17 #include "stat.hpp"
18 #include "interface/interface.hpp"
19 #include "messages.hpp"
20 #include "book.hpp"
21 #include "sound.hpp"
22 #include "shops.hpp"
23 #include "scores.hpp"
24 #include "magic/magic.hpp"
25 #include "monster.hpp"
26 #include "net.hpp"
27 #ifdef STEAMWORKS
28 #include <steam/steam_api.h>
29 #include "steam.hpp"
30 #endif
31 #include "menu.hpp"
32 #include "paths.hpp"
33 #include "player.hpp"
34 #include "cppfuncs.hpp"
35 #include "Directory.hpp"
36 #include "mod_tools.hpp"
37
38 /*-------------------------------------------------------------------------------
39
40 initGame
41
42 initializes certain game specific resources
43
44 -------------------------------------------------------------------------------*/
45
46 #define _LOADSTR1 language[746]
47 #define _LOADSTR2 language[747]
48 #define _LOADSTR3 language[748]
49 #define _LOADSTR4 language[749]
50
initGame()51 int initGame()
52 {
53 int c, x;
54 char name[32];
55 FILE* fp;
56
57 // setup some lists
58 booksRead.first = NULL;
59 booksRead.last = NULL;
60 lobbyChatboxMessages.first = NULL;
61 lobbyChatboxMessages.last = NULL;
62
63 // steam stuff
64 #ifdef STEAMWORKS
65 cpp_SteamServerWrapper_Instantiate(); //TODO: Remove these wrappers.
66 cpp_SteamServerClientWrapper_Instantiate();
67
68 cpp_SteamServerClientWrapper_OnP2PSessionRequest = &steam_OnP2PSessionRequest;
69 //cpp_SteamServerClientWrapper_OnGameOverlayActivated = &steam_OnGameOverlayActivated;
70 cpp_SteamServerClientWrapper_OnLobbyCreated = &steam_OnLobbyCreated;
71 cpp_SteamServerClientWrapper_OnGameJoinRequested = &steam_OnGameJoinRequested;
72 cpp_SteamServerClientWrapper_OnLobbyEntered = &steam_OnLobbyEntered;
73 cpp_SteamServerClientWrapper_GameServerPingOnServerResponded = &steam_GameServerPingOnServerResponded;
74 cpp_SteamServerClientWrapper_OnLobbyMatchListCallback = &steam_OnLobbyMatchListCallback;
75 cpp_SteamServerClientWrapper_OnP2PSessionConnectFail = &steam_OnP2PSessionConnectFail;
76 cpp_SteamServerClientWrapper_OnLobbyDataUpdate = &steam_OnLobbyDataUpdatedCallback;
77 #ifdef USE_EOS
78 cpp_SteamServerClientWrapper_OnRequestEncryptedAppTicket = &steam_OnRequestEncryptedAppTicket;
79 #endif //USE_EOS
80 #endif
81
82 // print a loading message
83 drawClearBuffers();
84 int w, h;
85 TTF_SizeUTF8(ttf16, _LOADSTR1, &w, &h);
86 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, _LOADSTR1);
87
88 GO_SwapBuffers(screen);
89
90 initGameControllers();
91
92 // load achievement images
93 Directory achievementsDir("images/achievements");
94 for (auto& item : achievementsDir.list)
95 {
96 std::string fullPath = achievementsDir.path + std::string("/") + item;
97 char* name = const_cast<char*>(fullPath.c_str()); // <- evil
98 achievementImages.emplace(std::make_pair(item, loadImage(name)));
99 }
100
101 // load model offsets
102 printlog( "loading model offsets...\n");
103 for ( c = 1; c < NUMMONSTERS; c++ )
104 {
105 // initialize all offsets to zero
106 for ( x = 0; x < 20; x++ )
107 {
108 limbs[c][x][0] = 0;
109 limbs[c][x][1] = 0;
110 limbs[c][x][2] = 0;
111 }
112
113 // open file
114 char filename[256];
115 strcpy(filename, "models/creatures/");
116 strcat(filename, monstertypename[c]);
117 strcat(filename, "/limbs.txt");
118 if ( (fp = openDataFile(filename, "r")) == NULL )
119 {
120 continue;
121 }
122
123 // read file
124 int line;
125 for ( line = 1; feof(fp) == 0; line++ )
126 {
127 char data[256];
128 int limb = 20;
129 int dummy;
130
131 // read line from file
132 fgets( data, 256, fp );
133
134 // skip blank and comment lines
135 if ( data[0] == '\n' || data[0] == '\r' || data[0] == '#' )
136 {
137 continue;
138 }
139
140 // process line
141 if ( sscanf( data, "%d", &limb ) != 1 || limb >= 20 || limb < 0 )
142 {
143 printlog( "warning: syntax error in '%s':%d\n invalid limb index!\n", filename, line);
144 continue;
145 }
146 if ( sscanf( data, "%d %f %f %f\n", &dummy, &limbs[c][limb][0], &limbs[c][limb][1], &limbs[c][limb][2] ) != 4 )
147 {
148 printlog( "warning: syntax error in '%s':%d\n invalid limb offsets!\n", filename, line);
149 continue;
150 }
151 }
152
153 // close file
154 fclose(fp);
155 }
156
157 // print a loading message
158 drawClearBuffers();
159 TTF_SizeUTF8(ttf16, _LOADSTR2, &w, &h);
160 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, _LOADSTR2);
161
162 GO_SwapBuffers(screen);
163
164 int newItems = 0;
165
166 // load item types
167 printlog( "loading items...\n");
168 std::string itemsDirectory = PHYSFS_getRealDir("items/items.txt");
169 itemsDirectory.append(PHYSFS_getDirSeparator()).append("items/items.txt");
170 fp = openDataFile(itemsDirectory.c_str(), "r");
171 for ( c = 0; !feof(fp); ++c )
172 {
173 if ( c > SPELLBOOK_DETECT_FOOD )
174 {
175 newItems = c - SPELLBOOK_DETECT_FOOD - 1;
176 items[c].name_identified = language[3500 + newItems * 2];
177 items[c].name_unidentified = language[3501 + newItems * 2];
178 }
179 else if ( c > ARTIFACT_BOW )
180 {
181 newItems = c - ARTIFACT_BOW - 1;
182 items[c].name_identified = language[2200 + newItems * 2];
183 items[c].name_unidentified = language[2201 + newItems * 2];
184 }
185 else
186 {
187 items[c].name_identified = language[1545 + c * 2];
188 items[c].name_unidentified = language[1546 + c * 2];
189 }
190 fscanf(fp, "%d", &items[c].index);
191 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
192 {
193 break;
194 }
195 fscanf(fp, "%d", &items[c].fpindex);
196 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
197 {
198 break;
199 }
200 fscanf(fp, "%d", &items[c].variations);
201 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
202 {
203 break;
204 }
205 fscanf(fp, "%s", name);
206 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
207 {
208 break;
209 }
210 if ( !strcmp(name, "WEAPON") )
211 {
212 items[c].category = WEAPON;
213 }
214 else if ( !strcmp(name, "ARMOR") )
215 {
216 items[c].category = ARMOR;
217 }
218 else if ( !strcmp(name, "AMULET") )
219 {
220 items[c].category = AMULET;
221 }
222 else if ( !strcmp(name, "POTION") )
223 {
224 items[c].category = POTION;
225 }
226 else if ( !strcmp(name, "SCROLL") )
227 {
228 items[c].category = SCROLL;
229 }
230 else if ( !strcmp(name, "MAGICSTAFF") )
231 {
232 items[c].category = MAGICSTAFF;
233 }
234 else if ( !strcmp(name, "RING") )
235 {
236 items[c].category = RING;
237 }
238 else if ( !strcmp(name, "SPELLBOOK") )
239 {
240 items[c].category = SPELLBOOK;
241 }
242 else if ( !strcmp(name, "TOOL") )
243 {
244 items[c].category = TOOL;
245 }
246 else if ( !strcmp(name, "FOOD") )
247 {
248 items[c].category = FOOD;
249 }
250 else if ( !strcmp(name, "BOOK") )
251 {
252 items[c].category = BOOK;
253 }
254 else if ( !strcmp(name, "THROWN") )
255 {
256 items[c].category = THROWN;
257 }
258 else if ( !strcmp(name, "SPELL_CAT") )
259 {
260 items[c].category = SPELL_CAT;
261 }
262 else
263 {
264 items[c].category = GEM;
265 }
266 fscanf(fp, "%d", &items[c].weight);
267 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
268 {
269 break;
270 }
271 fscanf(fp, "%d", &items[c].value);
272 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
273 {
274 break;
275 }
276 items[c].images.first = NULL;
277 items[c].images.last = NULL;
278 while ( 1 )
279 {
280 string_t* string = (string_t*) malloc(sizeof(string_t));
281 string->data = (char*) malloc(sizeof(char) * 64);
282 string->lines = 1;
283
284 node_t* node = list_AddNodeLast(&items[c].images);
285 node->element = string;
286 node->deconstructor = &stringDeconstructor;
287 node->size = sizeof(string_t);
288 string->node = node;
289
290 x = 0;
291 bool fileend = false;
292 while ( (string->data[x] = fgetc(fp)) != '\n' )
293 {
294 if ( feof(fp) )
295 {
296 fileend = true;
297 break;
298 }
299 x++;
300 }
301 if ( x == 0 || fileend )
302 {
303 list_RemoveNode(node);
304 break;
305 }
306 string->data[x] = 0;
307 }
308 }
309 for ( c = 0; c < NUMITEMS; c++ )
310 {
311 items[c].surfaces.first = NULL;
312 items[c].surfaces.last = NULL;
313 for ( x = 0; x < list_Size(&items[c].images); x++ )
314 {
315 SDL_Surface** surface = (SDL_Surface**) malloc(sizeof(SDL_Surface*));
316 node_t* node = list_AddNodeLast(&items[c].surfaces);
317 node->element = surface;
318 node->deconstructor = &defaultDeconstructor;
319 node->size = sizeof(SDL_Surface*);
320
321 node_t* node2 = list_Node(&items[c].images, x);
322 string_t* string = (string_t*)node2->element;
323 std::string itemImgDir;
324 if ( PHYSFS_getRealDir(string->data) != NULL )
325 {
326 itemImgDir = PHYSFS_getRealDir(string->data);
327 itemImgDir.append(PHYSFS_getDirSeparator()).append(string->data);
328 }
329 else
330 {
331 itemImgDir = string->data;
332 }
333 char imgFileChar[256];
334 strncpy(imgFileChar, itemImgDir.c_str(), 255);
335 *surface = loadImage(imgFileChar);
336 }
337 }
338 fclose(fp);
339 createBooks();
340 setupSpells();
341
342 randomPlayerNamesMale = getLinesFromDataFile(PLAYERNAMES_MALE_FILE);
343 randomPlayerNamesFemale = getLinesFromDataFile(PLAYERNAMES_FEMALE_FILE);
344 loadItemLists();
345
346 #if defined(USE_EOS) || defined(STEAMWORKS)
347 #else
348 if ( PHYSFS_getRealDir("mythsandoutcasts.key") != NULL )
349 {
350 std::string serial = PHYSFS_getRealDir("mythsandoutcasts.key");
351 serial.append(PHYSFS_getDirSeparator()).append("mythsandoutcasts.key");
352 // open the serial file
353 FILE* fp = nullptr;
354 if ( (fp = fopen(serial.c_str(), "rb")) != NULL )
355 {
356 char buf[64];
357 size_t len = fread(&buf, sizeof(char), 32, fp);
358 buf[len] = '\0';
359 serial = buf;
360 // compute hash
361 size_t DLCHash = serialHash(serial);
362 if ( DLCHash == 144425 )
363 {
364 printlog("[LICENSE]: Myths and Outcasts DLC license key found.");
365 enabledDLCPack1 = true;
366 }
367 else
368 {
369 printlog("[LICENSE]: DLC license key invalid.");
370 }
371 fclose(fp);
372 }
373 }
374 if ( PHYSFS_getRealDir("legendsandpariahs.key") != NULL )
375 {
376 std::string serial = PHYSFS_getRealDir("legendsandpariahs.key");
377 serial.append(PHYSFS_getDirSeparator()).append("legendsandpariahs.key");
378 // open the serial file
379 FILE* fp = nullptr;
380 if ( (fp = fopen(serial.c_str(), "rb")) != NULL )
381 {
382 char buf[64];
383 size_t len = fread(&buf, sizeof(char), 32, fp);
384 buf[len] = '\0';
385 serial = buf;
386 // compute hash
387 size_t DLCHash = serialHash(serial);
388 if ( DLCHash == 135398 )
389 {
390 printlog("[LICENSE]: Legends and Pariahs DLC license key found.");
391 enabledDLCPack2 = true;
392 }
393 else
394 {
395 printlog("[LICENSE]: DLC license key invalid.");
396 }
397 fclose(fp);
398 }
399 }
400 #endif
401
402 // print a loading message
403 drawClearBuffers();
404 TTF_SizeUTF8(ttf16, _LOADSTR3, &w, &h);
405 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, _LOADSTR3);
406
407 GO_SwapBuffers(screen);
408
409 #ifdef USE_FMOD
410 FMOD_ChannelGroup_SetVolume(music_group, musvolume / 128.f);
411 #elif defined USE_OPENAL
412 OPENAL_ChannelGroup_SetVolume(music_group, musvolume / 128.f);
413 #endif
414 removedEntities.first = NULL;
415 removedEntities.last = NULL;
416 safePacketsSent.first = NULL;
417 safePacketsSent.last = NULL;
418 for ( c = 0; c < MAXPLAYERS; c++ )
419 {
420 safePacketsReceivedMap[c].clear();
421 }
422 topscores.first = NULL;
423 topscores.last = NULL;
424 topscoresMultiplayer.first = NULL;
425 topscoresMultiplayer.last = NULL;
426 messages.first = NULL;
427 messages.last = NULL;
428 chestInv.first = NULL;
429 chestInv.last = NULL;
430 command_history.first = NULL;
431 command_history.last = NULL;
432 for ( c = 0; c < MAXPLAYERS; c++ )
433 {
434 invitemschest[c] = NULL;
435 openedChest[c] = NULL;
436 }
437 mousex = xres / 2;
438 mousey = yres / 2;
439
440 players = new Player*[MAXPLAYERS];
441 // default player stats
442 for (c = 0; c < MAXPLAYERS; c++)
443 {
444 players[c] = new Player();
445 // Stat set to 0 as monster type not needed, values will be filled with default, then overwritten by savegame or the charclass.cpp file
446 stats[c] = new Stat(0);
447 if (c > 0)
448 {
449 client_disconnected[c] = true;
450 }
451 players[c]->entity = nullptr;
452 stats[c]->sex = static_cast<sex_t>(0);
453 stats[c]->appearance = 0;
454 strcpy(stats[c]->name, "");
455 stats[c]->type = HUMAN;
456 stats[c]->playerRace = RACE_HUMAN;
457 stats[c]->FOLLOWERS.first = nullptr;
458 stats[c]->FOLLOWERS.last = nullptr;
459 stats[c]->inventory.first = nullptr;
460 stats[c]->inventory.last = nullptr;
461 stats[c]->clearStats();
462 entitiesToDelete[c].first = nullptr;
463 entitiesToDelete[c].last = nullptr;
464 if (c == 0)
465 {
466 initClass(c);
467 }
468 }
469
470 // load music
471 #ifdef SOUND
472 #ifdef USE_OPENAL
473 #define FMOD_ChannelGroup_SetVolume OPENAL_ChannelGroup_SetVolume
474 #define fmod_system 0
475 #define FMOD_SOFTWARE 0
476 #define FMOD_System_CreateStream(A, B, C, D, E) OPENAL_CreateStreamSound(B, E)
477 #define FMOD_SOUND OPENAL_BUFFER
478 int fmod_result;
479 #endif
480
481 FMOD_ChannelGroup_SetVolume(music_group, musvolume / 128.f);
482 fmod_result = FMOD_System_CreateStream(fmod_system, "music/introduction.ogg", FMOD_SOFTWARE, NULL, &introductionmusic);
483 fmod_result = FMOD_System_CreateStream(fmod_system, "music/intermission.ogg", FMOD_SOFTWARE, NULL, &intermissionmusic);
484 fmod_result = FMOD_System_CreateStream(fmod_system, "music/minetown.ogg", FMOD_SOFTWARE, NULL, &minetownmusic);
485 fmod_result = FMOD_System_CreateStream(fmod_system, "music/splash.ogg", FMOD_SOFTWARE, NULL, &splashmusic);
486 fmod_result = FMOD_System_CreateStream(fmod_system, "music/library.ogg", FMOD_SOFTWARE, NULL, &librarymusic);
487 fmod_result = FMOD_System_CreateStream(fmod_system, "music/shop.ogg", FMOD_SOFTWARE, NULL, &shopmusic);
488 fmod_result = FMOD_System_CreateStream(fmod_system, "music/herxboss.ogg", FMOD_SOFTWARE, NULL, &herxmusic);
489 fmod_result = FMOD_System_CreateStream(fmod_system, "music/temple.ogg", FMOD_SOFTWARE, NULL, &templemusic);
490 fmod_result = FMOD_System_CreateStream(fmod_system, "music/endgame.ogg", FMOD_SOFTWARE, NULL, &endgamemusic);
491 fmod_result = FMOD_System_CreateStream(fmod_system, "music/escape.ogg", FMOD_SOFTWARE, NULL, &escapemusic);
492 fmod_result = FMOD_System_CreateStream(fmod_system, "music/devil.ogg", FMOD_SOFTWARE, NULL, &devilmusic);
493 fmod_result = FMOD_System_CreateStream(fmod_system, "music/sanctum.ogg", FMOD_SOFTWARE, NULL, &sanctummusic);
494 fmod_result = FMOD_System_CreateStream(fmod_system, "music/tutorial.ogg", FMOD_SOFTWARE, NULL, &tutorialmusic);
495 if ( PHYSFS_getRealDir("music/gnomishmines.ogg") != NULL )
496 {
497 fmod_result = FMOD_System_CreateStream(fmod_system, "music/gnomishmines.ogg", FMOD_SOFTWARE, NULL, &gnomishminesmusic);
498 }
499 if ( PHYSFS_getRealDir("music/greatcastle.ogg") != NULL )
500 {
501 fmod_result = FMOD_System_CreateStream(fmod_system, "music/greatcastle.ogg", FMOD_SOFTWARE, NULL, &greatcastlemusic);
502 }
503 if ( PHYSFS_getRealDir("music/sokoban.ogg") != NULL )
504 {
505 fmod_result = FMOD_System_CreateStream(fmod_system, "music/sokoban.ogg", FMOD_SOFTWARE, NULL, &sokobanmusic);
506 }
507 if ( PHYSFS_getRealDir("music/caveslair.ogg") != NULL )
508 {
509 fmod_result = FMOD_System_CreateStream(fmod_system, "music/caveslair.ogg", FMOD_SOFTWARE, NULL, &caveslairmusic);
510 }
511 if ( PHYSFS_getRealDir("music/bramscastle.ogg") != NULL )
512 {
513 fmod_result = FMOD_System_CreateStream(fmod_system, "music/bramscastle.ogg", FMOD_SOFTWARE, NULL, &bramscastlemusic);
514 }
515 if ( PHYSFS_getRealDir("music/hamlet.ogg") != NULL )
516 {
517 fmod_result = FMOD_System_CreateStream(fmod_system, "music/hamlet.ogg", FMOD_SOFTWARE, NULL, &hamletmusic);
518 }
519 //fmod_result = FMOD_System_CreateStream(fmod_system, "music/story.ogg", FMOD_SOFTWARE, NULL, &storymusic);
520
521 if ( NUMMINESMUSIC > 0 )
522 {
523 minesmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMMINESMUSIC);
524 for ( c = 0; c < NUMMINESMUSIC; c++ )
525 {
526 snprintf(tempstr, 1000, "music/mines%02d.ogg", c);
527 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &minesmusic[c]);
528 }
529 }
530 if ( NUMSWAMPMUSIC > 0 )
531 {
532 swampmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMSWAMPMUSIC);
533 for ( c = 0; c < NUMSWAMPMUSIC; c++ )
534 {
535 snprintf(tempstr, 1000, "music/swamp%02d.ogg", c);
536 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &swampmusic[c]);
537 }
538 }
539 if ( NUMLABYRINTHMUSIC > 0 )
540 {
541 labyrinthmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMLABYRINTHMUSIC);
542 for ( c = 0; c < NUMLABYRINTHMUSIC; c++ )
543 {
544 snprintf(tempstr, 1000, "music/labyrinth%02d.ogg", c);
545 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &labyrinthmusic[c]);
546 }
547 }
548 if ( NUMRUINSMUSIC > 0 )
549 {
550 ruinsmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMRUINSMUSIC);
551 for ( c = 0; c < NUMRUINSMUSIC; c++ )
552 {
553 snprintf(tempstr, 1000, "music/ruins%02d.ogg", c);
554 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &ruinsmusic[c]);
555 }
556 }
557 if ( NUMUNDERWORLDMUSIC > 0 )
558 {
559 underworldmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMUNDERWORLDMUSIC);
560 for ( c = 0; c < NUMUNDERWORLDMUSIC; c++ )
561 {
562 snprintf(tempstr, 1000, "music/underworld%02d.ogg", c);
563 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &underworldmusic[c]);
564 }
565 }
566 if ( NUMHELLMUSIC > 0 )
567 {
568 hellmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMHELLMUSIC);
569 for ( c = 0; c < NUMHELLMUSIC; c++ )
570 {
571 snprintf(tempstr, 1000, "music/hell%02d.ogg", c);
572 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &hellmusic[c]);
573 }
574 }
575 if ( NUMMINOTAURMUSIC > 0 )
576 {
577 minotaurmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMMINOTAURMUSIC);
578 for ( c = 0; c < NUMMINOTAURMUSIC; c++ )
579 {
580 snprintf(tempstr, 1000, "music/minotaur%02d.ogg", c);
581 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &minotaurmusic[c]);
582 }
583 }
584 if ( NUMCAVESMUSIC > 0 )
585 {
586 cavesmusic = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*NUMCAVESMUSIC);
587 for ( c = 0; c < NUMCAVESMUSIC; c++ )
588 {
589 snprintf(tempstr, 1000, "music/caves%02d.ogg", c);
590 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &cavesmusic[c]);
591 }
592 }
593 if ( NUMCITADELMUSIC > 0 )
594 {
595 citadelmusic = (FMOD_SOUND**)malloc(sizeof(FMOD_SOUND*)*NUMCITADELMUSIC);
596 for ( c = 0; c < NUMCITADELMUSIC; c++ )
597 {
598 snprintf(tempstr, 1000, "music/citadel%02d.ogg", c);
599 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &citadelmusic[c]);
600 }
601 }
602 if ( NUMINTROMUSIC > 0 )
603 {
604 intromusic = (FMOD_SOUND**)malloc(sizeof(FMOD_SOUND*)*NUMINTROMUSIC);
605 for ( c = 0; c < NUMINTROMUSIC; c++ )
606 {
607 if ( c == 0 )
608 {
609 strcpy(tempstr, "music/intro.ogg");
610 }
611 else
612 {
613 snprintf(tempstr, 1000, "music/intro%02d.ogg", c);
614 }
615 fmod_result = FMOD_System_CreateStream(fmod_system, tempstr, FMOD_SOFTWARE, NULL, &intromusic[c]);
616 }
617 }
618 #ifdef USE_OPENAL
619 #undef FMOD_ChannelGroup_SetVolume
620 #undef fmod_system
621 #undef FMOD_SOFTWARE
622 #undef FMOD_System_CreateStream
623 #undef FMOD_SOUND
624 #endif
625
626 #endif
627
628 // print a loading message
629 drawClearBuffers();
630 TTF_SizeUTF8(ttf16, _LOADSTR4, &w, &h);
631 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, _LOADSTR4);
632
633 GO_SwapBuffers(screen);
634
635 // load extraneous game resources
636 title_bmp = loadImage("images/system/title.png");
637 logo_bmp = loadImage("images/system/logo.png");
638 cursor_bmp = loadImage("images/system/cursor.png");
639 cross_bmp = loadImage("images/system/cross.png");
640
641 loadAllScores(SCORESFILE);
642 loadAllScores(SCORESFILE_MULTIPLAYER);
643 gameModeManager.Tutorial.init();
644 if (!loadInterfaceResources())
645 {
646 printlog("Failed to load interface resources.\n");
647 return -1;
648 }
649
650 return 0;
651 }
652
653 /*-------------------------------------------------------------------------------
654
655 deinitGame
656
657 deinitializes certain game specific resources
658
659 -------------------------------------------------------------------------------*/
660
deinitGame()661 void deinitGame()
662 {
663 int c, x;
664
665 // send disconnect messages
666 if ( multiplayer == CLIENT )
667 {
668 strcpy((char*)net_packet->data, "DISCONNECT");
669 net_packet->data[10] = clientnum;
670 net_packet->address.host = net_server.host;
671 net_packet->address.port = net_server.port;
672 net_packet->len = 11;
673 sendPacketSafe(net_sock, -1, net_packet, 0);
674 printlog("disconnected from server.\n");
675 }
676 else if ( multiplayer == SERVER )
677 {
678 for ( x = 1; x < MAXPLAYERS; x++ )
679 {
680 if ( client_disconnected[x] == true )
681 {
682 continue;
683 }
684 strcpy((char*)net_packet->data, "DISCONNECT");
685 net_packet->data[10] = clientnum;
686 net_packet->address.host = net_clients[x - 1].host;
687 net_packet->address.port = net_clients[x - 1].port;
688 net_packet->len = 11;
689 sendPacketSafe(net_sock, -1, net_packet, x - 1);
690
691 stats[x]->freePlayerEquipment();
692 client_disconnected[x] = true;
693 }
694 }
695
696 // this short delay makes sure that the disconnect message gets out
697 Uint32 timetoshutdown = SDL_GetTicks();
698 while ( SDL_GetTicks() - timetoshutdown < 500 )
699 {
700 // handle network messages
701 if ( multiplayer == CLIENT )
702 {
703 clientHandleMessages(fpsLimit);
704 }
705 else if ( multiplayer == SERVER )
706 {
707 serverHandleMessages(fpsLimit);
708 }
709 if ( !(SDL_GetTicks() % 25) && multiplayer )
710 {
711 int j = 0;
712 node_t* node, *nextnode;
713 for ( node = safePacketsSent.first; node != NULL; node = nextnode )
714 {
715 nextnode = node->next;
716
717 packetsend_t* packet = (packetsend_t*)node->element;
718 sendPacket(packet->sock, packet->channel, packet->packet, packet->hostnum);
719 packet->tries++;
720 if ( packet->tries >= MAXTRIES )
721 {
722 list_RemoveNode(node);
723 }
724 j++;
725 if ( j >= MAXDELETES )
726 {
727 break;
728 }
729 }
730 }
731 }
732
733 saveAllScores(SCORESFILE);
734 saveAllScores(SCORESFILE_MULTIPLAYER);
735 list_FreeAll(&topscores);
736 list_FreeAll(&topscoresMultiplayer);
737 deleteAllNotificationMessages();
738 list_FreeAll(&removedEntities);
739 if ( title_bmp != nullptr )
740 {
741 SDL_FreeSurface(title_bmp);
742 }
743 if ( logo_bmp != nullptr )
744 {
745 SDL_FreeSurface(logo_bmp);
746 }
747 if ( cursor_bmp != nullptr )
748 {
749 SDL_FreeSurface(cursor_bmp);
750 }
751 if ( cross_bmp != nullptr )
752 {
753 SDL_FreeSurface(cross_bmp);
754 }
755 //if(sky_bmp!=NULL)
756 // SDL_FreeSurface(sky_bmp);
757 list_FreeAll(&chestInv);
758 freeInterfaceResources();
759 if ( books )
760 {
761 for ( c = 0; c < numbooks; c++ )
762 {
763 if ( books[c] )
764 {
765 if ( books[c]->name )
766 {
767 free(books[c]->name);
768 }
769 if ( books[c]->text )
770 {
771 free(books[c]->text);
772 }
773 if ( books[c]->bookgui_render_title )
774 {
775 free(books[c]->bookgui_render_title);
776 }
777 list_FreeAll(&books[c]->pages);
778 free(books[c]);
779 }
780 }
781 free(books);
782 }
783 appraisal_timer = 0;
784 appraisal_item = 0;
785 for ( c = 0; c < MAXPLAYERS; c++ )
786 {
787 list_FreeAll(&stats[c]->inventory);
788 }
789 if ( multiplayer == CLIENT )
790 {
791 if ( shopInv )
792 {
793 list_FreeAll(shopInv);
794 free(shopInv);
795 shopInv = NULL;
796 }
797 }
798 list_FreeAll(map.entities);
799 if ( map.creatures )
800 {
801 list_FreeAll(map.creatures); //TODO: Need to do this?
802 }
803 list_FreeAll(&messages);
804 if ( multiplayer == SINGLE )
805 {
806 list_FreeAll(&channeledSpells[0]);
807 }
808 else if ( multiplayer == CLIENT )
809 {
810 list_FreeAll(&channeledSpells[clientnum]);
811 }
812 else if ( multiplayer == SERVER )
813 {
814 for ( c = 0; c < MAXPLAYERS; ++c )
815 {
816 list_FreeAll(&channeledSpells[c]);
817 }
818 }
819 list_FreeAll(&spellList);
820 list_FreeAll(&command_history);
821
822 list_FreeAll(&safePacketsSent);
823 for ( c = 0; c < MAXPLAYERS; c++ )
824 {
825 safePacketsReceivedMap[c].clear();
826 }
827 #ifdef SOUND
828 #ifdef USE_OPENAL
829 #define FMOD_Channel_Stop OPENAL_Channel_Stop
830 #define FMOD_Sound_Release OPENAL_Sound_Release
831 #endif
832 if ( !no_sound )
833 {
834 FMOD_Channel_Stop(music_channel);
835 FMOD_Channel_Stop(music_channel2);
836 FMOD_Sound_Release(introductionmusic);
837 FMOD_Sound_Release(intermissionmusic);
838 FMOD_Sound_Release(minetownmusic);
839 FMOD_Sound_Release(splashmusic);
840 FMOD_Sound_Release(librarymusic);
841 FMOD_Sound_Release(shopmusic);
842 FMOD_Sound_Release(herxmusic);
843 FMOD_Sound_Release(templemusic);
844 FMOD_Sound_Release(endgamemusic);
845 FMOD_Sound_Release(escapemusic);
846 FMOD_Sound_Release(devilmusic);
847 FMOD_Sound_Release(sanctummusic);
848 FMOD_Sound_Release(gnomishminesmusic);
849 FMOD_Sound_Release(greatcastlemusic);
850 FMOD_Sound_Release(sokobanmusic);
851 FMOD_Sound_Release(caveslairmusic);
852 FMOD_Sound_Release(bramscastlemusic);
853 FMOD_Sound_Release(hamletmusic);
854 FMOD_Sound_Release(tutorialmusic);
855 for ( c = 0; c < NUMMINESMUSIC; c++ )
856 {
857 FMOD_Sound_Release(minesmusic[c]);
858 }
859 if ( minesmusic )
860 {
861 free(minesmusic);
862 }
863 for ( c = 0; c < NUMSWAMPMUSIC; c++ )
864 {
865 FMOD_Sound_Release(swampmusic[c]);
866 }
867 if ( swampmusic )
868 {
869 free(swampmusic);
870 }
871 for ( c = 0; c < NUMLABYRINTHMUSIC; c++ )
872 {
873 FMOD_Sound_Release(labyrinthmusic[c]);
874 }
875 if ( labyrinthmusic )
876 {
877 free(labyrinthmusic);
878 }
879 for ( c = 0; c < NUMRUINSMUSIC; c++ )
880 {
881 FMOD_Sound_Release(ruinsmusic[c]);
882 }
883 if ( ruinsmusic )
884 {
885 free(ruinsmusic);
886 }
887 for ( c = 0; c < NUMUNDERWORLDMUSIC; c++ )
888 {
889 FMOD_Sound_Release(underworldmusic[c]);
890 }
891 if ( underworldmusic )
892 {
893 free(underworldmusic);
894 }
895 for ( c = 0; c < NUMHELLMUSIC; c++ )
896 {
897 FMOD_Sound_Release(hellmusic[c]);
898 }
899 if ( hellmusic )
900 {
901 free(hellmusic);
902 }
903 for ( c = 0; c < NUMMINOTAURMUSIC; c++ )
904 {
905 FMOD_Sound_Release(minotaurmusic[c]);
906 }
907 if ( minotaurmusic )
908 {
909 free(minotaurmusic);
910 }
911 for ( c = 0; c < NUMCAVESMUSIC; c++ )
912 {
913 FMOD_Sound_Release(cavesmusic[c]);
914 }
915 if ( cavesmusic )
916 {
917 free(cavesmusic);
918 }
919 for ( c = 0; c < NUMCITADELMUSIC; c++ )
920 {
921 FMOD_Sound_Release(citadelmusic[c]);
922 }
923 if ( citadelmusic )
924 {
925 free(citadelmusic);
926 }
927 for ( c = 0; c < NUMINTROMUSIC; c++ )
928 {
929 FMOD_Sound_Release(intromusic[c]);
930 }
931 if ( intromusic )
932 {
933 free(intromusic);
934 }
935 }
936 #ifdef USE_OPENAL
937 #undef FMOD_Channel_Stop
938 #undef FMOD_Sound_Release
939 #endif
940 #endif
941
942 // free items
943 printlog( "freeing item data...\n");
944 for ( c = 0; c < NUMITEMS; c++ )
945 {
946 list_FreeAll(&items[c].images);
947 node_t* node, *nextnode;
948 for ( node = items[c].surfaces.first; node != NULL; node = nextnode )
949 {
950 nextnode = node->next;
951 SDL_Surface** surface = (SDL_Surface**)node->element;
952 if ( surface )
953 if ( *surface )
954 {
955 SDL_FreeSurface(*surface);
956 }
957 }
958 list_FreeAll(&items[c].surfaces);
959 }
960
961 freeSpells();
962
963 // pathmaps
964 if ( pathMapGrounded )
965 {
966 free(pathMapGrounded);
967 }
968 pathMapGrounded = NULL;
969 if ( pathMapFlying )
970 {
971 free(pathMapFlying);
972 }
973 pathMapFlying = NULL;
974
975 // clear steam achievement list
976 list_FreeAll(&booksRead);
977
978 // clear lobby chatbox data
979 list_FreeAll(&lobbyChatboxMessages);
980
981 // steam stuff
982 #ifdef STEAMWORKS
983 cpp_SteamServerWrapper_Destroy();
984 cpp_SteamServerClientWrapper_Destroy();
985 if ( currentLobby )
986 {
987 SteamMatchmaking()->LeaveLobby(*static_cast<CSteamID*>(currentLobby));
988 cpp_Free_CSteamID(currentLobby); //TODO: Remove these bodges.
989 currentLobby = NULL;
990 }
991 if ( lobbyToConnectTo )
992 {
993 cpp_Free_CSteamID(lobbyToConnectTo);
994 lobbyToConnectTo = NULL;
995 }
996 for ( c = 0; c < MAXPLAYERS; c++ )
997 {
998 if ( steamIDRemote[c] )
999 {
1000 cpp_Free_CSteamID(steamIDRemote[c]);
1001 steamIDRemote[c] = NULL;
1002 }
1003 }
1004 for ( c = 0; c < MAX_STEAM_LOBBIES; c++ )
1005 {
1006 if ( lobbyIDs[c] )
1007 {
1008 cpp_Free_CSteamID(lobbyIDs[c]);
1009 lobbyIDs[c] = NULL;
1010 }
1011 }
1012 #endif
1013 #if defined USE_EOS
1014 if ( EOS.CurrentLobbyData.currentLobbyIsValid() )
1015 {
1016 EOS.leaveLobby();
1017
1018 Uint32 shutdownTicks = SDL_GetTicks();
1019 while ( EOS.CurrentLobbyData.bAwaitingLeaveCallback )
1020 {
1021 #ifdef APPLE
1022 SDL_Event event;
1023 while ( SDL_PollEvent(&event) != 0 )
1024 {
1025 //Makes Mac work because Apple had to do it different.
1026 }
1027 #endif
1028 EOS_Platform_Tick(EOS.PlatformHandle);
1029 SDL_Delay(50);
1030 if ( SDL_GetTicks() - shutdownTicks >= 3000 )
1031 {
1032 break;
1033 }
1034 }
1035 }
1036 EOS.AccountManager.deinit();
1037 EOS.shutdown();
1038 #endif
1039
1040 //Close game controller
1041 /*if (game_controller)
1042 {
1043 SDL_GameControllerClose(game_controller);
1044 game_controller = nullptr;
1045 }*/
1046 if (game_controller)
1047 {
1048 delete game_controller;
1049 }
1050
1051 if ( shoparea )
1052 {
1053 free(shoparea);
1054 }
1055
1056 for (int i = 0; i < MAXPLAYERS; ++i)
1057 {
1058 delete players[i];
1059 }
1060 delete[] players;
1061 }
1062