/* Copyright (C) 2019 Nunuhara Cabbage * * 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 2 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 . */ #include #include #include "system4/ain.h" #include "system4/string.h" #include "system4/utfsjis.h" #include "cJSON.h" #include "input.h" #include "gfx/gfx.h" #include "mixer.h" #include "savedata.h" #include "vm.h" #include "xsystem4.h" #include "hll.h" #include "system4/file.h" static int SystemService_GetMixerName(int n, struct string **name) { const char *r = mixer_get_name(n); if (!r) return 0; *name = make_string(r, strlen(r)); return 1; } static bool SystemService_GetMixerDefaultVolume(int n, int *volume) { if (n < 0 || (unsigned)n >= config.mixer_nr_channels) return false; *volume = config.mixer_volumes[n]; return true; } static bool SystemService_SetMixerName(int n, struct string *name) { return mixer_set_name(n, name->text); } static int SystemService_GetGameVersion(void) { return ain->game_version; } static void SystemService_GetGameName(struct string **game_name) { if (*game_name) free_string(*game_name); *game_name = cstr_to_string(config.game_name); } HLL_WARN_UNIMPLEMENTED(false, bool, SystemService, AddURLMenu, struct string *title, struct string *url); static bool SystemService_IsFullScreen(void) { return false; } //bool SystemService_ChangeNormalScreen(void); HLL_WARN_UNIMPLEMENTED(false, bool, SystemService, ChangeFullScreen); HLL_WARN_UNIMPLEMENTED(false, bool, SystemService, InitMainWindowPosAndSize); //static bool SystemService_UpdateView(void); HLL_QUIET_UNIMPLEMENTED(false, bool, SystemService, UpdateView); static int SystemService_GetViewWidth(void) { return config.view_width; } static int SystemService_GetViewHeight(void) { return config.view_height; } static bool SystemService_MoveMouseCursorPosImmediately(int x, int y) { mouse_set_pos(x, y); return true; } static bool SystemService_SetHideMouseCursorByGame(bool hide) { return mouse_show_cursor(!hide); } //bool SystemService_GetHideMouseCursorByGame(void); HLL_WARN_UNIMPLEMENTED(false, bool, SystemService, SetUsePower2Texture, bool use); //bool SystemService_GetUsePower2Texture(void); enum window_settings_asect_ratio { ASPECT_RATIO_NORMAL, ASPECT_RATIO_FIXED }; enum window_settings_scaling_type { SCALING_NORMAL, SCALING_BICUBIC, }; struct window_settings { enum window_settings_asect_ratio aspect_ratio; enum window_settings_scaling_type scaling_type; bool wait_vsync; bool record_pos_size; bool minimize_by_full_screen_inactive; bool back_to_title_confirm; bool close_game_confirm; }; static struct window_settings window_settings = { .aspect_ratio = ASPECT_RATIO_NORMAL, .scaling_type = SCALING_NORMAL, .wait_vsync = false, .record_pos_size = false, .minimize_by_full_screen_inactive = true, .back_to_title_confirm = true, .close_game_confirm = true, }; enum window_settings_id { WINDOW_SETTINGS_ASPECT_RATIO = 0, WINDOW_SETTINGS_SCALING_TYPE = 1, WINDOW_SETTINGS_WAIT_VSYNC = 2, WINDOW_SETTINGS_RECORD_POS_SIZE = 3, WINDOW_SETTINGS_MINIMIZE_BY_FULL_SCREEN_INACTIVE = 4, WINDOW_SETTINGS_BACK_TO_TITLE_CONFIRM = 5, WINDOW_SETTINGS_CLOSE_GAME_CONFIRM = 6, }; static void save_window_settings(void) { cJSON *root = cJSON_CreateObject(); cJSON_AddBoolToObject(root, "wait_vsync", window_settings.wait_vsync); save_json("WindowSetting.json", root); cJSON_Delete(root); } static void load_window_settings(void) { cJSON *root = load_json("WindowSetting.json"); if (!root) return; cJSON *v; if ((v = cJSON_GetObjectItem(root, "wait_vsync"))) { window_settings.wait_vsync = cJSON_IsTrue(v); gfx_set_wait_vsync(window_settings.wait_vsync); } cJSON_Delete(root); } static bool SystemService_SetWindowSetting(int type, int value) { switch (type) { case WINDOW_SETTINGS_ASPECT_RATIO: window_settings.aspect_ratio = value; break; case WINDOW_SETTINGS_SCALING_TYPE: window_settings.scaling_type = value; break; case WINDOW_SETTINGS_WAIT_VSYNC: window_settings.wait_vsync = value; gfx_set_wait_vsync(value); break; case WINDOW_SETTINGS_RECORD_POS_SIZE: window_settings.record_pos_size = value; break; case WINDOW_SETTINGS_MINIMIZE_BY_FULL_SCREEN_INACTIVE: window_settings.minimize_by_full_screen_inactive = value; break; case WINDOW_SETTINGS_BACK_TO_TITLE_CONFIRM: window_settings.back_to_title_confirm = value; break; case WINDOW_SETTINGS_CLOSE_GAME_CONFIRM: window_settings.close_game_confirm = value; break; default: WARNING("Invalid window setting type: %d", type); return false; } save_window_settings(); return true; } static bool SystemService_GetWindowSetting(int type, int *value) { switch (type) { case WINDOW_SETTINGS_ASPECT_RATIO: *value = window_settings.aspect_ratio; break; case WINDOW_SETTINGS_SCALING_TYPE: *value = window_settings.scaling_type; break; case WINDOW_SETTINGS_WAIT_VSYNC: *value = window_settings.wait_vsync; break; case WINDOW_SETTINGS_RECORD_POS_SIZE: *value = window_settings.record_pos_size; break; case WINDOW_SETTINGS_MINIMIZE_BY_FULL_SCREEN_INACTIVE: *value = window_settings.minimize_by_full_screen_inactive; break; case WINDOW_SETTINGS_BACK_TO_TITLE_CONFIRM: *value = window_settings.back_to_title_confirm; break; case WINDOW_SETTINGS_CLOSE_GAME_CONFIRM: *value = window_settings.close_game_confirm; break; default: WARNING("Invalid window setting type: %d", type); return false; } return true; } // XXX: Values for 'type' above 1 are invalid in Haru Urare, may be different in other games #define NR_MOUSE_CURSOR_CONFIG 1 static int mouse_cursor_config[NR_MOUSE_CURSOR_CONFIG] = {0}; static bool SystemService_SetMouseCursorConfig(int type, int value) { if (type < 0 || type >= NR_MOUSE_CURSOR_CONFIG) { WARNING("Invalid mouse cursor config type: %d", type); return false; } mouse_cursor_config[type] = value; return true; } static bool SystemService_GetMouseCursorConfig(int type, int *value) { if (type < 0 || type >= NR_MOUSE_CURSOR_CONFIG) { WARNING("Invalid mouse cursor config type: %d", type); return false; } // XXX: the value returned here is always 1 or 0 *value = !!mouse_cursor_config[type]; return true; } //bool SystemService_RunProgram(struct string *program_file_name, struct string *parameter); //bool SystemService_IsOpenedMutex(struct string *mutex_name); void SystemService_GetGameFolderPath(struct string **folder_path) { char *sjis = utf2sjis(config.game_dir, 0); *folder_path = make_string(sjis, strlen(sjis)); free(sjis); } static void SystemService_GetTime(int *hour, int *min, int *sec) { int ms; get_time(hour, min, sec, &ms); } static bool SystemService_IsResetOnce(void) { return vm_reset_once; } static bool SystemService_IsResetOnce_Drapeko(struct string **text) { *text = cstr_to_string("XXX TTT YYY"); // ??? return vm_reset_once; } static char *get_manual_filename(void) { char *manual_path = path_join("Manual", "index.html"); char *file_path = path_join(config.game_dir, manual_path); free(manual_path); return file_path; } static bool SystemService_IsExistPlayingManual(void) { char *filename = get_manual_filename(); const bool exists = file_exists(filename); free(filename); return exists; } #ifndef _WIN32 static char *percent_encode(const char *str) { const char *hex = "0123456789ABCDEF"; // Worst case all characters are percent-encoded char *encoded = xmalloc(strlen(str) * 3 + 1); char *p = encoded; while (*str) { const unsigned char c = *str++; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~' || c == '/') { *p++ = (char)c; } else { *p++ = '%'; *p++ = hex[c >> 4]; *p++ = hex[c & 15]; } } *p = '\0'; return encoded; } #endif static void SystemService_OpenPlayingManual(void) { if (!SystemService_IsExistPlayingManual()) { return; } char *filename = get_manual_filename(); char *real_path = realpath_utf8(filename); free(filename); if (!real_path) { return; } #ifdef _WIN32 const char *prefix = "file:///"; char *path_component = real_path; #else const char *prefix = "file://"; char *path_component = percent_encode(real_path); free(real_path); #endif char *url = xmalloc(strlen(prefix) + strlen(path_component) + 1); strcpy(url, prefix); strcat(url, path_component); if (SDL_OpenURL(url) < 0) { WARNING("Failed to open manual at '%s': %s", url, SDL_GetError()); } free(url); free(path_component); } //static bool SystemService_IsExistSystemMessage(void); HLL_QUIET_UNIMPLEMENTED(false, bool, SystemService, IsExistSystemMessage); //static bool SystemService_PopSystemMessage(int *message); static void SystemService_RestrainScreensaver(void) { } //static int SystemService_Debug_GetUseVideoMemorySize(void); static void SystemService_Rance0123456789(struct string **text) { *text = cstr_to_string("-RANCE010ECNAR-"); // ??? } static void SystemService_XXXXX01XXXXXXXX(struct string **text) { *text = cstr_to_string("RANCE01RANCEKAKKOII"); } static void SystemService_Test(struct string **text) { *text = cstr_to_string("DELETE ALL 758490275489207548093"); } static void SystemService_DRPKT(struct string **text) { *text = cstr_to_string("DRPKT QWERTY NUFUAUEO 75849027582754829"); } static void SystemService_PreLink(void); static void SystemService_ModuleInit(void) { load_window_settings(); } HLL_LIBRARY(SystemService, HLL_EXPORT(_PreLink, SystemService_PreLink), HLL_EXPORT(_ModuleInit, SystemService_ModuleInit), HLL_EXPORT(GetMixerNumof, mixer_get_numof), HLL_EXPORT(GetMixerName, SystemService_GetMixerName), HLL_EXPORT(GetMixerVolume, mixer_get_volume), HLL_EXPORT(GetMixerDefaultVolume, SystemService_GetMixerDefaultVolume), HLL_EXPORT(GetMixerMute, mixer_get_mute), HLL_EXPORT(SetMixerName, SystemService_SetMixerName), HLL_EXPORT(SetMixerVolume, mixer_set_volume), HLL_EXPORT(SetMixerMute, mixer_set_mute), HLL_EXPORT(GetGameVersion, SystemService_GetGameVersion), HLL_EXPORT(GetGameName, SystemService_GetGameName), HLL_EXPORT(AddURLMenu, SystemService_AddURLMenu), HLL_EXPORT(IsFullScreen, SystemService_IsFullScreen), HLL_TODO_EXPORT(ChangeNormalScreen, SystemService_ChangeNormalScreen), HLL_EXPORT(ChangeFullScreen, SystemService_ChangeFullScreen), HLL_EXPORT(InitMainWindowPosAndSize, SystemService_InitMainWindowPosAndSize), HLL_EXPORT(UpdateView, SystemService_UpdateView), HLL_EXPORT(GetViewWidth, SystemService_GetViewWidth), HLL_EXPORT(GetViewHeight, SystemService_GetViewHeight), HLL_EXPORT(MoveMouseCursorPosImmediately, SystemService_MoveMouseCursorPosImmediately), HLL_EXPORT(SetHideMouseCursorByGame, SystemService_SetHideMouseCursorByGame), HLL_TODO_EXPORT(GetHideMouseCursorByGame, SystemService_GetHideMouseCursorByGame), HLL_EXPORT(SetUsePower2Texture, SystemService_SetUsePower2Texture), HLL_TODO_EXPORT(GetUsePower2Texture, SystemService_GetUsePower2Texture), HLL_EXPORT(SetWindowSetting, SystemService_SetWindowSetting), HLL_EXPORT(GetWindowSetting, SystemService_GetWindowSetting), HLL_EXPORT(SetMouseCursorConfig, SystemService_SetMouseCursorConfig), HLL_EXPORT(GetMouseCursorConfig, SystemService_GetMouseCursorConfig), HLL_TODO_EXPORT(RunProgram, SystemService_RunProgram), HLL_TODO_EXPORT(IsOpenedMutex, SystemService_IsOpenedMutex), HLL_EXPORT(GetGameFolderPath, SystemService_GetGameFolderPath), HLL_EXPORT(GetDate, get_date), HLL_EXPORT(GetTime, SystemService_GetTime), HLL_EXPORT(IsResetOnce, SystemService_IsResetOnce), HLL_EXPORT(OpenPlayingManual, SystemService_OpenPlayingManual), HLL_EXPORT(IsExistPlayingManual, SystemService_IsExistPlayingManual), HLL_EXPORT(IsExistSystemMessage, SystemService_IsExistSystemMessage), HLL_TODO_EXPORT(PopSystemMessage, SystemService_PopSystemMessage), HLL_EXPORT(RestrainScreensaver, SystemService_RestrainScreensaver), HLL_TODO_EXPORT(Debug_GetUseVideoMemorySize, SystemService_Debug_GetUseVideoMemorySize), HLL_EXPORT(Rance0123456789, SystemService_Rance0123456789), HLL_EXPORT(XXXXX01XXXXXXXX, SystemService_XXXXX01XXXXXXXX), HLL_EXPORT(Test, SystemService_Test), HLL_EXPORT(DRPKT, SystemService_DRPKT) ); static struct ain_hll_function *get_fun(int libno, const char *name) { int fno = ain_get_library_function(ain, libno, name); return fno >= 0 ? &ain->libraries[libno].functions[fno] : NULL; } static void SystemService_PreLink(void) { struct ain_hll_function *fun; int libno = ain_get_library(ain, "SystemService"); assert(libno >= 0); fun = get_fun(libno, "IsResetOnce"); if (fun && fun->nr_arguments == 1) { static_library_replace(&lib_SystemService, "IsResetOnce", SystemService_IsResetOnce_Drapeko); } }