cave-story-solaris/src/Main.cpp
Clownacy 8d296f0385 Allow backend to specify data folder
On the 3DS, I want the data files to go in the read-only ROMFS, while
save data goes on the SD card. This is impossible with the current
system, so I'm changing it.

The other backends will need updating to support this.
2020-10-11 15:58:48 +01:00

636 lines
12 KiB
C++

#include "Main.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "WindowsWrapper.h"
#include "Backends/Misc.h"
#include "Bitmap.h"
#include "CommonDefines.h"
#include "Config.h"
#include "Draw.h"
#include "Game.h"
#include "Generic.h"
#include "Input.h"
#include "KeyControl.h"
#include "MyChar.h"
#include "Organya.h"
#include "Profile.h"
#include "Resource.h"
#include "Sound.h"
#include "Triangle.h"
void InactiveWindow(void);
void ActiveWindow(void);
std::string gModulePath;
std::string gDataPath;
BOOL bFullscreen;
BOOL gbUseJoystick = FALSE;
int gJoystickButtonTable[8];
static BOOL bActive = TRUE;
static BOOL bFPS = FALSE;
static int windowWidth;
static int windowHeight;
#ifdef JAPANESE
static const char* const lpWindowName = "洞窟物語"; // "Cave Story"
#else
static const char* const lpWindowName = "Cave Story ~ Doukutsu Monogatari";
#endif
static void DragAndDropCallback(const char *path)
{
LoadProfile(path);
}
static void WindowFocusCallback(bool focus)
{
if (focus)
ActiveWindow();
else
InactiveWindow();
}
// Framerate stuff
static unsigned long CountFramePerSecound(void)
{
unsigned long current_tick; // The original name for this variable is unknown
static BOOL first = TRUE;
static unsigned long max_count;
static unsigned long count;
static unsigned long wait;
if (first)
{
wait = Backend_GetTicks();
first = FALSE;
}
current_tick = Backend_GetTicks();
++count;
if (wait + 1000 <= current_tick)
{
wait += 1000;
max_count = count;
count = 0;
}
return max_count;
}
void PutFramePerSecound(void)
{
if (bFPS)
{
const unsigned long fps = CountFramePerSecound();
PutNumber4(WINDOW_WIDTH - 40, 8, fps, FALSE);
}
}
// TODO - Inaccurate stack frame
int main(int argc, char *argv[])
{
(void)argc;
int i;
if (!Backend_Init(DragAndDropCallback, WindowFocusCallback))
return EXIT_FAILURE;
// Get executable's path, and path of the data folder
if (!Backend_GetPaths(&gModulePath, &gDataPath))
{
// Fall back on argv[0] if the backend cannot provide a path
gModulePath = argv[0];
for (size_t i = gModulePath.length();; --i)
{
if (i == 0 || gModulePath[i] == '\\' || gModulePath[i] == '/')
{
gModulePath.resize(i);
break;
}
}
gDataPath = gModulePath + "/data";
}
CONFIGDATA conf;
if (!LoadConfigData(&conf))
DefaultConfigData(&conf);
// Apply keybinds
// Swap X and Z buttons
switch (conf.attack_button_mode)
{
case 0:
gKeyJump = KEY_Z;
gKeyShot = KEY_X;
break;
case 1:
gKeyJump = KEY_X;
gKeyShot = KEY_Z;
break;
}
// Swap Okay and Cancel buttons
switch (conf.ok_button_mode)
{
case 0:
gKeyOk = gKeyJump;
gKeyCancel = gKeyShot;
break;
case 1:
gKeyOk = gKeyShot;
gKeyCancel = gKeyJump;
break;
}
// Swap left and right weapon switch keys
if (IsKeyFile("s_reverse"))
{
gKeyArms = KEY_ARMSREV;
gKeyArmsRev = KEY_ARMS;
}
// Alternate movement keys
switch (conf.move_button_mode)
{
case 0:
gKeyLeft = KEY_LEFT;
gKeyUp = KEY_UP;
gKeyRight = KEY_RIGHT;
gKeyDown = KEY_DOWN;
break;
case 1:
gKeyLeft = KEY_ALT_LEFT;
gKeyUp = KEY_ALT_UP;
gKeyRight = KEY_ALT_RIGHT;
gKeyDown = KEY_ALT_DOWN;
break;
}
// Set gamepad inputs
for (i = 0; i < 8; ++i)
{
switch (conf.joystick_button[i])
{
case 1:
gJoystickButtonTable[i] = gKeyJump;
break;
case 2:
gJoystickButtonTable[i] = gKeyShot;
break;
case 3:
gJoystickButtonTable[i] = gKeyArms;
break;
case 6:
gJoystickButtonTable[i] = gKeyArmsRev;
break;
case 4:
gJoystickButtonTable[i] = gKeyItem;
break;
case 5:
gJoystickButtonTable[i] = gKeyMap;
break;
}
}
RECT unused_rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
switch (conf.display_mode)
{
case 1:
case 2:
// Set window dimensions
if (conf.display_mode == 1)
{
windowWidth = WINDOW_WIDTH;
windowHeight = WINDOW_HEIGHT;
}
else
{
windowWidth = WINDOW_WIDTH * 2;
windowHeight = WINDOW_HEIGHT * 2;
}
#ifdef FIX_MAJOR_BUGS
if (conf.display_mode == 1)
{
if (!StartDirectDraw(lpWindowName, windowWidth, windowHeight, 0))
{
Backend_Deinit();
return EXIT_FAILURE;
}
}
else
{
if (!StartDirectDraw(lpWindowName, windowWidth, windowHeight, 1))
{
Backend_Deinit();
return EXIT_FAILURE;
}
}
#else
// Doesn't handle StartDirectDraw failing
if (conf.display_mode == 1)
StartDirectDraw(lpWindowName, windowWidth, windowHeight, 0);
else
StartDirectDraw(lpWindowName, windowWidth, windowHeight, 1);
#endif
break;
case 0:
case 3:
case 4:
// Set window dimensions
windowWidth = WINDOW_WIDTH * 2;
windowHeight = WINDOW_HEIGHT * 2;
#ifdef FIX_MAJOR_BUGS
if (!StartDirectDraw(lpWindowName, windowWidth, windowHeight, 2))
{
Backend_Deinit();
return EXIT_FAILURE;
}
#else
// Doesn't handle StartDirectDraw failing
StartDirectDraw(lpWindowName, windowWidth, windowHeight, 2);
#endif
bFullscreen = TRUE;
Backend_HideMouse();
break;
}
#ifdef DEBUG_SAVE
Backend_EnableDragAndDrop();
#endif
// Set up window icon
#ifndef _WIN32 // On Windows, we use native icons instead (so we can give the taskbar and window separate icons, like the original EXE does)
size_t window_icon_resource_size;
const unsigned char *window_icon_resource_data = FindResource("ICON_MINI", "ICON", &window_icon_resource_size);
if (window_icon_resource_data != NULL)
{
size_t window_icon_width, window_icon_height;
unsigned char *window_icon_rgb_pixels = DecodeBitmap(window_icon_resource_data, window_icon_resource_size, &window_icon_width, &window_icon_height, 3);
if (window_icon_rgb_pixels != NULL)
{
Backend_SetWindowIcon(window_icon_rgb_pixels, window_icon_width, window_icon_height);
FreeBitmap(window_icon_rgb_pixels);
}
}
#endif
// Set up the cursor
size_t cursor_resource_size;
const unsigned char *cursor_resource_data = FindResource("CURSOR_NORMAL", "CURSOR", &cursor_resource_size);
if (cursor_resource_data != NULL)
{
size_t cursor_width, cursor_height;
unsigned char *cursor_rgba_pixels = DecodeBitmap(cursor_resource_data, cursor_resource_size, &cursor_width, &cursor_height, 4);
if (cursor_rgba_pixels != NULL)
{
Backend_SetCursor(cursor_rgba_pixels, cursor_width, cursor_height);
FreeBitmap(cursor_rgba_pixels);
}
}
if (IsKeyFile("fps"))
bFPS = TRUE;
// Set rects
RECT rcLoading = {0, 0, 64, 8};
RECT rcFull = {0, 0, 0, 0};
rcFull.right = WINDOW_WIDTH;
rcFull.bottom = WINDOW_HEIGHT;
// Load the "LOADING" text
BOOL b = MakeSurface_File("Loading", SURFACE_ID_LOADING);
// Draw loading screen
CortBox(&rcFull, 0x000000);
PutBitmap3(&rcFull, (WINDOW_WIDTH / 2) - 32, (WINDOW_HEIGHT / 2) - 4, &rcLoading, SURFACE_ID_LOADING);
// Draw to screen
if (!Flip_SystemTask())
{
Backend_Deinit();
return EXIT_SUCCESS;
}
// Initialize sound
InitDirectSound();
// Initialize joystick
if (conf.bJoystick && InitDirectInput())
{
ResetJoystickStatus();
gbUseJoystick = TRUE;
}
// Initialize stuff
InitTextObject(conf.font_name);
InitTriangleTable();
// Run game code
Game();
// End stuff
EndTextObject();
EndDirectSound();
EndDirectDraw();
Backend_Deinit();
return EXIT_SUCCESS;
}
void InactiveWindow(void)
{
if (bActive)
{
bActive = FALSE;
StopOrganyaMusic();
SleepNoise();
}
PlaySoundObject(7, SOUND_MODE_STOP);
}
void ActiveWindow(void)
{
if (!bActive)
{
bActive = TRUE;
StopOrganyaMusic();
PlayOrganyaMusic();
ResetNoise();
}
PlaySoundObject(7, SOUND_MODE_PLAY_LOOP);
}
void JoystickProc(void);
BOOL SystemTask(void)
{
static bool previous_keyboard_state[BACKEND_KEYBOARD_TOTAL];
do
{
if (!Backend_SystemTask(bActive))
{
StopOrganyaMusic();
return FALSE;
}
} while(!bActive);
bool keyboard_state[BACKEND_KEYBOARD_TOTAL];
Backend_GetKeyboardState(keyboard_state);
for (unsigned int i = 0; i < BACKEND_KEYBOARD_TOTAL; ++i)
{
if (keyboard_state[i] && !previous_keyboard_state[i])
{
switch (i)
{
case BACKEND_KEYBOARD_ESCAPE:
gKey |= KEY_ESCAPE;
break;
case BACKEND_KEYBOARD_W:
gKey |= KEY_MAP;
break;
case BACKEND_KEYBOARD_LEFT:
gKey |= KEY_LEFT;
break;
case BACKEND_KEYBOARD_RIGHT:
gKey |= KEY_RIGHT;
break;
case BACKEND_KEYBOARD_UP:
gKey |= KEY_UP;
break;
case BACKEND_KEYBOARD_DOWN:
gKey |= KEY_DOWN;
break;
case BACKEND_KEYBOARD_X:
gKey |= KEY_X;
break;
case BACKEND_KEYBOARD_Z:
gKey |= KEY_Z;
break;
case BACKEND_KEYBOARD_S:
gKey |= KEY_ARMS;
break;
case BACKEND_KEYBOARD_A:
gKey |= KEY_ARMSREV;
break;
case BACKEND_KEYBOARD_LEFT_SHIFT:
case BACKEND_KEYBOARD_RIGHT_SHIFT:
gKey |= KEY_SHIFT;
break;
case BACKEND_KEYBOARD_F1:
gKey |= KEY_F1;
break;
case BACKEND_KEYBOARD_F2:
gKey |= KEY_F2;
break;
case BACKEND_KEYBOARD_Q:
gKey |= KEY_ITEM;
break;
case BACKEND_KEYBOARD_COMMA:
gKey |= KEY_ALT_LEFT;
break;
case BACKEND_KEYBOARD_PERIOD:
gKey |= KEY_ALT_DOWN;
break;
case BACKEND_KEYBOARD_FORWARD_SLASH:
gKey |= KEY_ALT_RIGHT;
break;
case BACKEND_KEYBOARD_L:
gKey |= KEY_L;
break;
case BACKEND_KEYBOARD_EQUALS:
gKey |= KEY_PLUS;
break;
case BACKEND_KEYBOARD_F5:
gbUseJoystick = FALSE;
break;
}
}
else if (!keyboard_state[i] && previous_keyboard_state[i])
{
switch (i)
{
case BACKEND_KEYBOARD_ESCAPE:
gKey &= ~KEY_ESCAPE;
break;
case BACKEND_KEYBOARD_W:
gKey &= ~KEY_MAP;
break;
case BACKEND_KEYBOARD_LEFT:
gKey &= ~KEY_LEFT;
break;
case BACKEND_KEYBOARD_RIGHT:
gKey &= ~KEY_RIGHT;
break;
case BACKEND_KEYBOARD_UP:
gKey &= ~KEY_UP;
break;
case BACKEND_KEYBOARD_DOWN:
gKey &= ~KEY_DOWN;
break;
case BACKEND_KEYBOARD_X:
gKey &= ~KEY_X;
break;
case BACKEND_KEYBOARD_Z:
gKey &= ~KEY_Z;
break;
case BACKEND_KEYBOARD_S:
gKey &= ~KEY_ARMS;
break;
case BACKEND_KEYBOARD_A:
gKey &= ~KEY_ARMSREV;
break;
case BACKEND_KEYBOARD_LEFT_SHIFT:
case BACKEND_KEYBOARD_RIGHT_SHIFT:
gKey &= ~KEY_SHIFT;
break;
case BACKEND_KEYBOARD_F1:
gKey &= ~KEY_F1;
break;
case BACKEND_KEYBOARD_F2:
gKey &= ~KEY_F2;
break;
case BACKEND_KEYBOARD_Q:
gKey &= ~KEY_ITEM;
break;
case BACKEND_KEYBOARD_COMMA:
gKey &= ~KEY_ALT_LEFT;
break;
case BACKEND_KEYBOARD_PERIOD:
gKey &= ~KEY_ALT_DOWN;
break;
case BACKEND_KEYBOARD_FORWARD_SLASH:
gKey &= ~KEY_ALT_RIGHT;
break;
case BACKEND_KEYBOARD_L:
gKey &= ~KEY_L;
break;
case BACKEND_KEYBOARD_EQUALS:
gKey &= ~KEY_PLUS;
break;
}
}
}
memcpy(previous_keyboard_state, keyboard_state, sizeof(keyboard_state));
// Run joystick code
if (gbUseJoystick)
JoystickProc();
return TRUE;
}
void JoystickProc(void)
{
int i;
DIRECTINPUTSTATUS status;
if (!GetJoystickStatus(&status))
return;
gKey &= (KEY_ESCAPE | KEY_F1 | KEY_F2);
// Set movement buttons
if (status.bLeft)
gKey |= gKeyLeft;
else
gKey &= ~gKeyLeft;
if (status.bRight)
gKey |= gKeyRight;
else
gKey &= ~gKeyRight;
if (status.bUp)
gKey |= gKeyUp;
else
gKey &= ~gKeyUp;
if (status.bDown)
gKey |= gKeyDown;
else
gKey &= ~gKeyDown;
// Clear held buttons
for (i = 0; i < 8; ++i)
gKey &= ~gJoystickButtonTable[i];
// Set held buttons
for (i = 0; i < 8; ++i)
if (status.bButton[i])
gKey |= gJoystickButtonTable[i];
}