~ubuntu-branches/debian/stretch/opentyrian/stretch

« back to all changes in this revision

Viewing changes to src/config.c

  • Committer: Package Import Robot
  • Author(s): Etienne Millon
  • Date: 2015-03-31 08:48:54 UTC
  • Revision ID: package-import@ubuntu.com-20150331084854-f5a4uoz7uv3vopk6
Tags: upstream-2.1.20130907+dfsg
ImportĀ upstreamĀ versionĀ 2.1.20130907+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * OpenTyrian: A modern cross-platform port of Tyrian
 
3
 * Copyright (C) 2007-2009  The OpenTyrian Development Team
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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.
 
18
 */
 
19
#include "config.h"
 
20
#include "episodes.h"
 
21
#include "file.h"
 
22
#include "joystick.h"
 
23
#include "loudness.h"
 
24
#include "mtrand.h"
 
25
#include "nortsong.h"
 
26
#include "opentyr.h"
 
27
#include "player.h"
 
28
#include "varz.h"
 
29
#include "vga256d.h"
 
30
#include "video.h"
 
31
#include "video_scale.h"
 
32
 
 
33
#include <unistd.h>
 
34
#include <sys/stat.h>
 
35
 
 
36
 
 
37
/* Configuration Load/Save handler */
 
38
 
 
39
const JE_byte cryptKey[10] = /* [1..10] */
 
40
{
 
41
        15, 50, 89, 240, 147, 34, 86, 9, 32, 208
 
42
};
 
43
 
 
44
const JE_KeySettingType defaultKeySettings =
 
45
{
 
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*/
 
48
};
 
49
 
 
50
const char defaultHighScoreNames[34][23] = /* [1..34] of string [22] */
 
51
{/*1P*/
 
52
/*TYR*/   "The Prime Chair", /*13*/
 
53
          "Transon Lohk",
 
54
          "Javi Onukala",
 
55
          "Mantori",
 
56
          "Nortaneous",
 
57
          "Dougan",
 
58
          "Reid",
 
59
          "General Zinglon",
 
60
          "Late Gyges Phildren",
 
61
          "Vykromod",
 
62
          "Beppo",
 
63
          "Borogar",
 
64
          "ShipMaster Carlos",
 
65
 
 
66
/*OTHER*/ "Jill", /*5*/
 
67
          "Darcy",
 
68
          "Jake Stone",
 
69
          "Malvineous Havershim",
 
70
          "Marta Louise Velasquez",
 
71
 
 
72
/*JAZZ*/  "Jazz Jackrabbit", /*3*/
 
73
          "Eva Earlong",
 
74
          "Devan Shell",
 
75
 
 
76
/*OMF*/   "Crystal Devroe", /*11*/
 
77
          "Steffan Tommas",
 
78
          "Milano Angston",
 
79
          "Christian",
 
80
          "Shirro",
 
81
          "Jean-Paul",
 
82
          "Ibrahim Hothe",
 
83
          "Angel",
 
84
          "Cossette Akira",
 
85
          "Raven",
 
86
          "Hans Kreissack",
 
87
 
 
88
/*DARE*/  "Tyler", /*2*/
 
89
          "Rennis the Rat Guard"
 
90
};
 
91
 
 
92
const char defaultTeamNames[22][25] = /* [1..22] of string [24] */
 
93
{
 
94
        "Jackrabbits",
 
95
        "Team Tyrian",
 
96
        "The Elam Brothers",
 
97
        "Dare to Dream Team",
 
98
        "Pinball Freaks",
 
99
        "Extreme Pinball Freaks",
 
100
        "Team Vykromod",
 
101
        "Epic All-Stars",
 
102
        "Hans Keissack's WARriors",
 
103
        "Team Overkill",
 
104
        "Pied Pipers",
 
105
        "Gencore Growlers",
 
106
        "Microsol Masters",
 
107
        "Beta Warriors",
 
108
        "Team Loco",
 
109
        "The Shellians",
 
110
        "Jungle Jills",
 
111
        "Murderous Malvineous",
 
112
        "The Traffic Department",
 
113
        "Clan Mikal",
 
114
        "Clan Patrok",
 
115
        "Carlos' Crawlers"
 
116
};
 
117
 
 
118
 
 
119
const JE_EditorItemAvailType initialItemAvail =
 
120
{
 
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 */
 
126
        0,0,0,0,0                                                                        /* Fill                     */
 
127
};
 
128
 
 
129
/* Last 2 bytes = Word
 
130
 *
 
131
 * Max Value = 1680
 
132
 * X div  60 = Armor  (1-28)
 
133
 * X div 168 = Shield (1-12)
 
134
 * X div 280 = Engine (1-06)
 
135
 */
 
