How does KQ8 determine whether Direct3D is supported?

Is the game being a ROYAL pain? Need a hint? Got a problem? This is the place to discuss King's Quest!

How does KQ8 determine whether Direct3D is supported?

Postby Expack3 » Mon Jul 27, 2015 11:27 am

I'm currently testing the latest version of dgVoodoo2, an upgraded version of dgVoodoo which now features robust DirectX1-7 and DDraw emulation, with King's Quest 8 (aka King's Quest: Mask of Eternity), and while DirectDraw mode works fine, and has worked fine with prior WIP versions and the latest stable release, Direct3D support has never been properly detected. As such, before I file a bug report with the developer, I was wondering how the game detects Direct3D support. If someone could please get back to me regarding this information, I'd greatly appreciate it!
You like manuals. You like manuals. You love them. You cannot resist manuals.
Your gameplay experience is meaningless without manuals.
User avatar
Expack3
Sierra Obsessed
 
Posts: 169
Joined: Wed Apr 25, 2012 7:58 pm
Gender: Not Specified

Re: How does KQ8 determine whether Direct3D is supported?

Postby Collector » Mon Jul 27, 2015 12:08 pm

Aroenai or NicoDE probably could better answer that than I could, but they have not been very active here lately.
01000010 01111001 01110100 01100101 00100000 01101101 01100101 00100001

Image
User avatar
Collector
Grand Poobah
 
Posts: 10372
Joined: Wed Oct 08, 2008 12:57 am
Location: Sierraland

Re: How does KQ8 determine whether Direct3D is supported?

Postby Expack3 » Mon Jul 27, 2015 4:48 pm

Collector wrote:Aroenai or NicoDE probably could better answer that than I could, but they have not been very active here lately.

Would you know where they tend to be active these days?
You like manuals. You like manuals. You love them. You cannot resist manuals.
Your gameplay experience is meaningless without manuals.
User avatar
Expack3
Sierra Obsessed
 
Posts: 169
Joined: Wed Apr 25, 2012 7:58 pm
Gender: Not Specified

Re: How does KQ8 determine whether Direct3D is supported?

Postby Collector » Mon Jul 27, 2015 7:27 pm

Not off hand, but they might see this thread within a couple of weeks or so.
01000010 01111001 01110100 01100101 00100000 01101101 01100101 00100001

Image
User avatar
Collector
Grand Poobah
 
Posts: 10372
Joined: Wed Oct 08, 2008 12:57 am
Location: Sierraland

Re: How does KQ8 determine whether Direct3D is supported?

Postby Aroenai » Wed Sep 16, 2015 1:57 am

Not a fault of dgVoodoo, the game disables the Direct3D option on real 3DFX hardware too. You can still force Direct3D using the assignGModeName line in Options.cs... I don't recall what you have to call it though, d3d-something?

Interesting to note, there is a dynamic lighting system for the Direct3D renderer but it's slow as molasses in normal Direct3D (hence why it's not accessible). If you use the dgVoodoo Direct3D renderer (no glide2x.dll) it will be full speed. Other than that, the only differences between the two are the lack of 800x600 and transparent shadows. I'd recommend playing at 640x480 with forced 1280x960 resolution if you can though, much better result than 800x600 since the interface art doesn't get warped (use an even multiple of 640x480). I actually have it set to 1920x1440 since my display is 3200x1800 and uses Nvidia Optimus + Intel HD 4600 so it doesn't have proper scaling :-p
Aroenai
Sierra Obsessed
 
Posts: 117
Joined: Thu Feb 26, 2009 11:42 pm
Location: Colorado
Gender: Male

Re: How does KQ8 determine whether Direct3D is supported?

Postby NicoDE » Wed Nov 04, 2015 5:25 pm

Expack3 wrote:Would you know where they tend to be active these days?

Sorry for the late reply. With my upgrade to Debian "Stretch" some time ago, VMware Player stopped working and all Windows related projects are on hold.
However, IDA is running fine with Wine... and here is the analysis as pseudo code:
cpp code
// MASK.EXE 1.0.0.3 DE/ES/FR/IT has been built with DXSDK6
#define DIRECTDRAW_VERSION 0x0600 /* DDCAPS, D3DDEVICEDESC */

