mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-29 18:38:04 +03:00
458 lines
13 KiB
C
458 lines
13 KiB
C
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
|
|
*
|
|
* 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 <http://gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#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);
|
|
}
|
|
}
|