136
 
 
137
 
 
138
JE_boolean smoothies[9] = /* [1..9] */
 
139
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
140
 
 
141
JE_byte starShowVGASpecialCode;
 
142
 
 
143
/* CubeData */
 
144
JE_word lastCubeMax, cubeMax;
 
145
JE_word cubeList[4]; /* [1..4] */
 
146
 
 
147
/* High-Score Stuff */
 
148
JE_boolean gameHasRepeated;  // can only get highscore on first play-through
 
149
 
 
150
/* Difficulty */
 
151
JE_shortint difficultyLevel, oldDifficultyLevel,
 
152
            initialDifficulty;  // can only get highscore on initial episode
 
153
 
 
154
/* Player Stuff */
 
155
uint    power, lastPower, powerAdd;
 
156
JE_byte shieldWait, shieldT;
 
157
 
 
158
JE_byte          shotRepeat[11], shotMultiPos[11];
 
159
JE_boolean       portConfigChange, portConfigDone;
 
160
 
 
161
/* Level Data */
 
162
char    lastLevelName[11], levelName[11]; /* string [10] */
 
163
JE_byte mainLevel, nextLevel, saveLevel;   /*Current Level #*/
 
164
 
 
165
/* Keyboard Junk */
 
166
JE_KeySettingType keySettings;
 
167
 
 
168
/* Configuration */
 
169
JE_shortint levelFilter, levelFilterNew, levelBrightness, levelBrightnessChg;
 
170
JE_boolean  filtrationAvail, filterActive, filterFade, filterFadeStart;
 
171
 
 
172
JE_boolean gameJustLoaded;
 
173
 
 
174
JE_boolean galagaMode;
 
175
 
 
176
JE_boolean extraGame;
 
177
 
 
178
JE_boolean twoPlayerMode, twoPlayerLinked, onePlayerAction, superTyrian;
 
179
JE_boolean trentWin = false;
 
180
JE_byte    superArcadeMode;
 
181
 
 
182
JE_byte    superArcadePowerUp;
 
183
 
 
184
JE_real linkGunDirec;
 
185
JE_byte inputDevice[2] = { 1, 2 }; // 0:any  1:keyboard  2:mouse  3+:joystick
 
186
 
 
187
JE_byte secretHint;
 
188
JE_byte background3over;
 
189
JE_byte background2over;
 
190
JE_byte gammaCorrection;
 
191
JE_boolean superPause = false;
 
192
JE_boolean explosionTransparent,
 
193
           youAreCheating,
 
194
           displayScore,
 
195
           background2, smoothScroll, wild, superWild, starActive,
 
196
           topEnemyOver,
 
197
           skyEnemyOverAll,
 
198
           background2notTransparent;
 
199
 
 
200
JE_byte soundEffects; // dummy value for config
 
201
JE_byte versionNum;   /* SW 1.0 and SW/Reg 1.1 = 0 or 1
 
202
                       * EA 1.2 = 2 */
 
203
 
 
204
JE_byte    fastPlay;
 
205
JE_boolean pentiumMode;
 
206
 
 
207
/* Savegame files */
 
208
JE_byte    gameSpeed;
 
209
JE_byte    processorType;  /* 1=386 2=486 3=Pentium Hyper */
 
210
 
 
211
JE_SaveFilesType saveFiles; /*array[1..saveLevelnum] of savefiletype;*/
 
212
JE_SaveGameTemp saveTemp;
 
213
 
 
214
JE_word editorLevel;   /*Initial value 800*/
 
215
 
 
216
 
 
217
cJSON *load_json( const char *filename )
 
218
{
 
219
        FILE *f = dir_fopen_warn(get_user_directory(), filename, "rb");
 
220
        if (f == NULL)
 
221
                return NULL;
 
222
        
 
223
        size_t buffer_len = ftell_eof(f);
 
224
        char *buffer = malloc(buffer_len + 1);
 
225
        
 
226
        fread(buffer, 1, buffer_len, f);
 
227
        buffer[buffer_len] = '\0';
 
228
        
 
229
        fclose(f);
 
230
        
 
231
        cJSON *root = cJSON_Parse(buffer);
 
232
        
 
233
        free(buffer);
 
234
        
 
235
        return root;
 
236
}
 
237
 
 
238
void save_json( cJSON *root, const char *filename )
 
239
{
 
240
        FILE *f = dir_fopen_warn(get_user_directory(), filename, "w+");
 
241
        if (f == NULL)
 
242
                return;
 
243
        
 
244
        char *buffer = cJSON_Print(root);
 
245
        
 
246
        if (buffer != NULL)
 
247
        {
 
248
                fputs(buffer, f);
 
249
                free(buffer);
 
250
        }
 
251
        
 
252
        fclose(f);
 
253
}
 
