8 Commits

Author SHA1 Message Date
Alexander Batalov
e97087b958 Remove pause window 2025-02-16 11:35:06 +03:00
Alexander Batalov
b31cea9331 Remove keyboard settings functions 2025-02-16 11:27:03 +03:00
Alexander Batalov
f5ade9fb19 Remove idle func 2025-02-16 10:56:28 +03:00
Alexander Batalov
f59637d0cc Remove focus func 2025-02-16 10:52:17 +03:00
Alexander Batalov
236774c7b2 Fix extra delay in loadsave screen 2025-02-16 10:01:08 +03:00
Alexander Batalov
f7d4fc4ffe Remove vcr 2025-02-16 09:51:46 +03:00
Alexander Batalov
135c62758f Update installation instructions
Closes #360
2025-02-15 14:50:42 +03:00
Alexander Batalov
2de74728ce Review main (#458) 2025-02-15 12:31:06 +03:00
21 changed files with 62 additions and 1294 deletions

View File

@@ -199,8 +199,6 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/scripts.h"
"src/select_file_list.cc"
"src/select_file_list.h"
"src/selfrun.cc"
"src/selfrun.h"
"src/skill_defs.h"
"src/skill.cc"
"src/skill.h"
@@ -230,8 +228,6 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/trait_defs.h"
"src/trait.cc"
"src/trait.h"
"src/vcr.cc"
"src/vcr.h"
"src/version.cc"
"src/version.h"
"src/widget.cc"

View File

@@ -18,6 +18,14 @@ Download and copy `fallout2-ce.exe` to your `Fallout2` folder. It serves as a dr
- Use Windows installation as a base - it contains data assets needed to play. Copy `Fallout2` folder somewhere, for example `/home/john/Desktop/Fallout2`.
- Alternatively you can extract the needed files from the GoG installer:
```console
$ sudo apt install innoextract
$ innoextract ~/Downloads/setup_fallout2_2.1.0.18.exe -I app
$ mv app Fallout2
```
- Download and copy `fallout2-ce` to this folder.
- Install [SDL2](https://libsdl.org/download-2.0.php):
@@ -36,6 +44,14 @@ $ sudo apt install libsdl2-2.0-0
- Alternatively you can use Fallout 2 from Macplay/The Omni Group as a base - you need to extract game assets from the original bundle. Mount CD/DMG, right click `Fallout 2` -> `Show Package Contents`, navigate to `Contents/Resources`. Copy `GameData` folder somewhere, for example `/Applications/Fallout2`.
- Or if you're a Terminal user and have Homebrew installed you can extract the needed files from the GoG installer:
```console
$ brew install innoextract
$ innoextract ~/Downloads/setup_fallout2_2.1.0.18.exe -I app
$ mv app /Applications/Fallout2
```
- Download and copy `fallout2-ce.app` to this folder.
- Run `fallout2-ce.app`.

View File

@@ -33,7 +33,6 @@
#include "text_object.h"
#include "tile.h"
#include "trait.h"
#include "vcr.h"
#include "worldmap.h"
namespace fallout {
@@ -3036,10 +3035,6 @@ void _dude_fidget()
return;
}
if (vcrGetState() != VCR_STATE_TURNED_OFF) {
return;
}
if ((gDude->flags & OBJECT_HIDDEN) != 0) {
return;
}

View File

@@ -95,10 +95,6 @@ static void audioEngineMixin(void* userData, Uint8* stream, int length)
bool audioEngineInit()
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) {
return false;
}
SDL_AudioSpec desiredSpec;
desiredSpec.freq = 22050;
desiredSpec.format = AUDIO_S16;
@@ -122,10 +118,6 @@ void audioEngineExit()
SDL_CloseAudioDevice(gAudioEngineDeviceId);
gAudioEngineDeviceId = -1;
}
if (SDL_WasInit(SDL_INIT_AUDIO)) {
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
}
void audioEnginePause()

View File

