2
* OpenTyrian: A modern cross-platform port of Tyrian
3
* Copyright (C) 2007-2009 The OpenTyrian Development Team
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31
#include "video_scale.h"
37
/* Configuration Load/Save handler */
39
const JE_byte cryptKey[10] = /* [1..10] */
41
15, 50, 89, 240, 147, 34, 86, 9, 32, 208
44
const JE_KeySettingType defaultKeySettings =
46
SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, SDLK_SPACE, SDLK_RETURN, SDLK_LCTRL, SDLK_LALT
47
/* 72, 80, 75, 77, 57, 28, 29, 56*/
50
const char defaultHighScoreNames[34][23] = /* [1..34] of string [22] */
52
/*TYR*/ "The Prime Chair", /*13*/
60
"Late Gyges Phildren",
66
/*OTHER*/ "Jill", /*5*/
69
"Malvineous Havershim",
70
"Marta Louise Velasquez",
72
/*JAZZ*/ "Jazz Jackrabbit", /*3*/
76
/*OMF*/ "Crystal Devroe", /*11*/
88
/*DARE*/ "Tyler", /*2*/
89
"Rennis the Rat Guard"
92
const char defaultTeamNames[22][25] = /* [1..22] of string [24] */
99
"Extreme Pinball Freaks",
102
"Hans Keissack's WARriors",
111
"Murderous Malvineous",
112
"The Traffic Department",
119
const JE_EditorItemAvailType initialItemAvail =
121
1,1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, /* Front/Rear Weapons 1-38 */
122
0,0,0,0,0,0,0,0,0,0,1, /* Fill */
123
1,0,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0,0, /* Sidekicks 51-68 */
124
0,0,0,0,0,0,0,0,0,0,0, /* Fill */
125
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Special Weapons 81-93 */
129
/* Last 2 bytes = Word
132
* X div 60 = Armor (1-28)
133
* X div 168 = Shield (1-12)
134
* X div 280 = Engine (1-06)
138
JE_boolean smoothies[9] = /* [1..9] */
139
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
141
JE_byte starShowVGASpecialCode;
144
JE_word lastCubeMax, cubeMax;
145
JE_word cubeList[4]; /* [1..4] */
147
/* High-Score Stuff */
148
JE_boolean gameHasRepeated; // can only get highscore on first play-through
151
JE_shortint difficultyLevel, oldDifficultyLevel,
152
initialDifficulty; // can only get highscore on initial episode
155
uint power, lastPower, powerAdd;
156
JE_byte shieldWait, shieldT;
158
JE_byte shotRepeat[11], shotMultiPos[11];
159
JE_boolean portConfigChange, portConfigDone;
162
char lastLevelName[11], levelName[11]; /* string [10] */
163
JE_byte mainLevel, nextLevel, saveLevel; /*Current Level #*/
166
JE_KeySettingType keySettings;
169
JE_shortint levelFilter, levelFilterNew, levelBrightness, levelBrightnessChg;
170
JE_boolean filtrationAvail, filterActive, filterFade, filterFadeStart;
172
JE_boolean gameJustLoaded;
174
JE_boolean galagaMode;
176
JE_boolean extraGame;
178
JE_boolean twoPlayerMode, twoPlayerLinked, onePlayerAction, superTyrian;
179
JE_boolean trentWin = false;
180
JE_byte superArcadeMode;
182
JE_byte superArcadePowerUp;
184
JE_real linkGunDirec;
185
JE_byte inputDevice[2] = { 1, 2 }; // 0:any 1:keyboard 2:mouse 3+:joystick
188
JE_byte background3over;
189
JE_byte background2over;
190
JE_byte gammaCorrection;
191
JE_boolean superPause = false;
192
JE_boolean explosionTransparent,
195
background2, smoothScroll, wild, superWild, starActive,
198
background2notTransparent;
200
JE_byte soundEffects; // dummy value for config
201
JE_byte versionNum; /* SW 1.0 and SW/Reg 1.1 = 0 or 1
205
JE_boolean pentiumMode;
209
JE_byte processorType; /* 1=386 2=486 3=Pentium Hyper */
211
JE_SaveFilesType saveFiles; /*array[1..saveLevelnum] of savefiletype;*/
212
JE_SaveGameTemp saveTemp;
214
JE_word editorLevel; /*Initial value 800*/
217
cJSON *load_json( const char *filename )
219
FILE *f = dir_fopen_warn(get_user_directory(), filename, "rb");
223
size_t buffer_len = ftell_eof(f);
224
char *buffer = malloc(buffer_len + 1);
226
fread(buffer, 1, buffer_len, f);
227
buffer[buffer_len] = '\0';
231
cJSON *root = cJSON_Parse(buffer);
238
void save_json( cJSON *root, const char *filename )
240
FILE *f = dir_fopen_warn(get_user_directory(), filename, "w+");
244
char *buffer = cJSON_Print(root);
255
bool load_opentyrian_config( void )
258
fullscreen_enabled = false;
259
set_scaler_by_name("Scale2x");
261
cJSON *root = load_json("opentyrian.conf");
265
cJSON *section = cJSON_GetObjectItem(root, "video");
270
if ((setting = cJSON_GetObjectItem(section, "fullscreen")))
271
fullscreen_enabled = (setting->type == cJSON_True);
273
if ((setting = cJSON_GetObjectItem(section, "scaler")))
274
set_scaler_by_name(setting->valuestring);
282
bool save_opentyrian_config( void )
284
cJSON *root = load_json("opentyrian.conf");
286
root = cJSON_CreateObject();
290
section = cJSON_CreateOrGetObjectItem(root, "video");
291
cJSON_ForceType(section, cJSON_Object);
296
setting = cJSON_CreateOrGetObjectItem(section, "fullscreen");
297
cJSON_SetBoolean(setting, fullscreen_enabled);
299
setting = cJSON_CreateOrGetObjectItem(section, "scaler");
300
cJSON_SetString(setting, scalers[scaler].name);
303
save_json(root, "opentyrian.conf");
310
static void playeritems_to_pitems( JE_PItemsType pItems, PlayerItems *items, JE_byte initial_episode_num )
312
pItems[0] = items->weapon[FRONT_WEAPON].id;
313
pItems[1] = items->weapon[REAR_WEAPON].id;
314
pItems[2] = items->super_arcade_mode;
315
pItems[3] = items->sidekick[LEFT_SIDEKICK];
316
pItems[4] = items->sidekick[RIGHT_SIDEKICK];
317
pItems[5] = items->generator;
318
pItems[6] = items->sidekick_level;
319
pItems[7] = items->sidekick_series;
320
pItems[8] = initial_episode_num;
321
pItems[9] = items->shield;
322
pItems[10] = items->special;
323
pItems[11] = items->ship;
326
static void pitems_to_playeritems( PlayerItems *items, JE_PItemsType pItems, JE_byte *initial_episode_num )
328
items->weapon[FRONT_WEAPON].id = pItems[0];
329
items->weapon[REAR_WEAPON].id = pItems[1];
330
items->super_arcade_mode = pItems[2];
331
items->sidekick[LEFT_SIDEKICK] = pItems[3];
332
items->sidekick[RIGHT_SIDEKICK] = pItems[4];
333
items->generator = pItems[5];
334
items->sidekick_level = pItems[6];
335
items->sidekick_series = pItems[7];
336
if (initial_episode_num != NULL)
337
*initial_episode_num = pItems[8];
338
items->shield = pItems[9];
339
items->special = pItems[10];
340
items->ship = pItems[11];
343
void JE_saveGame( JE_byte slot, const char *name )
345
saveFiles[slot-1].initialDifficulty = initialDifficulty;
346
saveFiles[slot-1].gameHasRepeated = gameHasRepeated;
347
saveFiles[slot-1].level = saveLevel;
350
player[0].items.super_arcade_mode = SA_SUPERTYRIAN;
351
else if (superArcadeMode == SA_NONE && onePlayerAction)
352
player[0].items.super_arcade_mode = SA_ARCADE;
354
player[0].items.super_arcade_mode = superArcadeMode;
356
playeritems_to_pitems(saveFiles[slot-1].items, &player[0].items, initial_episode_num);
359
playeritems_to_pitems(saveFiles[slot-1].lastItems, &player[1].items, 0);
361
playeritems_to_pitems(saveFiles[slot-1].lastItems, &player[0].last_items, 0);
363
saveFiles[slot-1].score = player[0].cash;
364
saveFiles[slot-1].score2 = player[1].cash;
366
memcpy(&saveFiles[slot-1].levelName, &lastLevelName, sizeof(lastLevelName));
367
saveFiles[slot-1].cubes = lastCubeMax;
369
if (strcmp(lastLevelName, "Completed") == 0)
371
temp = episodeNum - 1;
374
temp = EPISODE_AVAILABLE; /* JE: {Episodemax is 4 for completion purposes} */
376
saveFiles[slot-1].episode = temp;
380
saveFiles[slot-1].episode = episodeNum;
383
saveFiles[slot-1].difficulty = difficultyLevel;
384
saveFiles[slot-1].secretHint = secretHint;
385
saveFiles[slot-1].input1 = inputDevice[0];
386
saveFiles[slot-1].input2 = inputDevice[1];
388
strcpy(saveFiles[slot-1].name, name);
390
for (uint port = 0; port < 2; ++port)
392
// if two-player, use first player's front and second player's rear weapon
393
saveFiles[slot-1].power[port] = player[twoPlayerMode ? port : 0].items.weapon[port].power;
396
JE_saveConfiguration();
399
void JE_loadGame( JE_byte slot )
402
onePlayerAction = false;
403
twoPlayerMode = false;
407
initialDifficulty = saveFiles[slot-1].initialDifficulty;
408
gameHasRepeated = saveFiles[slot-1].gameHasRepeated;
409
twoPlayerMode = (slot-1) > 10;
410
difficultyLevel = saveFiles[slot-1].difficulty;
412
pitems_to_playeritems(&player[0].items, saveFiles[slot-1].items, &initial_episode_num);
414
superArcadeMode = player[0].items.super_arcade_mode;
416
if (superArcadeMode == SA_SUPERTYRIAN)
418
if (superArcadeMode != SA_NONE)
419
onePlayerAction = true;
420
if (superArcadeMode > SA_NORTSHIPZ)
421
superArcadeMode = SA_NONE;
425
onePlayerAction = false;
427
pitems_to_playeritems(&player[1].items, saveFiles[slot-1].lastItems, NULL);
431
pitems_to_playeritems(&player[0].last_items, saveFiles[slot-1].lastItems, NULL);
434
/* Compatibility with old version */
435
if (player[1].items.sidekick_level < 101)
437
player[1].items.sidekick_level = 101;
438
player[1].items.sidekick_series = player[1].items.sidekick[LEFT_SIDEKICK];
441
player[0].cash = saveFiles[slot-1].score;
442
player[1].cash = saveFiles[slot-1].score2;
444
mainLevel = saveFiles[slot-1].level;
445
cubeMax = saveFiles[slot-1].cubes;
446
lastCubeMax = cubeMax;
448
secretHint = saveFiles[slot-1].secretHint;
449
inputDevice[0] = saveFiles[slot-1].input1;
450
inputDevice[1] = saveFiles[slot-1].input2;
452
for (uint port = 0; port < 2; ++port)
454
// if two-player, use first player's front and second player's rear weapon
455
player[twoPlayerMode ? port : 0].items.weapon[port].power = saveFiles[slot-1].power[port];
458
int episode = saveFiles[slot-1].episode;
460
memcpy(&levelName, &saveFiles[slot-1].levelName, sizeof(levelName));
462
if (strcmp(levelName, "Completed") == 0)
464
if (episode == EPISODE_AVAILABLE)
467
} else if (episode < EPISODE_AVAILABLE) {
470
/* Increment episode. Episode EPISODE_AVAILABLE goes to 1. */
473
JE_initEpisode(episode);
474
saveLevel = mainLevel;
475
memcpy(&lastLevelName, &levelName, sizeof(levelName));
478
void JE_initProcessorType( void )
480
/* SYN: Originally this proc looked at your hardware specs and chose appropriate options. We don't care, so I'll just set
481
decent defaults here. */
486
explosionTransparent = true;
487
filtrationAvail = false;
491
switch (processorType)
495
displayScore = false;
496
explosionTransparent = false;
498
case 2: /* 486 - Default */
500
case 3: /* High Detail */
501
smoothScroll = false;
503
case 4: /* Pentium */
505
filtrationAvail = true;
507
case 5: /* Nonstandard VGA */
508
smoothScroll = false;
510
case 6: /* SuperWild */
513
filtrationAvail = true;
519
case 1: /* Slug Mode */
531
case 5: /* Pentium Hyper */
538
void JE_setNewGameSpeed( void )
556
smoothScroll = false;
577
frameCount = frameCountMax;
582
void JE_encryptSaveTemp( void )
588
memcpy(&s3, &saveTemp, sizeof(s3));
591
for (x = 0; x < SAVE_FILE_SIZE; x++)
595
saveTemp[SAVE_FILE_SIZE] = y;
598
for (x = 0; x < SAVE_FILE_SIZE; x++)
602
saveTemp[SAVE_FILE_SIZE+1] = y;
605
for (x = 0; x < SAVE_FILE_SIZE; x++)
609
saveTemp[SAVE_FILE_SIZE+2] = y;
612
for (x = 0; x < SAVE_FILE_SIZE; x++)
616
saveTemp[SAVE_FILE_SIZE+3] = y;
618
for (x = 0; x < SAVE_FILE_SIZE; x++)
620
saveTemp[x] = saveTemp[x] ^ cryptKey[(x+1) % 10];
623
saveTemp[x] = saveTemp[x] ^ saveTemp[x - 1];
628
void JE_decryptSaveTemp( void )
630
JE_boolean correct = true;
635
/* Decrypt save game file */
636
for (x = (SAVE_FILE_SIZE - 1); x >= 0; x--)
638
s2[x] = (JE_byte)saveTemp[x] ^ (JE_byte)(cryptKey[(x+1) % 10]);
641
s2[x] ^= (JE_byte)saveTemp[x - 1];
646
/* for (x = 0; x < SAVE_FILE_SIZE; x++) printf("%c", s2[x]); */
648
/* Check save file for correctitude */
650
for (x = 0; x < SAVE_FILE_SIZE; x++)
654
if (saveTemp[SAVE_FILE_SIZE] != y)
657
printf("Failed additive checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE], y);
661
for (x = 0; x < SAVE_FILE_SIZE; x++)
665
if (saveTemp[SAVE_FILE_SIZE+1] != y)
668
printf("Failed subtractive checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+1], y);
672
for (x = 0; x < SAVE_FILE_SIZE; x++)
676
if (saveTemp[SAVE_FILE_SIZE+2] != y)
679
printf("Failed multiplicative checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+2], y);
683
for (x = 0; x < SAVE_FILE_SIZE; x++)
687
if (saveTemp[SAVE_FILE_SIZE+3] != y)
690
printf("Failed XOR'd checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+3], y);
693
/* Barf and die if save file doesn't validate */
696
fprintf(stderr, "Error reading save file!\n");
700
/* Keep decrypted version plz */
701
memcpy(&saveTemp, &s2, sizeof(s2));
704
#ifndef TARGET_MACOSX
705
const char *get_user_directory( void )
707
static char user_dir[500] = "";
709
if (strlen(user_dir) == 0)
713
snprintf(user_dir, sizeof(user_dir), "%s/.opentyrian", getenv("HOME"));
715
strcpy(user_dir, ".");
716
#endif // TARGET_UNIX
721
#endif // TARGET_MACOSX
724
Uint8 joyButtonAssign[4] = {1, 4, 5, 5};
725
Uint8 inputDevice_ = 0, jConfigure = 0, midiPort = 1;
727
void JE_loadConfiguration( void )
734
fi = dir_fopen_warn(get_user_directory(), "tyrian.cfg", "rb");
735
if (fi && ftell_eof(fi) == 20 + sizeof(keySettings))
737
/* SYN: I've hardcoded the sizes here because the .CFG file format is fixed
738
anyways, so it's not like they'll change. */
740
efread(&background2, 1, 1, fi);
741
efread(&gameSpeed, 1, 1, fi);
743
efread(&inputDevice_, 1, 1, fi);
744
efread(&jConfigure, 1, 1, fi);
746
efread(&versionNum, 1, 1, fi);
748
efread(&processorType, 1, 1, fi);
749
efread(&midiPort, 1, 1, fi);
750
efread(&soundEffects, 1, 1, fi);
751
efread(&gammaCorrection, 1, 1, fi);
752
efread(&difficultyLevel, 1, 1, fi);
754
efread(joyButtonAssign, 1, 4, fi);
756
efread(&tyrMusicVolume, 2, 1, fi);
757
efread(&fxVolume, 2, 1, fi);
759
efread(inputDevice, 1, 2, fi);
761
efread(keySettings, sizeof(*keySettings), COUNTOF(keySettings), fi);
767
printf("\nInvalid or missing TYRIAN.CFG! Continuing using defaults.\n\n");
770
memcpy(&keySettings, &defaultKeySettings, sizeof(keySettings));
772
tyrMusicVolume = fxVolume = 128;
778
load_opentyrian_config();
780
if (tyrMusicVolume > 255)
781
tyrMusicVolume = 255;
787
set_volume(tyrMusicVolume, fxVolume);
789
fi = dir_fopen_warn(get_user_directory(), "tyrian.sav", "rb");
793
fseek(fi, 0, SEEK_SET);
794
efread(saveTemp, 1, sizeof(saveTemp), fi);
795
JE_decryptSaveTemp();
797
/* SYN: The original mostly blasted the save file into raw memory. However, our lives are not so
798
easy, because the C struct is necessarily a different size. So instead we have to loop
799
through each record and load fields manually. *emo tear* :'( */
802
for (z = 0; z < SAVE_FILES_NUM; z++)
804
memcpy(&saveFiles[z].encode, p, sizeof(JE_word)); p += 2;
805
saveFiles[z].encode = SDL_SwapLE16(saveFiles[z].encode);
807
memcpy(&saveFiles[z].level, p, sizeof(JE_word)); p += 2;
808
saveFiles[z].level = SDL_SwapLE16(saveFiles[z].level);
810
memcpy(&saveFiles[z].items, p, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType);
812
memcpy(&saveFiles[z].score, p, sizeof(JE_longint)); p += 4;
813
saveFiles[z].score = SDL_SwapLE32(saveFiles[z].score);
815
memcpy(&saveFiles[z].score2, p, sizeof(JE_longint)); p += 4;
816
saveFiles[z].score2 = SDL_SwapLE32(saveFiles[z].score2);
818
/* SYN: Pascal strings are prefixed by a byte holding the length! */
819
memset(&saveFiles[z].levelName, 0, sizeof(saveFiles[z].levelName));
820
memcpy(&saveFiles[z].levelName, &p[1], *p);
823
/* This was a BYTE array, not a STRING, in the original. Go fig. */
824
memcpy(&saveFiles[z].name, p, 14);
827
memcpy(&saveFiles[z].cubes, p, sizeof(JE_byte)); p++;
828
memcpy(&saveFiles[z].power, p, sizeof(JE_byte) * 2); p += 2;
829
memcpy(&saveFiles[z].episode, p, sizeof(JE_byte)); p++;
830
memcpy(&saveFiles[z].lastItems, p, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType);
831
memcpy(&saveFiles[z].difficulty, p, sizeof(JE_byte)); p++;
832
memcpy(&saveFiles[z].secretHint, p, sizeof(JE_byte)); p++;
833
memcpy(&saveFiles[z].input1, p, sizeof(JE_byte)); p++;
834
memcpy(&saveFiles[z].input2, p, sizeof(JE_byte)); p++;
836
/* booleans were 1 byte in pascal -- working around it */
838
memcpy(&temp, p, 1); p++;
839
saveFiles[z].gameHasRepeated = temp != 0;
841
memcpy(&saveFiles[z].initialDifficulty, p, sizeof(JE_byte)); p++;
843
memcpy(&saveFiles[z].highScore1, p, sizeof(JE_longint)); p += 4;
844
saveFiles[z].highScore1 = SDL_SwapLE32(saveFiles[z].highScore1);
846
memcpy(&saveFiles[z].highScore2, p, sizeof(JE_longint)); p += 4;
847
saveFiles[z].highScore2 = SDL_SwapLE32(saveFiles[z].highScore2);
849
memset(&saveFiles[z].highScoreName, 0, sizeof(saveFiles[z].highScoreName));
850
memcpy(&saveFiles[z].highScoreName, &p[1], *p);
853
memcpy(&saveFiles[z].highScoreDiff, p, sizeof(JE_byte)); p++;
856
/* SYN: This is truncating to bytes. I have no idea what this is doing or why. */
857
/* TODO: Figure out what this is about and make sure it isn't broked. */
858
editorLevel = (saveTemp[SIZEOF_SAVEGAMETEMP - 5] << 8) | saveTemp[SIZEOF_SAVEGAMETEMP - 6];
862
/* We didn't have a save file! Let's make up random stuff! */
865
for (z = 0; z < 100; z++)
867
saveTemp[SAVE_FILES_SIZE + z] = initialItemAvail[z];
870
for (z = 0; z < SAVE_FILES_NUM; z++)
872
saveFiles[z].level = 0;
874
for (y = 0; y < 14; y++)
876
saveFiles[z].name[y] = ' ';
878
saveFiles[z].name[14] = 0;
880
saveFiles[z].highScore1 = ((mt_rand() % 20) + 1) * 1000;
884
saveFiles[z].highScore2 = ((mt_rand() % 20) + 1) * 1000;
885
strcpy(saveFiles[z].highScoreName, defaultTeamNames[mt_rand() % 22]);
887
strcpy(saveFiles[z].highScoreName, defaultHighScoreNames[mt_rand() % 34]);
892
JE_initProcessorType();
895
void JE_saveConfiguration( void )
901
snprintf(dir, sizeof(dir), "%s/.opentyrian", getenv("HOME"));
911
for (z = 0; z < SAVE_FILES_NUM; z++)
913
JE_SaveFileType tempSaveFile;
914
memcpy(&tempSaveFile, &saveFiles[z], sizeof(tempSaveFile));
916
tempSaveFile.encode = SDL_SwapLE16(tempSaveFile.encode);
917
memcpy(p, &tempSaveFile.encode, sizeof(JE_word)); p += 2;
919
tempSaveFile.level = SDL_SwapLE16(tempSaveFile.level);
920
memcpy(p, &tempSaveFile.level, sizeof(JE_word)); p += 2;
922
memcpy(p, &tempSaveFile.items, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType);
924
tempSaveFile.score = SDL_SwapLE32(tempSaveFile.score);
925
memcpy(p, &tempSaveFile.score, sizeof(JE_longint)); p += 4;
927
tempSaveFile.score2 = SDL_SwapLE32(tempSaveFile.score2);
928
memcpy(p, &tempSaveFile.score2, sizeof(JE_longint)); p += 4;
930
/* SYN: Pascal strings are prefixed by a byte holding the length! */
931
memset(p, 0, sizeof(tempSaveFile.levelName));
932
*p = strlen(tempSaveFile.levelName);
933
memcpy(&p[1], &tempSaveFile.levelName, *p);
936
/* This was a BYTE array, not a STRING, in the original. Go fig. */
937
memcpy(p, &tempSaveFile.name, 14);
940
memcpy(p, &tempSaveFile.cubes, sizeof(JE_byte)); p++;
941
memcpy(p, &tempSaveFile.power, sizeof(JE_byte) * 2); p += 2;
942
memcpy(p, &tempSaveFile.episode, sizeof(JE_byte)); p++;
943
memcpy(p, &tempSaveFile.lastItems, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType);
944
memcpy(p, &tempSaveFile.difficulty, sizeof(JE_byte)); p++;
945
memcpy(p, &tempSaveFile.secretHint, sizeof(JE_byte)); p++;
946
memcpy(p, &tempSaveFile.input1, sizeof(JE_byte)); p++;
947
memcpy(p, &tempSaveFile.input2, sizeof(JE_byte)); p++;
949
/* booleans were 1 byte in pascal -- working around it */
950
Uint8 temp = tempSaveFile.gameHasRepeated != false;
951
memcpy(p, &temp, 1); p++;
953
memcpy(p, &tempSaveFile.initialDifficulty, sizeof(JE_byte)); p++;
955
tempSaveFile.highScore1 = SDL_SwapLE32(tempSaveFile.highScore1);
956
memcpy(p, &tempSaveFile.highScore1, sizeof(JE_longint)); p += 4;
958
tempSaveFile.highScore2 = SDL_SwapLE32(tempSaveFile.highScore2);
959
memcpy(p, &tempSaveFile.highScore2, sizeof(JE_longint)); p += 4;
961
memset(p, 0, sizeof(tempSaveFile.highScoreName));
962
*p = strlen(tempSaveFile.highScoreName);
963
memcpy(&p[1], &tempSaveFile.highScoreName, *p);
966
memcpy(p, &tempSaveFile.highScoreDiff, sizeof(JE_byte)); p++;
969
saveTemp[SIZEOF_SAVEGAMETEMP - 6] = editorLevel >> 8;
970
saveTemp[SIZEOF_SAVEGAMETEMP - 5] = editorLevel;
972
JE_encryptSaveTemp();
974
f = dir_fopen_warn(get_user_directory(), "tyrian.sav", "wb");
977
efwrite(saveTemp, 1, sizeof(saveTemp), f);
979
#if (_BSD_SOURCE || _XOPEN_SOURCE >= 500)
983
JE_decryptSaveTemp();
985
f = dir_fopen_warn(get_user_directory(), "tyrian.cfg", "wb");
988
efwrite(&background2, 1, 1, f);
989
efwrite(&gameSpeed, 1, 1, f);
991
efwrite(&inputDevice_, 1, 1, f);
992
efwrite(&jConfigure, 1, 1, f);
994
efwrite(&versionNum, 1, 1, f);
995
efwrite(&processorType, 1, 1, f);
996
efwrite(&midiPort, 1, 1, f);
997
efwrite(&soundEffects, 1, 1, f);
998
efwrite(&gammaCorrection, 1, 1, f);
999
efwrite(&difficultyLevel, 1, 1, f);
1000
efwrite(joyButtonAssign, 1, 4, f);
1002
efwrite(&tyrMusicVolume, 2, 1, f);
1003
efwrite(&fxVolume, 2, 1, f);
1005
efwrite(inputDevice, 1, 2, f);
1007
efwrite(keySettings, sizeof(*keySettings), COUNTOF(keySettings), f);
1012
save_opentyrian_config();
1014
#if (_BSD_SOURCE || _XOPEN_SOURCE >= 500)