254
 
 
255
bool load_opentyrian_config( void )
 
256
{
 
257
        // defaults
 
258
        fullscreen_enabled = false;
 
259
        set_scaler_by_name("Scale2x");
 
260
        
 
261
        cJSON *root = load_json("opentyrian.conf");
 
262
        if (root == NULL)
 
263
                return false;
 
264
        
 
265
        cJSON *section = cJSON_GetObjectItem(root, "video");
 
266
        if (section != NULL)
 
267
        {
 
268
                cJSON *setting;
 
269
                
 
270
                if ((setting = cJSON_GetObjectItem(section, "fullscreen")))
 
271
                        fullscreen_enabled = (setting->type == cJSON_True);
 
272
                
 
273
                if ((setting = cJSON_GetObjectItem(section, "scaler")))
 
274
                        set_scaler_by_name(setting->valuestring);
 
275
        }
 
276
        
 
277
        cJSON_Delete(root);
 
278
        
 
279
        return true;
 
280
}
 
281
 
 
282
bool save_opentyrian_config( void )
 
283
{
 
284
        cJSON *root = load_json("opentyrian.conf");
 
285
        if (root == NULL)
 
286
                root = cJSON_CreateObject();
 
287
        
 
288
        cJSON *section;
 
289
        
 
290
        section = cJSON_CreateOrGetObjectItem(root, "video");
 
291
        cJSON_ForceType(section, cJSON_Object);
 
292
        
 
293
        {
 
294
                cJSON *setting;
 
295
                
 
296
                setting = cJSON_CreateOrGetObjectItem(section, "fullscreen");
 
297
                cJSON_SetBoolean(setting, fullscreen_enabled);
 
298
                
 
299
                setting = cJSON_CreateOrGetObjectItem(section, "scaler");
 
300
                cJSON_SetString(setting, scalers[scaler].name);
 
301
        }
 
302
        
 
303
        save_json(root, "opentyrian.conf");
 
304
        
 
305
        cJSON_Delete(root);
 
306
        
 
307
        return true;
 
308
}
 
309
 
 
310
static void playeritems_to_pitems( JE_PItemsType pItems, PlayerItems *items, JE_byte initial_episode_num )
 
311
{
 
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;
 
324
}
 
325
 
 
326
static void pitems_to_playeritems( PlayerItems *items, JE_PItemsType pItems, JE_byte *initial_episode_num )
 
327
{
 
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];
 
341
}
 
342
 
 
343
void JE_saveGame( JE_byte slot, const char *name )
 
344
{
 
345
        saveFiles[slot-1].initialDifficulty = initialDifficulty;
 
346
        saveFiles[slot-1].gameHasRepeated = gameHasRepeated;
 
347
        saveFiles[slot-1].level = saveLevel;
 
348
        
 
349
        if (superTyrian)
 
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;
 
353
        else
 
354
                player[0].items.super_arcade_mode = superArcadeMode;
 
355
        
 
356
        playeritems_to_pitems(saveFiles[slot-1].items, &player[0].items, initial_episode_num);
 
357
        
 
358
        if (twoPlayerMode)
 
359
                playeritems_to_pitems(saveFiles[slot-1].lastItems, &player[1].items, 0);
 
360
        else
 
361
                playeritems_to_pitems(saveFiles[slot-1].lastItems, &player[0].last_items, 0);
 
362
        
 
363
        saveFiles[slot-1].score  = player[0].cash;
 
364
        saveFiles[slot-1].score2 = player[1].cash;
 
365
        
 
366
        memcpy(&saveFiles[slot-1].levelName, &lastLevelName, sizeof(lastLevelName));
 
367
        saveFiles[slot-1].cubes  = lastCubeMax;
 
368
 
 
369
        if (strcmp(lastLevelName, "Completed") == 0)
 
370
        {
 
371
                temp = episodeNum - 1;
 
372
                if (temp < 1)
 
373
                {
 
374
                        temp = EPISODE_AVAILABLE; /* JE: {Episodemax is 4 for completion purposes} */
 
375
                }
 
376
                saveFiles[slot-1].episode = temp;
 
377
        }
 
378
        else
 
379
        {
 
380
                saveFiles[slot-1].episode = episodeNum;
 
381
        }
 
382
 
 
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];
 
387
 
 
388
        strcpy(saveFiles[slot-1].name, name);
 
389
        
 
390
        for (uint port = 0; port < 2; ++port)
 
391
        {
 
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;
 
394
        }
 
395
        
 
396
        JE_saveConfiguration();
 
397
}
 
398
 
 
399
void JE_loadGame( JE_byte slot )
 