// template<typename T, short Grow = 5>
// struct KQArray {
// int count;
// int capacity;
// short grow;
// short flags;
// T *array;
// };
// template<typename T, short Grow = 5>
// struct KQPtrArray : public KQArray<T*, Grow> {
// };

////////////////////////////////////////////////////////////////////////////////
// Direct Draw
////////////////////////////////////////////////////////////////////////////////

HMODULE dd_module = NULL;
HWND dd_window = NULL;
LPDIRECTDRAW dd = NULL;
DDCAPS dd_hal_caps;
DDCAPS dd_hel_caps;
BOOL dd_write_only = FALSE;

BOOL dd_create(HWND a_window)
{
dd_module = LoadLibraryA("DDRAW.DLL");
LPDIRECTDRAWCREATE DirectDrawCreate = GetProcAddress(dd_module, "DirectDrawCreate");
if (NULL == DirectDrawCreate) {
if (dd_module != NULL) {
FreeLibrary(dd_module);
// yes, dd_module isn't reset
}
return (FALSE);
}
dd_window = a_window;
if (DirectDrawCreate(NULL, &dd, NULL) != DD_OK) {
return (FALSE);
}
dd_hal_caps.dwSize = sizeof(dd_hal_caps);
dd_hel_caps.dwSize = sizeof(dd_hel_caps);
if (IDirectDraw_GetCaps(dd, &dd_hal_caps, &dd_hel_caps) != DD_OK) {
return (FALSE);
}
if (DDSCAPS_WRITEONLY & dd_hal_caps.ddsCaps.dwCaps) {
dd_write_only = TRUE;
}
return (TRUE);
}

////////////////////////////////////////////////////////////////////////////////
// Direct 3D
////////////////////////////////////////////////////////////////////////////////

struct KQD3DDeviceInfo {
BOOL valid;
GUID guid;
D3DDEVICEDESC desc;
char *driver_name;
BOOL filter_mip;
BOOL filter_mode;
BOOL blend_color;
BOOL blend_inv;
BOOL blend_mode;
BOOL unknown;
BOOL filter_linear;
BOOL texture_transparency;
BOOL alpha_src;
BOOL alpha_cmp;
};

struct KQD3DDisplayMode {
int width;
int height;
int bpp;
DDSURFACEDESC desc;
};

BOOL d3d_created = FALSE;
HWND d3d_window = NULL;
LPDIRECTDRAWCREATE d3d_DirectDrawCreate = NULL;
LPDIRECTDRAWENUMERATEA d3d_DirectDrawEnumerateA = NULL;
KQArray<LPDIRECTDRAW2> d3d_driver_dd;
KQPtrArray<char> d3d_driver_name;
KQArray<LPDIRECT3D2> d3d_driver_d3d;
KQArray<KQD3DDeviceInfo> d3d_device_info;
KQArray<LPDIRECT3DDEVICE2> d3d_device_intf;
KQPtrArray<KQArray<KQD3DDisplayMode>> d3d_display_modes;

BOOL d3d_driver_add(GUID *a_guid, LPSTR a_desc, LPSTR a_name)
{
LPDIRECTDRAW dd = NULL;
LPDIRECTDRAW2 dd2 = NULL;
if (DD_OK == d3d_DirectDrawCreate(a_guid, &dd, NULL)) {
if (S_OK == IDirectDraw_QueryInterface(dd, &IID_IDirectDraw2, &dd2)) {
DDCAPS hal_caps;
DDCAPS hel_caps;
hal_caps.dwSize = sizeof(hal_caps);
hel_caps.dwSize = sizeof(hel_caps);
IDirectDraw2_GetCaps(dd2, &hal_caps, &hel_caps);
if ((DDCAPS_3D & hal_caps.dwCaps) != 0) {
char *name = new char[strlen("D3D-") + strlen(a_name) + 2];
strcpy(name, "D3D-");
strcat(name, a_name);
d3d_driver_dd.push_back(dd2);
d3d_driver_name.push_back(name);
} else {
IDirectDraw2_Release(dd2);
}
}
IDirectDraw_Release(dd);
}
return (TRUE);
}

BOOL PASCAL d3d_driver_enum(GUID *a_guid, LPSTR a_desc, LPSTR a_name, LPVOID a_info)
{
return (d3d_driver_add(a_guid, a_desc, a_name));
}

