a5ec8db5f7
build / build (push) Failing after 5s
dependency (SDL2, SDL2_mixer, fluidsynth-lite, a MIDI soundfont) prebuilt, so compiling the engine needs no network access - just the image and the engine source. Add res/assets/extract_assets.sh to pull the game's data files out of a purchased GOG installer, and a Makefile that assembles a runnable dist/ from the two. Also add `make package`, which builds a redistributable tarball that omits the proprietary game assets (shipping res/GET_ASSETS.txt instead) plus license information for both the MIT tooling and the GPLv3 engine, and a Gitea Actions workflow that builds and publishes it to dl.ladkau.de on every push.
1556 lines
42 KiB
C
1556 lines
42 KiB
C
/*
|
|
|
|
Copyright (C) 2015-2018 Night Dive Studios, LLC.
|
|
|
|
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/>.
|
|
|
|
*/
|
|
/*
|
|
* $Source: r:/prj/cit/src/RCS/setup.c $
|
|
* $Revision: 1.141 $
|
|
* $Author: dc $
|
|
* $Date: 1994/11/23 00:05:51 $
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <SDL.h>
|
|
|
|
// TODO: extract this into a compatibility header
|
|
#ifdef _MSC_VER
|
|
#ifndef F_OK
|
|
#define F_OK 0
|
|
#endif
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef SVGA_SUPPORT
|
|
#include "fullscrn.h"
|
|
#endif
|
|
|
|
#include "archiveformat.h"
|
|
#include "setup.h"
|
|
#include "colors.h"
|
|
#include "cybmem.h"
|
|
#include "diffq.h"
|
|
#include "gamewrap.h"
|
|
#include "gr2ss.h"
|
|
#include "hud.h"
|
|
#include "init.h"
|
|
#include "miscqvar.h"
|
|
#include "player.h"
|
|
#include "version.h"
|
|
#include "wrapper.h"
|
|
#include "verify.h"
|
|
#include "sdl_events.h"
|
|
#include "cybstrng.h"
|
|
#include "gamestrn.h"
|
|
|
|
#include "mainloop.h"
|
|
#include "tools.h"
|
|
#include "input.h"
|
|
#include "game_screen.h"
|
|
#include "hkeyfunc.h"
|
|
#include "loops.h"
|
|
#include "keydefs.h"
|
|
#include "status.h"
|
|
#include "cutsloop.h"
|
|
#include "musicai.h"
|
|
#include "palfx.h"
|
|
#include "gamescr.h"
|
|
#include "faketime.h"
|
|
|
|
#include "2d.h"
|
|
#include "splash.h"
|
|
#include "splshpal.h"
|
|
#include "tickcount.h"
|
|
#include "MacTune.h"
|
|
#include "Shock.h"
|
|
#include "Xmi.h"
|
|
|
|
#ifdef PLAYTEST
|
|
#include <mprintf.h>
|
|
#endif
|
|
|
|
#define KEYBOARD_FOCUS_COLOR (RED_BASE + 3)
|
|
#define NORMAL_ENTRY_COLOR (RED_BASE + 7)
|
|
#define CURRENT_DIFF_COLOR (RED_BASE + 3)
|
|
#define SELECTED_COLOR (RED_BASE)
|
|
#define UNAVAILABLE_COLOR (RED_BASE + 11)
|
|
|
|
uiSlab setup_slab;
|
|
LGRegion setup_root_region;
|
|
uchar play_intro_anim;
|
|
uchar save_game_exists = FALSE;
|
|
SetupMode setup_mode;
|
|
SetupMode last_setup_mode;
|
|
int intro_num;
|
|
int splash_num;
|
|
int diff_sum = 0;
|
|
bool do_fades = false;
|
|
ubyte valid_save;
|
|
uchar setup_bio_started = FALSE;
|
|
uchar start_first_time = TRUE;
|
|
bool waiting_for_key = false;
|
|
|
|
static uchar direct_into_cutscene = FALSE;
|
|
|
|
extern char which_lang;
|
|
extern uchar clear_player_data;
|
|
extern char current_cutscene;
|
|
extern char curr_vol_lev;
|
|
extern char curr_sfx_vol;
|
|
extern uchar fullscrn_vitals;
|
|
extern uchar fullscrn_icons;
|
|
extern uchar map_notes_on;
|
|
extern uchar audiolog_setting;
|
|
extern uchar mouseLefty;
|
|
#ifdef AUDIOLOGS
|
|
extern char curr_alog_vol;
|
|
#endif
|
|
|
|
errtype draw_difficulty_char(int char_num);
|
|
errtype draw_difficulty_description(int which_cat, int color);
|
|
errtype journey_newgame_func(void);
|
|
errtype journey_continue_func(uchar draw_stuff);
|
|
errtype draw_username(int color, char *string);
|
|
|
|
//*****************************************************************************
|
|
|
|
// DIFFICULTY
|
|
|
|
#define DIFF_DONE_X1 119
|
|
#define DIFF_DONE_Y1 179
|
|
#define DIFF_DONE_X2 203
|
|
#define DIFF_DONE_Y2 198
|
|
|
|
#define DIFF_NAME_X 57
|
|
#define DIFF_NAME_Y 49
|
|
#define DIFF_NAME_X2 253
|
|
#define DIFF_NAME_Y2 65
|
|
#define DIFF_NAME_TEXT_X 124
|
|
|
|
#define DIFF_X_BASE 28
|
|
#define DIFF_W_BASE 156
|
|
#define DIFF_W_ELEM 32
|
|
#define DIFF_H_ELEM 20
|
|
|
|
#define DIFF_OPT_TOP 99
|
|
#define DIFF_OPT_DELTA 53
|
|
#define DIFF_OPT_HEIGHT 24
|
|
#define DIFF_STRING_OFFSET_Y 10
|
|
#define DIFF_STRING_OFFSET_X 13
|
|
|
|
#define DIFF_TITLE1_X1 12
|
|
#define DIFF_TITLE1_Y1 70
|
|
#define DIFF_TITLE1_X2 155
|
|
#define DIFF_TITLE1_Y2 93
|
|
#define DIFF_TITLE1_OPT_TOP 94
|
|
#define DIFF_TITLE1_OPT_BOTTOM 118
|
|
#define DIFF_TITLE1_LEFT1 25
|
|
#define DIFF_TITLE1_RIGHT1 45
|
|
|
|
#define DIFF_TITLE2_X1 169
|
|
#define DIFF_TITLE2_Y1 70
|
|
#define DIFF_TITLE2_X2 311
|
|
#define DIFF_TITLE2_Y2 93
|
|
|
|
#define DIFF_TITLE3_X1 12
|
|
#define DIFF_TITLE3_Y1 123
|
|
#define DIFF_TITLE3_X2 155
|
|
#define DIFF_TITLE3_Y2 146
|
|
|
|
#define DIFF_TITLE4_X1 169
|
|
#define DIFF_TITLE4_Y1 123
|
|
#define DIFF_TITLE4_X2 311
|
|
#define DIFF_TITLE4_Y2 146
|
|
|
|
#define DIFF_SIZE_X DIFF_TITLE1_RIGHT1 - DIFF_TITLE1_LEFT1
|
|
#define DIFF_SIZE_Y DIFF_TITLE1_OPT_BOTTOM - DIFF_TITLE1_OPT_TOP
|
|
|
|
// why +2?
|
|
#define build_diff_x(char_num) \
|
|
((DIFF_X_BASE + (DIFF_W_ELEM * (char_num & 3)) + (((char_num >> 2) & 1) * DIFF_W_BASE)) + 2)
|
|
#define build_diff_y(char_num) ((DIFF_OPT_TOP + ((char_num >> 3) * DIFF_OPT_DELTA)) + 2)
|
|
|
|
#define NUM_DIFF_CATEGORIES 4
|
|
|
|
#define CATEGORY_STRING_BASE REF_STR_diffCategories
|
|
#define DIFF_STRING_BASE REF_STR_diffStrings
|
|
#define DIFF_NAME REF_STR_diffName
|
|
#define DIFF_START REF_STR_diffStart
|
|
|
|
#define FLASH_TIME (CIT_CYCLE / 8)
|
|
|
|
#define COMPUTE_DIFF_STRING_X(wcat) (DIFF_X_BASE + (DIFF_W_BASE * (wcat & 1)) - DIFF_STRING_OFFSET_X)
|
|
#define COMPUTE_DIFF_STRING_Y(wcat) (DIFF_OPT_TOP + ((wcat >> 1) * DIFF_OPT_DELTA) - DIFF_STRING_OFFSET_Y)
|
|
|
|
#define REF_IMG_bmDifficultyScreen 0x26d0000
|
|
|
|
char curr_diff = 0;
|
|
uchar start_selected = FALSE;
|
|
|
|
short diff_titles_x[] = {DIFF_TITLE1_X1, DIFF_TITLE2_X1, DIFF_TITLE3_X1, DIFF_TITLE4_X1};
|
|
short diff_titles_y[] = {DIFF_TITLE1_Y1, DIFF_TITLE2_Y1, DIFF_TITLE3_Y1, DIFF_TITLE4_Y1};
|
|
char *valid_char_string = "0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ";
|
|
|
|
LGRect name_rect = {{DIFF_NAME_TEXT_X, DIFF_NAME_Y}, {DIFF_NAME_X2, DIFF_NAME_Y2}};
|
|
|
|
errtype compute_new_diff(void) {
|
|
int i, new_sum = 0;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
new_sum += player_struct.difficulty[i];
|
|
diff_sum = new_sum;
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype difficulty_draw(uchar full) {
|
|
int i;
|
|
|
|
uiHideMouse(NULL);
|
|
|
|
if (full) {
|
|
draw_raw_res_bm_temp(REF_IMG_bmDifficultyScreen, 0, 0);
|
|
status_bio_draw();
|
|
}
|
|
|
|
setup_mode = SETUP_DIFFICULTY;
|
|
|
|
for (i = 0; i < NUM_DIFF_CATEGORIES; i++) {
|
|
if (i == curr_diff && !start_selected)
|
|
gr_set_fcolor(KEYBOARD_FOCUS_COLOR);
|
|
else
|
|
gr_set_fcolor(NORMAL_ENTRY_COLOR);
|
|
|
|
res_draw_string(RES_citadelFont, CATEGORY_STRING_BASE + i, diff_titles_x[i] + 12, diff_titles_y[i] + 2);
|
|
}
|
|
|
|
if (start_selected)
|
|
gr_set_fcolor(KEYBOARD_FOCUS_COLOR);
|
|
else
|
|
gr_set_fcolor(NORMAL_ENTRY_COLOR);
|
|
|
|
res_draw_string(RES_citadelFont, DIFF_START, DIFF_DONE_X1 + 13, DIFF_DONE_Y1 + 2);
|
|
|
|
if (full) {
|
|
for (i = 0; i < 16; i++)
|
|
draw_difficulty_char(i);
|
|
for (i = 0; i < 4; i++)
|
|
draw_difficulty_description(i, NORMAL_ENTRY_COLOR);
|
|
|
|
gr_set_fcolor(KEYBOARD_FOCUS_COLOR);
|
|
res_draw_string(RES_citadelFont, DIFF_NAME, DIFF_NAME_X, DIFF_NAME_Y);
|
|
draw_username(NORMAL_ENTRY_COLOR, player_struct.name);
|
|
}
|
|
|
|
uiShowMouse(NULL);
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype draw_username(int color, char *string) {
|
|
gr_set_fcolor(color);
|
|
uiHideMouse(&name_rect);
|
|
res_draw_text(RES_citadelFont, string, DIFF_NAME_TEXT_X, DIFF_NAME_Y);
|
|
uiShowMouse(&name_rect);
|
|
|
|
return OK;
|
|
}
|
|
|
|
void flash_username(void) {
|
|
long flash_done;
|
|
|
|
uiHideMouse(&name_rect);
|
|
gr_set_fcolor(SELECTED_COLOR - 4);
|
|
res_draw_string(RES_citadelFont, DIFF_NAME, DIFF_NAME_X, DIFF_NAME_Y);
|
|
flash_done = *tmd_ticks + FLASH_TIME;
|
|
while (TickCount() < flash_done) {
|
|
SDLDraw();
|
|
}
|
|
gr_set_fcolor(KEYBOARD_FOCUS_COLOR);
|
|
res_draw_string(RES_citadelFont, DIFF_NAME, DIFF_NAME_X, DIFF_NAME_Y);
|
|
uiShowMouse(&name_rect);
|
|
}
|
|
|
|
errtype draw_difficulty_line(int which_line) {
|
|
int i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
draw_difficulty_char((which_line * 4) + i);
|
|
draw_difficulty_description(which_line, NORMAL_ENTRY_COLOR);
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype draw_difficulty_description(int which_cat, int color) {
|
|
if (color != -1)
|
|
gr_set_fcolor(color);
|
|
res_draw_string(RES_smallTechFont, DIFF_STRING_BASE + (which_cat * 4) + player_struct.difficulty[which_cat],
|
|
COMPUTE_DIFF_STRING_X(which_cat), COMPUTE_DIFF_STRING_Y(which_cat));
|
|
|
|
return OK;
|
|
}
|
|
|
|
// char_num 1-16
|
|
errtype draw_difficulty_char(int char_num) {
|
|
char buff[] = "X";
|
|
|
|
uiHideMouse(NULL);
|
|
if (player_struct.difficulty[char_num / 4] == char_num % 4)
|
|
gr_set_fcolor(CURRENT_DIFF_COLOR);
|
|
else
|
|
gr_set_fcolor(NORMAL_ENTRY_COLOR);
|
|
buff[0] = (char_num & 3) + '0';
|
|
res_draw_text(RES_citadelFont, buff, build_diff_x(char_num), build_diff_y(char_num));
|
|
uiShowMouse(NULL);
|
|
|
|
return OK;
|
|
}
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
|
|
// JOURNEY
|
|
|
|
#define JOURNEY_OPT1_TOP 66
|
|
#define JOURNEY_OPT1_BOT 88
|
|
|
|
#define JOURNEY_OPT2_TOP 97
|
|
#define JOURNEY_OPT2_BOT 119
|
|
|
|
#define JOURNEY_OPT3_TOP 129
|
|
#define JOURNEY_OPT3_BOT 160
|
|
|
|
#define JOURNEY_OPT4_TOP 160
|
|
#define JOURNEY_OPT4_BOT 182
|
|
|
|
#define SETUP_STRING_BASE REF_STR_journeyOpts
|
|
|
|
#define NUM_SETUP_LINES 4
|
|
|
|
#define JOURNEY_OPT_LEFT 79
|
|
#define JOURNEY_OPT_RIGHT 247
|
|
|
|
#define REF_IMG_bmJourneyOnwards 0x26c0000
|
|
|
|
#ifdef DEMO
|
|
char curr_setup_line = 1;
|
|
#else
|
|
char curr_setup_line = 0;
|
|
#endif
|
|
|
|
int journey_y[8] = {JOURNEY_OPT1_TOP, JOURNEY_OPT1_BOT, JOURNEY_OPT2_TOP, JOURNEY_OPT2_BOT,
|
|
JOURNEY_OPT3_TOP, JOURNEY_OPT3_BOT, JOURNEY_OPT4_TOP, JOURNEY_OPT4_BOT};
|
|
|
|
short setup_tops[] = {JOURNEY_OPT1_TOP, JOURNEY_OPT2_TOP, JOURNEY_OPT3_TOP, JOURNEY_OPT4_TOP};
|
|
|
|
errtype journey_draw(char part) {
|
|
char i;
|
|
|
|
uiHideMouse(NULL);
|
|
|
|
if (setup_bio_started) {
|
|
status_bio_end();
|
|
setup_bio_started = FALSE;
|
|
}
|
|
|
|
// extract into buffer - AFTER we've stopped biorhythms (which used that buffer.....)
|
|
if (part == 0)
|
|
draw_raw_res_bm_temp(REF_IMG_bmJourneyOnwards, 0, 0);
|
|
|
|
for (i = 0; i < NUM_SETUP_LINES; i++) {
|
|
if ((part == 0) || (part - 1 == i)) {
|
|
int col;
|
|
|
|
if (i == curr_setup_line)
|
|
col = KEYBOARD_FOCUS_COLOR;
|
|
else
|
|
col = NORMAL_ENTRY_COLOR;
|
|
|
|
#ifdef DEMO
|
|
if ((i == NUM_SETUP_LINES - 1) || (i == 0))
|
|
#else
|
|
if (i == NUM_SETUP_LINES - 1) // why is NUM_SETUP_LINES-1 necessarily continue?
|
|
#endif
|
|
{
|
|
|
|
#ifndef DEMO
|
|
if (!save_game_exists)
|
|
#endif
|
|
|
|
col = UNAVAILABLE_COLOR;
|
|
}
|
|
gr_set_fcolor(col);
|
|
res_draw_string(RES_citadelFont, SETUP_STRING_BASE + i, JOURNEY_OPT_LEFT + 15, setup_tops[i] + 4);
|
|
}
|
|
}
|
|
uiShowMouse(NULL);
|
|
|
|
setup_mode = SETUP_JOURNEY;
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype journey_intro_func(uchar draw_stuff) {
|
|
|
|
#ifdef DEMO
|
|
uiShowMouse(NULL); // need to leave it hidden
|
|
return OK;
|
|
#else
|
|
if (draw_stuff)
|
|
res_draw_string(RES_citadelFont, SETUP_STRING_BASE, JOURNEY_OPT_LEFT + 15, JOURNEY_OPT1_TOP + 2);
|
|
uiShowMouse(NULL); // need to leave it hidden
|
|
|
|
MacTuneKillCurrentTheme();
|
|
|
|
return play_cutscene(START_CUTSCENE, FALSE);
|
|
#endif
|
|
}
|
|
|
|
errtype journey_newgame_func(void) {
|
|
clear_player_data = TRUE;
|
|
|
|
DEBUG("Load object data");
|
|
object_data_load();
|
|
|
|
player_struct.level = 0xFF;
|
|
|
|
DEBUG("Create initial game");
|
|
create_initial_game_func(0, 0, 0);
|
|
|
|
INFO("Started new game!");
|
|
|
|
change_mode_func(0, 0, GAME_LOOP);
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype journey_difficulty_func(uchar draw_stuff) {
|
|
if (draw_stuff)
|
|
res_draw_string(RES_citadelFont, SETUP_STRING_BASE + 1, JOURNEY_OPT_LEFT + 15, JOURNEY_OPT2_TOP + 2);
|
|
uiShowMouse(NULL);
|
|
difficulty_draw(TRUE);
|
|
compute_new_diff();
|
|
status_bio_set(DIFF_BIO);
|
|
status_bio_start();
|
|
setup_bio_started = TRUE;
|
|
|
|
return OK;
|
|
}
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
|
|
// CREDITS
|
|
|
|
#define CredResFnt (RES_coloraliasedFont)
|
|
#define CredColor (GREEN_BASE + 4)
|
|
#define CredResource (RES_credits)
|
|
|
|
int credits_inp = 0;
|
|
|
|
void *credits_txtscrn;
|
|
|
|
int CreditsTune;
|
|
|
|
// set this when game is won, then stats will be shown once before credits
|
|
int WonGame_ShowStats = 0;
|
|
|
|
// ticks: 0 wait forever
|
|
int WaitForKey(ulong ticks) {
|
|
ulong end_ticks = (ulong)TickCount();
|
|
ulong key_ticks = end_ticks + (!ticks ? 500 : (ticks * 1 / 8));
|
|
end_ticks = ticks ? end_ticks + ticks : 0;
|
|
int ch;
|
|
|
|
// wait for specified elapsed ticks or keypress
|
|
for (;;) {
|
|
|
|
// loop win or elevator music
|
|
int i = 0;
|
|
if (music_on && !IsPlaying(i)) {
|
|
int track;
|
|
|
|
if (WonGame_ShowStats)
|
|
track = 0;
|
|
else
|
|
track = 1 + CreditsTune;
|
|
|
|
if (track >= 0 && track < NumTracks) {
|
|
// int volume = (int)curr_vol_lev * 127 / 100; //convert from 0-100 to 0-127
|
|
StartTrack(i, track);
|
|
|
|
if (!WonGame_ShowStats)
|
|
CreditsTune = (CreditsTune + 1) % 8;
|
|
}
|
|
}
|
|
|
|
pump_events();
|
|
SDLDraw();
|
|
|
|
kbs_event ev = kb_next();
|
|
ch = ev.ascii;
|
|
ticks = (ulong)TickCount();
|
|
|
|
if ((ch == 27 || ch == ' ' || ch == '\r') && ticks >= key_ticks)
|
|
break;
|
|
if (end_ticks && ticks >= end_ticks)
|
|
break;
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
void PrintWinStats(void) {
|
|
char buf[256], buf_temp[256];
|
|
int x, y = 15;
|
|
short w, h;
|
|
|
|
grs_font *fon = gr_get_font();
|
|
gr_set_font(ResLock(RES_coloraliasedFont));
|
|
|
|
gr_clear(0);
|
|
|
|
sprintf(buf, "CONGRATULATIONS!");
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12 * 2;
|
|
|
|
sprintf(buf, "YOU HAVE COMPLETED SYSTEM SHOCK!");
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12;
|
|
|
|
sprintf(buf, "HIT ESC TO VIEW CREDITS.");
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12 * 2;
|
|
|
|
sprintf(buf, "STATISTICS");
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12;
|
|
|
|
// underline
|
|
short x1 = SCONV_X((320 - w) / 2);
|
|
short x2 = SCONV_X((320 - w) / 2 + w - 1);
|
|
for (; x1 <= x2; x1++) {
|
|
short y1 = SCONV_Y(y);
|
|
short y2 = SCONV_Y(y + 1);
|
|
y2 = y1 + (y2 - y1) / 3;
|
|
for (; y1 <= y2; y1++)
|
|
gr_set_pixel(GREEN_BASE + 4, x1, y1);
|
|
}
|
|
|
|
y += 4;
|
|
|
|
sprintf(buf, "TIME: %u", player_struct.game_time);
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12;
|
|
|
|
sprintf(buf, "KILLS: %d", player_struct.num_victories);
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12;
|
|
|
|
sprintf(buf, "REGENERATIONS: %d", player_struct.num_deaths);
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12;
|
|
|
|
uint8_t stupid = 0;
|
|
for (uint8_t i = 0; i < 4; i++)
|
|
stupid += (player_struct.difficulty[i] * player_struct.difficulty[i]);
|
|
sprintf(buf, "DIFFICULTY INDEX: %d", stupid);
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
y += 12;
|
|
|
|
int score;
|
|
// death is 10 anti-kills, but you always keep at least a third of your kills.
|
|
score = player_struct.num_victories - lg_min(player_struct.num_deaths * 10, player_struct.num_victories * 2 / 3);
|
|
score = score * 10000;
|
|
score = score - lg_min(score * 2 / 3, ((player_struct.game_time / (CIT_CYCLE * 36)) * 100));
|
|
score = score * (stupid + 1) / 37; // 9 * 4 + 1 is best difficulty factor
|
|
if (stupid == 36) {
|
|
score += 2222222; // secret kevin bonus
|
|
}
|
|
sprintf(buf, "SCORE: %d", score);
|
|
gr_string_size(buf, &w, &h);
|
|
ss_string(buf, (320 - w) / 2, y);
|
|
|
|
ResUnlock(RES_coloraliasedFont);
|
|
gr_set_font(fon);
|
|
|
|
WaitForKey(0);
|
|
}
|
|
|
|
void PrintCredits(void) {
|
|
// Credits display reverse-engineered from text resources
|
|
|
|
int end = 0, line = 0, x, y = 15, columns = 1, cur_col = 0;
|
|
int underline = 0, last_underline = 0;
|
|
char buf[256];
|
|
|
|
gr_clear(0);
|
|
|
|
while (!end) {
|
|
get_string((RES_credits << 16) | line, buf, sizeof(buf));
|
|
line++;
|
|
|
|
int len = strlen(buf);
|
|
|
|
if (*buf == '^') {
|
|
for (int i = 1; i < len; i++) {
|
|
switch (buf[i]) {
|
|
case 'E':
|
|
WaitForKey(0);
|
|
end = 1;
|
|
break;
|
|
case 'p':
|
|
WaitForKey(200);
|
|
break;
|
|
case 'G':
|
|
if (WaitForKey(2000) == 27)
|
|
end = 1;
|
|
gr_clear(0);
|
|
y = 15;
|
|
break;
|
|
case 'N':
|
|
break; // dunno
|
|
case '1':
|
|
columns = 1;
|
|
cur_col = 0;
|
|
break;
|
|
case '2':
|
|
columns = 2;
|
|
cur_col = 0;
|
|
break;
|
|
case 'H':
|
|
underline = 3;
|
|
break;
|
|
case 'T':
|
|
underline = 2;
|
|
break;
|
|
case 'h':
|
|
underline = 1;
|
|
break;
|
|
case 'c':
|
|
underline = 0;
|
|
break;
|
|
case 'S':
|
|
y += 10;
|
|
break;
|
|
case 'L':
|
|
y = 15 * (buf[++i] - '0');
|
|
break;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
grs_font *fon = gr_get_font();
|
|
gr_set_font(ResLock(RES_coloraliasedFont));
|
|
short w, h;
|
|
gr_string_size(buf, &w, &h);
|
|
x = (columns == 1) ? (320 - w) / 2 : (cur_col == 0) ? 320 / 2 - 8 - w : 320 / 2 + 8;
|
|
ss_string(buf, x, y);
|
|
ResUnlock(RES_coloraliasedFont);
|
|
gr_set_font(fon);
|
|
|
|
if (underline) {
|
|
short x1, x2, y1, y2;
|
|
|
|
x1 = SCONV_X(x);
|
|
x2 = SCONV_X(x + w - 1);
|
|
for (; x1 <= x2; x1++) {
|
|
y1 = SCONV_Y(y + h + 1);
|
|
y2 = SCONV_Y(y + h + 2);
|
|
if (underline == 2)
|
|
y2 = y1 + (y2 - y1) / 2;
|
|
else
|
|
y2 = y1 + (y2 - y1) / 3;
|
|
for (; y1 <= y2; y1++)
|
|
gr_set_pixel(GREEN_BASE + 4, x1, y1);
|
|
}
|
|
|
|
if (underline == 3) {
|
|
x1 = SCONV_X(x + 1);
|
|
x2 = SCONV_X(x + w - 1 - 1);
|
|
for (; x1 <= x2; x1++) {
|
|
y1 = SCONV_Y(y + h + 1);
|
|
y2 = SCONV_Y(y + h + 2);
|
|
y1 = y1 + (y2 - y1) / 3;
|
|
for (; y1 <= y2; y1++)
|
|
gr_set_pixel(GREEN_BASE + 4, x1, y1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (columns == 1) {
|
|
y += underline ? 14 : 11;
|
|
underline = 0;
|
|
} else {
|
|
if (!cur_col)
|
|
last_underline = underline;
|
|
else {
|
|
y += (underline || last_underline) ? 14 : 11;
|
|
underline = 0;
|
|
}
|
|
cur_col ^= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
errtype journey_credits_func(uchar draw_stuff) {
|
|
setup_mode = SETUP_CREDITS;
|
|
|
|
if (draw_stuff) {
|
|
if (music_on) {
|
|
if (WonGame_ShowStats) {
|
|
MacTuneLoadTheme("endloop", 0);
|
|
} else {
|
|
CreditsTune = 0;
|
|
load_score_guts(7); // elevator
|
|
}
|
|
}
|
|
|
|
if (WonGame_ShowStats)
|
|
PrintWinStats();
|
|
PrintCredits();
|
|
|
|
WonGame_ShowStats = 0;
|
|
|
|
journey_credits_done();
|
|
} else {
|
|
if (credits_inp != 0) {
|
|
journey_credits_done();
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
void journey_credits_done(void) {
|
|
kb_flush();
|
|
mouse_flush();
|
|
|
|
credits_inp = 0;
|
|
|
|
uiShowMouse(NULL);
|
|
|
|
journey_draw(0);
|
|
|
|
if (music_on)
|
|
MacTuneLoadTheme("titloop", 0);
|
|
}
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
|
|
// CONTINUE
|
|
|
|
#define SG_SLOT_HT 17
|
|
#define SG_SLOT_WD 169
|
|
#define SG_SLOT_OFFSET_X 21
|
|
#define SG_SLOT_OFFSET_Y 6
|
|
#define SG_SLOT_X 79
|
|
#define SG_SLOT_Y 62
|
|
|
|
#define REF_IMG_bmContinueScreen 0x26e0000
|
|
|
|
char curr_sg = 0;
|
|
|
|
errtype draw_sg_slot(int slot_num) {
|
|
char temp[64];
|
|
short sz, x, y;
|
|
|
|
uiHideMouse(NULL);
|
|
|
|
if (curr_sg == slot_num)
|
|
gr_set_fcolor(KEYBOARD_FOCUS_COLOR);
|
|
else
|
|
gr_set_fcolor(NORMAL_ENTRY_COLOR);
|
|
|
|
// if slot_num == -1 highlight the curr_sg slot with the SELECTED_COLOR color
|
|
if (slot_num == -1) {
|
|
gr_set_fcolor(SELECTED_COLOR);
|
|
slot_num = curr_sg;
|
|
}
|
|
|
|
if (valid_save & (1 << slot_num)) {
|
|
sz = strlen(comments[slot_num]);
|
|
strcpy(temp, comments[slot_num]);
|
|
} else {
|
|
get_string(REF_STR_UnusedSave, temp, 64);
|
|
}
|
|
|
|
gr_set_font(ResLock(RES_smallTechFont));
|
|
gr_string_size(temp, &x, &y);
|
|
|
|
while ((x > SG_SLOT_WD - SG_SLOT_OFFSET_X) && (sz > 0)) {
|
|
sz--;
|
|
strcpy(temp, "");
|
|
strncpy(temp, comments[slot_num], sz);
|
|
temp[sz] = '\0';
|
|
gr_string_size(temp, &x, &y);
|
|
}
|
|
|
|
ResUnlock(RES_smallTechFont); // was RES_CitadelFont
|
|
|
|
res_draw_text(RES_smallTechFont, temp, SG_SLOT_X + SG_SLOT_OFFSET_X,
|
|
SG_SLOT_Y + SG_SLOT_OFFSET_Y + (slot_num * SG_SLOT_HT));
|
|
|
|
uiShowMouse(NULL);
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype draw_savegame_names(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_SAVE_SLOTS; i++)
|
|
draw_sg_slot(i);
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype load_that_thar_game(int which_slot) {
|
|
DEBUG("load_that_thar_game %i", which_slot);
|
|
|
|
errtype retval;
|
|
|
|
if (valid_save & (1 << which_slot)) {
|
|
draw_sg_slot(-1); // highlight the current save game slot with SELECTED_COLOR
|
|
|
|
clear_player_data = TRUE; // initializes the player struct in object_data_load
|
|
object_data_load();
|
|
player_create_initial();
|
|
player_struct.level = 0xFF; // make sure we load textures
|
|
Poke_SaveName(which_slot);
|
|
change_mode_func(0, 0, GAME_LOOP);
|
|
retval = load_game(save_game_name);
|
|
if (retval != OK) {
|
|
strcpy(comments[which_slot], "<< INVALID GAME >>");
|
|
uiHideMouse(NULL);
|
|
journey_continue_func(TRUE);
|
|
return retval;
|
|
}
|
|
|
|
gr2ss_override = OVERRIDE_ALL; // CC: This fixed popups cursors drawing tiny after loading
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype journey_continue_func(uchar draw_stuff) {
|
|
|
|
#ifndef DEMO
|
|
if (save_game_exists) {
|
|
// draw_raw_res_bm_extract(REF_IMG_bmContinueScreen, 0, 0);
|
|
|
|
// do what the above line does, but hack bitmap height
|
|
Ref rid = REF_IMG_bmContinueScreen;
|
|
int i = REFINDEX(rid);
|
|
RefTable *rt = ResReadRefTable(REFID(rid));
|
|
if (RefIndexValid(rt, i)) {
|
|
FrameDesc *f = RefLock(rid);
|
|
grs_bitmap bm = f->bm;
|
|
bm.h = 200; // SUPER HACK: resource reports 320
|
|
ss_bitmap(&bm, 0, 0);
|
|
RefUnlock(rid);
|
|
}
|
|
ResFreeRefTable(rt);
|
|
|
|
setup_mode = SETUP_CONTINUE;
|
|
draw_savegame_names();
|
|
}
|
|
#endif
|
|
|
|
uiShowMouse(NULL);
|
|
|
|
return OK;
|
|
}
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
|
|
// SETUP
|
|
|
|
#define DO_FADES
|
|
|
|
#define SECRET_MISSION_DIFFICULTY_QB 0xB0
|
|
|
|
#define ALT(x) ((x) | KB_FLAG_ALT)
|
|
|
|
#define CFG_NAME_VAR "name"
|
|
|
|
char diff_qvars[4] = {COMBAT_DIFF_QVAR, MISSION_DIFF_QVAR, PUZZLE_DIFF_QVAR, CYBER_DIFF_QVAR};
|
|
|
|
typedef errtype (*journey_func)(uchar draw_stuff);
|
|
|
|
journey_func journey_funcs[4] = {journey_intro_func, journey_difficulty_func, journey_credits_func,
|
|
journey_continue_func};
|
|
|
|
// if there are two different input events - only lets one call a journey_func
|
|
uchar journey_lock = FALSE;
|
|
|
|
void go_and_start_the_game_already(void) {
|
|
INFO("New Journey");
|
|
|
|
char i;
|
|
|
|
#ifdef GAMEONLY
|
|
if (strlen(player_struct.name) == 0) {
|
|
flash_username();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
uiHideMouse(NULL);
|
|
gr_set_fcolor(SELECTED_COLOR);
|
|
res_draw_string(RES_citadelFont, DIFF_START, DIFF_DONE_X1 + 13, DIFF_DONE_Y1 + 2);
|
|
uiShowMouse(NULL);
|
|
|
|
journey_newgame_func();
|
|
|
|
#ifdef SVGA_SUPPORT
|
|
QUESTVAR_SET(SCREENMODE_QVAR, convert_use_mode);
|
|
#endif
|
|
|
|
QUESTVAR_SET(MUSIC_VOLUME_QVAR, (curr_vol_lev * curr_vol_lev) / 100);
|
|
QUESTVAR_SET(SFX_VOLUME_QVAR, (curr_sfx_vol * curr_sfx_vol) / 100);
|
|
|
|
#ifdef AUDIOLOGS
|
|
QUESTVAR_SET(ALOG_VOLUME_QVAR, (curr_alog_vol * curr_alog_vol) / 100);
|
|
QUESTVAR_SET(ALOG_OPT_QVAR, audiolog_setting);
|
|
#endif
|
|
|
|
QUESTVAR_SET(FULLSCRN_ICON_QVAR, fullscrn_icons);
|
|
QUESTVAR_SET(FULLSCRN_VITAL_QVAR, fullscrn_vitals);
|
|
QUESTVAR_SET(AMAP_NOTES_QVAR, map_notes_on);
|
|
QUESTVAR_SET(HUDCOLOR_QVAR, hud_color_bank);
|
|
QUESTVAR_SET(SCREENMODE_QVAR, 3);
|
|
QUESTVAR_SET(DCLICK_QVAR, FIX_UNIT / 3);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
QUESTVAR_SET(diff_qvars[i], player_struct.difficulty[i]);
|
|
if (QUESTVAR_GET(MISSION_DIFF_QVAR) == 3)
|
|
hud_set(HUD_GAMETIME);
|
|
|
|
strncpy(player_struct.version, SYSTEM_SHOCK_VERSION, 6);
|
|
|
|
if (setup_bio_started) {
|
|
status_bio_end();
|
|
setup_bio_started = FALSE;
|
|
}
|
|
|
|
gr2ss_override = OVERRIDE_ALL; // CC: This fixed popups cursors drawing tiny
|
|
}
|
|
|
|
uchar intro_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t user_data) {
|
|
int which_one = -1;
|
|
int i = 0;
|
|
int old_diff;
|
|
uchar diff_changed;
|
|
|
|
#ifndef NO_DUMMIES
|
|
intptr_t dummy = user_data;
|
|
LGRegion *dummy2 = r;
|
|
#endif
|
|
|
|
if (ev->mouse_data.action & MOUSE_LDOWN) {
|
|
// If in the splash screen, advance
|
|
if (waiting_for_key) {
|
|
waiting_for_key = false;
|
|
return OK;
|
|
}
|
|
|
|
switch (setup_mode) {
|
|
case SETUP_JOURNEY:
|
|
if (!journey_lock) {
|
|
if ((ev->pos.x > JOURNEY_OPT_LEFT) && (ev->pos.x < JOURNEY_OPT_RIGHT)) {
|
|
while ((which_one == -1) && (i <= 6)) {
|
|
if ((ev->pos.y > journey_y[i]) && (ev->pos.y < journey_y[i + 1]))
|
|
which_one = i >> 1;
|
|
else
|
|
i += 2;
|
|
}
|
|
TRACE("%s: which_one = %d", __FUNCTION__, which_one);
|
|
if (which_one != -1) {
|
|
uiHideMouse(NULL);
|
|
gr_set_fcolor(SELECTED_COLOR);
|
|
journey_lock = TRUE;
|
|
journey_funcs[which_one](TRUE);
|
|
journey_lock = FALSE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SETUP_CREDITS:
|
|
credits_inp = -1;
|
|
break;
|
|
|
|
case SETUP_CONTINUE:
|
|
if ((ev->pos.x >= SG_SLOT_X) && (ev->pos.x <= SG_SLOT_X + SG_SLOT_WD) && (ev->pos.y >= SG_SLOT_Y) &&
|
|
(ev->pos.y <= SG_SLOT_Y + (NUM_SAVE_SLOTS * SG_SLOT_HT))) {
|
|
char which = (ev->pos.y - SG_SLOT_Y) / SG_SLOT_HT;
|
|
char old_sg = curr_sg;
|
|
|
|
curr_sg = which;
|
|
draw_sg_slot(old_sg);
|
|
load_that_thar_game(which);
|
|
}
|
|
break;
|
|
|
|
case SETUP_DIFFICULTY:
|
|
diff_changed = FALSE;
|
|
// given that these are all rectangles, i bet you could just get mouse pos and divide, eh?
|
|
for (i = 0; i < 16; i++) {
|
|
if ((ev->pos.x > (build_diff_x(i) - 2)) && (ev->pos.x < (build_diff_x(i) - 2 + DIFF_SIZE_X)) &&
|
|
(ev->pos.y > (build_diff_y(i) - 2)) && (ev->pos.y < (build_diff_y(i) - 2 + DIFF_SIZE_Y))) {
|
|
old_diff = player_struct.difficulty[i / 4];
|
|
draw_difficulty_description(i / 4, 0);
|
|
player_struct.difficulty[i / 4] = i % 4;
|
|
TRACE("%s: difficulty %d set to %d (verify = %d)", __FUNCTION__, i / 4, i % 4,
|
|
player_struct.difficulty[i / 4]);
|
|
draw_difficulty_char(((i / 4) * 4) + old_diff);
|
|
draw_difficulty_char(i);
|
|
draw_difficulty_description(i / 4, NORMAL_ENTRY_COLOR);
|
|
diff_changed = TRUE;
|
|
}
|
|
}
|
|
if (diff_changed)
|
|
compute_new_diff();
|
|
else if ((ev->pos.x > DIFF_DONE_X1) && (ev->pos.x < DIFF_DONE_X2) && (ev->pos.y > DIFF_DONE_Y1) &&
|
|
(ev->pos.y < DIFF_DONE_Y2))
|
|
go_and_start_the_game_already();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
uchar intro_key_handler(uiEvent *ev, LGRegion *r, intptr_t user_data) {
|
|
int code = ev->cooked_key_data.code & ~(KB_FLAG_DOWN | KB_FLAG_2ND);
|
|
char old_diff, old_setup_line = curr_setup_line, n = 0;
|
|
|
|
if (ev->cooked_key_data.code & KB_FLAG_DOWN) {
|
|
// If in the splash screen, advance
|
|
if (waiting_for_key) {
|
|
waiting_for_key = false;
|
|
return OK;
|
|
}
|
|
|
|
switch (setup_mode) {
|
|
case SETUP_JOURNEY:
|
|
switch (code) {
|
|
case KEY_UP:
|
|
n = NUM_SETUP_LINES - 2; // sneaky fallthrough action
|
|
case KEY_DOWN:
|
|
n++;
|
|
curr_setup_line = (curr_setup_line + n) % NUM_SETUP_LINES;
|
|
#ifdef DEMO
|
|
if (curr_setup_line == NUM_SETUP_LINES - 1) // why is NUM_SETUP_LINES-1 necessarily continue?
|
|
curr_setup_line = 2;
|
|
if (curr_setup_line == 0)
|
|
curr_setup_line = 1;
|
|
#else
|
|
if (curr_setup_line == NUM_SETUP_LINES - 1) // why is NUM_SETUP_LINES-1 necessarily continue?
|
|
if (!save_game_exists)
|
|
curr_setup_line = (curr_setup_line + n) % NUM_SETUP_LINES;
|
|
#endif
|
|
journey_draw(old_setup_line + 1);
|
|
journey_draw(curr_setup_line + 1);
|
|
break;
|
|
|
|
case KEY_ENTER:
|
|
if (!journey_lock) {
|
|
uiHideMouse(NULL);
|
|
gr_set_fcolor(SELECTED_COLOR);
|
|
journey_lock = TRUE;
|
|
journey_funcs[curr_setup_line](TRUE);
|
|
journey_lock = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SETUP_CREDITS:
|
|
credits_inp = code;
|
|
break;
|
|
|
|
case SETUP_CONTINUE:
|
|
switch (code) {
|
|
case KEY_UP:
|
|
case KEY_LEFT:
|
|
n = NUM_SAVE_SLOTS - 2;
|
|
case KEY_DOWN:
|
|
case KEY_RIGHT:
|
|
n++;
|
|
old_diff = curr_sg;
|
|
curr_sg = (curr_sg + n) % NUM_SAVE_SLOTS;
|
|
draw_sg_slot(old_diff);
|
|
draw_sg_slot(curr_sg);
|
|
break;
|
|
|
|
case KEY_ENTER:
|
|
load_that_thar_game(curr_sg);
|
|
break;
|
|
|
|
case KEY_ESC:
|
|
journey_draw(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SETUP_DIFFICULTY:
|
|
switch (code) {
|
|
case ALT('X'): // Don't print the X when user ALT-X's out of the game
|
|
case ALT('x'):
|
|
break;
|
|
|
|
case '-':
|
|
case KEY_LEFT:
|
|
n = NUM_DIFF_CATEGORIES - 2; // note sneaky -2 for fallthrough
|
|
case '+':
|
|
case KEY_RIGHT:
|
|
n++; // n now NDC-1 or 1
|
|
if (!start_selected) {
|
|
old_diff = player_struct.difficulty[curr_diff];
|
|
draw_difficulty_description(curr_diff, 0);
|
|
player_struct.difficulty[curr_diff] =
|
|
(player_struct.difficulty[curr_diff] + n) % NUM_DIFF_CATEGORIES;
|
|
draw_difficulty_char(curr_diff * NUM_DIFF_CATEGORIES + player_struct.difficulty[curr_diff]);
|
|
draw_difficulty_char(curr_diff * NUM_DIFF_CATEGORIES + old_diff);
|
|
draw_difficulty_description(curr_diff, NORMAL_ENTRY_COLOR);
|
|
compute_new_diff();
|
|
}
|
|
break;
|
|
|
|
case KEY_UP:
|
|
case (KEY_TAB | KB_FLAG_SHIFT):
|
|
n = NUM_DIFF_CATEGORIES - 2; // sneaky fallthrough
|
|
case KEY_DOWN:
|
|
case KEY_TAB:
|
|
n++; // now -1 or 1
|
|
if (start_selected && n == 1) {
|
|
start_selected = FALSE;
|
|
curr_diff = 0;
|
|
} else if (start_selected && n == NUM_DIFF_CATEGORIES - 1) {
|
|
start_selected = FALSE;
|
|
curr_diff = NUM_DIFF_CATEGORIES - 1;
|
|
} else if ((curr_diff == NUM_DIFF_CATEGORIES - 1 && n == 1) ||
|
|
(curr_diff == 0 && n == NUM_DIFF_CATEGORIES - 1))
|
|
start_selected = TRUE;
|
|
else {
|
|
start_selected = FALSE;
|
|
curr_diff = (curr_diff + n) % NUM_DIFF_CATEGORIES;
|
|
}
|
|
difficulty_draw(FALSE);
|
|
break;
|
|
|
|
case KEY_ENTER:
|
|
go_and_start_the_game_already();
|
|
break;
|
|
|
|
case KEY_ESC:
|
|
journey_draw(0);
|
|
break;
|
|
|
|
default: {
|
|
draw_username(0, player_struct.name);
|
|
n = strlen(player_struct.name);
|
|
short c = ev->cooked_key_data.code;
|
|
if (kb_isprint(c) && (n < sizeof(player_struct.name)) &&
|
|
(((c & 0xff) >= 128 && (c & 0xff) <= 155) || ((c & 0xff) >= 160 && (c & 0xff) <= 165) ||
|
|
strchr(valid_char_string, c & 0xFF) != NULL)) {
|
|
player_struct.name[n] = (c & 0xFF);
|
|
player_struct.name[n + 1] = '\0';
|
|
}
|
|
if (((c & 0xFF) == KEY_BS) && (n > 0))
|
|
player_struct.name[n - 1] = '\0';
|
|
draw_username(NORMAL_ENTRY_COLOR, player_struct.name);
|
|
} break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (main_kb_callback(ev, r, user_data));
|
|
}
|
|
|
|
errtype load_savegame_names(void) {
|
|
int i;
|
|
int file;
|
|
|
|
valid_save = 0;
|
|
|
|
DEBUG("Grabbing save game names");
|
|
|
|
for (i = 0; i < NUM_SAVE_SLOTS; i++) {
|
|
Poke_SaveName(i);
|
|
|
|
#ifdef __APPLE__
|
|
char full_save_game_name[1024];
|
|
sprintf(full_save_game_name, "%s%s", SDL_GetPrefPath("Interrupt", "SystemShock"), save_game_name);
|
|
if (access(full_save_game_name, F_OK) != -1) {
|
|
#else
|
|
if (access(save_game_name, F_OK) != -1) {
|
|
#endif
|
|
file = ResOpenFile(save_game_name);
|
|
if (ResInUse(OLD_SAVE_GAME_ID_BASE)) {
|
|
#ifdef OLD_SG_FORMAT
|
|
ResExtract(OLD_SAVE_GAME_ID_BASE, FORMAT_RAW, comments[i]);
|
|
valid_save |= (1 << i);
|
|
#else
|
|
strcpy(comments[i], "<< BAD VERSION >>");
|
|
#endif
|
|
} else {
|
|
if (ResInUse(SAVELOAD_VERIFICATION_ID)) {
|
|
int verify_cookie;
|
|
|
|
ResExtract(SAVELOAD_VERIFICATION_ID, FORMAT_U32, &verify_cookie);
|
|
switch (verify_cookie) {
|
|
case OLD_VERIFY_COOKIE_VALID:
|
|
// Uncomment these lines to reject Shock Floppy save games
|
|
// sprintf(comments[i], "<< %s >>",get_temp_string(REF_STR_BadVersion + 1));
|
|
// break;
|
|
|
|
case VERIFY_COOKIE_VALID:
|
|
ResExtract(SAVE_GAME_ID_BASE, FORMAT_RAW, comments[i]);
|
|
valid_save |= (1 << i);
|
|
break;
|
|
|
|
default:
|
|
sprintf(comments[i], "<< %s >>", get_temp_string(REF_STR_BadVersion));
|
|
break;
|
|
}
|
|
} else
|
|
sprintf(comments[i], "<< %s >>", get_temp_string(REF_STR_BadVersion));
|
|
}
|
|
|
|
ResCloseFile(file);
|
|
} else
|
|
*(comments[i]) = '\0';
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
errtype setup_init(void) {
|
|
#ifndef GAMEONLY
|
|
int data[1];
|
|
int cnt;
|
|
#endif
|
|
|
|
generic_reg_init(TRUE, &setup_root_region, NULL, &setup_slab, intro_key_handler, intro_mouse_handler);
|
|
|
|
#ifndef GAMEONLY
|
|
cnt = 1;
|
|
// if (config_get_value("intro", CONFIG_INT_TYPE, data, &cnt))
|
|
{
|
|
physics_running = TRUE;
|
|
time_passes = TRUE;
|
|
_current_loop = SETUP_LOOP;
|
|
}
|
|
if (!config_get_raw(CFG_NAME_VAR, player_struct.name, 40))
|
|
strcpy(player_struct.name, get_temp_string(REF_STR_DefaultPlayName));
|
|
load_savegame_names();
|
|
#endif
|
|
|
|
setup_mode = SETUP_JOURNEY;
|
|
|
|
return OK;
|
|
}
|
|
|
|
void pause_for_key(ulong wait_time) {
|
|
waiting_for_key = true;
|
|
|
|
ulong wait_until = TickCount() + wait_time;
|
|
|
|
while (waiting_for_key && ((ulong)TickCount() < wait_until)) {
|
|
input_chk();
|
|
pump_events();
|
|
SDLDraw();
|
|
}
|
|
|
|
waiting_for_key = false;
|
|
}
|
|
|
|
void splash_draw(bool show_splash) {
|
|
int pal_file;
|
|
|
|
if (!show_splash)
|
|
return;
|
|
|
|
// Need to load the splash palette file
|
|
|
|
INFO("Loading splshpal.res");
|
|
pal_file = ResOpenFile("res/data/splshpal.res");
|
|
|
|
INFO("Loading splash.res");
|
|
splash_num = ResOpenFile("res/data/splash.res");
|
|
|
|
if (pal_file < 0)
|
|
INFO("Could not open splshpal.res!");
|
|
|
|
uchar splash_pal[768];
|
|
ResExtract(RES_splashPalette, FORMAT_RAW, splash_pal);
|
|
|
|
// Set initial palette
|
|
|
|
gr_set_pal(0, 256, splash_pal);
|
|
|
|
// Set screen mode
|
|
|
|
#ifdef SVGA_SUPPORT
|
|
change_svga_screen_mode();
|
|
#endif
|
|
|
|
// clear the screen
|
|
gr_clear(0);
|
|
|
|
HotkeyContext = SETUP_CONTEXT;
|
|
uiSetCurrentSlab(&setup_slab);
|
|
|
|
// Draw Origin Logo
|
|
|
|
#ifdef DO_FADES
|
|
do_fades = true && pal_fx_on;
|
|
#endif
|
|
|
|
uiHideMouse(NULL);
|
|
draw_full_res_bm(REF_IMG_bmOriginSplash, 0, 0, do_fades);
|
|
pause_for_key(500);
|
|
|
|
if (do_fades)
|
|
palfx_fade_down();
|
|
|
|
// Draw LGS Logo
|
|
|
|
uiHideMouse(NULL);
|
|
draw_full_res_bm(REF_IMG_bmLGSplash, 0, 0, do_fades);
|
|
pause_for_key(500);
|
|
|
|
if (do_fades)
|
|
palfx_fade_down();
|
|
|
|
// Draw System Shock title
|
|
|
|
uiHideMouse(NULL);
|
|
draw_full_res_bm(REF_IMG_bmSystemShockTitle, 0, 0, do_fades);
|
|
pause_for_key(500);
|
|
|
|
if (do_fades)
|
|
palfx_fade_down();
|
|
|
|
// Original palette
|
|
gr_set_pal(0, 256, ppall);
|
|
}
|
|
|
|
void setup_loop(void) {
|
|
bool draw_stuff = FALSE;
|
|
|
|
// loop title music
|
|
int i = 0;
|
|
if (music_on && !IsPlaying(i)) {
|
|
int track = 0;
|
|
if (track >= 0 && track < NumTracks) {
|
|
// int volume = (int)curr_vol_lev * 127 / 100; //convert from 0-100 to 0-127
|
|
StartTrack(i, track);
|
|
}
|
|
}
|
|
|
|
if (last_setup_mode != setup_mode) {
|
|
uiHideMouse(NULL);
|
|
gr_clear(0xFF);
|
|
draw_stuff = TRUE;
|
|
}
|
|
|
|
last_setup_mode = setup_mode;
|
|
|
|
switch (setup_mode) {
|
|
case SETUP_DIFFICULTY:
|
|
difficulty_draw(draw_stuff);
|
|
break;
|
|
case SETUP_JOURNEY:
|
|
journey_draw(draw_stuff);
|
|
break;
|
|
case SETUP_CONTINUE:
|
|
journey_continue_func(draw_stuff);
|
|
break;
|
|
case SETUP_CREDITS:
|
|
journey_credits_func(draw_stuff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if these don't get reset, sticky residue of any old game sticks around
|
|
void empty_slate(void) {
|
|
flush_resource_cache();
|
|
|
|
extern uint _fr_glob_flags;
|
|
_fr_glob_flags = 0;
|
|
|
|
extern uchar *shodan_bitmask;
|
|
shodan_bitmask = NULL;
|
|
|
|
extern uchar alternate_death;
|
|
alternate_death = FALSE;
|
|
|
|
extern uiSlab fullscreen_slab;
|
|
extern uiSlab main_slab;
|
|
uiPopSlabCursor(&fullscreen_slab);
|
|
uiPopSlabCursor(&main_slab);
|
|
|
|
extern uchar fire_slam;
|
|
fire_slam = FALSE;
|
|
|
|
extern short inventory_page;
|
|
inventory_page = 0;
|
|
|
|
extern short inv_last_page;
|
|
inv_last_page = -1;
|
|
|
|
extern void physics_zero_all_controls(void);
|
|
physics_zero_all_controls();
|
|
|
|
extern int mlook_enabled;
|
|
mlook_enabled = 0;
|
|
|
|
extern uchar weapon_button_up;
|
|
weapon_button_up = TRUE;
|
|
}
|
|
|
|
void setup_start(void) {
|
|
int do_i_svg = -1, i_invuln = 0;
|
|
|
|
empty_slate();
|
|
|
|
player_struct.name[0] = 0;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
player_struct.difficulty[i] = 2;
|
|
|
|
MacTuneKillCurrentTheme();
|
|
|
|
// Check to see whether or not to play the intro cut scene
|
|
#ifdef GAMEONLY
|
|
load_savegame_names();
|
|
#endif
|
|
|
|
save_game_exists = (valid_save != 0);
|
|
|
|
if (setup_mode != SETUP_CREDITS) {
|
|
if (!save_game_exists && start_first_time) {
|
|
play_intro_anim = TRUE;
|
|
} else {
|
|
play_intro_anim = FALSE;
|
|
}
|
|
setup_mode = SETUP_JOURNEY;
|
|
}
|
|
|
|
if (!start_first_time)
|
|
closedown_game(TRUE);
|
|
start_first_time = FALSE;
|
|
|
|
#ifdef GADGET
|
|
// got rid of pointer type mismatch since one was a region and the other a gadget
|
|
// someone should probably go and figure it out
|
|
_current_root = NULL;
|
|
#endif
|
|
_current_3d_flag = ANIM_UPDATE;
|
|
_current_fr_context = NULL;
|
|
_current_view = &setup_root_region;
|
|
static_change_copy();
|
|
message_info("");
|
|
|
|
#ifdef SVGA_SUPPORT
|
|
change_svga_screen_mode();
|
|
#endif
|
|
|
|
// clear the screen
|
|
gr_clear(0);
|
|
|
|
HotkeyContext = SETUP_CONTEXT;
|
|
uiSetCurrentSlab(&setup_slab);
|
|
|
|
// flush the keyboard and mouse - so we don't read old events
|
|
kb_flush();
|
|
mouse_flush();
|
|
|
|
intro_num = ResOpenFile("res/data/intro.res");
|
|
|
|
// slam in the right palette
|
|
load_da_palette();
|
|
|
|
if (do_i_svg != -1) {
|
|
#ifdef PLAYTEST
|
|
player_invulnerable = i_invuln;
|
|
#endif
|
|
uiShowMouse(NULL);
|
|
} else if (!play_intro_anim) {
|
|
uiShowMouse(NULL);
|
|
switch (setup_mode) {
|
|
case SETUP_DIFFICULTY:
|
|
difficulty_draw(TRUE);
|
|
break;
|
|
case SETUP_JOURNEY:
|
|
journey_draw(0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
direct_into_cutscene = FALSE;
|
|
} else {
|
|
direct_into_cutscene = TRUE;
|
|
|
|
play_cutscene(START_CUTSCENE, FALSE);
|
|
}
|
|
|
|
if (music_on)
|
|
MacTuneLoadTheme("titloop", 0);
|
|
|
|
CaptureMouse(false);
|
|
}
|
|
|
|
void setup_exit(void) {
|
|
ResCloseFile(intro_num);
|
|
ResCloseFile(splash_num);
|
|
|
|
#ifdef PALFX_FADES
|
|
if (pal_fx_on)
|
|
palfx_fade_down();
|
|
else {
|
|
gr_set_fcolor(BLACK);
|
|
gr_rect(0, 0, 320, 200);
|
|
}
|
|
#endif
|
|
|
|
// must get rid of mouse - to maintain hidden mouse after loop
|
|
if (!direct_into_cutscene)
|
|
uiHideMouse(NULL);
|
|
|
|
direct_into_cutscene = FALSE;
|
|
|
|
MacTuneKillCurrentTheme();
|
|
}
|
|
//*****************************************************************************
|