400
{
 
401
        superTyrian = false;
 
402
        onePlayerAction = false;
 
403
        twoPlayerMode = false;
 
404
        extraGame = false;
 
405
        galagaMode = false;
 
406
 
 
407
        initialDifficulty = saveFiles[slot-1].initialDifficulty;
 
408
        gameHasRepeated   = saveFiles[slot-1].gameHasRepeated;
 
409
        twoPlayerMode     = (slot-1) > 10;
 
410
        difficultyLevel   = saveFiles[slot-1].difficulty;
 
411
        
 
412
        pitems_to_playeritems(&player[0].items, saveFiles[slot-1].items, &initial_episode_num);
 
413
        
 
414
        superArcadeMode = player[0].items.super_arcade_mode;
 
415
        
 
416
        if (superArcadeMode == SA_SUPERTYRIAN)
 
417
                superTyrian = true;
 
418
        if (superArcadeMode != SA_NONE)
 
419
                onePlayerAction = true;
 
420
        if (superArcadeMode > SA_NORTSHIPZ)
 
421
                superArcadeMode = SA_NONE;
 
422
        
 
423
        if (twoPlayerMode)
 
424
        {
 
425
                onePlayerAction = false;
 
426
                
 
427
                pitems_to_playeritems(&player[1].items, saveFiles[slot-1].lastItems, NULL);
 
428
        }
 
429
        else
 
430
        {
 
431
                pitems_to_playeritems(&player[0].last_items, saveFiles[slot-1].lastItems, NULL);
 
432
        }
 
433
 
 
434
        /* Compatibility with old version */
 
435
        if (player[1].items.sidekick_level < 101)
 
436
        {
 
437
                player[1].items.sidekick_level = 101;
 
438
                player[1].items.sidekick_series = player[1].items.sidekick[LEFT_SIDEKICK];
 
439
        }
 
440
        
 
441
        player[0].cash = saveFiles[slot-1].score;
 
442
        player[1].cash = saveFiles[slot-1].score2;
 
443
        
 
444
        mainLevel   = saveFiles[slot-1].level;
 
445
        cubeMax     = saveFiles[slot-1].cubes;
 
446
        lastCubeMax = cubeMax;
 
447
 
 
448
        secretHint = saveFiles[slot-1].secretHint;
 
449
        inputDevice[0] = saveFiles[slot-1].input1;
 
450
        inputDevice[1] = saveFiles[slot-1].input2;
 
451
 
 
452
        for (uint port = 0; port < 2; ++port)
 
453
        {
 
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];
 
456
        }
 
457
        
 
458
        int episode = saveFiles[slot-1].episode;
 
459
 
 
460
        memcpy(&levelName, &saveFiles[slot-1].levelName, sizeof(levelName));
 
461
 
 
462
        if (strcmp(levelName, "Completed") == 0)
 
463
        {
 
464
                if (episode == EPISODE_AVAILABLE)
 
465
                {
 
466
                        episode = 1;
 
467
                } else if (episode < EPISODE_AVAILABLE) {
 
468
                        episode++;
 
469
                }
 
470
                /* Increment episode.  Episode EPISODE_AVAILABLE goes to 1. */
 
471
        }
 
472
 
 
473
        JE_initEpisode(episode);
 
474
        saveLevel = mainLevel;
 
475
        memcpy(&lastLevelName, &levelName, sizeof(levelName));
 
476
}
 
477
 
 
478
void JE_initProcessorType( void )
 
479
{
 
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. */
 
482
 
 
483
        wild = false;
 
484
        superWild = false;
 
485
        smoothScroll = true;
 
486
        explosionTransparent = true;
 
487
        filtrationAvail = false;
 
488
        background2 = true;
 
489
        displayScore = true;
 
490
 
 
491
        switch (processorType)
 
492
        {
 
493
                case 1: /* 386 */
 
494
                        background2 = false;
 
495
                        displayScore = false;
 
496
                        explosionTransparent = false;
 
497
                        break;
 
498
                case 2: /* 486 - Default */
 
499
                        break;
 
500
                case 3: /* High Detail */
 
501
                        smoothScroll = false;
 
502
                        break;
 
503
                case 4: /* Pentium */
 
504
                        wild = true;
 
505
                        filtrationAvail = true;
 
506
                        break;
 
507
                case 5: /* Nonstandard VGA */
 
508
                        smoothScroll = false;
 
509
                        break;
 
510
                case 6: /* SuperWild */
 
511
                        wild = true;
 
512
                        superWild = true;
 
513
                        filtrationAvail = true;
 
514
                        break;
 
515
        }
 
516
 
 
517
        switch (gameSpeed)
 
518
        {
 
519
                case 1:  /* Slug Mode */
 
520
                        fastPlay = 3;
 
521
                        break;
 
522
                case 2:  /* Slower */
 
523
                        fastPlay = 4;
 
524
                        break;
 
525
                case 3: /* Slow */
 
526
                        fastPlay = 5;
 
527
                        break;
 
528
                case 4: /* Normal */
 
529
                        fastPlay = 0;
 
530
                        break;
 
531
                case 5: /* Pentium Hyper */
 
532
                        fastPlay = 1;
 
533
                        break;
 
534
        }
 
535
 
 
536
}
 