HRESULT d3d_device_find(GUID *a_guid, LPSTR a_desc, LPSTR a_name, D3DDEVICEDESC *a_hal, D3DDEVICEDESC *a_hel, KQD3DDeviceInfo *a_info)
{
if (0 == (D3DCOLOR_RGB & a_hal->dcmColorModel)) {
return (DDENUMRET_OK);
}
BOOL valid = TRUE;
if (0 == (D3DDD_DEVICEZBUFFERBITDEPTH & a_hal->dwFlags)) {
valid = FALSE;
}
if (0 == ((DDBD_16 | DDBD_24 | DDBD_32) & a_hal->dwDeviceZBufferBitDepth)) {
valid = FALSE;
}
if (0 == (D3DPCMPCAPS_LESSEQUAL & a_hal->dpcTriCaps.dwZCmpCaps)) {
valid = FALSE;
}
if (0 == (D3DPRASTERCAPS_FOGVERTEX & a_hal->dpcTriCaps.dwRasterCaps)) {
valid = FALSE;
}
if (0 == (D3DPSHADECAPS_FOGGOURAUD & a_hal->dpcTriCaps.dwShadeCaps)) {
valid = FALSE;
}
if (((D3DPBLENDCAPS_SRCALPHA & a_hal->dpcTriCaps.dwSrcBlendCaps) != 0) &&
((D3DPBLENDCAPS_INVSRCALPHA & a_hal->dpcTriCaps.dwDestBlendCaps) != 0)) {
a_info->alpha_src = FALSE;
} else if (
((D3DPBLENDCAPS_INVSRCALPHA & a_hal->dpcTriCaps.dwSrcBlendCaps) != 0) &&
((D3DPBLENDCAPS_SRCALPHA & a_hal->dpcTriCaps.dwDestBlendCaps) != 0)) {
valid = FALSE;
} else {
a_info->alpha_src = TRUE;
}
a_info->alpha_cmp = TRUE;
if (a_info->alpha_src != FALSE) {
if (0 == (D3DPCMPCAPS_ALWAYS & a_hal->dpcTriCaps.dwAlphaCmpCaps)) {
a_info->alpha_cmp = FALSE;
}
} else {
if (0 == (D3DPCMPCAPS_LESSEQUAL & a_hal->dpcTriCaps.dwAlphaCmpCaps)) {
a_info->alpha_cmp = FALSE;
}
}
if (0 == (D3DPSHADECAPS_COLORGOURAUDRGB & a_hal->dpcTriCaps.dwShadeCaps)) {
valid = FALSE;
}
a_info->filter_mip = (((
D3DPTFILTERCAPS_MIPNEAREST |
D3DPTFILTERCAPS_MIPLINEAR |
D3DPTFILTERCAPS_LINEARMIPNEAREST |
D3DPTFILTERCAPS_LINEARMIPLINEAR) &
a_hal->dpcTriCaps.dwTextureFilterCaps) != 0) ? TRUE : FALSE;
a_info->filter_mode = 2;
if ((D3DPTEXTURECAPS_PERSPECTIVE | D3DPTEXTURECAPS_ALPHA) != (
(D3DPTEXTURECAPS_PERSPECTIVE | D3DPTEXTURECAPS_ALPHA) & a_hal->dpcTriCaps.dwTextureCaps)) {
valid = FALSE;
}
a_info->texture_transparency = TRUE;
if (0 == (D3DPTEXTURECAPS_TRANSPARENCY & a_hal->dpcTriCaps.dwTextureCaps)) {
a_info->texture_transparency = FALSE;
}
if (0 == (D3DPTBLENDCAPS_MODULATE & a_hal->dpcTriCaps.dwTextureBlendCaps)) {
valid = FALSE;
}
if ((((D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR) & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) &&
((D3DPTFILTERCAPS_LINEAR & a_hal->dpcTriCaps.dwTextureFilterCaps) != 0)) {
a_info->filter_linear = TRUE;
a_info->blend_color = TRUE;
if ((D3DPBLENDCAPS_SRCCOLOR & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) {
a_info->blend_inv = FALSE;
a_info->blend_mode = 3;
} else {
a_info->blend_inv = TRUE;
a_info->blend_mode = 4;
}
} else if (
(((D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA) & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) &&
((D3DPTFILTERCAPS_LINEAR & a_hal->dpcTriCaps.dwTextureFilterCaps) != 0)) {
a_info->filter_linear = TRUE;
a_info->blend_color = FALSE;
if ((D3DPBLENDCAPS_SRCCOLOR & a_hal->dpcTriCaps.dwDestBlendCaps) != 0) {
a_info->blend_inv = FALSE;
a_info->blend_mode = 5;
} else {
a_info->blend_inv = TRUE;
a_info->blend_mode = 6;
}
} else {
a_info->filter_linear = FALSE;
valid = FALSE;
}
if (0 == (D3DPSHADECAPS_SPECULARGOURAUDRGB & a_hal->dpcTriCaps.dwShadeCaps)) {
valid = FALSE;
}
if (valid != FALSE) {
a_info->valid = TRUE;
a_info->guid = *a_guid;
memcpy(&a_info->desc, a_hal, sizeof(a_info->desc));
int n = strlen(a_info->driver_name) + 1;
for (int i = 0; i < n; ++i) {
char *c = &a_info->driver_name[i];
if (' ' == *c) {
*c = '-';
}
}
return (DDENUMRET_CANCEL);
}
a_info->driver_name = NULL;
return (DDENUMRET_OK);
}

HRESULT CALLBACK d3d_device_enum(GUID *a_guid, LPSTR a_desc, LPSTR a_name, LPD3DDEVICEDESC a_hal, LPD3DDEVICEDESC a_hel, LPVOID a_info)
{
return (d3d_device_find(a_guid, a_desc, a_name, a_hal, a_hel, a_info);
}

BOOL d3d_create(HWND a_window)
{
if (TRUE == d3d_created) {
return (TRUE);
}
d3d_window = window;
d3d_module = LoadLibraryA("DDRAW.DLL");
d3d_DirectDrawCreate = GetProcAddress(d3d_module, "DirectDrawCreate");
d3d_DirectDrawEnumerateA = GetProcAddress(d3d_module, "DirectDrawEnumerateA");
if ((NULL == d3d_DirectDrawCreate) ||
(NULL == d3d_DirectDrawEnumerateA ||
(d3d_DirectDrawEnumerateA(d3d_driver_enum, NULL) != DD_OK)) {
if (d3d_DirectDrawEnumerateA != NULL) {
for (int i = 0; i < d3d_driver_dd.count; ++i) {
LPDIRECTDRAW2 dd = d3d_driver_dd.array[i];
if (dd != NULL) {
IDirectDraw2_Release(dd);
}
d3d_driver_dd.array[i] = NULL;
}
d3d_driver_dd.clear();
}
if (d3d_module != NULL) {
FreeLibrary(d3d_module);
}
d3d_window = NULL;
return (FALSE);
}
d3d_driver_d3d.resize(d3d_driver_dd.count);
d3d_device_info.resize(d3d_driver_dd.count);
for (int i = 0; i < d3d_driver_dd.count; ++i) {
LPDIRECT3D2 d3d = NULL;
IDirectDraw2_QueryInterface(d3d_driver_dd.array[i], &IID_IDirect3D2, &d3d);
d3d_driver_d3d.array[i] = d3d;
d3d_device_info.array[i].valid = FALSE;
d3d_device_info.array[i].name = d3d_driver_name.array[i];
if (d3d2 != NULL) {
IDirect3D2_EnumDevices(d3d2, d3d_device_enum, &d3d_device_info.array[i]);
}
if (TRUE == d3d_device_info.array[i].valid) {
d3d_driver_name.array[i] = NULL;
}
}
d3d_device_intf.resize(d3d_driver_dd.count);
for (int i = 0; i < d3d_device_intf.count; ++i) {
d3d_device_intf.array[i] = NULL;
}
d3d_display_modes.resize(d3d_driver_dd.count);
for (int i = 0; i < d3d_display_modes.count; ++i) {
d3d_display_modes.array[i] = new KQArray<KQD3DDisplayMode>;
}
d3d_created = TRUE;
return (TRUE);
}

HRESULT PASCAL d3d_display_modes_add(LPDDSURFACEDESC a_desc, LPVOID a_info)
{
KQArray<KQD3DDisplayMode> *modes = a_info;
if (16 == a_desc->ddpfPixelFormat.dwRGBBitCount) {
KQD3DDisplayMode mode;
mode.height = a_desc->dwHeight;
mode.width = a_desc->dwWidth;
mode.bpp = 16;
memcpy(&mode.desc, a_desc, sizeof(mode.desc));
modes->push_back(mode);
}
return (DDENUMRET_OK);
}

HRESULT d3d_display_modes_enum(int a_driver, KQArray<KQD3DDisplayMode> *a_modes)
{
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_BACKBUFFERCOUNT | DDSD_CAPS;
ddsd.dwBackBufferCount = 2;
ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_FLIP;
a_modes->clear();
return (IDirectDraw2_EnumDisplayModes(d3d_driver_dd.array[a_driver], 0, &ddsd, a_modes, d3d_display_modes_add);
}

This is the base DD and D3D initialization. I included the display mode enumeration to document the 16-bit filter.
All structures and member names are pure guesswork, but the "code" should be sufficient to answer the topic.
User avatar
NicoDE
Sierra Lover
 
Posts: 79
Joined: Wed Jun 04, 2014 3:01 am
Location: Germany

Re: How does KQ8 determine whether Direct3D is supported?

Postby NicoDE » Fri Nov 06, 2015 2:36 am

Got access to a Windows 7 machine: DD and D3D seem to work with dgVoodoo 2.45 with default default settings (dgVoodoo setup is detected as potential security threat and the user overrides for the virus scanner are disabled). So it seems I'm too late and the research is obsolete :-)
User avatar
NicoDE
Sierra Lover
 
Posts: 79
Joined: Wed Jun 04, 2014 3:01 am
Location: Germany

Re: How does KQ8 determine whether Direct3D is supported?

Postby Expack3 » Fri Nov 06, 2015 8:39 am

NicoDE wrote:Got access to a Windows 7 machine: DD and D3D seem to work with dgVoodoo 2.45 with default default settings (dgVoodoo setup is detected as potential security threat and the user overrides for the virus scanner are disabled). So it seems I'm too late and the research is obsolete :-)

Just tested on Windows 10 Pro x64; DirectDraw works, as always, but Direct3D still doesn't work, even with default settings. Do note I'm using the GOG.com release, so if you used an original release copy and associated patches, that might have something to do with it.
You like manuals. You like manuals. You love them. You cannot resist manuals.
Your gameplay experience is meaningless without manuals.
User avatar
Expack3
Sierra Obsessed
 
Posts: 169
Joined: Wed Apr 25, 2012 7:58 pm
Gender: Not Specified

Re: How does KQ8 determine whether Direct3D is supported?

Postby Expack3 » Fri Nov 06, 2015 9:05 am

As an update, the current version of dgVoodoo2 works - just had to remove nGlide so I could see the needed option as per Aroenai's reply to this thread.

I suppose the reason for this is because the game clearly has no way to enumerate multiple graphics cards to the user; thus, if you have a 3DFX-compatible graphics card, it disables Direct3D support to prevent you from choosing a sub-standard mode for your graphics card.
You like manuals. You like manuals. You love them. You cannot resist manuals.
Your gameplay experience is meaningless without manuals.
User avatar
Expack3
Sierra Obsessed
 
Posts: 169
Joined: Wed Apr 25, 2012 7:58 pm
Gender: Not Specified

Re: How does KQ8 determine whether Direct3D is supported?

Postby Expack3 » Fri Nov 06, 2015 9:27 am

Aroenai wrote:Not a fault of dgVoodoo, the game disables the Direct3D option on real 3DFX hardware too. You can still force Direct3D using the assignGModeName line in Options.cs... I don't recall what you have to call it though, d3d-something?

Interesting to note, there is a dynamic lighting system for the Direct3D renderer but it's slow as molasses in normal Direct3D (hence why it's not accessible). If you use the dgVoodoo Direct3D renderer (no glide2x.dll) it will be full speed. Other than that, the only differences between the two are the lack of 800x600 and transparent shadows. I'd recommend playing at 640x480 with forced 1280x960 resolution if you can though, much better result than 800x600 since the interface art doesn't get warped (use an even multiple of 640x480). I actually have it set to 1920x1440 since my display is 3200x1800 and uses Nvidia Optimus + Intel HD 4600 so it doesn't have proper scaling :-p

How did I not see this until today? Thanks, Aroenai! That indeed solved the problem. Of course, now that that's sorted out, I find an actual bug with dgVoodoo2 which I have promptly reported to the developer.
You like manuals. You like manuals. You love them. You cannot resist manuals.
Your gameplay experience is meaningless without manuals.
User avatar
Expack3
Sierra Obsessed
 
Posts: 169
Joined: Wed Apr 25, 2012 7:58 pm
Gender: Not Specified

Re: How does KQ8 determine whether Direct3D is supported?

Postby NicoDE » Fri Nov 06, 2015 4:05 pm

Expack3 wrote:Do note I'm using the GOG.com release, so if you used an original release copy and associated patches, that might have something to do with it.

I'm using the official Patch 1.3 DE/FR (also included in the official Spanish and Italian release) because it is the most recent Mask.exe (by linker timestamp) known to me. This binary has also been used for the GOG.com release (with some incomplete and missing hacks).
This binary has been compiled with the DirectX SDK 6.0 - therefore you need DX6 to run that version (I guess that the developer was not aware of the renamed "ddsCaps" member in the DDCAPS structure and that the game is now accessing a field that has been introduced with DX6). I didn't analyze the DD/D3D code of the other KQMoE releases - they might be working with earlier DX versions (IIRC the DXSDK6 has been released after the initial 1.0 release of KQMoE).
User avatar
NicoDE
Sierra Lover
 
Posts: 79
Joined: Wed Jun 04, 2014 3:01 am
Location: Germany

Re: How does KQ8 determine whether Direct3D is supported?

Postby Aroenai » Tue Nov 10, 2015 12:05 am

Expack3 wrote:How did I not see this until today? Thanks, Aroenai! That indeed solved the problem. Of course, now that that's sorted out, I find an actual bug with dgVoodoo2 which I have promptly reported to the developer.


That issue has been around for a while, for whatever reason it's more noticeable on some video cards than others. It has something to do with the way the captions are drawn on the screen, but it's significantly better than it was originally. I think I mentioned that to Dege back when I first reached out to him about KQMOE support.

Nico, were you ever able to take a look at that mouse stuff again?

Sidenote, I've got a Mac to play around with now and I'm pretty sure we can get OS X support with Wine Bottler and Nico's runtime patch + nGlide. Haven't tried it yet though.
Aroenai
Sierra Obsessed
 
Posts: 117
Joined: Thu Feb 26, 2009 11:42 pm
Location: Colorado
Gender: Male

Re: How does KQ8 determine whether Direct3D is supported?

Postby NicoDE » Tue Nov 10, 2015 3:57 am

Aroenai wrote:Nico, were you ever able to take a look at that mouse stuff again?

No. In April I started a rewrite of KQMoEFix with config options, logging/tracing, important fixes, and later an installer/setup application. In the currently published version the TalkComplete bug is only fixed for one class. I already rewrote the fix to handle all affected classes (like the proposed assembly patch for the SHP installer binary). Another issue is the shim for the window creation hook. The GOG team and the current version of KQMoEFix just limit the CBT hook to the current thread. But this is not enough, it has to been done for all threads in the application to satisfy the application logic. I'm currently planning to drop all existing special mouse and window handling in the next release and retesting the game with the current versions of dgVoodoo2 and nGlide on Windows and Wine. Thereafter I have to trace down the real problems and try to fix them as clean as possible. The existing logic is too complex and seems to introduce more problems than it solves.

Aroenai wrote:Sidenote, I've got a Mac to play around with now and I'm pretty sure we can get OS X support with Wine Bottler and Nico's runtime patch + nGlide. Haven't tried it yet though.

I got some reports with issues on the Mac, but with the next release of KQMoEFix I expect it has to be retested again.
User avatar
NicoDE
Sierra Lover
 
Posts: 79
Joined: Wed Jun 04, 2014 3:01 am
Location: Germany


Return to The King's Quest Series

Who is online

Users browsing this forum: No registered users and 1 guest

cron