shithub: cstory

ref: 451945e80cc0a51384de0e292c294795733e7696
dir: /src/Main.cpp/

View raw version
#include "Main.h"

#include <stddef.h>
#include <stdio.h>
#include <string.h>

#include <shlwapi.h>

#include "WindowsWrapper.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 "Sound.h"
#include "Triangle.h"

char gModulePath[MAX_PATH];
char gDataPath[MAX_PATH];

int gJoystickButtonTable[8];

HWND ghWnd;
BOOL bFullscreen;

static BOOL gbUseJoystick = FALSE;
static BOOL bFps = FALSE;
static BOOL bActive = TRUE;

static HANDLE hObject;
static HANDLE hMutex;
static HINSTANCE ghInstance;

static int windowWidth;
static int windowHeight;

static const char *mutex_name = "Doukutsu";

#ifdef JAPANESE
static const char *lpWindowName = "\x93\xB4\x8C\x41\x95\xA8\x8C\xEA";
#else
static const char *lpWindowName = "Cave Story ~ Doukutsu Monogatari";
#endif

// Framerate stuff
void PutFramePerSecound()
{
	if (bFps)
		PutNumber4(WINDOW_WIDTH - 40, 8, GetFramePerSecound(), FALSE);
}

int GetFramePerSecound()
{
/*	unsigned int current_tick;
	static BOOL need_new_base_tick = TRUE;
	static int frames_this_second;
	static int current_frame;
	static int base_tick;

	if (need_new_base_tick)
	{
		base_tick = SDL_GetTicks();
		need_new_base_tick = FALSE;
	}

	current_tick = SDL_GetTicks();
	++current_frame;

	if (base_tick + 1000 <= current_tick)
	{
		base_tick += 1000;
		frames_this_second = current_frame;
		current_frame = 0;
	}

	return frames_this_second;*/
	return 0;
}

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	hObject = OpenMutexA(MUTEX_ALL_ACCESS, 0, mutex_name);
	if (hObject != NULL)
	{
		CloseHandle(hObject);
		return 0;
	}

	hMutex = CreateMutexA(NULL, FALSE, mutex_name);

	ghInstance = hInstance;

	// Get executable's path
	GetModuleFileNameA(NULL, gModulePath, MAX_PATH);
	PathRemoveFileSpecA(gModulePath);

	// Get path of the data folder
	strcpy(gDataPath, gModulePath);
	strcat(gDataPath, "\\data");

	CONFIG 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 (CheckFileExists("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 (int 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};

	WNDCLASSEXA wndclassex;
	memset(&wndclassex, 0, sizeof(WNDCLASSEXA));
	wndclassex.cbSize = sizeof(WNDCLASSEXA);
//	wndclassex.lpfnWndProc = WindowProcedure;
	wndclassex.hInstance = hInstance;
	wndclassex.hbrBackground = (HBRUSH)GetStockObject(3);
	wndclassex.lpszClassName = lpWindowName;
	wndclassex.hCursor = LoadCursorA(hInstance, "CURSOR_NORMAL");
	wndclassex.hIcon = LoadIconA(hInstance, "0");
	wndclassex.hIconSm = LoadIconA(hInstance, "ICON_MINI");

	HWND hWnd;

	switch (conf.display_mode)
	{
		case 1:
		case 2:
		{
			wndclassex.lpszMenuName = "MENU_MAIN";
			if (RegisterClassExA(&wndclassex) == 0)
			{
				ReleaseMutex(hMutex);
				return 0;
			}

			// Set window dimensions
			if (conf.display_mode == 1)
			{
				windowWidth = WINDOW_WIDTH;
				windowHeight = WINDOW_HEIGHT;
			}
			else
			{
				windowWidth = WINDOW_WIDTH * 2;
				windowHeight = WINDOW_HEIGHT * 2;
			}

			int nWidth = windowWidth + 2 * GetSystemMetrics(7) + 2;

			int nHeight = (2 * GetSystemMetrics(8) + GetSystemMetrics(4)) + GetSystemMetrics(15) + windowHeight + 2;
			int x = (GetSystemMetrics(0) - nWidth) / 2;
			int y = (GetSystemMetrics(1) - nHeight) / 2;
			SetWindowPadding(GetSystemMetrics(7) + 1, GetSystemMetrics(8) + GetSystemMetrics(4) + GetSystemMetrics(15) + 1);

			hWnd = CreateWindowExA(0, lpWindowName, lpWindowName, 0x10CA0000u, x, y, nWidth, nHeight, 0, 0, hInstance, 0);
			ghWnd = hWnd;

			if (hWnd == NULL)
			{
				ReleaseMutex(hMutex);
				return 0;
			}

			HMENU v18 = GetMenu(hWnd);

			if (conf.display_mode == 1)
				StartDirectDraw(hWnd, 0, 0);
			else
				StartDirectDraw(hWnd, 1, 0);

			break;
		}

		case 0:
		case 3:
		case 4:
		{
			if (RegisterClassExA(&wndclassex) == 0)
			{
				ReleaseMutex(hMutex);
				return 0;
			}

			// Set window dimensions
			windowWidth = WINDOW_WIDTH * 2;
			windowHeight = WINDOW_HEIGHT * 2;

			SetWindowPadding(0, 0);
			hWnd = CreateWindowExA(0, lpWindowName, lpWindowName, 0x90080000, 0, 0, GetSystemMetrics(0), GetSystemMetrics(1), 0, 0, hInstance, 0);
			ghWnd = hWnd;
			if (hWnd == NULL)
			{
				ReleaseMutex(hMutex);
				return 0;
			}

			// Set colour depth
			int depth;

			switch (conf.display_mode)
			{
				case 0:
					depth = 16;
					break;
				case 3:
					depth = 24;
					break;
				case 4:
					depth = 32;
					break;
			}

			StartDirectDraw(ghWnd, 2, depth);
			bFullscreen = TRUE;

			ShowCursor(0);
			break;
		}
	}

	// 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 - 64) / 2, (WINDOW_HEIGHT - 8) / 2, &rcLoading, SURFACE_ID_LOADING);

	// Draw to screen
	if (!Flip_SystemTask(ghWnd))
	{
		ReleaseMutex(hMutex);
		return 1;
	}
	else
	{
		// Initialize sound
		InitDirectSound(hWnd);

		// Initialize joystick
		if (conf.bJoystick && InitDirectInput(hInstance, hWnd))
		{
			ResetJoystickStatus();
			gbUseJoystick = TRUE;
		}

		// Initialize stuff
		InitTextObject(conf.font_name);
		InitTriangleTable();

		// Run game code
		Game(hWnd);

		// End stuff
		EndDirectSound();
		EndTextObject();
		EndDirectDraw(hWnd);

		ReleaseMutex(hMutex);
	}

	return 1;
}

void InactiveWindow()
{
	if (bActive)
	{
		bActive = FALSE;
		StopOrganyaMusic();
		SleepNoise();
	}

	PlaySoundObject(7, 0);
}

void ActiveWindow()
{
	if (!bActive)
	{
		bActive = TRUE;
		StopOrganyaMusic();
		PlayOrganyaMusic();
		ResetNoise();
	}

	PlaySoundObject(7, -1);
}

void JoystickProc()
{
/*	JOYSTICK_STATUS status;

	if (GetJoystickStatus(&status))
	{
		// Clear held buttons
		gKey &= (KEY_ESCAPE | KEY_F2 | KEY_F1);

		// Set movement buttons
		if (status.bLeft)
			gKey |= gKeyLeft;
		if (status.bRight)
			gKey |= gKeyRight;
		if (status.bUp)
			gKey |= gKeyUp;
		if (status.bDown)
			gKey |= gKeyDown;

		// Set held buttons
		for (int i = 0; i < 8; i++)
		{
			if (status.bButton[i])
				gKey |= gJoystickButtonTable[i];
		}
	}*/
}

#define DO_KEY_PRESS(key) \
	if (event.type == SDL_KEYDOWN) \
		gKey |= key; \
	else \
		gKey &= ~key; \
	break;

BOOL SystemTask()
{
	// Handle window events
	BOOL focusGained = TRUE;
/*
	while (SDL_PollEvent(NULL) || !focusGained)
	{
		SDL_Event event;
		SDL_WaitEvent(&event);

		switch (event.type)
		{
			case SDL_QUIT:
				return FALSE;

			case SDL_WINDOWEVENT:
				switch (event.window.event)
				{
					case SDL_WINDOWEVENT_FOCUS_GAINED:
						focusGained = TRUE;
						ActiveWindow();
						break;

					case SDL_WINDOWEVENT_FOCUS_LOST:
						focusGained = FALSE;
						InactiveWindow();
						break;

					default:
						break;
				}
				break;

			case SDL_DROPFILE:
				LoadProfile(event.drop.file);
				SDL_free(event.drop.file);
				break;

			case SDL_KEYDOWN:
			case SDL_KEYUP:
#ifdef FIX_BUGS
				// BUG FIX: Pixel relied on key codes for input, but these differ based on keyboard layout.
				// This would break the alternate movement keys on typical English keyboards, since the '=' key is in a completely different place to where it is on a Japanese keyboard.
				// To solve this, we use scancodes instead, which are based on the physical location of keys, rather than their meaning.
				switch (event.key.keysym.scancode)
				{
					case SDL_SCANCODE_ESCAPE:
						DO_KEY_PRESS(KEY_ESCAPE)

					case SDL_SCANCODE_W:
						DO_KEY_PRESS(KEY_MAP)

					case SDL_SCANCODE_LEFT:
						DO_KEY_PRESS(KEY_LEFT)

					case SDL_SCANCODE_RIGHT:
						DO_KEY_PRESS(KEY_RIGHT)

					case SDL_SCANCODE_UP:
						DO_KEY_PRESS(KEY_UP)

					case SDL_SCANCODE_DOWN:
						DO_KEY_PRESS(KEY_DOWN)

					case SDL_SCANCODE_X:
						DO_KEY_PRESS(KEY_X)

					case SDL_SCANCODE_Z:
						DO_KEY_PRESS(KEY_Z)

					case SDL_SCANCODE_S:
						DO_KEY_PRESS(KEY_ARMS)

					case SDL_SCANCODE_A:
						DO_KEY_PRESS(KEY_ARMSREV)

					case SDL_SCANCODE_RSHIFT:
					case SDL_SCANCODE_LSHIFT:
						DO_KEY_PRESS(KEY_SHIFT)

					case SDL_SCANCODE_F1:
						DO_KEY_PRESS(KEY_F1)

					case SDL_SCANCODE_F2:
						DO_KEY_PRESS(KEY_F2)

					case SDL_SCANCODE_Q:
						DO_KEY_PRESS(KEY_ITEM)

					case SDL_SCANCODE_COMMA:
						DO_KEY_PRESS(KEY_ALT_LEFT)

					case SDL_SCANCODE_PERIOD:
						DO_KEY_PRESS(KEY_ALT_DOWN)

					case SDL_SCANCODE_SLASH:
						DO_KEY_PRESS(KEY_ALT_RIGHT)

					case SDL_SCANCODE_L:
						DO_KEY_PRESS(KEY_ALT_UP)

					case SDL_SCANCODE_SEMICOLON:
						DO_KEY_PRESS(KEY_PLUS)

					case SDL_SCANCODE_F5:
						gbUseJoystick = FALSE;
						break;

					default:
						break;
				}
				break;
#else
				switch (event.key.keysym.sym)
				{
					case SDLK_ESCAPE:
						DO_KEY_PRESS(KEY_ESCAPE)

					case SDLK_w:
						DO_KEY_PRESS(KEY_MAP)

					case SDLK_LEFT:
						DO_KEY_PRESS(KEY_LEFT)

					case SDLK_RIGHT:
						DO_KEY_PRESS(KEY_RIGHT)

					case SDLK_UP:
						DO_KEY_PRESS(KEY_UP)

					case SDLK_DOWN:
						DO_KEY_PRESS(KEY_DOWN)

					case SDLK_x:
						DO_KEY_PRESS(KEY_X)

					case SDLK_z:
						DO_KEY_PRESS(KEY_Z)

					case SDLK_s:
						DO_KEY_PRESS(KEY_ARMS)

					case SDLK_a:
						DO_KEY_PRESS(KEY_ARMSREV)

					case SDLK_RSHIFT:
					case SDLK_LSHIFT:
						DO_KEY_PRESS(KEY_SHIFT)

					case SDLK_F1:
						DO_KEY_PRESS(KEY_F1)

					case SDLK_F2:
						DO_KEY_PRESS(KEY_F2)

					case SDLK_q:
						DO_KEY_PRESS(KEY_ITEM)

					case SDLK_COMMA:
						DO_KEY_PRESS(KEY_ALT_LEFT)

					case SDLK_PERIOD:
						DO_KEY_PRESS(KEY_ALT_DOWN)

					case SDLK_SLASH:
						DO_KEY_PRESS(KEY_ALT_RIGHT)

					case SDLK_l:
						DO_KEY_PRESS(KEY_ALT_UP)

					case SDLK_SEMICOLON:
						DO_KEY_PRESS(KEY_PLUS)

					case SDLK_F5:
						gbUseJoystick = FALSE;
						break;
				}
				break;
#endif
		}
	}
*/
	// Run joystick code
	if (gbUseJoystick)
		JoystickProc();

	return TRUE;
}