537
 
 
538
void JE_setNewGameSpeed( void )
 
539
{
 
540
        pentiumMode = false;
 
541
 
 
542
        switch (fastPlay)
 
543
        {
 
544
        case 0:
 
545
                speed = 0x4300;
 
546
                smoothScroll = true;
 
547
                frameCountMax = 2;
 
548
                break;
 
549
        case 1:
 
550
                speed = 0x3000;
 
551
                smoothScroll = true;
 
552
                frameCountMax = 2;
 
553
                break;
 
554
        case 2:
 
555
                speed = 0x2000;
 
556
                smoothScroll = false;
 
557
                frameCountMax = 2;
 
558
                break;
 
559
        case 3:
 
560
                speed = 0x5300;
 
561
                smoothScroll = true;
 
562
                frameCountMax = 4;
 
563
                break;
 
564
        case 4:
 
565
                speed = 0x4300;
 
566
                smoothScroll = true;
 
567
                frameCountMax = 3;
 
568
                break;
 
569
        case 5:
 
570
                speed = 0x4300;
 
571
                smoothScroll = true;
 
572
                frameCountMax = 2;
 
573
                pentiumMode = true;
 
574
                break;
 
575
        }
 
576
 
 
577
  frameCount = frameCountMax;
 
578
  JE_resetTimerInt();
 
579
  JE_setTimerInt();
 
580
}
 
581
 
 
582
void JE_encryptSaveTemp( void )
 
583
{
 
584
        JE_SaveGameTemp s3;
 
585
        JE_word x;
 
586
        JE_byte y;
 
587
 
 
588
        memcpy(&s3, &saveTemp, sizeof(s3));
 
589
 
 
590
        y = 0;
 
591
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
592
        {
 
593
                y += s3[x];
 
594
        }
 
595
        saveTemp[SAVE_FILE_SIZE] = y;
 
596
 
 
597
        y = 0;
 
598
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
599
        {
 
600
                y -= s3[x];
 
601
        }
 
602
        saveTemp[SAVE_FILE_SIZE+1] = y;
 
603
 
 
604
        y = 1;
 
605
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
606
        {
 
607
                y = (y * s3[x]) + 1;
 
608
        }
 
609
        saveTemp[SAVE_FILE_SIZE+2] = y;
 
610
 
 
611
        y = 0;
 
612
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
613
        {
 
614
                y = y ^ s3[x];
 
615
        }
 
616
        saveTemp[SAVE_FILE_SIZE+3] = y;
 
617
 
 
618
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
619
        {
 
620
                saveTemp[x] = saveTemp[x] ^ cryptKey[(x+1) % 10];
 
621
                if (x > 0)
 
622
                {
 
623
                        saveTemp[x] = saveTemp[x] ^ saveTemp[x - 1];
 
624
                }
 
625
        }
 
626
}
 
627
 
 
628
void JE_decryptSaveTemp( void )
 