@@ -8,10 +8,6 @@ static int gMouseWheelDeltaY = 0;
// 0x4E0400
bool directInputInit()
{
if (SDL_InitSubSystem(SDL_INIT_EVENTS) != 0) {
return false;
}
if (!mouseDeviceInit()) {
goto err;
}
@@ -32,7 +28,6 @@ err:
// 0x4E0478
void directInputFree()
{
SDL_QuitSubSystem(SDL_INIT_EVENTS);
}
// 0x4E04E8

View File

@@ -188,7 +188,6 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
fontSetCurrent(font);
screenshotHandlerConfigure(KEY_F12, gameTakeScreenshot);
pauseHandlerConfigure(-1, nullptr);
tileDisable();

View File

@@ -13,7 +13,6 @@
#include "svga.h"
#include "text_font.h"
#include "touch.h"
#include "vcr.h"
#include "win32.h"
namespace fallout {
@@ -40,20 +39,10 @@ typedef struct TickerListNode {
} TickerListNode;
static int dequeueInputEvent();
static void pauseGame();
static int pauseHandlerDefaultImpl();
static void screenshotBlitter(unsigned char* src, int src_pitch, int a3, int x, int y, int width, int height, int dest_x, int dest_y);
static void buildNormalizedQwertyKeys();
static void _GNW95_process_key(KeyboardData* data);
static void idleImpl();
// 0x51E234
static IdleFunc* _idle_func = nullptr;
// 0x51E238
static FocusFunc* _focus_func = nullptr;
// 0x51E23C
static int gKeyboardKeyRepeatRate = 80;
@@ -82,18 +71,12 @@ static int _input_mx;
// 0x6AC754
static int _input_my;
// 0x6AC75C
static bool gPaused;
// 0x6AC760
static int gScreenshotKeyCode;
// 0x6AC764
static int _using_msec_timer;
// 0x6AC768
static int gPauseKeyCode;
// 0x6AC76C
static ScreenshotHandler* gScreenshotHandler;
@@ -103,9 +86,6 @@ static int gInputEventQueueReadIndex;
// 0x6AC774
static unsigned char* gScreenshotBuffer;
// 0x6AC778
static PauseHandler* gPauseHandler;
// 0x6AC77C
static int gInputEventQueueWriteIndex;
@@ -146,17 +126,10 @@ int inputInit(int a1)
_input_mx = -1;
_input_my = -1;
gRunLoopDisabled = 0;
gPaused = false;
gPauseKeyCode = KEY_ALT_P;
gPauseHandler = pauseHandlerDefaultImpl;
gScreenshotHandler = screenshotHandlerDefaultImpl;
gTickerListHead = nullptr;
gScreenshotKeyCode = KEY_ALT_C;
// SFALL: Set idle function.
// CE: Prevents frying CPU when window is not focused.
inputSetIdleFunc(idleImpl);
return 0;
}
@@ -214,9 +187,7 @@ void _process_bk()
tickersExecute();
if (vcrUpdate() != 3) {
_mouse_info();
}
_mouse_info();
v1 = _win_check_all_buttons();
if (v1 != -1) {
@@ -238,11 +209,6 @@ void enqueueInputEvent(int a1)
return;
}
if (a1 == gPauseKeyCode) {
pauseGame();
return;
}
if (a1 == gScreenshotKeyCode) {
takeScreenshot();
return;
@@ -305,10 +271,6 @@ void inputEventQueueReset()
// 0x4C8D1C
void tickersExecute()
{
if (gPaused) {
return;
}
if (gRunLoopDisabled) {
return;
}
@@ -378,74 +340,6 @@ void tickersDisable()
gRunLoopDisabled = true;
}
// 0x4C8DFC
static void pauseGame()
{
if (!gPaused) {
gPaused = true;
int win = gPauseHandler();
while (inputGetInput() != KEY_ESCAPE) {
}
gPaused = false;
windowDestroy(win);
}
}
// 0x4C8E38
static int pauseHandlerDefaultImpl()
{
int windowWidth = fontGetStringWidth("Paused") + 32;
int windowHeight = 3 * fontGetLineHeight() + 16;
int win = windowCreate((rectGetWidth(&_scr_size) - windowWidth) / 2,
(rectGetHeight(&_scr_size) - windowHeight) / 2,
windowWidth,
windowHeight,
256,
WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
if (win == -1) {
return -1;
}
windowDrawBorder(win);
unsigned char* windowBuffer = windowGetBuffer(win);
fontDrawText(windowBuffer + 8 * windowWidth + 16,
"Paused",
windowWidth,
windowWidth,
_colorTable[31744]);
_win_register_text_button(win,
(windowWidth - fontGetStringWidth("Done") - 16) / 2,
windowHeight - 8 - fontGetLineHeight() - 6,
-1,
-1,
-1,
KEY_ESCAPE,
"Done",
0);
windowRefresh(win);
return win;
}
// 0x4C8F34
void pauseHandlerConfigure(int keyCode, PauseHandler* handler)
{
gPauseKeyCode = keyCode;
if (handler == nullptr) {
handler = pauseHandlerDefaultImpl;
}
gPauseHandler = handler;
}
// 0x4C8F4C
void takeScreenshot()
{
@@ -670,70 +564,6 @@ unsigned int _get_bk_time()
return gTickerLastTimestamp;
}
// NOTE: Unused.
//
// 0x4C9418
void inputSetKeyboardKeyRepeatRate(int value)
{
gKeyboardKeyRepeatRate = value;
}
// NOTE: Unused.
//
// 0x4C9420
int inputGetKeyboardKeyRepeatRate()
{
return gKeyboardKeyRepeatRate;
}
// NOTE: Unused.
//
// 0x4C9428
void inputSetKeyboardKeyRepeatDelay(int value)
{
gKeyboardKeyRepeatDelay = value;
}
// NOTE: Unused.
//
// 0x4C9430
int inputGetKeyboardKeyRepeatDelay()
{
return gKeyboardKeyRepeatDelay;
}
// NOTE: Unused.
//
// 0x4C9438
void inputSetFocusFunc(FocusFunc* func)
{
_focus_func = func;
}
// NOTE: Unused.
//
// 0x4C9440
FocusFunc* inputGetFocusFunc()
{
return _focus_func;
}
// NOTE: Unused.
//
// 0x4C9448
void inputSetIdleFunc(IdleFunc* func)
{
_idle_func = func;
}
// NOTE: Unused.
//
// 0x4C9450
IdleFunc* inputGetIdleFunc()
{
return _idle_func;
}
// 0x4C9490
static void buildNormalizedQwertyKeys()
{
@@ -1171,52 +1001,30 @@ static void _GNW95_process_key(KeyboardData* data)
data->key = gNormalizedQwertyKeys[data->key];
if (gVcrState == VCR_STATE_PLAYING) {
if ((gVcrTerminateFlags & VCR_TERMINATE_ON_KEY_PRESS) != 0) {
gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED;
vcrStop();
}
RepeatInfo* ptr = &(_GNW95_key_time_stamps[scanCode]);
if (data->down == 1) {
ptr->tick = getTicks();
ptr->repeatCount = 0;
} else {
RepeatInfo* ptr = &(_GNW95_key_time_stamps[scanCode]);
if (data->down == 1) {
ptr->tick = getTicks();
ptr->repeatCount = 0;
} else {
ptr->tick = -1;
}
// Ignore keys which were remapped to -1.
if (data->key == -1) {
return;
}
_kb_simulate_key(data);
ptr->tick = -1;
}
// Ignore keys which were remapped to -1.
if (data->key == -1) {
return;
}
_kb_simulate_key(data);
}
// 0x4C9EEC
void _GNW95_lost_focus()
{
if (_focus_func != nullptr) {
_focus_func(false);
}
while (!gProgramIsActive) {
_GNW95_process_message();
if (_idle_func != nullptr) {
_idle_func();
}
SDL_Delay(125);
}
if (_focus_func != nullptr) {
_focus_func(true);
}
}
static void idleImpl()
{
SDL_Delay(125);
}
void beginTextInput()

View File

@@ -3,11 +3,8 @@
namespace fallout {
typedef void(IdleFunc)();
typedef void(FocusFunc)(bool focus);
typedef void(TickerProc)();
typedef int(PauseHandler)();
typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, unsigned char* palette);
int inputInit(int a1);
@@ -22,7 +19,6 @@ void tickersAdd(TickerProc* fn);
void tickersRemove(TickerProc* fn);
void tickersEnable();
void tickersDisable();
void pauseHandlerConfigure(int keyCode, PauseHandler* fn);
void takeScreenshot();
int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, unsigned char* palette);
void screenshotHandlerConfigure(int keyCode, ScreenshotHandler* handler);
@@ -32,14 +28,6 @@ void inputBlockForTocks(unsigned int ms);
unsigned int getTicksSince(unsigned int a1);
unsigned int getTicksBetween(unsigned int a1, unsigned int a2);
unsigned int _get_bk_time();
void inputSetKeyboardKeyRepeatRate(int value);
int inputGetKeyboardKeyRepeatRate();
void inputSetKeyboardKeyRepeatDelay(int value);
int inputGetKeyboardKeyRepeatDelay();
void inputSetFocusFunc(FocusFunc* func);
FocusFunc* inputGetFocusFunc();
void inputSetIdleFunc(IdleFunc* func);
IdleFunc* inputGetIdleFunc();
int _GNW95_input_init();
void _GNW95_process_message();
void _GNW95_clear_time_stamps();

View File

@@ -43,7 +43,6 @@
#include "text_object.h"
#include "tile.h"
#include "trait.h"
#include "vcr.h"
#include "worldmap.h"
namespace fallout {
@@ -780,12 +779,7 @@ static void opRandom(Program* program)
data[arg] = programStackPopInteger(program);
}
int result;
if (vcrGetState() == VCR_STATE_TURNED_OFF) {
result = randomBetween(data[1], data[0]);
} else {
result = (data[0] - data[1]) / 2;
}
int result = randomBetween(data[1], data[0]);
programStackPushInteger(program, result);
}

View File

@@ -4,7 +4,6 @@
#include "input.h"
#include "svga.h"
#include "vcr.h"
namespace fallout {
@@ -208,18 +207,6 @@ int keyboardGetLayout()
// TODO: Key type is likely short.
void _kb_simulate_key(KeyboardData* data)
{
if (gVcrState == 0) {
if (_vcr_buffer_index != VCR_BUFFER_CAPACITY - 1) {
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
vcrEntry->type = VCR_ENTRY_TYPE_KEYBOARD_EVENT;
vcrEntry->keyboardEvent.key = data->key & 0xFFFF;
vcrEntry->time = _vcr_time;
vcrEntry->counter = _vcr_counter;
_vcr_buffer_index++;
}
}
_kb_idle_start_time = _get_bk_time();
int key = data->key;

View File

@@ -1226,8 +1226,6 @@ int lsgLoadGame(int mode)
_dbleclkcntr = 24;
doubleClickSlot = -1;
}
delay_ms(1000 / 24 - (getTicks() - time));
}
if (rc == 1) {

View File

@@ -30,7 +30,6 @@
#include "proto.h"
#include "random.h"
#include "scripts.h"
#include "selfrun.h"
#include "settings.h"
#include "sfall_config.h"
#include "sfall_global_scripts.h"
@@ -54,9 +53,6 @@ static int _main_load_new(char* fname);
static int main_loadgame_new();
static void main_unload_new();
static void mainLoop();
static void _main_selfrun_exit();
static void _main_selfrun_record();
static void _main_selfrun_play();
static void showDeath();
static void _main_death_voiceover_callback();
static int _mainDeathGrabTextFile(const char* fileName, char* dest);
@@ -68,28 +64,9 @@ static char _mainMap[] = "artemple.map";
// 0x5194D8
static int _main_game_paused = 0;
// 0x5194DC
static char** _main_selfrun_list = nullptr;
// 0x5194E0
static int _main_selfrun_count = 0;
// 0x5194E4
static int _main_selfrun_index = 0;
// 0x5194E8
static bool _main_show_death_scene = false;
// A switch to pick selfrun vs. intro video for screensaver:
// - `false` - will play next selfrun recording
// - `true` - will play intro video
//
// This value will alternate on every attempt, even if there are no selfrun
// recordings.
//
// 0x5194EC
static bool gMainMenuScreensaverCycle = false;
// 0x614838
static bool _main_death_voiceover_done;
@@ -211,7 +188,8 @@ int falloutMain(int argc, char** argv)
debugPrint("Main menu timed-out\n");
// FALLTHROUGH
case MAIN_MENU_SCREENSAVER:
_main_selfrun_play();
mainMenuWindowHide(true);
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_PAUSE_MUSIC);
break;
case MAIN_MENU_OPTIONS:
mainMenuWindowHide(true);
@@ -236,7 +214,6 @@ int falloutMain(int argc, char** argv)
backgroundSoundDelete();
break;
case MAIN_MENU_SELFRUN:
_main_selfrun_record();
break;
}
}
@@ -257,14 +234,6 @@ static bool falloutInit(int argc, char** argv)
return false;
}
if (_main_selfrun_list != nullptr) {
_main_selfrun_exit();
}
if (selfrunInitFileList(&_main_selfrun_list, &_main_selfrun_count) == 0) {
_main_selfrun_index = 0;
}
return true;
}
@@ -285,9 +254,6 @@ static void main_exit_system()
{
backgroundSoundDelete();
// NOTE: Uninline.
_main_selfrun_exit();
gameExit();
}
@@ -392,115 +358,6 @@ static void mainLoop()
}
}
// 0x480F38
static void _main_selfrun_exit()
{
if (_main_selfrun_list != nullptr) {
selfrunFreeFileList(&_main_selfrun_list);
}
_main_selfrun_count = 0;
_main_selfrun_index = 0;
_main_selfrun_list = nullptr;
}
// 0x480F64
static void _main_selfrun_record()
{
SelfrunData selfrunData;
bool ready = false;
char** fileList;
int fileListLength = fileNameListInit("maps\\*.map", &fileList, 0, 0);
if (fileListLength != 0) {
int selectedFileIndex = _win_list_select("Select Map", fileList, fileListLength, nullptr, 80, 80, 0x10000 | 0x100 | 4);
if (selectedFileIndex != -1) {
// NOTE: It's size is likely 13 chars (on par with SelfrunData
// fields), but due to the padding it takes 16 chars on stack.
char recordingName[SELFRUN_RECORDING_FILE_NAME_LENGTH];
recordingName[0] = '\0';
if (_win_get_str(recordingName, sizeof(recordingName) - 2, "Enter name for recording (8 characters max, no extension):", 100, 100) == 0) {
memset(&selfrunData, 0, sizeof(selfrunData));
if (selfrunPrepareRecording(recordingName, fileList[selectedFileIndex], &selfrunData) == 0) {
ready = true;
}
}
}
fileNameListFree(&fileList, 0);
}
if (ready) {
mainMenuWindowHide(true);
mainMenuWindowFree();
backgroundSoundDelete();
randomSeedPrerandom(0xBEEFFEED);
// NOTE: Uninline.
main_reset_system();
_proto_dude_init("premade\\combat.gcd");
_main_load_new(selfrunData.mapFileName);
selfrunRecordingLoop(&selfrunData);
paletteFadeTo(gPaletteWhite);
// NOTE: Uninline.
main_unload_new();
// NOTE: Uninline.
main_reset_system();
mainMenuWindowInit();
if (_main_selfrun_list != nullptr) {
_main_selfrun_exit();
}
if (selfrunInitFileList(&_main_selfrun_list, &_main_selfrun_count) == 0) {
_main_selfrun_index = 0;
}
}
}
// 0x48109C
static void _main_selfrun_play()
{
if (!gMainMenuScreensaverCycle && _main_selfrun_count > 0) {
SelfrunData selfrunData;
if (selfrunPreparePlayback(_main_selfrun_list[_main_selfrun_index], &selfrunData) == 0) {
mainMenuWindowHide(true);
mainMenuWindowFree();
backgroundSoundDelete();
randomSeedPrerandom(0xBEEFFEED);
// NOTE: Uninline.
main_reset_system();
_proto_dude_init("premade\\combat.gcd");
_main_load_new(selfrunData.mapFileName);
selfrunPlaybackLoop(&selfrunData);
paletteFadeTo(gPaletteWhite);
// NOTE: Uninline.
main_unload_new();
// NOTE: Uninline.
main_reset_system();
mainMenuWindowInit();
}
_main_selfrun_index++;
if (_main_selfrun_index >= _main_selfrun_count) {
_main_selfrun_index = 0;
}
} else {
mainMenuWindowHide(true);
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_PAUSE_MUSIC);
}
gMainMenuScreensaverCycle = !gMainMenuScreensaverCycle;
}
// 0x48118C
static void showDeath()
{

View File

@@ -7,7 +7,6 @@
#include "memory.h"
#include "svga.h"
#include "touch.h"
#include "vcr.h"
namespace fallout {
@@ -455,22 +454,9 @@ void _mouse_info()
x = (int)(x * gMouseSensitivity);
y = (int)(y * gMouseSensitivity);
if (gVcrState == VCR_STATE_PLAYING) {
if (((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_PRESS) != 0 && buttons != 0)
|| ((gVcrTerminateFlags & VCR_TERMINATE_ON_MOUSE_MOVE) != 0 && (x != 0 || y != 0))) {
gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_TERMINATED;
vcrStop();
return;
}
x = 0;
y = 0;
buttons = last_buttons;
}
_mouse_simulate_input(x, y, buttons);
// TODO: Move to `_mouse_simulate_input`.
// TODO: Record wheel event in VCR.
gMouseWheelX = mouseData.wheelX;
gMouseWheelY = mouseData.wheelY;
@@ -496,23 +482,7 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons)
return;
}
if (delta_x || delta_y || buttons != last_buttons) {
if (gVcrState == 0) {
if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) {
vcrDump();
}
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
vcrEntry->type = VCR_ENTRY_TYPE_MOUSE_EVENT;
vcrEntry->time = _vcr_time;
vcrEntry->counter = _vcr_counter;
vcrEntry->mouseEvent.dx = delta_x;
vcrEntry->mouseEvent.dy = delta_y;
vcrEntry->mouseEvent.buttons = buttons;
_vcr_buffer_index++;
}
} else {
if (delta_x == 0 && delta_y == 0 && buttons == last_buttons) {
if (last_buttons == 0) {
if (!_mouse_idling) {
_mouse_idle_start_time = getTicks();

View File

@@ -1,256 +0,0 @@
#include "selfrun.h"
#include <stdlib.h>
#include "db.h"
#include "game.h"
#include "input.h"
#include "kb.h"
#include "mouse.h"
#include "platform_compat.h"
#include "settings.h"
#include "svga.h"
#include "vcr.h"
namespace fallout {
// 0x51C8D8
int gSelfrunState = SELFRUN_STATE_TURNED_OFF;
// 0x4A8BE0
int selfrunInitFileList(char*** fileListPtr, int* fileListLengthPtr)
{
if (fileListPtr == nullptr) {
return -1;
}
if (fileListLengthPtr == nullptr) {
return -1;
}
*fileListLengthPtr = fileNameListInit("selfrun\\*.sdf", fileListPtr, 0, 0);
return 0;
}
// 0x4A8C10
int selfrunFreeFileList(char*** fileListPtr)
{
if (fileListPtr == nullptr) {
return -1;
}
fileNameListFree(fileListPtr, 0);
return 0;
}
// 0x4A8C28
int selfrunPreparePlayback(const char* fileName, SelfrunData* selfrunData)
{
if (fileName == nullptr) {
return -1;
}
if (selfrunData == nullptr) {
return -1;
}
if (vcrGetState() != VCR_STATE_TURNED_OFF) {
return -1;
}
if (gSelfrunState != SELFRUN_STATE_TURNED_OFF) {
return -1;
}
char path[COMPAT_MAX_PATH];
snprintf(path, sizeof(path), "%s%s", "selfrun\\", fileName);
if (selfrunReadData(path, selfrunData) != 0) {
return -1;
}
gSelfrunState = SELFRUN_STATE_PLAYING;
return 0;
}
// 0x4A8C88
void selfrunPlaybackLoop(SelfrunData* selfrunData)
{
if (gSelfrunState == SELFRUN_STATE_PLAYING) {
char path[COMPAT_MAX_PATH];
snprintf(path, sizeof(path), "%s%s", "selfrun\\", selfrunData->recordingFileName);
if (vcrPlay(path, VCR_TERMINATE_ON_KEY_PRESS | VCR_TERMINATE_ON_MOUSE_PRESS, selfrunPlaybackCompleted)) {
bool cursorWasHidden = cursorIsHidden();
if (cursorWasHidden) {
mouseShowCursor();
}
while (gSelfrunState == SELFRUN_STATE_PLAYING) {
sharedFpsLimiter.mark();
int keyCode = inputGetInput();
if (keyCode != selfrunData->stopKeyCode) {
gameHandleKey(keyCode, false);
}
renderPresent();
sharedFpsLimiter.throttle();
}
while (mouseGetEvent() != 0) {
sharedFpsLimiter.mark();
inputGetInput();
renderPresent();
sharedFpsLimiter.throttle();
}
if (cursorWasHidden) {
mouseHideCursor();
}
}
}
}
// 0x4A8D28
int selfrunPrepareRecording(const char* recordingName, const char* mapFileName, SelfrunData* selfrunData)
{
if (recordingName == nullptr) {
return -1;
}
if (mapFileName == nullptr) {
return -1;
}
if (vcrGetState() != VCR_STATE_TURNED_OFF) {
return -1;
}
if (gSelfrunState != SELFRUN_STATE_TURNED_OFF) {
return -1;
}
snprintf(selfrunData->recordingFileName, sizeof(selfrunData->recordingFileName), "%s%s", recordingName, ".vcr");
strcpy(selfrunData->mapFileName, mapFileName);
selfrunData->stopKeyCode = KEY_CTRL_R;
char path[COMPAT_MAX_PATH];
snprintf(path, sizeof(path), "%s%s%s", "selfrun\\", recordingName, ".sdf");
if (selfrunWriteData(path, selfrunData) != 0) {
return -1;
}
gSelfrunState = SELFRUN_STATE_RECORDING;
return 0;
}
// 0x4A8DDC
void selfrunRecordingLoop(SelfrunData* selfrunData)
{
if (gSelfrunState == SELFRUN_STATE_RECORDING) {
char path[COMPAT_MAX_PATH];
snprintf(path, sizeof(path), "%s%s", "selfrun\\", selfrunData->recordingFileName);
if (vcrRecord(path)) {
if (!cursorIsHidden()) {
mouseShowCursor();
}
bool done = false;
while (!done) {
sharedFpsLimiter.mark();
int keyCode = inputGetInput();
if (keyCode == selfrunData->stopKeyCode) {
vcrStop();
_game_user_wants_to_quit = 2;
done = true;
} else {
gameHandleKey(keyCode, false);
}
renderPresent();
sharedFpsLimiter.throttle();
}
}
gSelfrunState = SELFRUN_STATE_TURNED_OFF;
}
}
// 0x4A8E74
void selfrunPlaybackCompleted(int reason)
{
_game_user_wants_to_quit = 2;
gSelfrunState = SELFRUN_STATE_TURNED_OFF;
}
// 0x4A8E8C
int selfrunReadData(const char* path, SelfrunData* selfrunData)
{
if (path == nullptr) {
return -1;
}
if (selfrunData == nullptr) {
return -1;
}
File* stream = fileOpen(path, "rb");
if (stream == nullptr) {
return -1;
}
int rc = -1;
if (fileReadFixedLengthString(stream, selfrunData->recordingFileName, SELFRUN_RECORDING_FILE_NAME_LENGTH) == 0
&& fileReadFixedLengthString(stream, selfrunData->mapFileName, SELFRUN_MAP_FILE_NAME_LENGTH) == 0
&& fileReadInt32(stream, &(selfrunData->stopKeyCode)) == 0) {
rc = 0;
}
fileClose(stream);
return rc;
}
// 0x4A8EF4
int selfrunWriteData(const char* path, SelfrunData* selfrunData)
{
if (path == nullptr) {
return -1;
}
if (selfrunData == nullptr) {
return -1;
}
char selfrunDirectoryPath[COMPAT_MAX_PATH];
snprintf(selfrunDirectoryPath, sizeof(selfrunDirectoryPath), "%s\\%s", settings.system.master_patches_path.c_str(), "selfrun\\");
compat_mkdir(selfrunDirectoryPath);
File* stream = fileOpen(path, "wb");
if (stream == nullptr) {
return -1;
}
int rc = -1;
if (fileWriteFixedLengthString(stream, selfrunData->recordingFileName, SELFRUN_RECORDING_FILE_NAME_LENGTH) == 0
&& fileWriteFixedLengthString(stream, selfrunData->mapFileName, SELFRUN_MAP_FILE_NAME_LENGTH) == 0
&& fileWriteInt32(stream, selfrunData->stopKeyCode) == 0) {
rc = 0;
}
fileClose(stream);
return rc;
}
} // namespace fallout

View File

@@ -1,37 +0,0 @@
#ifndef SELFRUN_H
#define SELFRUN_H
namespace fallout {
#define SELFRUN_RECORDING_FILE_NAME_LENGTH 13
#define SELFRUN_MAP_FILE_NAME_LENGTH 13
typedef enum SelfrunState {
SELFRUN_STATE_TURNED_OFF,
SELFRUN_STATE_PLAYING,
SELFRUN_STATE_RECORDING,
} SelfrunState;
typedef struct SelfrunData {
char recordingFileName[SELFRUN_RECORDING_FILE_NAME_LENGTH];
char mapFileName[SELFRUN_MAP_FILE_NAME_LENGTH];
int stopKeyCode;
} SelfrunData;
static_assert(sizeof(SelfrunData) == 32, "wrong size");
extern int gSelfrunState;
int selfrunInitFileList(char*** fileListPtr, int* fileListLengthPtr);
int selfrunFreeFileList(char*** fileListPtr);
int selfrunPreparePlayback(const char* fileName, SelfrunData* selfrunData);
void selfrunPlaybackLoop(SelfrunData* selfrunData);
int selfrunPrepareRecording(const char* recordingName, const char* mapFileName, SelfrunData* selfrunData);
void selfrunRecordingLoop(SelfrunData* selfrunData);
void selfrunPlaybackCompleted(int reason);
int selfrunReadData(const char* path, SelfrunData* selfrunData);
int selfrunWriteData(const char* path, SelfrunData* selfrunData);
} // namespace fallout
#endif /* SELFRUN_H */

View File

@@ -175,10 +175,6 @@ int _GNW95_init_window(int width, int height, bool fullscreen, int scale)
if (gSdlWindow == nullptr) {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
return -1;
}
Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI;
if (fullscreen) {

View File

@@ -1,441 +0,0 @@
#include "vcr.h"
#include <stdlib.h>
#include "delay.h"
#include "input.h"
#include "kb.h"
#include "memory.h"
#include "mouse.h"
#include "svga.h"
namespace fallout {
static bool vcrInitBuffer();
static bool vcrFreeBuffer();
static bool vcrClear();
static bool vcrLoad();
// 0x51E2F0
VcrEntry* _vcr_buffer = nullptr;
// number of entries in _vcr_buffer
// 0x51E2F4
int _vcr_buffer_index = 0;
// 0x51E2F8
unsigned int gVcrState = VCR_STATE_TURNED_OFF;
// 0x51E2FC
unsigned int _vcr_time = 0;
// 0x51E300
unsigned int _vcr_counter = 0;
// 0x51E304
unsigned int gVcrTerminateFlags = 0;
// 0x51E308
int gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_NONE;
// 0x51E30C
static unsigned int _vcr_start_time = 0;
// 0x51E310
static int _vcr_registered_atexit = 0;
// 0x51E314
static File* gVcrFile = nullptr;
// 0x51E318
static int _vcr_buffer_end = 0;
// 0x51E31C
static VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback = nullptr;
// 0x51E320
static unsigned int gVcrRequestedTerminationFlags = 0;
// 0x51E324
static int gVcrOldKeyboardLayout = 0;
// 0x6AD940
static VcrEntry stru_6AD940;
// 0x4D2680
bool vcrRecord(const char* fileName)
{
if (gVcrState != VCR_STATE_TURNED_OFF) {
return false;
}
if (fileName == nullptr) {
return false;
}
// NOTE: Uninline.
if (!vcrInitBuffer()) {
return false;
}
gVcrFile = fileOpen(fileName, "wb");
if (gVcrFile == nullptr) {
// NOTE: Uninline.
vcrFreeBuffer();
return false;
}
if (_vcr_registered_atexit == 0) {
_vcr_registered_atexit = atexit(vcrStop);
}
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
vcrEntry->type = VCR_ENTRY_TYPE_INITIAL_STATE;
vcrEntry->time = 0;
vcrEntry->counter = 0;
vcrEntry->initial.keyboardLayout = keyboardGetLayout();
while (mouseGetEvent() != 0) {
_mouse_info();
}
mouseGetPosition(&(vcrEntry->initial.mouseX), &(vcrEntry->initial.mouseY));
_vcr_counter = 1;
_vcr_buffer_index++;
_vcr_start_time = getTicks();
keyboardReset();
gVcrState = VCR_STATE_RECORDING;
return true;
}
// 0x4D27EC
bool vcrPlay(const char* fileName, unsigned int terminationFlags, VcrPlaybackCompletionCallback* callback)
{
if (gVcrState != VCR_STATE_TURNED_OFF) {
return false;
}
if (fileName == nullptr) {
return false;
}
// NOTE: Uninline.
if (!vcrInitBuffer()) {
return false;
}
gVcrFile = fileOpen(fileName, "rb");
if (gVcrFile == nullptr) {
// NOTE: Uninline.
vcrFreeBuffer();
return false;
}
if (!vcrLoad()) {
fileClose(gVcrFile);
// NOTE: Uninline.
vcrFreeBuffer();
return false;
}
while (mouseGetEvent() != 0) {
_mouse_info();
}
keyboardReset();
gVcrRequestedTerminationFlags = terminationFlags;
gVcrPlaybackCompletionCallback = callback;
gVcrPlaybackCompletionReason = VCR_PLAYBACK_COMPLETION_REASON_COMPLETED;
gVcrTerminateFlags = 0;
_vcr_counter = 0;
_vcr_time = 0;
_vcr_start_time = getTicks();
gVcrState = VCR_STATE_PLAYING;
stru_6AD940.time = 0;
stru_6AD940.counter = 0;
return true;
}
// 0x4D28F4
void vcrStop()
{
if (gVcrState == VCR_STATE_RECORDING || gVcrState == VCR_STATE_PLAYING) {
gVcrState |= VCR_STATE_STOP_REQUESTED;
}
keyboardReset();
}
// 0x4D2918
int vcrGetState()
{
return gVcrState;
}
// 0x4D2930
int vcrUpdate()
{
if ((gVcrState & VCR_STATE_STOP_REQUESTED) != 0) {
gVcrState &= ~VCR_STATE_STOP_REQUESTED;
switch (gVcrState) {
case VCR_STATE_RECORDING:
vcrDump();
fileClose(gVcrFile);
gVcrFile = nullptr;
// NOTE: Uninline.
vcrFreeBuffer();
break;
case VCR_STATE_PLAYING:
fileClose(gVcrFile);
gVcrFile = nullptr;
// NOTE: Uninline.
vcrFreeBuffer();
keyboardSetLayout(gVcrOldKeyboardLayout);
if (gVcrPlaybackCompletionCallback != nullptr) {
gVcrPlaybackCompletionCallback(gVcrPlaybackCompletionReason);
}
break;
}
gVcrState = VCR_STATE_TURNED_OFF;
}
switch (gVcrState) {
case VCR_STATE_RECORDING:
_vcr_counter++;
_vcr_time = getTicksSince(_vcr_start_time);
if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) {
vcrDump();
}
break;
case VCR_STATE_PLAYING:
if (_vcr_buffer_index < _vcr_buffer_end || vcrLoad()) {
VcrEntry* vcrEntry = &(_vcr_buffer[_vcr_buffer_index]);
if (stru_6AD940.counter < vcrEntry->counter) {
if (vcrEntry->time > stru_6AD940.time) {
unsigned int delay = stru_6AD940.time;
delay += (_vcr_counter - stru_6AD940.counter)
* (vcrEntry->time - stru_6AD940.time)
/ (vcrEntry->counter - stru_6AD940.counter);
delay_ms(delay - (getTicks() - _vcr_start_time));
}
}
_vcr_counter++;
int rc = 0;
while (_vcr_counter >= _vcr_buffer[_vcr_buffer_index].counter) {
_vcr_time = getTicksSince(_vcr_start_time);
if (_vcr_time > _vcr_buffer[_vcr_buffer_index].time + 5
|| _vcr_time < _vcr_buffer[_vcr_buffer_index].time - 5) {
_vcr_start_time += _vcr_time - _vcr_buffer[_vcr_buffer_index].time;
}
switch (_vcr_buffer[_vcr_buffer_index].type) {
case VCR_ENTRY_TYPE_INITIAL_STATE:
gVcrState = VCR_STATE_TURNED_OFF;
gVcrOldKeyboardLayout = keyboardGetLayout();
keyboardSetLayout(_vcr_buffer[_vcr_buffer_index].initial.keyboardLayout);
while (mouseGetEvent() != 0) {
_mouse_info();
}
gVcrState = VCR_ENTRY_TYPE_INITIAL_STATE;
mouseHideCursor();
_mouse_set_position(_vcr_buffer[_vcr_buffer_index].initial.mouseX, _vcr_buffer[_vcr_buffer_index].initial.mouseY);
mouseShowCursor();
keyboardReset();
gVcrTerminateFlags = gVcrRequestedTerminationFlags;
_vcr_start_time = getTicks();
_vcr_counter = 0;
break;
case VCR_ENTRY_TYPE_KEYBOARD_EVENT:
if (1) {
KeyboardData keyboardData;
keyboardData.key = _vcr_buffer[_vcr_buffer_index].keyboardEvent.key;
_kb_simulate_key(&keyboardData);
}
break;
case VCR_ENTRY_TYPE_MOUSE_EVENT:
rc = 3;
_mouse_simulate_input(_vcr_buffer[_vcr_buffer_index].mouseEvent.dx, _vcr_buffer[_vcr_buffer_index].mouseEvent.dy, _vcr_buffer[_vcr_buffer_index].mouseEvent.buttons);
break;
}
memcpy(&stru_6AD940, &(_vcr_buffer[_vcr_buffer_index]), sizeof(stru_6AD940));
_vcr_buffer_index++;
}
return rc;
} else {
// NOTE: Uninline.
vcrStop();
}
break;
}
return 0;
}
// NOTE: Inlined.
//
// 0x4D2C64
static bool vcrInitBuffer()
{
if (_vcr_buffer == nullptr) {
_vcr_buffer = (VcrEntry*)internal_malloc(sizeof(*_vcr_buffer) * VCR_BUFFER_CAPACITY);
if (_vcr_buffer == nullptr) {
return false;
}
}
// NOTE: Uninline.
vcrClear();
return true;
}
// NOTE: Inlined.
//
// 0x4D2C98
static bool vcrFreeBuffer()
{
if (_vcr_buffer == nullptr) {
return false;
}
// NOTE: Uninline.
vcrClear();
internal_free(_vcr_buffer);
_vcr_buffer = nullptr;
return true;
}
// 0x4D2CD0
static bool vcrClear()
{
if (_vcr_buffer == nullptr) {
return false;
}
_vcr_buffer_index = 0;
return true;
}
// 0x4D2CF0
bool vcrDump()
{
if (_vcr_buffer == nullptr) {
return false;
}
if (gVcrFile == nullptr) {
return false;
}
for (int index = 0; index < _vcr_buffer_index; index++) {
if (!vcrWriteEntry(&(_vcr_buffer[index]), gVcrFile)) {
return false;
}
}
// NOTE: Uninline.
if (!vcrClear()) {
return false;
}
return true;
}
// 0x4D2D74
static bool vcrLoad()
{
if (gVcrFile == nullptr) {
return false;
}
// NOTE: Uninline.
if (!vcrClear()) {
return false;
}
for (_vcr_buffer_end = 0; _vcr_buffer_end < VCR_BUFFER_CAPACITY; _vcr_buffer_end++) {
if (!vcrReadEntry(&(_vcr_buffer[_vcr_buffer_end]), gVcrFile)) {
break;
}
}
if (_vcr_buffer_end == 0) {
return false;
}
return true;
}
// 0x4D2E00
bool vcrWriteEntry(VcrEntry* vcrEntry, File* stream)
{
if (fileWriteUInt32(stream, vcrEntry->type) == -1) return false;
if (fileWriteUInt32(stream, vcrEntry->time) == -1) return false;
if (fileWriteUInt32(stream, vcrEntry->counter) == -1) return false;
switch (vcrEntry->type) {
case VCR_ENTRY_TYPE_INITIAL_STATE:
if (fileWriteInt32(stream, vcrEntry->initial.mouseX) == -1) return false;
if (fileWriteInt32(stream, vcrEntry->initial.mouseY) == -1) return false;
if (fileWriteInt32(stream, vcrEntry->initial.keyboardLayout) == -1) return false;
return true;
case VCR_ENTRY_TYPE_KEYBOARD_EVENT:
if (fileWriteInt16(stream, vcrEntry->keyboardEvent.key) == -1) return false;
return true;
case VCR_ENTRY_TYPE_MOUSE_EVENT:
if (fileWriteInt32(stream, vcrEntry->mouseEvent.dx) == -1) return false;
if (fileWriteInt32(stream, vcrEntry->mouseEvent.dy) == -1) return false;
if (fileWriteInt32(stream, vcrEntry->mouseEvent.buttons) == -1) return false;
return true;
}
return false;
}
// 0x4D2EE4
bool vcrReadEntry(VcrEntry* vcrEntry, File* stream)
{
if (fileReadUInt32(stream, &(vcrEntry->type)) == -1) return false;
if (fileReadUInt32(stream, &(vcrEntry->time)) == -1) return false;
if (fileReadUInt32(stream, &(vcrEntry->counter)) == -1) return false;
switch (vcrEntry->type) {
case VCR_ENTRY_TYPE_INITIAL_STATE:
if (fileReadInt32(stream, &(vcrEntry->initial.mouseX)) == -1) return false;
if (fileReadInt32(stream, &(vcrEntry->initial.mouseY)) == -1) return false;
if (fileReadInt32(stream, &(vcrEntry->initial.keyboardLayout)) == -1) return false;
return true;
case VCR_ENTRY_TYPE_KEYBOARD_EVENT:
if (fileReadInt16(stream, &(vcrEntry->keyboardEvent.key)) == -1) return false;
return true;
case VCR_ENTRY_TYPE_MOUSE_EVENT:
if (fileReadInt32(stream, &(vcrEntry->mouseEvent.dx)) == -1) return false;
if (fileReadInt32(stream, &(vcrEntry->mouseEvent.dy)) == -1) return false;
if (fileReadInt32(stream, &(vcrEntry->mouseEvent.buttons)) == -1) return false;
return true;
}
return false;
}
} // namespace fallout

View File

@@ -1,88 +0,0 @@
#ifndef FALLOUT_VCR_H_
#define FALLOUT_VCR_H_
#include "db.h"
namespace fallout {
#define VCR_BUFFER_CAPACITY 4096
typedef enum VcrState {
VCR_STATE_RECORDING,
VCR_STATE_PLAYING,
VCR_STATE_TURNED_OFF,
} VcrState;
#define VCR_STATE_STOP_REQUESTED 0x80000000
typedef enum VcrTerminationFlags {
// Specifies that VCR playback should stop if any key is pressed.
VCR_TERMINATE_ON_KEY_PRESS = 0x01,
// Specifies that VCR playback should stop if mouse is mouved.
VCR_TERMINATE_ON_MOUSE_MOVE = 0x02,
// Specifies that VCR playback should stop if any mouse button is pressed.
VCR_TERMINATE_ON_MOUSE_PRESS = 0x04,
} VcrTerminationFlags;
typedef enum VcrPlaybackCompletionReason {
VCR_PLAYBACK_COMPLETION_REASON_NONE = 0,
// Indicates that VCR playback completed normally.
VCR_PLAYBACK_COMPLETION_REASON_COMPLETED = 1,
// Indicates that VCR playback terminated according to termination flags.
VCR_PLAYBACK_COMPLETION_REASON_TERMINATED = 2,
} VcrPlaybackCompletionReason;
typedef enum VcrEntryType {
VCR_ENTRY_TYPE_NONE = 0,
VCR_ENTRY_TYPE_INITIAL_STATE = 1,
VCR_ENTRY_TYPE_KEYBOARD_EVENT = 2,
VCR_ENTRY_TYPE_MOUSE_EVENT = 3,
} VcrEntryType;
typedef void(VcrPlaybackCompletionCallback)(int reason);
typedef struct VcrEntry {
unsigned int type;
unsigned int time;
unsigned int counter;
union {
struct {
int mouseX;
int mouseY;
int keyboardLayout;
} initial;
struct {
short key;
} keyboardEvent;
struct {
int dx;
int dy;
int buttons;
} mouseEvent;
};
} VcrEntry;
extern VcrEntry* _vcr_buffer;
extern int _vcr_buffer_index;
extern unsigned int gVcrState;
extern unsigned int _vcr_time;
extern unsigned int _vcr_counter;
extern unsigned int gVcrTerminateFlags;
extern int gVcrPlaybackCompletionReason;
bool vcrRecord(const char* fileName);
bool vcrPlay(const char* fileName, unsigned int terminationFlags, VcrPlaybackCompletionCallback* callback);
void vcrStop();
int vcrGetState();
int vcrUpdate();
bool vcrDump();
bool vcrWriteEntry(VcrEntry* ptr, File* stream);
bool vcrReadEntry(VcrEntry* ptr, File* stream);
} // namespace fallout
#endif /* FALLOUT_VCR_H_ */

View File

@@ -18,32 +18,24 @@
namespace fallout {
#ifdef _WIN32
// 0x51E444
bool gProgramIsActive = false;
// GNW95MUTEX
HANDLE _GNW95_mutex = nullptr;
#ifdef _WIN32
HANDLE GNW95_mutex = nullptr;
#endif
// 0x4DE700
int main(int argc, char* argv[])
{
_GNW95_mutex = CreateMutexA(0, TRUE, "GNW95MUTEX");
if (GetLastError() == ERROR_SUCCESS) {
SDL_ShowCursor(SDL_DISABLE);
int rc;
gProgramIsActive = true;
falloutMain(argc, argv);
CloseHandle(_GNW95_mutex);
#if _WIN32
GNW95_mutex = CreateMutexA(0, TRUE, "GNW95MUTEX");
if (GetLastError() != ERROR_SUCCESS) {
return 0;
}
return 0;
}
#else
bool gProgramIsActive = false;
#endif
int main(int argc, char* argv[])
{
#if __APPLE__ && TARGET_OS_IOS
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
@@ -62,12 +54,24 @@ int main(int argc, char* argv[])
chdir(SDL_AndroidGetExternalStoragePath());
#endif
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
return EXIT_FAILURE;
}
atexit(SDL_Quit);
SDL_ShowCursor(SDL_DISABLE);
gProgramIsActive = true;
return falloutMain(argc, argv);
}
rc = falloutMain(argc, argv);
#if _WIN32
CloseHandle(GNW95_mutex);
#endif
return rc;
}
} // namespace fallout
int main(int argc, char* argv[])

View File

@@ -9,7 +9,7 @@ namespace fallout {
#ifdef _WIN32
extern bool gProgramIsActive;
extern HANDLE _GNW95_mutex;
extern HANDLE GNW95_mutex;
#else
extern bool gProgramIsActive;
#endif

View File

@@ -16,7 +16,6 @@
#include "palette.h"
#include "svga.h"
#include "text_font.h"
#include "vcr.h"
#include "win32.h"
#include "window_manager_private.h"
@@ -114,8 +113,8 @@ static ButtonGroup gButtonGroups[BUTTON_GROUP_LIST_CAPACITY];
int windowManagerInit(VideoSystemInitProc* videoSystemInitProc, VideoSystemExitProc* videoSystemExitProc, int a3)
{
#ifdef _WIN32
CloseHandle(_GNW95_mutex);
_GNW95_mutex = INVALID_HANDLE_VALUE;
CloseHandle(GNW95_mutex);
GNW95_mutex = INVALID_HANDLE_VALUE;
#endif
if (_GNW95_already_running) {
@@ -1015,9 +1014,7 @@ void win_drag(int win)
tickersExecute();
if (vcrUpdate() != 3) {
_mouse_info();
}
_mouse_info();
while ((mouseGetEvent() & MOUSE_EVENT_ANY_BUTTON_UP) == 0) {
sharedFpsLimiter.mark();
@@ -1046,9 +1043,7 @@ void win_drag(int win)
mouseGetPosition(&mx, &my);
tickersExecute();
if (vcrUpdate() != 3) {
_mouse_info();
}
_mouse_info();
dx = mx;
dy = my;