mirror of
https://git.zap.org.au/git/trader.git
synced 2024-11-03 17:27:29 -05:00
Move game_load() and game_save() functions to their own source file
This commit is contained in:
parent
36c9a57db0
commit
dd40b94301
@ -33,6 +33,7 @@ trader_SOURCES = \
|
||||
trader.c trader.h \
|
||||
globals.c globals.h \
|
||||
game.c game.h \
|
||||
fileio.c fileio.h \
|
||||
help.c help.h \
|
||||
intf.c intf.h \
|
||||
utils.c utils.h \
|
||||
|
@ -12,9 +12,11 @@ source code is split up among the following files:
|
||||
trader.c - Main program, command-line interface
|
||||
system.h - All system header files are included here
|
||||
globals.h - Global game constants and variables
|
||||
globals.c - Global game variables
|
||||
game.h - Game functions header file
|
||||
game.c - Game functions for Star Traders
|
||||
globals.c - Global game variable definitions
|
||||
game.h - Game starting and ending routines header file
|
||||
game.c - Game starting and ending routines for Star Traders
|
||||
fileio.h - Load and save game file routines header file
|
||||
fileio.c - Load and save game file routines
|
||||
help.h - Help text routines header file
|
||||
help.c - Help text routines: how to play Star Traders
|
||||
intf.h - Basic text input/output header file
|
||||
|
441
src/fileio.c
Normal file
441
src/fileio.c
Normal file
@ -0,0 +1,441 @@
|
||||
/************************************************************************
|
||||
* *
|
||||
* Star Traders: A Game of Interstellar Trading *
|
||||
* Copyright (C) 1990-2011, John Zaitseff *
|
||||
* *
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
Author: John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
$Id$
|
||||
|
||||
This file, fileio.c, contains the implementation of the game load and
|
||||
save functions used in Star Traders.
|
||||
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
|
||||
#include "trader.h"
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module constants and macros *
|
||||
************************************************************************/
|
||||
|
||||
// Game loading and saving constants
|
||||
|
||||
static const int game_file_crypt_key[] = {
|
||||
0x50, 0x52, 0x55, 0x59, 0x5A, 0x5C, 0x5F,
|
||||
0x90, 0x92, 0x95, 0x99, 0x9A, 0x9C, 0x9F,
|
||||
0xA0, 0xA2, 0xA5, 0xA9, 0xAA, 0xAC, 0xAF,
|
||||
0xD0, 0xD2, 0xD5, 0xD9, 0xDA, 0xDC, 0xDF
|
||||
};
|
||||
|
||||
#define GAME_FILE_CRYPT_KEY_SIZE (sizeof(game_file_crypt_key) / sizeof(int))
|
||||
|
||||
|
||||
// Macros used in load_game()
|
||||
|
||||
#define load_game_scanf(_fmt, _var, _cond) \
|
||||
do { \
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) { \
|
||||
err_exit("%s: missing field on line %d", filename, lineno); \
|
||||
} \
|
||||
if (sscanf(unscramble(crypt_key, buf, BUFSIZE), _fmt "\n", \
|
||||
&(_var)) != 1) { \
|
||||
err_exit("%s: illegal field on line %d: `%s'", \
|
||||
filename, lineno, buf); \
|
||||
} \
|
||||
if (! (_cond)) { \
|
||||
err_exit("%s: illegal value on line %d: `%s'", \
|
||||
filename, lineno, buf); \
|
||||
} \
|
||||
lineno++; \
|
||||
} while (0)
|
||||
|
||||
#define load_game_read_int(_var, _cond) \
|
||||
load_game_scanf("%d", _var, _cond)
|
||||
#define load_game_read_long(_var, _cond) \
|
||||
load_game_scanf("%ld", _var, _cond)
|
||||
#define load_game_read_double(_var, _cond) \
|
||||
load_game_scanf("%lf", _var, _cond)
|
||||
|
||||
#define load_game_read_bool(_var) \
|
||||
do { \
|
||||
int b; \
|
||||
\
|
||||
load_game_scanf("%d", b, (b == false) || (b == true)); \
|
||||
(_var) = b; \
|
||||
} while (0)
|
||||
|
||||
#define load_game_read_string(_var) \
|
||||
do { \
|
||||
char *s; \
|
||||
int len; \
|
||||
\
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) { \
|
||||
err_exit("%s: missing field on line %d", filename, lineno); \
|
||||
} \
|
||||
if (strlen(unscramble(crypt_key, buf, BUFSIZE)) == 0) { \
|
||||
err_exit("%s: illegal value on line %d", filename, lineno); \
|
||||
} \
|
||||
lineno++; \
|
||||
\
|
||||
s = malloc(strlen(buf) + 1); \
|
||||
if (s == NULL) { \
|
||||
err_exit("out of memory"); \
|
||||
} \
|
||||
\
|
||||
strcpy(s, buf); \
|
||||
len = strlen(s); \
|
||||
if (len > 0 && s[len - 1] == '\n') { \
|
||||
s[len - 1] = '\0'; \
|
||||
} \
|
||||
\
|
||||
(_var) = s; \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Macros used in save_game()
|
||||
|
||||
#define save_game_printf(_fmt, _var) \
|
||||
do { \
|
||||
snprintf(buf, BUFSIZE, _fmt "\n", _var); \
|
||||
scramble(crypt_key, buf, BUFSIZE); \
|
||||
fprintf(file, "%s", buf); \
|
||||
} while (0)
|
||||
|
||||
#define save_game_write_int(_var) \
|
||||
save_game_printf("%d", _var)
|
||||
#define save_game_write_long(_var) \
|
||||
save_game_printf("%ld", _var)
|
||||
#define save_game_write_double(_var) \
|
||||
save_game_printf("%2.20e", _var)
|
||||
#define save_game_write_bool(_var) \
|
||||
save_game_printf("%d", (int) _var)
|
||||
#define save_game_write_string(_var) \
|
||||
save_game_printf("%s", _var)
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Game load and save function definitions *
|
||||
************************************************************************/
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Function: load_game - Load a saved game from disk
|
||||
Arguments: num - Game number to load (1-9)
|
||||
Returns: bool - True if game loaded successfully, else false
|
||||
|
||||
This function loads a previously-saved game from disk. True is
|
||||
returned if this could be done successfully.
|
||||
*/
|
||||
|
||||
bool load_game (int num)
|
||||
{
|
||||
char *buf, *filename;
|
||||
FILE *file;
|
||||
int saved_errno, lineno;
|
||||
|
||||
int crypt_key;
|
||||
int n, i, j, x, y;
|
||||
char c;
|
||||
|
||||
|
||||
assert((num >= 1) && (num <= 9));
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit("out of memory");
|
||||
}
|
||||
|
||||
filename = game_filename(num);
|
||||
assert(filename != NULL);
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
// File could not be opened
|
||||
|
||||
if (errno == ENOENT) {
|
||||
// File not found
|
||||
newtxwin(7, 40, LINE_OFFSET + 9, COL_CENTER(40));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Found ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d has not been saved to disk", num);
|
||||
|
||||
wait_for_key(curwin, 5, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
} else {
|
||||
// Some other file error
|
||||
saved_errno = errno;
|
||||
|
||||
newtxwin(9, 70, LINE_OFFSET + 9, COL_CENTER(70));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Loaded ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d could not be loaded from disk", num);
|
||||
center(curwin, 5, ATTR_ERROR_WINDOW, "File %s: %s", filename,
|
||||
strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the game file header
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing header in game file", filename);
|
||||
}
|
||||
if (strcmp(buf, GAME_FILE_HEADER "\n") != 0) {
|
||||
err_exit("%s: not a valid game file", filename);
|
||||
}
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing subheader in game file", filename);
|
||||
}
|
||||
if (strcmp(buf, GAME_FILE_API_VERSION "\n") != 0) {
|
||||
err_exit("%s: saved under a different version of Star Traders",
|
||||
filename);
|
||||
}
|
||||
|
||||
lineno = 3;
|
||||
|
||||
// Read in the game file encryption key
|
||||
if (fscanf(file, "%i\n", &crypt_key) != 1) {
|
||||
err_exit("%s: illegal or missing field on line %d", filename, lineno);
|
||||
}
|
||||
lineno++;
|
||||
|
||||
// Read in various game variables
|
||||
load_game_read_int(n, n == MAX_X);
|
||||
load_game_read_int(n, n == MAX_Y);
|
||||
load_game_read_int(max_turn, max_turn >= 1);
|
||||
load_game_read_int(turn_number, (turn_number >= 1) && (turn_number <= max_turn));
|
||||
load_game_read_int(number_players, (number_players >= 1) && (number_players < MAX_PLAYERS));
|
||||
load_game_read_int(current_player, (current_player >= 0) && (current_player < number_players));
|
||||
load_game_read_int(first_player, (first_player >= 0) && (first_player < number_players));
|
||||
load_game_read_int(n, n == MAX_COMPANIES);
|
||||
load_game_read_double(interest_rate, interest_rate > 0.0);
|
||||
|
||||
// Read in player data
|
||||
for (i = 0; i < number_players; i++) {
|
||||
load_game_read_string(player[i].name);
|
||||
load_game_read_double(player[i].cash, player[i].cash >= 0.0);
|
||||
load_game_read_double(player[i].debt, player[i].debt >= 0.0);
|
||||
load_game_read_bool(player[i].in_game);
|
||||
|
||||
for (j = 0; j < MAX_COMPANIES; j++) {
|
||||
load_game_read_long(player[i].stock_owned[j], player[i].stock_owned[j] >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Read in company data
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
company[i].name = company_name[i];
|
||||
load_game_read_double(company[i].share_price, company[i].share_price > 0.0);
|
||||
load_game_read_double(company[i].share_return, true);
|
||||
load_game_read_long(company[i].stock_issued, company[i].stock_issued >= 0);
|
||||
load_game_read_long(company[i].max_stock, company[i].max_stock >= 0);
|
||||
load_game_read_bool(company[i].on_map);
|
||||
}
|
||||
|
||||
// Read in galaxy map
|
||||
for (x = 0; x < MAX_X; x++) {
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing field on line %d", filename, lineno);
|
||||
}
|
||||
if (strlen(unscramble(crypt_key, buf, BUFSIZE)) != (MAX_Y + 1)) {
|
||||
err_exit("%s: illegal field on line %d", filename, lineno);
|
||||
}
|
||||
lineno++;
|
||||
|
||||
for (y = 0; y < MAX_Y; y++) {
|
||||
c = buf[y];
|
||||
if ((c == MAP_EMPTY) || (c == MAP_OUTPOST) || (c == MAP_STAR) ||
|
||||
((c >= MAP_A) && (c <= MAP_LAST))) {
|
||||
galaxy_map[x][y] = (map_val_t) c;
|
||||
} else {
|
||||
err_exit("%s: illegal value on line %d", filename, lineno - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read in a dummy sentinal value
|
||||
load_game_read_int(n, n == GAME_FILE_SENTINEL);
|
||||
|
||||
if (fclose(file) == EOF) {
|
||||
errno_exit("%s", filename);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Function: save_game - Save the current game to disk
|
||||
Arguments: num - Game number to use (1-9)
|
||||
Returns: bool - True if game saved successfully, else false
|
||||
|
||||
This function saves the current game to disk. True is returned if this
|
||||
could be done successfully.
|
||||
*/
|
||||
|
||||
bool save_game (int num)
|
||||
{
|
||||
const char *data_dir;
|
||||
char *buf, *filename;
|
||||
FILE *file;
|
||||
int saved_errno;
|
||||
struct stat statbuf;
|
||||
int crypt_key;
|
||||
int i, j, x, y;
|
||||
char *p;
|
||||
|
||||
|
||||
assert((num >= 1) && (num <= 9));
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit("out of memory");
|
||||
}
|
||||
|
||||
crypt_key = game_file_crypt_key[randi(GAME_FILE_CRYPT_KEY_SIZE)];
|
||||
|
||||
// Create the data directory, if needed
|
||||
data_dir = data_directory();
|
||||
if (data_dir != NULL) {
|
||||
if (mkdir(data_dir, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
|
||||
saved_errno = errno;
|
||||
if ((saved_errno == EEXIST) && (stat(data_dir, &statbuf) == 0)
|
||||
&& S_ISDIR(statbuf.st_mode)) {
|
||||
; // Do nothing: directory already exists
|
||||
} else {
|
||||
// Data directory could not be created
|
||||
|
||||
newtxwin(9, 70, LINE_OFFSET + 9, COL_CENTER(70));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Saved ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d could not be saved to disk", num);
|
||||
center(curwin, 5, ATTR_ERROR_WINDOW, "Directory %s: %s",
|
||||
data_dir, strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filename = game_filename(num);
|
||||
assert(filename != NULL);
|
||||
|
||||
file = fopen(filename, "w");
|
||||
if (file == NULL) {
|
||||
// File could not be opened for writing
|
||||
saved_errno = errno;
|
||||
|
||||
newtxwin(9, 70, LINE_OFFSET + 9, COL_CENTER(70));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Saved ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d could not be saved to disk", num);
|
||||
center(curwin, 5, ATTR_ERROR_WINDOW, "File %s: %s", filename,
|
||||
strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write out the game file header and encryption key
|
||||
fprintf(file, "%s\n" "%s\n", GAME_FILE_HEADER, GAME_FILE_API_VERSION);
|
||||
fprintf(file, "%d\n", crypt_key);
|
||||
|
||||
// Write out various game variables
|
||||
save_game_write_int(MAX_X);
|
||||
save_game_write_int(MAX_Y);
|
||||
save_game_write_int(max_turn);
|
||||
save_game_write_int(turn_number);
|
||||
save_game_write_int(number_players);
|
||||
save_game_write_int(current_player);
|
||||
save_game_write_int(first_player);
|
||||
save_game_write_int(MAX_COMPANIES);
|
||||
save_game_write_double(interest_rate);
|
||||
|
||||
// Write out player data
|
||||
for (i = 0; i < number_players; i++) {
|
||||
save_game_write_string(player[i].name);
|
||||
save_game_write_double(player[i].cash);
|
||||
save_game_write_double(player[i].debt);
|
||||
save_game_write_bool(player[i].in_game);
|
||||
|
||||
for (j = 0; j < MAX_COMPANIES; j++) {
|
||||
save_game_write_long(player[i].stock_owned[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Write out company data
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
save_game_write_double(company[i].share_price);
|
||||
save_game_write_double(company[i].share_return);
|
||||
save_game_write_long(company[i].stock_issued);
|
||||
save_game_write_long(company[i].max_stock);
|
||||
save_game_write_bool(company[i].on_map);
|
||||
}
|
||||
|
||||
// Write out galaxy map
|
||||
for (x = 0; x < MAX_X; x++) {
|
||||
memset(buf, 0, MAX_Y + 2);
|
||||
for (p = buf, y = 0; y < MAX_Y; p++, y++) {
|
||||
*p = (char) galaxy_map[x][y];
|
||||
}
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
|
||||
scramble(crypt_key, buf, BUFSIZE);
|
||||
fprintf(file, "%s", buf);
|
||||
}
|
||||
|
||||
// Write out a dummy sentinal value
|
||||
save_game_write_int(GAME_FILE_SENTINEL);
|
||||
|
||||
if (fclose(file) == EOF) {
|
||||
errno_exit("%s", filename);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return true;
|
||||
}
|
43
src/fileio.h
Normal file
43
src/fileio.h
Normal file
@ -0,0 +1,43 @@
|
||||
/************************************************************************
|
||||
* *
|
||||
* Star Traders: A Game of Interstellar Trading *
|
||||
* Copyright (C) 1990-2011, John Zaitseff *
|
||||
* *
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
Author: John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
$Id$
|
||||
|
||||
This file, fileio.h, contains declarations for the load and save game
|
||||
functions used in Star Traders.
|
||||
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef included_FILEIO_H
|
||||
#define included_FILEIO_H 1
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Game load and save function declarations *
|
||||
************************************************************************/
|
||||
|
||||
extern bool load_game (int num);
|
||||
extern bool save_game (int num);
|
||||
|
||||
|
||||
#endif /* included_FILEIO_H */
|
410
src/game.c
410
src/game.c
@ -9,8 +9,8 @@
|
||||
Author: John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
$Id$
|
||||
|
||||
This file, game.c, contains the implementation of the game functions
|
||||
used in Star Traders.
|
||||
This file, game.c, contains the implementation of the starting and
|
||||
ending game functions used in Star Traders.
|
||||
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
@ -31,105 +31,6 @@
|
||||
#include "trader.h"
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Module constants and macros *
|
||||
************************************************************************/
|
||||
|
||||
// Game loading and saving constants
|
||||
|
||||
static const int game_file_crypt_key[] = {
|
||||
0x50, 0x52, 0x55, 0x59, 0x5A, 0x5C, 0x5F,
|
||||
0x90, 0x92, 0x95, 0x99, 0x9A, 0x9C, 0x9F,
|
||||
0xA0, 0xA2, 0xA5, 0xA9, 0xAA, 0xAC, 0xAF,
|
||||
0xD0, 0xD2, 0xD5, 0xD9, 0xDA, 0xDC, 0xDF
|
||||
};
|
||||
|
||||
#define GAME_FILE_CRYPT_KEY_SIZE (sizeof(game_file_crypt_key) / sizeof(int))
|
||||
|
||||
|
||||
// Macros used in load_game()
|
||||
|
||||
#define load_game_scanf(_fmt, _var, _cond) \
|
||||
do { \
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) { \
|
||||
err_exit("%s: missing field on line %d", filename, lineno); \
|
||||
} \
|
||||
if (sscanf(unscramble(crypt_key, buf, BUFSIZE), _fmt "\n", \
|
||||
&(_var)) != 1) { \
|
||||
err_exit("%s: illegal field on line %d: `%s'", \
|
||||
filename, lineno, buf); \
|
||||
} \
|
||||
if (! (_cond)) { \
|
||||
err_exit("%s: illegal value on line %d: `%s'", \
|
||||
filename, lineno, buf); \
|
||||
} \
|
||||
lineno++; \
|
||||
} while (0)
|
||||
|
||||
#define load_game_read_int(_var, _cond) \
|
||||
load_game_scanf("%d", _var, _cond)
|
||||
#define load_game_read_long(_var, _cond) \
|
||||
load_game_scanf("%ld", _var, _cond)
|
||||
#define load_game_read_double(_var, _cond) \
|
||||
load_game_scanf("%lf", _var, _cond)
|
||||
|
||||
#define load_game_read_bool(_var) \
|
||||
do { \
|
||||
int b; \
|
||||
\
|
||||
load_game_scanf("%d", b, (b == false) || (b == true)); \
|
||||
(_var) = b; \
|
||||
} while (0)
|
||||
|
||||
#define load_game_read_string(_var) \
|
||||
do { \
|
||||
char *s; \
|
||||
int len; \
|
||||
\
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) { \
|
||||
err_exit("%s: missing field on line %d", filename, lineno); \
|
||||
} \
|
||||
if (strlen(unscramble(crypt_key, buf, BUFSIZE)) == 0) { \
|
||||
err_exit("%s: illegal value on line %d", filename, lineno); \
|
||||
} \
|
||||
lineno++; \
|
||||
\
|
||||
s = malloc(strlen(buf) + 1); \
|
||||
if (s == NULL) { \
|
||||
err_exit("out of memory"); \
|
||||
} \
|
||||
\
|
||||
strcpy(s, buf); \
|
||||
len = strlen(s); \
|
||||
if (len > 0 && s[len - 1] == '\n') { \
|
||||
s[len - 1] = '\0'; \
|
||||
} \
|
||||
\
|
||||
(_var) = s; \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Macros used in save_game()
|
||||
|
||||
#define save_game_printf(_fmt, _var) \
|
||||
do { \
|
||||
snprintf(buf, BUFSIZE, _fmt "\n", _var); \
|
||||
scramble(crypt_key, buf, BUFSIZE); \
|
||||
fprintf(file, "%s", buf); \
|
||||
} while (0)
|
||||
|
||||
#define save_game_write_int(_var) \
|
||||
save_game_printf("%d", _var)
|
||||
#define save_game_write_long(_var) \
|
||||
save_game_printf("%ld", _var)
|
||||
#define save_game_write_double(_var) \
|
||||
save_game_printf("%2.20e", _var)
|
||||
#define save_game_write_bool(_var) \
|
||||
save_game_printf("%d", (int) _var)
|
||||
#define save_game_write_string(_var) \
|
||||
save_game_printf("%s", _var)
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Internal function declarations *
|
||||
************************************************************************/
|
||||
@ -588,313 +489,6 @@ void end_game (void)
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Function: load_game - Load a saved game from disk
|
||||
Arguments: num - Game number to load (1-9)
|
||||
Returns: bool - True if game loaded successfully, else false
|
||||
|
||||
This function loads a previously-saved game from disk. True is
|
||||
returned if this could be done successfully.
|
||||
*/
|
||||
|
||||
bool load_game (int num)
|
||||
{
|
||||
char *buf, *filename;
|
||||
FILE *file;
|
||||
int saved_errno, lineno;
|
||||
|
||||
int crypt_key;
|
||||
int n, i, j, x, y;
|
||||
char c;
|
||||
|
||||
|
||||
assert((num >= 1) && (num <= 9));
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit("out of memory");
|
||||
}
|
||||
|
||||
filename = game_filename(num);
|
||||
assert(filename != NULL);
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
// File could not be opened
|
||||
|
||||
if (errno == ENOENT) {
|
||||
// File not found
|
||||
newtxwin(7, 40, LINE_OFFSET + 9, COL_CENTER(40));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Found ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d has not been saved to disk", num);
|
||||
|
||||
wait_for_key(curwin, 5, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
} else {
|
||||
// Some other file error
|
||||
saved_errno = errno;
|
||||
|
||||
newtxwin(9, 70, LINE_OFFSET + 9, COL_CENTER(70));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Loaded ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d could not be loaded from disk", num);
|
||||
center(curwin, 5, ATTR_ERROR_WINDOW, "File %s: %s", filename,
|
||||
strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the game file header
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing header in game file", filename);
|
||||
}
|
||||
if (strcmp(buf, GAME_FILE_HEADER "\n") != 0) {
|
||||
err_exit("%s: not a valid game file", filename);
|
||||
}
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing subheader in game file", filename);
|
||||
}
|
||||
if (strcmp(buf, GAME_FILE_API_VERSION "\n") != 0) {
|
||||
err_exit("%s: saved under a different version of Star Traders",
|
||||
filename);
|
||||
}
|
||||
|
||||
lineno = 3;
|
||||
|
||||
// Read in the game file encryption key
|
||||
if (fscanf(file, "%i\n", &crypt_key) != 1) {
|
||||
err_exit("%s: illegal or missing field on line %d", filename, lineno);
|
||||
}
|
||||
lineno++;
|
||||
|
||||
// Read in various game variables
|
||||
load_game_read_int(n, n == MAX_X);
|
||||
load_game_read_int(n, n == MAX_Y);
|
||||
load_game_read_int(max_turn, max_turn >= 1);
|
||||
load_game_read_int(turn_number, (turn_number >= 1) && (turn_number <= max_turn));
|
||||
load_game_read_int(number_players, (number_players >= 1) && (number_players < MAX_PLAYERS));
|
||||
load_game_read_int(current_player, (current_player >= 0) && (current_player < number_players));
|
||||
load_game_read_int(first_player, (first_player >= 0) && (first_player < number_players));
|
||||
load_game_read_int(n, n == MAX_COMPANIES);
|
||||
load_game_read_double(interest_rate, interest_rate > 0.0);
|
||||
|
||||
// Read in player data
|
||||
for (i = 0; i < number_players; i++) {
|
||||
load_game_read_string(player[i].name);
|
||||
load_game_read_double(player[i].cash, player[i].cash >= 0.0);
|
||||
load_game_read_double(player[i].debt, player[i].debt >= 0.0);
|
||||
load_game_read_bool(player[i].in_game);
|
||||
|
||||
for (j = 0; j < MAX_COMPANIES; j++) {
|
||||
load_game_read_long(player[i].stock_owned[j], player[i].stock_owned[j] >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Read in company data
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
company[i].name = company_name[i];
|
||||
load_game_read_double(company[i].share_price, company[i].share_price > 0.0);
|
||||
load_game_read_double(company[i].share_return, true);
|
||||
load_game_read_long(company[i].stock_issued, company[i].stock_issued >= 0);
|
||||
load_game_read_long(company[i].max_stock, company[i].max_stock >= 0);
|
||||
load_game_read_bool(company[i].on_map);
|
||||
}
|
||||
|
||||
// Read in galaxy map
|
||||
for (x = 0; x < MAX_X; x++) {
|
||||
if (fgets(buf, BUFSIZE, file) == NULL) {
|
||||
err_exit("%s: missing field on line %d", filename, lineno);
|
||||
}
|
||||
if (strlen(unscramble(crypt_key, buf, BUFSIZE)) != (MAX_Y + 1)) {
|
||||
err_exit("%s: illegal field on line %d", filename, lineno);
|
||||
}
|
||||
lineno++;
|
||||
|
||||
for (y = 0; y < MAX_Y; y++) {
|
||||
c = buf[y];
|
||||
if ((c == MAP_EMPTY) || (c == MAP_OUTPOST) || (c == MAP_STAR) ||
|
||||
((c >= MAP_A) && (c <= MAP_LAST))) {
|
||||
galaxy_map[x][y] = (map_val_t) c;
|
||||
} else {
|
||||
err_exit("%s: illegal value on line %d", filename, lineno - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read in a dummy sentinal value
|
||||
load_game_read_int(n, n == GAME_FILE_SENTINEL);
|
||||
|
||||
if (fclose(file) == EOF) {
|
||||
errno_exit("%s", filename);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Function: save_game - Save the current game to disk
|
||||
Arguments: num - Game number to use (1-9)
|
||||
Returns: bool - True if game saved successfully, else false
|
||||
|
||||
This function saves the current game to disk. True is returned if this
|
||||
could be done successfully.
|
||||
*/
|
||||
|
||||
bool save_game (int num)
|
||||
{
|
||||
const char *data_dir;
|
||||
char *buf, *filename;
|
||||
FILE *file;
|
||||
int saved_errno;
|
||||
struct stat statbuf;
|
||||
int crypt_key;
|
||||
int i, j, x, y;
|
||||
char *p;
|
||||
|
||||
|
||||
assert((num >= 1) && (num <= 9));
|
||||
|
||||
buf = malloc(BUFSIZE);
|
||||
if (buf == NULL) {
|
||||
err_exit("out of memory");
|
||||
}
|
||||
|
||||
crypt_key = game_file_crypt_key[randi(GAME_FILE_CRYPT_KEY_SIZE)];
|
||||
|
||||
// Create the data directory, if needed
|
||||
data_dir = data_directory();
|
||||
if (data_dir != NULL) {
|
||||
if (mkdir(data_dir, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
|
||||
saved_errno = errno;
|
||||
if ((saved_errno == EEXIST) && (stat(data_dir, &statbuf) == 0)
|
||||
&& S_ISDIR(statbuf.st_mode)) {
|
||||
; // Do nothing: directory already exists
|
||||
} else {
|
||||
// Data directory could not be created
|
||||
|
||||
newtxwin(9, 70, LINE_OFFSET + 9, COL_CENTER(70));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Saved ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d could not be saved to disk", num);
|
||||
center(curwin, 5, ATTR_ERROR_WINDOW, "Directory %s: %s",
|
||||
data_dir, strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filename = game_filename(num);
|
||||
assert(filename != NULL);
|
||||
|
||||
file = fopen(filename, "w");
|
||||
if (file == NULL) {
|
||||
// File could not be opened for writing
|
||||
saved_errno = errno;
|
||||
|
||||
newtxwin(9, 70, LINE_OFFSET + 9, COL_CENTER(70));
|
||||
wbkgd(curwin, ATTR_ERROR_WINDOW);
|
||||
box(curwin, 0, 0);
|
||||
|
||||
center(curwin, 1, ATTR_ERROR_TITLE, " Game Not Saved ");
|
||||
center(curwin, 3, ATTR_ERROR_STR,
|
||||
"Game %d could not be saved to disk", num);
|
||||
center(curwin, 5, ATTR_ERROR_WINDOW, "File %s: %s", filename,
|
||||
strerror(saved_errno));
|
||||
|
||||
wait_for_key(curwin, 7, ATTR_WAITERROR_STR);
|
||||
deltxwin();
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write out the game file header and encryption key
|
||||
fprintf(file, "%s\n" "%s\n", GAME_FILE_HEADER, GAME_FILE_API_VERSION);
|
||||
fprintf(file, "%d\n", crypt_key);
|
||||
|
||||
// Write out various game variables
|
||||
save_game_write_int(MAX_X);
|
||||
save_game_write_int(MAX_Y);
|
||||
save_game_write_int(max_turn);
|
||||
save_game_write_int(turn_number);
|
||||
save_game_write_int(number_players);
|
||||
save_game_write_int(current_player);
|
||||
save_game_write_int(first_player);
|
||||
save_game_write_int(MAX_COMPANIES);
|
||||
save_game_write_double(interest_rate);
|
||||
|
||||
// Write out player data
|
||||
for (i = 0; i < number_players; i++) {
|
||||
save_game_write_string(player[i].name);
|
||||
save_game_write_double(player[i].cash);
|
||||
save_game_write_double(player[i].debt);
|
||||
save_game_write_bool(player[i].in_game);
|
||||
|
||||
for (j = 0; j < MAX_COMPANIES; j++) {
|
||||
save_game_write_long(player[i].stock_owned[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Write out company data
|
||||
for (i = 0; i < MAX_COMPANIES; i++) {
|
||||
save_game_write_double(company[i].share_price);
|
||||
save_game_write_double(company[i].share_return);
|
||||
save_game_write_long(company[i].stock_issued);
|
||||
save_game_write_long(company[i].max_stock);
|
||||
save_game_write_bool(company[i].on_map);
|
||||
}
|
||||
|
||||
// Write out galaxy map
|
||||
for (x = 0; x < MAX_X; x++) {
|
||||
memset(buf, 0, MAX_Y + 2);
|
||||
for (p = buf, y = 0; y < MAX_Y; p++, y++) {
|
||||
*p = (char) galaxy_map[x][y];
|
||||
}
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
|
||||
scramble(crypt_key, buf, BUFSIZE);
|
||||
fprintf(file, "%s", buf);
|
||||
}
|
||||
|
||||
// Write out a dummy sentinal value
|
||||
save_game_write_int(GAME_FILE_SENTINEL);
|
||||
|
||||
if (fclose(file) == EOF) {
|
||||
errno_exit("%s", filename);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Function: select_moves - Select NUMBER_MOVES random moves
|
||||
Arguments: (none)
|
||||
|
@ -9,8 +9,8 @@
|
||||
Author: John Zaitseff <J.Zaitseff@zap.org.au>
|
||||
$Id$
|
||||
|
||||
This file, game.h, contains declarations for the main game functions
|
||||
used in Star Traders.
|
||||
This file, game.h, contains declarations for the starting and ending
|
||||
game functions used in Star Traders.
|
||||
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
@ -42,9 +42,6 @@
|
||||
extern void init_game (void);
|
||||
extern void end_game (void);
|
||||
|
||||
extern bool load_game (int num);
|
||||
extern bool save_game (int num);
|
||||
|
||||
extern void select_moves (void);
|
||||
extern void get_move (void);
|
||||
extern void process_move (void);
|
||||
|
@ -50,6 +50,7 @@
|
||||
|
||||
#include "globals.h"
|
||||
#include "game.h"
|
||||
#include "fileio.h"
|
||||
#include "help.h"
|
||||
#include "intf.h"
|
||||
#include "utils.h"
|
||||
|
Loading…
Reference in New Issue
Block a user