629
{
 
630
        JE_boolean correct = true;
 
631
        JE_SaveGameTemp s2;
 
632
        int x;
 
633
        JE_byte y;
 
634
 
 
635
        /* Decrypt save game file */
 
636
        for (x = (SAVE_FILE_SIZE - 1); x >= 0; x--)
 
637
        {
 
638
                s2[x] = (JE_byte)saveTemp[x] ^ (JE_byte)(cryptKey[(x+1) % 10]);
 
639
                if (x > 0)
 
640
                {
 
641
                        s2[x] ^= (JE_byte)saveTemp[x - 1];
 
642
                }
 
643
 
 
644
        }
 
645
 
 
646
        /* for (x = 0; x < SAVE_FILE_SIZE; x++) printf("%c", s2[x]); */
 
647
 
 
648
        /* Check save file for correctitude */
 
649
        y = 0;
 
650
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
651
        {
 
652
                y += s2[x];
 
653
        }
 
654
        if (saveTemp[SAVE_FILE_SIZE] != y)
 
655
        {
 
656
                correct = false;
 
657
                printf("Failed additive checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE], y);
 
658
        }
 
659
 
 
660
        y = 0;
 
661
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
662
        {
 
663
                y -= s2[x];
 
664
        }
 
665
        if (saveTemp[SAVE_FILE_SIZE+1] != y)
 
666
        {
 
667
                correct = false;
 
668
                printf("Failed subtractive checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+1], y);
 
669
        }
 
670
 
 
671
        y = 1;
 
672
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
673
        {
 
674
                y = (y * s2[x]) + 1;
 
675
        }
 
676
        if (saveTemp[SAVE_FILE_SIZE+2] != y)
 
677
        {
 
678
                correct = false;
 
679
                printf("Failed multiplicative checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+2], y);
 
680
        }
 
681
 
 
682
        y = 0;
 
683
        for (x = 0; x < SAVE_FILE_SIZE; x++)
 
684
        {
 
685
                y = y ^ s2[x];
 
686
        }
 
687
        if (saveTemp[SAVE_FILE_SIZE+3] != y)
 
688
        {
 
689
                correct = false;
 
690
                printf("Failed XOR'd checksum: %d vs %d\n", saveTemp[SAVE_FILE_SIZE+3], y);
 
691
        }
 
692
 
 
693
        /* Barf and die if save file doesn't validate */
 
694
        if (!correct)
 
695
        {
 
696
                fprintf(stderr, "Error reading save file!\n");
 
697
                exit(255);
 
698
        }
 
699
 
 
700
        /* Keep decrypted version plz */
 
701
        memcpy(&saveTemp, &s2, sizeof(s2));
 
702
}
 
703
 
 
704
#ifndef TARGET_MACOSX
 
705
const char *get_user_directory( void )
 
706
{
 
707
        static char user_dir[500] = "";
 
708
        
 
709
        if (strlen(user_dir) == 0)
 
710
        {
 
711
#ifdef TARGET_UNIX
 
712
                if (getenv("HOME"))
 
713
                        snprintf(user_dir, sizeof(user_dir), "%s/.opentyrian", getenv("HOME"));
 
714
#else
 
715
                strcpy(user_dir, ".");
 
716
#endif // TARGET_UNIX
 
717
        }
 
718
        
 
719
        return user_dir;
 
720
}
 
721
#endif // TARGET_MACOSX
 
722
 
 
723
// for compatibility
 
724
Uint8 joyButtonAssign[4] = {1, 4, 5, 5};
 
725
Uint8 inputDevice_ = 0, jConfigure = 0, midiPort = 1;
 
726
 
 
727
void JE_loadConfiguration( void )
 
728
{
 
729
        FILE *fi;
 
730
        int z;
 
731
        JE_byte *p;
 
732
        int y;
 
733
        
 
734
        fi = dir_fopen_warn(get_user_directory(), "tyrian.cfg", "rb");
 
735
        if (fi && ftell_eof(fi) == 20 + sizeof(keySettings))
 
736
        {
 
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. */
 
739
                background2 = 0;
 
740
                efread(&background2, 1, 1, fi);
 
741
                efread(&gameSpeed, 1, 1, fi);
 
742
                
 
743
                efread(&inputDevice_, 1, 1, fi);
 
744
                efread(&jConfigure, 1, 1, fi);
 
745
                
 
746
                efread(&versionNum, 1, 1, fi);
 
747
                
 
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);
 
753
                
 
754
                efread(joyButtonAssign, 1, 4, fi);
 
755
                
 
756
                efread(&tyrMusicVolume, 2, 1, fi);
 
757
                efread(&fxVolume, 2, 1, fi);
 
758
                
 
759
                efread(inputDevice, 1, 2, fi);
 
760
                
 
761
                efread(keySettings, sizeof(*keySettings), COUNTOF(keySettings), fi);
 
762
                
 
763
                fclose(fi);
 
764
        }
 
765
        else
 
766
        {
 
767
                printf("\nInvalid or missing TYRIAN.CFG! Continuing using defaults.\n\n");
 
768
                
 
769
                soundEffects = 1;
 
770
                memcpy(&keySettings, &defaultKeySettings, sizeof(keySettings));
 
771
                background2 = true;
 
772
                tyrMusicVolume = fxVolume = 128;
 
773
                gammaCorrection = 0;
 
774
                processorType = 3;
 
775
                gameSpeed = 4;
 
776
        }
 
777
        
 
778
        load_opentyrian_config();
 
779
        
 
780
        if (tyrMusicVolume > 255)
 
781
                tyrMusicVolume = 255;
 
782
        if (fxVolume > 255)
 
783
                fxVolume = 255;
 
784
        
 
785
        JE_calcFXVol();
 
786
        
 
787
        set_volume(tyrMusicVolume, fxVolume);
 
788
        
 
789
        fi = dir_fopen_warn(get_user_directory(), "tyrian.sav", "rb");
 
790
        if (fi)
 
791
        {
 
792
 
 
793
                fseek(fi, 0, SEEK_SET);
 
794
                efread(saveTemp, 1, sizeof(saveTemp), fi);
 
795
                JE_decryptSaveTemp();
 
796
 
 
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* :'( */
 
800
 
 
801
                p = saveTemp;
 
802
                for (z = 0; z < SAVE_FILES_NUM; z++)
 
803
                {
 
804
                        memcpy(&saveFiles[z].encode, p, sizeof(JE_word)); p += 2;
 
805
                        saveFiles[z].encode = SDL_SwapLE16(saveFiles[z].encode);
 
806
                        
 
807
                        memcpy(&saveFiles[z].level, p, sizeof(JE_word)); p += 2;
 
808
                        saveFiles[z].level = SDL_SwapLE16(saveFiles[z].level);
 
809
                        
 
810
                        memcpy(&saveFiles[z].items, p, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType);
 
811
                        
 
812
                        memcpy(&saveFiles[z].score, p, sizeof(JE_longint)); p += 4;
 
813
                        saveFiles[z].score = SDL_SwapLE32(saveFiles[z].score);
 
814
                        
 
815
                        memcpy(&saveFiles[z].score2, p, sizeof(JE_longint)); p += 4;
 
816
                        saveFiles[z].score2 = SDL_SwapLE32(saveFiles[z].score2);
 
817
                        
 
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);
 
821
                        p += 10;
 
822
                        
 
823
                        /* This was a BYTE array, not a STRING, in the original. Go fig. */
 
824
                        memcpy(&saveFiles[z].name, p, 14);
 
825
                        p += 14;
 
826
                        
 
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++;
 
835
                        
 
836
                        /* booleans were 1 byte in pascal -- working around it */
 
837
                        Uint8 temp;
 
838
                        memcpy(&temp, p, 1); p++;
 
839
                        saveFiles[z].gameHasRepeated = temp != 0;
 
840
                        
 
841
                        memcpy(&saveFiles[z].initialDifficulty, p, sizeof(JE_byte)); p++;
 
842
                        
 
843
                        memcpy(&saveFiles[z].highScore1, p, sizeof(JE_longint)); p += 4;
 
844
                        saveFiles[z].highScore1 = SDL_SwapLE32(saveFiles[z].highScore1);
 
845
                        
 
846
                        memcpy(&saveFiles[z].highScore2, p, sizeof(JE_longint)); p += 4;
 
847
                        saveFiles[z].highScore2 = SDL_SwapLE32(saveFiles[z].highScore2);
 
848
                        
 
849
                        memset(&saveFiles[z].highScoreName, 0, sizeof(saveFiles[z].highScoreName));
 
850
                        memcpy(&saveFiles[z].highScoreName, &p[1], *p);
 
851
                        p += 30;
 
852
                        
 
853
                        memcpy(&saveFiles[z].highScoreDiff, p, sizeof(JE_byte)); p++;
 
854
                }
 
855
 
 
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];
 
859
 
 
860
                fclose(fi);
 
861
        } else {
 
862
                /* We didn't have a save file! Let's make up random stuff! */
 
863
                editorLevel = 800;
 
864
 
 
865
                for (z = 0; z < 100; z++)
 
866
                {
 
867
                        saveTemp[SAVE_FILES_SIZE + z] = initialItemAvail[z];
 
868
                }
 
869
 
 
870
                for (z = 0; z < SAVE_FILES_NUM; z++)
 
871
                {
 
872
                        saveFiles[z].level = 0;
 
873
 
 
874
                        for (y = 0; y < 14; y++)
 
875
                        {
 
876
                                saveFiles[z].name[y] = ' ';
 
877
                        }
 
878
                        saveFiles[z].name[14] = 0;
 
879
 
 
880
                        saveFiles[z].highScore1 = ((mt_rand() % 20) + 1) * 1000;
 
881
 
 
882
                        if (z % 6 > 2)
 
883
                        {
 
884
                                saveFiles[z].highScore2 = ((mt_rand() % 20) + 1) * 1000;
 
885
                                strcpy(saveFiles[z].highScoreName, defaultTeamNames[mt_rand() % 22]);
 
886
                        } else {
 
887
                                strcpy(saveFiles[z].highScoreName, defaultHighScoreNames[mt_rand() % 34]);
 
888
                        }
 
889
                }
 
890
        }
 
891
        
 
892
        JE_initProcessorType();
 
893
}
 
894
 
 
895
void JE_saveConfiguration( void )
 
896
{
 
897
#ifdef TARGET_UNIX
 
898
        if (getenv("HOME"))
 
899
        {
 
900
                char dir[1000];
 
901
                snprintf(dir, sizeof(dir), "%s/.opentyrian", getenv("HOME"));
 
902
                mkdir(dir, 0755);
 
903
        }
 
904
#endif /* HOME */
 
905
        
 
906
        FILE *f;
 
907
        JE_byte *p;
 
908
        int z;
 
909
 
 
910
        p = saveTemp;
 
911
        for (z = 0; z < SAVE_FILES_NUM; z++)
 
912
        {
 
913
                JE_SaveFileType tempSaveFile;
 
914
                memcpy(&tempSaveFile, &saveFiles[z], sizeof(tempSaveFile));
 
915
                
 
916
                tempSaveFile.encode = SDL_SwapLE16(tempSaveFile.encode);
 
917
                memcpy(p, &tempSaveFile.encode, sizeof(JE_word)); p += 2;
 
918
                
 
919
                tempSaveFile.level = SDL_SwapLE16(tempSaveFile.level);
 
920
                memcpy(p, &tempSaveFile.level, sizeof(JE_word)); p += 2;
 
921
                
 
922
                memcpy(p, &tempSaveFile.items, sizeof(JE_PItemsType)); p += sizeof(JE_PItemsType);
 
923
                
 
924
                tempSaveFile.score = SDL_SwapLE32(tempSaveFile.score);
 
925
                memcpy(p, &tempSaveFile.score, sizeof(JE_longint)); p += 4;
 
926
                
 
927
                tempSaveFile.score2 = SDL_SwapLE32(tempSaveFile.score2);
 
928
                memcpy(p, &tempSaveFile.score2, sizeof(JE_longint)); p += 4;
 
929
                
 
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);
 
934
                p += 10;
 
935
                
 
936
                /* This was a BYTE array, not a STRING, in the original. Go fig. */
 
937
                memcpy(p, &tempSaveFile.name, 14);
 
938
                p += 14;
 
939
                
 
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++;
 
948
                
 
949
                /* booleans were 1 byte in pascal -- working around it */
 
950
                Uint8 temp = tempSaveFile.gameHasRepeated != false;
 
951
                memcpy(p, &temp, 1); p++;
 
952
                
 
953
                memcpy(p, &tempSaveFile.initialDifficulty, sizeof(JE_byte)); p++;
 
954
                
 
955
                tempSaveFile.highScore1 = SDL_SwapLE32(tempSaveFile.highScore1);
 
956
                memcpy(p, &tempSaveFile.highScore1, sizeof(JE_longint)); p += 4;
 
957
                
 
958
                tempSaveFile.highScore2 = SDL_SwapLE32(tempSaveFile.highScore2);
 
959
                memcpy(p, &tempSaveFile.highScore2, sizeof(JE_longint)); p += 4;
 
960
                
 
961
                memset(p, 0, sizeof(tempSaveFile.highScoreName));
 
962
                *p = strlen(tempSaveFile.highScoreName);
 
963
                memcpy(&p[1], &tempSaveFile.highScoreName, *p);
 
964
                p += 30;
 
965
                
 
966
                memcpy(p, &tempSaveFile.highScoreDiff, sizeof(JE_byte)); p++;
 
967
        }
 
