Extract vcr
This commit is contained in:
parent
a1c1e03da0
commit
5f9ceb7f5d
|
@ -225,6 +225,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||||
"src/trait.h"
|
"src/trait.h"
|
||||||
"src/trap.cc"
|
"src/trap.cc"
|
||||||
"src/trap.h"
|
"src/trap.h"
|
||||||
|
"src/vcr.cc"
|
||||||
|
"src/vcr.h"
|
||||||
"src/version.cc"
|
"src/version.cc"
|
||||||
"src/version.h"
|
"src/version.h"
|
||||||
"src/widget.cc"
|
"src/widget.cc"
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "text_object.h"
|
#include "text_object.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "trait.h"
|
#include "trait.h"
|
||||||
|
#include "vcr.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
|
|
424
src/core.cc
424
src/core.cc
|
@ -14,6 +14,7 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "mmx.h"
|
#include "mmx.h"
|
||||||
#include "text_font.h"
|
#include "text_font.h"
|
||||||
|
#include "vcr.h"
|
||||||
#include "win32.h"
|
#include "win32.h"
|
||||||
#include "window_manager.h"
|
#include "window_manager.h"
|
||||||
#include "window_manager_private.h"
|
#include "window_manager_private.h"
|
||||||
|
@ -120,49 +121,6 @@ int gModifierKeysState = 0;
|
||||||
// 0x51E2EC
|
// 0x51E2EC
|
||||||
int (*_kb_scan_to_ascii)() = keyboardDequeueLogicalKeyCode;
|
int (*_kb_scan_to_ascii)() = keyboardDequeueLogicalKeyCode;
|
||||||
|
|
||||||
// 0x51E2F0
|
|
||||||
VcrEntry* _vcr_buffer = NULL;
|
|
||||||
|
|
||||||
// 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
|
|
||||||
unsigned int _vcr_start_time = 0;
|
|
||||||
|
|
||||||
// 0x51E310
|
|
||||||
int _vcr_registered_atexit = 0;
|
|
||||||
|
|
||||||
// 0x51E314
|
|
||||||
File* gVcrFile = NULL;
|
|
||||||
|
|
||||||
// 0x51E318
|
|
||||||
int _vcr_buffer_end = 0;
|
|
||||||
|
|
||||||
// 0x51E31C
|
|
||||||
VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback = NULL;
|
|
||||||
|
|
||||||
// 0x51E320
|
|
||||||
unsigned int gVcrRequestedTerminationFlags = 0;
|
|
||||||
|
|
||||||
// 0x51E324
|
|
||||||
int gVcrOldKeyboardLayout = 0;
|
|
||||||
|
|
||||||
// A map of SDL_SCANCODE_* constants normalized for QWERTY keyboard.
|
// A map of SDL_SCANCODE_* constants normalized for QWERTY keyboard.
|
||||||
//
|
//
|
||||||
// 0x6ABC70
|
// 0x6ABC70
|
||||||
|
@ -369,9 +327,6 @@ int gKeyboardLayout;
|
||||||
// 0x6AD93C
|
// 0x6AD93C
|
||||||
unsigned char gPressedPhysicalKeysCount;
|
unsigned char gPressedPhysicalKeysCount;
|
||||||
|
|
||||||
// 0x6AD940
|
|
||||||
VcrEntry stru_6AD940;
|
|
||||||
|
|
||||||
SDL_Window* gSdlWindow = NULL;
|
SDL_Window* gSdlWindow = NULL;
|
||||||
SDL_Surface* gSdlSurface = NULL;
|
SDL_Surface* gSdlSurface = NULL;
|
||||||
SDL_Renderer* gSdlRenderer = NULL;
|
SDL_Renderer* gSdlRenderer = NULL;
|
||||||
|
@ -4468,383 +4423,6 @@ int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x4D2680
|
|
||||||
bool vcrRecord(const char* fileName)
|
|
||||||
{
|
|
||||||
if (gVcrState != VCR_STATE_TURNED_OFF) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileName == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Uninline.
|
|
||||||
if (!vcrInitBuffer()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
gVcrFile = fileOpen(fileName, "wb");
|
|
||||||
if (gVcrFile == NULL) {
|
|
||||||
// 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 = _get_time();
|
|
||||||
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 == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Uninline.
|
|
||||||
if (!vcrInitBuffer()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
gVcrFile = fileOpen(fileName, "rb");
|
|
||||||
if (gVcrFile == NULL) {
|
|
||||||
// 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 = _get_time();
|
|
||||||
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 = NULL;
|
|
||||||
|
|
||||||
// NOTE: Uninline.
|
|
||||||
vcrFreeBuffer();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case VCR_STATE_PLAYING:
|
|
||||||
fileClose(gVcrFile);
|
|
||||||
gVcrFile = NULL;
|
|
||||||
|
|
||||||
// NOTE: Uninline.
|
|
||||||
vcrFreeBuffer();
|
|
||||||
|
|
||||||
keyboardSetLayout(gVcrOldKeyboardLayout);
|
|
||||||
|
|
||||||
if (gVcrPlaybackCompletionCallback != NULL) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
while (getTicksSince(_vcr_start_time) < delay) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_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 = _get_time();
|
|
||||||
_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
|
|
||||||
bool vcrInitBuffer()
|
|
||||||
{
|
|
||||||
if (_vcr_buffer == NULL) {
|
|
||||||
_vcr_buffer = (VcrEntry*)internal_malloc(sizeof(*_vcr_buffer) * VCR_BUFFER_CAPACITY);
|
|
||||||
if (_vcr_buffer == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Uninline.
|
|
||||||
vcrClear();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Inlined.
|
|
||||||
//
|
|
||||||
// 0x4D2C98
|
|
||||||
bool vcrFreeBuffer()
|
|
||||||
{
|
|
||||||
if (_vcr_buffer == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Uninline.
|
|
||||||
vcrClear();
|
|
||||||
|
|
||||||
internal_free(_vcr_buffer);
|
|
||||||
_vcr_buffer = NULL;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x4D2CD0
|
|
||||||
bool vcrClear()
|
|
||||||
{
|
|
||||||
if (_vcr_buffer == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_vcr_buffer_index = 0;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x4D2CF0
|
|
||||||
bool vcrDump()
|
|
||||||
{
|
|
||||||
if (_vcr_buffer == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gVcrFile == NULL) {
|
|
||||||
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
|
|
||||||
bool vcrLoad()
|
|
||||||
{
|
|
||||||
if (gVcrFile == NULL) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int screenGetWidth()
|
int screenGetWidth()
|
||||||
{
|
{
|
||||||
// TODO: Make it on par with _xres;
|
// TODO: Make it on par with _xres;
|
||||||
|
|
87
src/core.h
87
src/core.h
|
@ -363,44 +363,6 @@ typedef enum KeyboardLayout {
|
||||||
KEYBOARD_LAYOUT_SPANISH,
|
KEYBOARD_LAYOUT_SPANISH,
|
||||||
} KeyboardLayout;
|
} KeyboardLayout;
|
||||||
|
|
||||||
#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 struct STRUCT_6ABF50 {
|
typedef struct STRUCT_6ABF50 {
|
||||||
// Time when appropriate key was pressed down or -1 if it's up.
|
// Time when appropriate key was pressed down or -1 if it's up.
|
||||||
int tick;
|
int tick;
|
||||||
|
@ -426,27 +388,6 @@ typedef struct TickerListNode {
|
||||||
struct TickerListNode* next;
|
struct TickerListNode* next;
|
||||||
} TickerListNode;
|
} TickerListNode;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
typedef struct LogicalKeyEntry {
|
typedef struct LogicalKeyEntry {
|
||||||
short field_0;
|
short field_0;
|
||||||
short unmodified;
|
short unmodified;
|
||||||
|
@ -463,7 +404,6 @@ typedef struct KeyboardEvent {
|
||||||
|
|
||||||
typedef int(PauseHandler)();
|
typedef int(PauseHandler)();
|
||||||
typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, unsigned char* palette);
|
typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, unsigned char* palette);
|
||||||
typedef void(VcrPlaybackCompletionCallback)(int reason);
|
|
||||||
|
|
||||||
extern IdleFunc* _idle_func;
|
extern IdleFunc* _idle_func;
|
||||||
extern FocusFunc* _focus_func;
|
extern FocusFunc* _focus_func;
|
||||||
|
@ -492,20 +432,6 @@ extern int gKeyboardEventQueueReadIndex;
|
||||||
extern short word_51E2E8;
|
extern short word_51E2E8;
|
||||||
extern int gModifierKeysState;
|
extern int gModifierKeysState;
|
||||||
extern int (*_kb_scan_to_ascii)();
|
extern int (*_kb_scan_to_ascii)();
|
||||||
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;
|
|
||||||
extern unsigned int _vcr_start_time;
|
|
||||||
extern int _vcr_registered_atexit;
|
|
||||||
extern File* gVcrFile;
|
|
||||||
extern int _vcr_buffer_end;
|
|
||||||
extern VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback;
|
|
||||||
extern unsigned int gVcrRequestedTerminationFlags;
|
|
||||||
extern int gVcrOldKeyboardLayout;
|
|
||||||
|
|
||||||
extern int gNormalizedQwertyKeys[SDL_NUM_SCANCODES];
|
extern int gNormalizedQwertyKeys[SDL_NUM_SCANCODES];
|
||||||
extern InputEvent gInputEventQueue[40];
|
extern InputEvent gInputEventQueue[40];
|
||||||
|
@ -567,7 +493,6 @@ extern unsigned int _kb_idle_start_time;
|
||||||
extern KeyboardEvent gLastKeyboardEvent;
|
extern KeyboardEvent gLastKeyboardEvent;
|
||||||
extern int gKeyboardLayout;
|
extern int gKeyboardLayout;
|
||||||
extern unsigned char gPressedPhysicalKeysCount;
|
extern unsigned char gPressedPhysicalKeysCount;
|
||||||
extern VcrEntry stru_6AD940;
|
|
||||||
|
|
||||||
extern SDL_Window* gSdlWindow;
|
extern SDL_Window* gSdlWindow;
|
||||||
extern SDL_Surface* gSdlSurface;
|
extern SDL_Surface* gSdlSurface;
|
||||||
|
@ -677,18 +602,6 @@ void keyboardBuildItalianConfiguration();
|
||||||
void keyboardBuildSpanishConfiguration();
|
void keyboardBuildSpanishConfiguration();
|
||||||
void _kb_init_lock_status();
|
void _kb_init_lock_status();
|
||||||
int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr);
|
int keyboardPeekEvent(int index, KeyboardEvent** keyboardEventPtr);
|
||||||
bool vcrRecord(const char* fileName);
|
|
||||||
bool vcrPlay(const char* fileName, unsigned int terminationFlags, VcrPlaybackCompletionCallback* callback);
|
|
||||||
void vcrStop();
|
|
||||||
int vcrGetState();
|
|
||||||
int vcrUpdate();
|
|
||||||
bool vcrInitBuffer();
|
|
||||||
bool vcrFreeBuffer();
|
|
||||||
bool vcrClear();
|
|
||||||
bool vcrDump();
|
|
||||||
bool vcrLoad();
|
|
||||||
bool vcrWriteEntry(VcrEntry* ptr, File* stream);
|
|
||||||
bool vcrReadEntry(VcrEntry* ptr, File* stream);
|
|
||||||
|
|
||||||
int screenGetWidth();
|
int screenGetWidth();
|
||||||
int screenGetHeight();
|
int screenGetHeight();
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "text_object.h"
|
#include "text_object.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "trait.h"
|
#include "trait.h"
|
||||||
|
#include "vcr.h"
|
||||||
#include "worldmap.h"
|
#include "worldmap.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "game_config.h"
|
#include "game_config.h"
|
||||||
#include "platform_compat.h"
|
#include "platform_compat.h"
|
||||||
|
#include "vcr.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,438 @@
|
||||||
|
#include "vcr.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
static bool vcrInitBuffer();
|
||||||
|
static bool vcrFreeBuffer();
|
||||||
|
static bool vcrClear();
|
||||||
|
static bool vcrLoad();
|
||||||
|
|
||||||
|
// 0x51E2F0
|
||||||
|
VcrEntry* _vcr_buffer = NULL;
|
||||||
|
|
||||||
|
// 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 = NULL;
|
||||||
|
|
||||||
|
// 0x51E318
|
||||||
|
static int _vcr_buffer_end = 0;
|
||||||
|
|
||||||
|
// 0x51E31C
|
||||||
|
static VcrPlaybackCompletionCallback* gVcrPlaybackCompletionCallback = NULL;
|
||||||
|
|
||||||
|
// 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 == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Uninline.
|
||||||
|
if (!vcrInitBuffer()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gVcrFile = fileOpen(fileName, "wb");
|
||||||
|
if (gVcrFile == NULL) {
|
||||||
|
// 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 = _get_time();
|
||||||
|
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 == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Uninline.
|
||||||
|
if (!vcrInitBuffer()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gVcrFile = fileOpen(fileName, "rb");
|
||||||
|
if (gVcrFile == NULL) {
|
||||||
|
// 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 = _get_time();
|
||||||
|
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 = NULL;
|
||||||
|
|
||||||
|
// NOTE: Uninline.
|
||||||
|
vcrFreeBuffer();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VCR_STATE_PLAYING:
|
||||||
|
fileClose(gVcrFile);
|
||||||
|
gVcrFile = NULL;
|
||||||
|
|
||||||
|
// NOTE: Uninline.
|
||||||
|
vcrFreeBuffer();
|
||||||
|
|
||||||
|
keyboardSetLayout(gVcrOldKeyboardLayout);
|
||||||
|
|
||||||
|
if (gVcrPlaybackCompletionCallback != NULL) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
while (getTicksSince(_vcr_start_time) < delay) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_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 = _get_time();
|
||||||
|
_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 == NULL) {
|
||||||
|
_vcr_buffer = (VcrEntry*)internal_malloc(sizeof(*_vcr_buffer) * VCR_BUFFER_CAPACITY);
|
||||||
|
if (_vcr_buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Uninline.
|
||||||
|
vcrClear();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Inlined.
|
||||||
|
//
|
||||||
|
// 0x4D2C98
|
||||||
|
static bool vcrFreeBuffer()
|
||||||
|
{
|
||||||
|
if (_vcr_buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Uninline.
|
||||||
|
vcrClear();
|
||||||
|
|
||||||
|
internal_free(_vcr_buffer);
|
||||||
|
_vcr_buffer = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x4D2CD0
|
||||||
|
static bool vcrClear()
|
||||||
|
{
|
||||||
|
if (_vcr_buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_vcr_buffer_index = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x4D2CF0
|
||||||
|
bool vcrDump()
|
||||||
|
{
|
||||||
|
if (_vcr_buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gVcrFile == NULL) {
|
||||||
|
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 == NULL) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // fallout
|
|
@ -0,0 +1,88 @@
|
||||||
|
#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_ */
|
|
@ -14,6 +14,7 @@
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
#include "pointer_registry.h"
|
#include "pointer_registry.h"
|
||||||
#include "text_font.h"
|
#include "text_font.h"
|
||||||
|
#include "vcr.h"
|
||||||
#include "win32.h"
|
#include "win32.h"
|
||||||
#include "window_manager_private.h"
|
#include "window_manager_private.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue