ref: 2cd6692a00c2af3644183b362ffc6dcaddc77981
dir: /src/Main.cpp/
#include "Main.h" #include <stddef.h> #include <stdio.h> #include <string.h> #include <SDL.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 "Resource.h" #include "Sound.h" #include "Triangle.h" #include "Types.h" // These two are defined in Draw.cpp. This is a bit of a hack. extern SDL_Window *gWindow; extern SDL_Renderer *gRenderer; char gModulePath[PATH_LENGTH]; char gDataPath[PATH_LENGTH]; int gJoystickButtonTable[8]; bool gbUseJoystick = false; bool bFps = false; bool bActive = true; #ifdef JAPANESE const char *lpWindowName = "洞窟物語エンジン2"; #else const char *lpWindowName = "Cave Story Engine 2 ~ Doukutsu Monogatari Enjin 2"; #endif // A replication of MSVC's rand algorithm static unsigned long int next = 1; int rep_rand() { next = ((next) * 214013 + 2531011); return ((next) >> 16) & 0x7FFF; } void rep_srand(unsigned int seed) { next = seed; } // 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; } int main(int argc, char *argv[]) { // Get executable's path strcpy(gModulePath, SDL_GetBasePath()); if (gModulePath[strlen(gModulePath) - 1] == '/' || gModulePath[strlen(gModulePath) - 1] == '\\') gModulePath[strlen(gModulePath) - 1] = '\0'; // String cannot end in slash or stuff will probably break (original does this through a windows.h provided function) // Get path of the data folder strcpy(gDataPath, gModulePath); strcat(gDataPath, "/data"); #ifdef WINDOWS // Set the window icons. See res/ICON/ICON.rc. SDL_SetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON, "101"); SDL_SetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL, "102"); #endif // Initialize SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) >= 0) { // Load configuration CONFIG config; if (!LoadConfigData(&config)) DefaultConfigData(&config); // Apply keybinds // Swap X and Z buttons if (config.attack_button_mode) { if (config.attack_button_mode == 1) { gKeyJump = KEY_X; gKeyShot = KEY_Z; } } else { gKeyJump = KEY_Z; gKeyShot = KEY_X; } // Swap Okay and Cancel buttons if (config.ok_button_mode) { if (config.ok_button_mode == 1) { gKeyOk = gKeyShot; gKeyCancel = gKeyJump; } } else { gKeyOk = gKeyJump; gKeyCancel = gKeyShot; } // Swap left and right weapon switch keys if (CheckFileExists("s_reverse")) { gKeyArms = KEY_ARMSREV; gKeyArmsRev = KEY_ARMS; } // Alternate movement keys if (config.move_button_mode) { if (config.move_button_mode == 1) { gKeyLeft = KEY_ALT_LEFT; gKeyUp = KEY_ALT_UP; gKeyRight = KEY_ALT_RIGHT; gKeyDown = KEY_ALT_DOWN; } } else { gKeyLeft = KEY_LEFT; gKeyUp = KEY_UP; gKeyRight = KEY_RIGHT; gKeyDown = KEY_DOWN; } // Set gamepad inputs for (int i = 0; i < 8; i++) { switch (config.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; default: continue; } } RECT unused_rect = {0, 0, 320, 240}; // Load cursor size_t size; const unsigned char *data = FindResource("CURSOR_NORMAL", "CURSOR", &size); if (data) { SDL_RWops *fp = SDL_RWFromConstMem(data, size); SDL_Surface *cursor_surface = SDL_LoadBMP_RW(fp, 1); SDL_SetColorKey(cursor_surface, SDL_TRUE, SDL_MapRGB(cursor_surface->format, 0xFF, 0, 0xFF)); // Pink regions are transparent SDL_Cursor *cursor = SDL_CreateColorCursor(cursor_surface, 0, 0); // Don't worry, the hotspots are accurate to the original files if (cursor) SDL_SetCursor(cursor); else printf("Failed to load cursor\n"); SDL_FreeSurface(cursor_surface); } else { printf("Failed to load cursor\n"); } // Get window dimensions and colour depth int windowWidth; int windowHeight; int colourDepth; switch (config.display_mode) { case 1: case 2: // Set window dimensions if (config.display_mode == 1) { windowWidth = WINDOW_WIDTH; windowHeight = WINDOW_HEIGHT; } else { windowWidth = WINDOW_WIDTH * 2; windowHeight = WINDOW_HEIGHT * 2; } // Create window gWindow = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowWidth, windowHeight, 0); if (gWindow) { if (config.display_mode == 1) StartDirectDraw(0, 0); else StartDirectDraw(1, 0); break; } break; case 0: case 3: case 4: // Set window dimensions windowWidth = WINDOW_WIDTH * 2; windowHeight = WINDOW_HEIGHT * 2; // Create window gWindow = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowWidth, windowHeight, 0); if (gWindow) { // Set colour depth switch (config.display_mode) { case 0: colourDepth = 16; break; case 3: colourDepth = 24; break; case 4: colourDepth = 32; break; } StartDirectDraw(2, colourDepth); fullscreen = true; SDL_ShowCursor(0); break; } break; } // Create window if (gWindow) { // Check debug things if (CheckFileExists("fps")) bFps = true; #ifndef WINDOWS // Load icon size_t size; const unsigned char *data = FindResource("ICON_MINI", "ICON", &size); if (data) { SDL_RWops *fp = SDL_RWFromConstMem(data, size); SDL_Surface *iconSurf = SDL_LoadBMP_RW(fp, 1); SDL_Surface *iconConverted = SDL_ConvertSurfaceFormat(iconSurf, SDL_PIXELFORMAT_RGB888, 0); SDL_FreeSurface(iconSurf); SDL_Surface *iconSurfUpscaled = SDL_CreateRGBSurfaceWithFormat(0, 256, 256, 0, SDL_PIXELFORMAT_RGB888); SDL_LowerBlitScaled(iconConverted, NULL, iconSurfUpscaled, NULL); SDL_FreeSurface(iconConverted); SDL_SetWindowIcon(gWindow, iconSurfUpscaled); SDL_FreeSurface(iconSurfUpscaled); } else { printf("Failed to load icon\n"); } #endif // Set rects RECT loading_rect = {0, 0, 64, 8}; RECT clip_rect = {0, 0, windowWidth, windowHeight}; // Load the "LOADING" text MakeSurface_File("Loading", SURFACE_ID_LOADING); // Draw loading screen CortBox(&clip_rect, 0x000000); PutBitmap3(&clip_rect, (WINDOW_WIDTH - 64) / 2, (WINDOW_HEIGHT - 8) / 2, &loading_rect, SURFACE_ID_LOADING); // Draw to screen if (Flip_SystemTask()) { // Initialize sound InitDirectSound(); // Initialize joystick if (config.bJoystick && InitDirectInput()) { ResetJoystickStatus(); gbUseJoystick = true; } // Initialize stuff InitTextObject(config.font_name); InitTriangleTable(); // Run game code Game(); // End stuff EndDirectSound(); EndTextObject(); EndDirectDraw(); } } } else { SDL_Quit(); return -1; } SDL_Quit(); return 0; } 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; break; 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; }