968
        
 
969
        saveTemp[SIZEOF_SAVEGAMETEMP - 6] = editorLevel >> 8;
 
970
        saveTemp[SIZEOF_SAVEGAMETEMP - 5] = editorLevel;
 
971
        
 
972
        JE_encryptSaveTemp();
 
973
        
 
974
        f = dir_fopen_warn(get_user_directory(), "tyrian.sav", "wb");
 
975
        if (f)
 
976
        {
 
977
                efwrite(saveTemp, 1, sizeof(saveTemp), f);
 
978
                fclose(f);
 
979
#if (_BSD_SOURCE || _XOPEN_SOURCE >= 500)
 
980
                sync();
 
981
#endif
 
982
        }
 
983
        JE_decryptSaveTemp();
 
984
        
 
985
        f = dir_fopen_warn(get_user_directory(), "tyrian.cfg", "wb");
 
986
        if (f)
 
987
        {
 
988
                efwrite(&background2, 1, 1, f);
 
989
                efwrite(&gameSpeed, 1, 1, f);
 
990
                
 
991
                efwrite(&inputDevice_, 1, 1, f);
 
992
                efwrite(&jConfigure, 1, 1, f);
 
993
                
 
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);
 
1001
                
 
1002
                efwrite(&tyrMusicVolume, 2, 1, f);
 
1003
                efwrite(&fxVolume, 2, 1, f);
 
1004
                
 
1005
                efwrite(inputDevice, 1, 2, f);
 
1006
                
 
1007
                efwrite(keySettings, sizeof(*keySettings), COUNTOF(keySettings), f);
 
1008
                
 
1009
                fclose(f);
 
1010
        }
 
1011
        
 
1012
        save_opentyrian_config();
 
1013
        
 
1014
#if (_BSD_SOURCE || _XOPEN_SOURCE >= 500)
 
1015
        sync();
 
1016
#endif
 
1017
}
 
1018