ref: 846d34eaf1b622a415c5b4dc09081e8d4c531f63
dir: /src/Main.cpp/
#include "Main.h" #include <stddef.h> #include <stdint.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; }