Author Topic: Hacking Lemmings Revolution  (Read 47590 times)

0 Members and 1 Guest are viewing this topic.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Hacking Lemmings Revolution
« on: April 13, 2012, 12:54:51 AM »
Investigation into the problems with Lemmings Revolution on Windows 7 turned up some unfortunate results regarding how the game was designed to work with DirectX 7. The short description is that as DirectX continued to change and be updated, specific behaviors of DirectX 7 were either deprecated or fixed, resulting in a Lemmings game that has been falling apart over time.

Since we're basically looking at a program that relies on a deprecated specification, fixing it will be a time-consuming endeavor. Basically what's required is that we create our own versions of the DirectX DLLs that behave in the way DirectX 7 did back in the day, then feed them to the Lemmings Revolution EXE in place of the modern DLL files.

Lemmings Revolution fortunately has a fairly rudimentary construction, so it's not necessary to re-implement the entire DirectX API. It doesn't even use Direct3D proper (instead deferring to DirectDraw's basic 3D functionality), so the subset of DirectX that needs to be replaced for Lemmings Revolution to function properly is pretty much this:
If we can produce a couple of replacement DLLs, say ldraw.dll and lsound.dll, we can circumvent the problems cropping up due to DirectX's updates and pull Lemmings Revolution back into the realm of things that will continue to work according to current API specs.

Such an initiative I would refer to as DirectL. (-:

EDIT: Renaming thread

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #1 on: April 13, 2012, 03:10:56 AM »
After some research, I was able to determine that the IUnknown interface's QueryInterface() method is all sorts of handy for getting pointers to things without needing to import DLL functions directly. When used on an IDirectDraw (which inherits IUnknown) with IID_IDirect3D as the GUID, an IDirect3D is returned. From there, we can make or get an IDirect3DDevice, which is where the 3D stuff comes from. All without loading direct3d.dll.

There's a good dozen or so ways that all end up at the same place. So in order to properly determine exactly what Lemmings Revolution does to get to where it needs to be, we'd need to just let it link against a custom DLL and see what it tries to do. Once all of the features the game actually uses are implemented, the rest of it can be left unimplemented.

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: DirectL
« Reply #2 on: April 13, 2012, 06:50:06 PM »
later today, I'm gonna have a look at this again. I'll play the game and mess around and see if I can figure anything out. (I need to read over your posts again first)
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #3 on: April 13, 2012, 08:01:39 PM »
The fact is, the game is not completely toast on Win7, at least when I tried on my Win7 laptop.  The main issues I recall running into is no sound and music, and text display problems where the text is invisible.

So rather than trying to fix everything (and given the game's release history, there are probably some bugs that happen even on the original OS [Win95/Win98] the game was released for), one could focus first on the sound/music issue and then the text display problem, and finally deal with the rest later if ever.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #4 on: April 13, 2012, 09:07:19 PM »
Precisely what I was thinking. With a replacement for the old DirectSound bindings, the game would be back up into the "pretty good" state, since the menu elements seem to come back after you've played a level.

I really doubt the game is any fancier than simple stereo. There isn't a lot to audio that would have to be implemented.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #5 on: April 15, 2012, 06:30:54 PM »
Image-heavy post alert! Dial-up users beware! *Snicker* Yeah, dial-up. Anyway...

Here's what the title screen is supposed to look like:



It looks this way in the original release, on Windows XP, in Wine and even on Windows 7 after you've played a level.

Before playing a level, none of the alpha channels on Windows 7 seem to be activated. This is what the title screen looks like:




Proceeding into the level select screen, this is what we see:



This is how it looks in the original release and in Wine.

In XP, we get this:



And in Windows 7, before playing a level:



Aaaand after playing a level:



By the looks of it, XP is somehow sending the wrong color instructions to DirectX for the text shadow, while Windows 7 just isn't sending any at all.


Within the game, Windows XP, Windows 7 and Wine all render *something* incorrectly. After trying for two days to get Windows 98 with DirectX 7 up and running on something, I had to resort to a Google Images search to get an idea of how the game was supposed to look in the original release:



Wine does it pretty good, but the icons on the right-hand side of the screen have funky colors, and the texture filtering on "Let's Go!" is set to point resize:



XP begins to degrade even further, with different funky icon colors and all of the foreground elements turned cyan, although the "Let's Go" is blinear:



Lastly, Windows 7 just doesn't even try anymore and renders all the foreground elements (except the animated Lemming icons) in pure black:




After completing a level, you get a summary of how you did:



That's how it looks in the original release and in Wine.



XP's is kinda hard to read. It's real dark.



7's, unsurprisingly, is even harder to read because it's the same color as the background.

Offline Mr. K

  • Posts: 793
  • Former admin, always Lemmings fan
    • View Profile
    • Wafflenet
Re: DirectL
« Reply #6 on: April 17, 2012, 12:12:57 AM »
Heh, those screenshots took me back many years.  I got Lemmings Revolution at Christmas once and my PC ran it with similar graphical problems (the blank results screen, and the level selection icons didn't appear at all) because the Riva TNT card it had was too old.  Took about a year until I upgraded to a Radeon 7500 to play it without randomly clicking on the level select trying to hit the right icon by chance.

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: DirectL
« Reply #7 on: April 17, 2012, 03:10:36 AM »
have you played it recently? We're trying to get it running on Windows 7 properly (with little luck so far)

could graphics and/or sound cards be a key?
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #8 on: April 17, 2012, 04:30:36 AM »
*Looks at the first post of the thread*

The problem lies mainly in the driver architecture of Windows XP and Windows 7, which is different from the one in Windows 98. There are probably also some changes that came about in DirectX 8, so the game wouldn't have worked properly for very long.

I don't know exactly what Revolution is trying to do at this point, but I know I can fill in the blanks and do something else to make it look and sound right.

Offline Mr. K

  • Posts: 793
  • Former admin, always Lemmings fan
    • View Profile
    • Wafflenet
Re: DirectL
« Reply #9 on: April 17, 2012, 01:10:54 PM »
have you played it recently? We're trying to get it running on Windows 7 properly (with little luck so far)

could graphics and/or sound cards be a key?
I haven't tried playing it in a very long time, in fact, last time I did I was using a Pentium II with Windows 98 (my aforementioned system).  However, perhaps the similarities can be notable.  Lemmings Revolution says it needs a DX7-compatible card.  Perhaps just as my old Riva TNT didn't implement some DX7 features (it is a DX5-level card), neither does DX9 or Windows 7's version, DX9Ex.  I haven't yet had time to go deep into looking at what features might have been deprecated between DX7 and 9, but my first guess would be DirectDraw since we seem to mostly have issues with the 2D portions of the game (menus, UI, etc).  As far as I can tell, DirectDraw has been deprecated since DX8 and was merged into Direct3D, which might be what's causing headaches.

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #10 on: April 19, 2012, 11:20:14 AM »
Okay, with regards to sound in Lemmings Revolution, I have some good news.  I think I've figured out the problem (or one of the problems anyway) some people might have with sound on Win7 (and probably Vista), and it can be fixed yourself without having to patch or change the program in any way! 8)

(Please refer to attached screenshots.)

Step 1:  find the sound icon at bottom right of your screen (circled orange in screenshot).  Click on icon with your right mouse button (ie. "right-click"), then select "Playback Devices" from the popup menu.

Step 2:  a popup window appears, showing a list of all "devices" you can play audio to on your computer.  You might think your computer only has one output device you can play sounds to, but apparently on Vista and Win7, a lot of computers might have this "high-definition audio device" support that provides two or more outputs for sound, like my screenshot.

The irony however is that other than the (presumably working) audio device you are currently using (shown with green checkmark in the popup), the other ones listed probably won't work for you.  For example, in my screenshot, the other one listed as "Digital Audio (S/PDIF)", I have never gotten sound to work playing out of that device.  (I later looked up Wikipedia and S/PDIF seems to be some fancy connector to connect to Hi-Fi equipment, so maybe I just don't have such a fancy setup to take advantage.)

Now the problem turns out to be that, rather than using the working device that the system has selected for playback (ie. the one with green checkmark in the popup), Lemmings Revolution apparently has its own way of picking which audio device to use to play sound, and unfortunately its choice is often the wrong one (eg. the S/PDIF on my computer which I can't get sound out of).  This turns out to be the reason for no sound. :XD:

The solution?  Just disable all the other audio devices on the computer that you aren't using anyway.  Thus the final step.

Step 3:  For each device other than the working one with green checkmark, right-click on the device entry.  A popup menu appears, select "Disable".  Just as depicted in screenshot.

The device entry should either go away in the list, or become grayed out with accompanying "disabled" in the text next to the device icon.  Repeat this until you are left with just the one device with the green checkmark (ie. the one currently in use that actually plays sound).  Now click OK to dismiss the popup.

[note: if you make a mistake, or somehow need to re-enable those secondary devices at a later time, you can right-click on a blank space in the list and select menu option "show disabled devices", and then use the right-click menu to re-enable any device you previously disabled.  The right-click menu also lets you specify which device to use by default for playback (ie. where the green checkmark goes), in case you messed that up.]

===============

After I did that on my computer (leaving only the "Speakers" device enabled), sound now works on Lemmings Revolution!  Hurray! :thumbsup:  [disclaimer: obviously your mileage may vary, but no harm trying at least!]

Of course the graphics are still messed up.  I'm afraid that won't have any easy solutions. :(

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #11 on: April 19, 2012, 08:45:06 PM »
Very nice find, ccexplore!

I loaded Revolution in a debugger and stuck a breakpoint on DirectSoundCreate(). This told me where in the EXE that function was being called, and I had a friend tell me exactly how the stdcall calling convention passes its parameters. What I landed on was this:



That's Lemmings Revolution.exe in a hex editor. That 8B 00 highlighted is the instruction responsible for selecting the pointer of the sound driver passed to DirectSoundCreate():
Code: [Select]
8B 00    MOV EAX, DWORD PTR [EAX]
What I did was change it to 31 C0, which is an XOR instruction on EAX with itself, aka setting it to zero:
Code: [Select]
31 C0    XOR EAX, EAX
Loading up the game in Windows 7 works like a charm now, at least as far as audio is concerned.

An edited EXE file is attached to this post with this fix.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #12 on: April 19, 2012, 11:00:45 PM »
So I said to myself, "Self, most of the graphics work. Really the only problems are the alpha thing, the colors, and that the 5-4-3-2-1 don't appear. Why implement the entire DirectX API when I could just override the parts of it necessary to get it working correctly again?"

With that, I started development on an LDRAW.DLL to replace DDRAW.DLL, and told the EXE to load from that. It's currently just a passthrough, but the game works just fine with it and I can do some investigating to nail down exactly what Lemmings is doing wrong and reinterpret it on the way through to the graphics hardware.

DirectDrawEnumerate() does not actually use the DirectX API function of the same name. Instead, it simply returns a fake video device called "Lemmings Forum Compatibility Hack" that slyly returns a driver GUID of NULL, meaning when the game uses it, it will always use the default display driver. At some point I want to test this in a VM to see if it works now.

DirectDrawCreate() currently just calls the DirectX function, but the beauty here is that I can do some processing on the IDirectDraw that comes back--redirecting some of its methods to functions of my own design so I can intercept the faulty commands as they head toward DirectX from the application.

Both functions produce console output, just so I could make sure they were working correctly. When I reconfigured the EXE file's subsystem, I found that Take 2 had some debug messages of their own in there too. O-:


Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #13 on: April 20, 2012, 05:41:14 AM »
Okay, about to turn in for the night, but progress is coming along. After much fidgeting with the internal workings of the COM interface, I was able to set up a system to plug my own functions into DirectX so I can process the parameters as a pass-through. QueryInterface() is a curious beast indeed, but I've got it trapped in my little web too. (-:<

Just before posting this, I got the game to successfully boot while trapping the IDirectDraw4 objects that the game ultimately uses for drawing... I think. I'll have to look up some of the GUIDs, but here's the latest console output:

Code: [Select]
DirectL - DirectDrawEnumerate()
DirectL - DirectDrawCreate() -- Created IDirectDraw 0x006A4668
DirectL - IUnknown::QueryInterface(0x006A4668,
    9C59509A-39BD-11D1-8C4A-00C04FD930C5) -- Created IDirectDraw4 0x006A4688
DirectL - IUnknown::Release(0x006A4668)
DirectL - IUnknown::QueryInterface(0x006A4688,
    BB223240-E72B-11D0-A9B4-00AA00C0993E)
DirectL - IUnknown::QueryInterface(0x006A4688,
    6C14DB80-A733-11CE-A521-0020AF0BE560)
DirectL - IUnknown::QueryInterface(0x006A4688,
    9C59509A-39BD-11D1-8C4A-00C04FD930C5)
DirectL - IUnknown::Release(0x006A4688)
DirectL - DirectDrawCreate() -- Created IDirectDraw 0x006BC288
DirectL - IUnknown::QueryInterface(0x006BC288,
    9C59509A-39BD-11D1-8C4A-00C04FD930C5) -- Created IDirectDraw4 0x006BC2A8
DirectL - IUnknown::Release(0x006BC288)
DirectL - IDirectDraw4::SetDisplayMode(0x006BC2A8, 640, 480, 16, 0, 0x00000000)
DirectL - IUnknown::QueryInterface(0x006BC2A8,
    BB223240-E72B-11D0-A9B4-00AA00C0993E)
DirectL - IUnknown::QueryInterface(0x006BC2A8,
    6C14DB80-A733-11CE-A521-0020AF0BE560)
DirectL - IUnknown::QueryInterface(0x006BC2A8,
    9C59509A-39BD-11D1-8C4A-00C04FD930C5)
DirectL - IUnknown::Release(0x006BC2A8)
Initialising Memory Card311,15339, Allocated at 023A5298
10661,558577, Allocated at 05880020
311,15339, Allocated at 023A8E90
10661,558577, Allocated at 05DD0020
10661,558577, Allocated at 05E60020

EDIT:
The GUIDs in the snippet above correspond with the following interfaces:

9C59509A-39BD-11D1-8C4A-00C04FD930C5 = IID_IDirectDraw4
BB223240-E72B-11D0-A9B4-00AA00C0993E = IID_IDirect3D3
6C14DB80-A733-11CE-A521-0020AF0BE560 = IID_IDirectDraw

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: DirectL
« Reply #14 on: April 20, 2012, 09:01:31 PM »
great work on this so far. I hope you can solve the graphics issues :thumbsup:

here's something else I forgot to mention earlier;
(taken from GameFAQs to prove I'm not the only one experiencing this problem):

** Level 058 ("The high dive") is unplayable due to a glitch in the program
      that causes Lemmings Revolution to shut down immediately when you try to
      load it. A patch on the Internet is supposed to fix this, but it doesn't
      work either. Fortunately, thanks to the way you open up two levels for
      every one level you beat, you can easily play around this one and beat
      all the others.

http://www.gamefaqs.com/pc/914154-lemmings-revolution/faqs/30084

the exact message that comes up is:
fatal error:
textures\Cylinder\el4_kf_l\OUT_el4_kf_l_7_0Hi.bmp


(note: there's no 'missing this file' or anything just the above) I hope that helps

I can't verify if that patch actually works or not, I can't find it. But I think this is only Windows 7 because I could always play that level before

---
also, thought I'd mention that curiously, the bomber count down numbers are not black like the rest of the text, but rather it doesn't show up at all. you can see a "graphic" above the lemming in certain situations (example: when it's in front of other text like the save number (I think))
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #15 on: April 20, 2012, 09:31:41 PM »
After much experimentation, it has become apparent that I won't be able to inject custom code into existing DirectX interfaces: there's just too much funky stuff going on behind the scenes and lots of things break when I try to mess with them. At this point it's really a matter of using them as they are, or not at all.

So what I'm looking at is similar to what I mentioned in the first post: I'll have to implement IDirectDraw entirely, where all of MY methods just bounce through to the actual DirectX methods except when I need to hook into something. That won't be hard, but it WILL require a complete restart of the project. (-:

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #16 on: April 21, 2012, 12:39:16 AM »
Wheee! I tried a fully phony approach and it worked! I'm just allocating my own fake DirectX interfaces in memory and linking them with actual interfaces spawned by DirectX proper, then using a simple implementation to bridge the game. The bonus here is that if I want to hook into any particular method, I've got the function body right there for adding code to.

Another bonus is that I stuck debug output in every method, so I can see all of them as they're called by Lemmings Revolution:

Code: [Select]
DirectDrawEnumerate()
DirectDrawCreate()
  Created IDirectDraw 0x0284E860
IDirectDraw::QueryInterface(0x0284E860, IID_IDirectDraw4)
  Created IDirectDraw4 0x006B99D8
IDirectDraw::Release(0x0284E860)
  Object deleted
IDirectDraw4::SetCooperativeLevel(0x006B99D8)
IDirectDraw4::QueryInterface(0x006B99D8, IID_IDirect3D3)
  Created IDirect3D3 0x0284E8D8
IDirect3D3::EnumDevices(0x0284E8D8)
IDirectDraw4::GetCaps(0x006B99D8)
IDirectDraw4::EnumDisplayModes(0x006B99D8)
IDirectDraw4::GetDisplayMode(0x006B99D8)
IDirect3D3::Release(0x0284E8D8)
  1 reference remains
IDirectDraw4::Release(0x006B99D8)
  Object deleted
DirectDrawCreate()
  Created IDirectDraw 0x006B8FE0
IDirectDraw::QueryInterface(0x006B8FE0, IID_IDirectDraw4)
  Created IDirectDraw4 0x006B9D08
IDirectDraw::Release(0x006B8FE0)
  Object deleted
IDirectDraw4::GetAvailableVidMem(0x006B9D08)
IDirectDraw4::GetAvailableVidMem(0x006B9D08)
IDirectDraw4::SetCooperativeLevel(0x006B9D08)
IDirectDraw4::SetDisplayMode(0x006B9D08, 640, 480, 16)
IDirectDraw4::QueryInterface(0x006B9D08, IID_IDirect3D3)
  Created IDirect3D3 0x0284E880
IDirect3D3::FindDevice(0x0284E880)
IDirect3D3::EnumZBufferFormats(0x0284E880)
IDirect3D3::CreateDevice(0x0284E880)
IDirect3D3::CreateViewport(0x0284E880)

(Main menu here)

IDirectDraw4::GetAvailableVidMem(0x006B9D08)
IDirect3D3::EvictManagedTextures(0x0284E880)
IDirect3D3::Release(0x0284E880)
  2 references remain
IDirect3D3::Release(0x0284E880)
  1 reference remains
IDirectDraw4::SetCooperativeLevel(0x006B9D08)
IDirectDraw4::Release(0x006B9D08)
  Object deleted

IDirectDraw4::CreateSurface() is excluded from this output because there are lots of them. It returns a DirectDrawSurface4 (even though this link is for version 7) interface, which as you can see has a lot of members. I'm not THAT bored right now, so I'll get to implementing that particular bridge later, but I do have IDirectDraw, IDirectDraw4 and IDirect3D3 implemented for peering into.

Somewhere just beneath the IDirectDrawSurface4 and/or IDirect3D3 interfaces is the parameter responsible for causing the colors to show up incorrectly. With any luck, it will just be a simple EXE edit to pass the right value, rather than requiring this DLL thing to be present.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #17 on: April 23, 2012, 01:31:51 AM »
I've ruled out IDirectDrawSurface4 as the source of the problem. This leaves IDirect3D3 as the culprit; specifically its CreateDevice() method which results in an IDirect3DDevice3. I can't provide an official link to that, though, because the internet seems to have no recollection of it ever existing. This so-called "device" object is the rendering context--the interface that communicates with the video back-end. It supports viewport selections, target device contexts, transformation matrices and--oh goody!--drawing primitives. Consider the images in the first post, showing the clock icon in the bottom corner of the screen. The way those colors are screwed up, I seriously doubt it's a full-color texture. It looks paletted, and the palette itself is going wonky and eventually AWOL. Not even Wine in all its accuracy will display those icons correctly.

Thing is, though, how exactly does IDirect3DDevice3 make textures? Version 8 introduced a CreateTexture() method, but that's nowhere to be seen here in version 3. My guess is that it's using QueryInterface() with something like IID_IDirect3DTexture, but I won't know that for sure until I implement the interface and see what happens.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #18 on: April 23, 2012, 02:52:31 AM »
I was able to get IDirect3DDevice3 implemented in my DLL without issue. It functions properly, and it was not in fact creating textures via its QueryInterface() method. The only other place that could come from, I figured, was the IDirectDrawSurface4 objects. Subsequently, I was able to verify that textures are indeed coming from IDirectDrawSurface4::QueryInterface() passing IID_IDirect3DTexture2 as the interface ID. This is exactly the information I've been wanting to know about, because it provides a solution to the original problem.

The implication here is that we can intercept texture data as it comes from Lemmings Revolution, swapping them out with different data of our own design that function properly on the display. If we construct true-color textures and inject those in place of the paletted ones, it won't matter worth beans what the states of the internal palette objects look like. I'm familiar with the game having been playing it recently, and the following need to be addressed:
  • The Lemming, Balloon and Clock icons on the right-hand side of the main game screen should be replaced with true-color bitmaps.
  • The on-screen text and selected-skill hilight border need to show up as white.
  • The text in the menus needs to change color. Sometimes it's red, sometimes it's black. It's the same character map texture either way.
Those first two should be doable with a straight-up texture replacement. The last one will take some clever manipulation of the game engine, but it won't be difficult. I've already got IDirect3DDevice3 ready to bend over backwards for me, so we'll see what needs to be done.

Links of interest, mainly for self reference:

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #19 on: April 23, 2012, 04:07:28 AM »
Wow, this keeps getting stranger. Take a look at this debug output:

Code: [Select]
IDirectDraw4::CreateSurface(0x009CA0C8)
  16x16 @ 0x00000000
  Created IDirectDrawSurface4 0x009C99C0
IDirectDrawSurface4::QueryInterface(0x009C99C0, IID_IDirect3DTexture2)
IDirectDrawSurface4::GetSurfaceDesc(0x009C99C0)
IDirectDraw4::CreateSurface(0x009CA0C8)
  16x16 @ 0x00000000
  Created IDirectDrawSurface4 0x009C9A90
IDirectDrawSurface4::GetDC(0x009C9A90)
IDirectDrawSurface4::ReleaseDC(0x009C9A90)
IDirectDrawSurface4::Blt(0x009C99C0)
IDirectDrawSurface4::Release(0x009C9A90)
  Object deleted
IDirectDrawSurface4::Lock(0x009C99C0)
IDirectDrawSurface4::Unlock(0x009C99C0)

First off, pixel data is NOT sent to the surface object when it's created. So much for the easy way.

Secondly, it creates a second surface object (using the descriptor from the first), which copies its contents into the first then deletes itself? Weird, but so far so good...

Then... Wait, what goes on in between that GetDC() and ReleaseDC()? A debugger confirms there's a BitBlt() in there, which is not an unusual way to initialize the contents of a surface object. Okay, fine. Nothing strange there.

But then there's also a Lock() and Unlock() right after that? Lock() is used to map the video memory into the process's address spaceOk, but... it doesn't need to do that to initialize the pixel data! Does it need to read it for whatever reason? This doesn't make sense.

Okay, so blitting is a one-way operation. Since it's being used, we know bitmap data is being transferred from process memory to video memory in between GetDC() and ReleaseDC(). Whatever that Lock() and Unlock() are used for, who knows. Hopefully we won't have to worry about it.

Since GDI is being used to manage texture data rather than DirectDraw directly, I'll have to redirect KERNEL32.DLL as well (since apparently the EXE is importing BitBlt() through that somehow, even though it's located in GDI32.DLL). Hopefully I can use the device context handles from that to extract the bitmaps it's writing into texture memory. And assuming there isn't even more weirdness going on, hopefully supplementing those with true-color bitmaps will solve the first part of the compatibility issue.

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: DirectL
« Reply #20 on: April 23, 2012, 05:21:53 PM »
The implication here is that we can intercept texture data as it comes from Lemmings Revolution, swapping them out with different data of our own design that function properly on the display. If we construct true-color textures and inject those in place of the paletted ones, it won't matter worth beans what the states of the internal palette objects look like. I'm familiar with the game having been playing it recently, and the following need to be addressed:
  • The Lemming, Balloon and Clock icons on the right-hand side of the main game screen should be replaced with true-color bitmaps.
  • The on-screen text and selected-skill hilight border need to show up as white.
  • The text in the menus needs to change color. Sometimes it's red, sometimes it's black. It's the same character map texture either way.
Those first two should be doable with a straight-up texture replacement. The last one will take some clever manipulation of the game engine, but it won't be difficult. I've already got IDirect3DDevice3 ready to bend over backwards for me, so we'll see what needs to be done.

don't forget; the bomber timer over a lemming doesn't show correctly. This is particularly strange since it doesn't show up as black but instead doesn't show up at all.  (however you can still see the "blank image: sometimes.
Also some objects in the background image are funny; for example the lolly pops and sheep in the "river background" are black
also, *sigh* I forgot another few items; the tips of switches should be red, they are discolored in the same way.
-The fish, in water tanks, they were orange or goldfish; same thing.

I apologize if what I say you already talked about but I don't understand the programming jargon.
It seems that most of the faulty objects are all objects that move or are dynamic. the letters, numbers, switches. Does the programming group the objects in this way (or some way)?  That might help locate the problem
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #21 on: April 23, 2012, 07:44:01 PM »
I'm onto something. It's not DirectX after all: it's Lemmings. I was able to intercept textures on the way in from the application and got these:



No alpha channel is present in that image, but it's the correct, full-color, non-paletted icons for the status figures on the screen.

Interestingly, Windows 7 didn't dump these. I guess there was an error in the DC I was reading from. I'll look at it more closely later on. What we know is that, for whatever reason, Windows 7 probably doesn't get these pixels whatsoever.

After those are applied to DirectDraw, they turn into this:



The subsystem stretched all three out so they were 32 pixels wide. Iiiiiinteresting...

Remember how I said you can populate a texture with GetDC -> BitBlt -> ReleaseDC? Well, that's where these images are coming from. In fact, I was dumping them from the DC right before and after ReleaseDC() was called.

Remember also how I said there was an additional Lock() -> Unlock() right after? Well, take a look at what that did:



Uh-huh. Look familiar?



Lock() is used to give the program access to the texture memory as though it was ordinary RAM. What goes on between that and Unlock() happens in the program itself, reading from and writing to texture memory.

Lemmings Revolution itself is screwing up the colors. And can you blame it? Rather that feed colors directly into DirectX, it first blits into a GDI DC, then subsequently accesses the memory through Lock(). That is not--I repeat--that is NOT the way to initialize a texture. Apparently at some point DirectX decided that textures should be square or something (I really don't know what's going on with that one) and Lemmings was expecting everything to work exactly as it did in Windows 98.

That's the bad news. The good news is that, since it's not an issue with DirectX whatsoever, once all of the textures are loaded correctly, every last piece of the color problem will sort itself out.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #22 on: April 24, 2012, 12:51:57 AM »
I was able to isolate the function responsible for loading pixel data into IDirectDrawSurface4 objects. It constructs a DC that's used as the source in BitBlt(), and all of the textures from that exported just fine, even in Windows 7. It seems the DirectX destination DC isn't accepting some of them. I'm still not sure what's going on between Lock() and Unlock(), but it looks like it has something to do with the alpha channel. In fact, all textures that have built-in alpha channels (as opposed to using a color key for transparency) appear to be missing all their color.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #23 on: April 24, 2012, 12:59:49 AM »
Alright! Just as I was hoping, simply not calling that function at all results in pure, un-textured polygons. And what's more, they're the right colors! In fact, even the numbers that show up for Exploders are back, albeit white squares at the moment. Everything's functioning properly without bogus texture data involved!

All I need to do is make a replacement for that function and we should be good to go.

Here we have the level results screen, with very red lettering.


Likewise, the shadows behind the text on the level select screen are properly red as well.


EDIT:
Personal note in case of catastrophe: The function in question is in process address range 00472DB9-0047393B

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #24 on: April 24, 2012, 07:12:32 PM »
I'm up to my eyeballs in assembly, but progress is being made. I opted to just pick apart the function instruction-for-instruction and generate an equivalent to the source code that eventually became Lemmings Revolution.exe. There's a lot of code to go through (it's one of THOSE functions), so there's still a few hours of this ahead of me, and don't be surprised if I do other things between now and the time I finish. (-:

Once an analog to the source code is produced, I'll test that out to be sure my work yields the same results as the function in the game. After that, it will be a simple matter to make changes such that the textures are once again loaded correctly. It'll be the first time in ten years anyone's seen that Lemming icon with the colors it's supposed to have. (-:

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #25 on: April 25, 2012, 12:59:23 AM »
I'm close. Very, very close. We now have proper alpha channels:



What Lemmings does is load a BMP image into a GDI bitmap object, then passes that to a function to convert it into a Direct3D texture object. This is accomplished with BitBlt(). However, all of the textures are passed as either paletted or 24-bit RGB, which means no transparency except in the case of a color key. What it does instead is pass in an alpha buffer when appropriate, then writes that to the texture after BitBlt() by using Lock() and Unlock(). Or at least, that's the idea. It doesn't do that correctly, though. I haven't looked totally into it since I now know how textures are supposed to be processed, but I'm pretty sure it's incorrect handling of the RGB channel bit masks that's causing the colors to screw up.

Right now, I appear to be missing a little detail that either tells the game to accept the textures I'm generating or tells Direct3D to just-plain-work-dammit, but as soon as I figure out what it is that turns my byte arrays into on-screen pixels, we're in business.

EDIT:
Got it! Direct3D wasn't liking my custom channel masks. Now all I gotta do is give it the texture data. (-:<

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #26 on: April 25, 2012, 02:48:40 AM »
Woo! Got it working! However, due to the way I'm processing all textures as 32-bit RGBA, any of the paletted textures that handled transparency with a key index... aren't transparent. However, I have a solution for that which should make the entire game just the way it was on launch day!

Colors are back, Exploder numbers are back, right-side-of-screen icons are back... Today is a good day.




Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #27 on: April 25, 2012, 03:37:18 AM »
Wow, awesome progress! :thumbsup: 8)

Only thing I want to add is, when you're all done, it would be good to include information on what patching is done on your EXE, sorta like the xvi32 screenshot you made for the DirectSound-related patch.  Because there seems to be multiple versions of the game out there with various other fixes, and no one has been able to sort out which such version is the most updated.  So it may be best to eventually have a patch program that tries to find and patch the relevant bytes even if their exact location in file may be slightly different between versions of the EXE.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #28 on: April 25, 2012, 05:45:41 AM »
There's a patch on Download.com, so it's built off of that. If you get that patch to run and work, applying MY patch should work as well.

Which, by the way, is done now. Go check it out. (-:

http://www.lemmingsforums.com/index.php?topic=620.0

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #29 on: April 25, 2012, 10:05:43 AM »
Okay, I'll give that a try and do diff between the two to work out the exact changes you made, and then I should be able to make it in the future so that it's possible to apply your changes to "any" version of the game.

The reason that is of interest is because there seems to be quite a few versions out there it seems.  For example, I alone have two copies of the game, one published by "Take 2 Interactive", another by "Take 2 Interactive Europe".  The former's CD actually comes with both an unpatched and patched version of EXE (which are not diff-identical), and the EXE from the latter is also different from the first two.  (Granted, the differences may turn out to be superficial, I certainly haven't bothered to analyze in any manner.)  This is not to mention what other people may own, given what we find out onthis thread.  Also, patched/unpatched versions (at least what I own) have known subtle differences in game mechanics.  All that confusion makes it reasonable to want to be able to apply the sound/graphical fix to multiple versions of the EXE, rather than having to stick with the version on CNET downloads.

But for now I think I'll just wait until you've finished tweaking your changes first.  Nice work once again.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #30 on: April 25, 2012, 05:08:34 PM »
Okay, I'll give that a try and do diff between the two to work out the exact changes you made [...]

But I already know what changes I made. |-:

I patched the following to the EXE at address 00072DB9:
00472DB9 | 6A 00       | PUSH    0
00472DBB | 6A 01       | PUSH    1
00472DBD | E8 FE400300 | CALL    DirectDrawEnumerateA
00472DC2 | FFE0        | JMP     NEAR EAX

And the following at address 00098B55:
00498B55 | 31C0 | XOR     EAX, EAX |

And at 000BDBA3, replaced DDRAW.DLL with PATCH.DLL

I also forgot to reset the subsystem type in the PE header up at the beginning of the file. It's currently set to 3, which is a console app, as opposed to 2 for a GUI app. The only thing this really affects is the presence of a console window, which is generally invisible because of the fullscreen nature of the program, so I'll save that and group it with the next round of tweaks.


How it works

Since I couldn't reliably get the address of functions in my DLL that weren't explicitly imported by the EXE, I stuck a hook into my implementation of DirectDrawEnumerateA that, if passed 1 as the callback address, the function would return the address of my custom texture processing function. 00472DB9 is the address of the game's texture processor, which I've overwritten with a very simple patch function that just calls DirectDrawEnumerateA for the address of MY function, then calls my function.

This way, if we want to make other changes in the future, we can pass in a 2 or 3 or whatever to get the addresses of other custom functions. It's really an elegant way to inject custom code into the existing application.

I'll gladly put up the source code to the DLL somewhere so people can poke around with it, but attaching it to or posting it in a forum post doesn't quite seem like an appropriate way to do that.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #31 on: April 25, 2012, 06:48:56 PM »
Woo! An update already! Also, an idea.


The Patcher
As ccexplore pointed out, there's who-knows-how-many versions of Lemmings Revolution out there. I think instead of forcing everyone to just use one particular EXE of our own design, we can distribute a patching program that will edit whatever EXE file the user happens to have, patching it to work with the texture edit. This way, that "Unknown String" error is virtually impossible to occur, and we get the added benefit of not actually distributing a copyrighted file.

If we can round up as many copies of Lemmings Revolution and its patches as we can, we can construct a list of them so the patcher knows what to change in order to get the textures working again. And whatever else we decide our DLL should do.


The Update
In yesterday's hack, I was passing all textures through my own function, even the ones that worked before. As it turns out (and an examination of the assembly confirms), the problem only occurred when the texture was having an alpha channel injected after the fact. All of the paletted textures that had transparency done with a color key were just fine. Nonetheless, all of them went through my function.

The thing is, I'm not sure how those color keys were determined, so when my function came across paletted textures, they weren't transparent at all (see earlier screen shot). My solution to that was to run a checksum on all of them, then put those in a list along with the color value of the pixels that were supposed to be transparent. That worked, more or less, but it wasn't 100% accurate. The bomb icon had a couple of holes in it, the main cursor had some black dots appear, etc. It wasn't great, but it was better than it was because all the other textures looked correct now.

So it occurred to me, "You know, the game knows what to do with the paletted textures, and handles them correctly. If I just let it do its thing in the event an alpha mask is not present, it should make all of the textures load 100% correctly." And that's exactly what I did. I removed the checksum/color value code from the DLL and told it to return to the function in Lemmings Revolution if no alpha mask was provided. Otherwise, it will keep doing what it was doing yesterday and construct an RGBA pixel buffer for a write-once operation to texture memory.

Man does it look good now. Textures are now processed with 100% accuracy to the way the game was designed to look. This is incredibly satisfying. (-:



Not that it matters to anyone here, but the new patch to the texture function looks like this:

    00472DC8 | 51            | PUSH    ECX      |
    00472DC9 | 6A 00         | PUSH    0        |
    00472DCB | 6A 01         | PUSH    1        |
    00472DCD | E8 EE400300   | CALL    004A6EC0 |
    00472DD2 | FFD0          | CALL    NEAR EAX |
    00472DD4 | 83F8 04       | CMP     EAX, 4   |
    00472DD7 | 0F84 5B0B0000 | JE      00473938 |
    00472DDD | 90            | NOP              |
    00472DDE | 90            | NOP              |
    00472DDF | 90            | NOP              |
    00472DE0 | 90            | NOP              |

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #32 on: April 25, 2012, 07:08:47 PM »
I've identified the source of the original problem. IDirectDrawSurface::Lock() cannot be used for both read and write operations at the same time. If it's used for a write-only operation, it's part of the spec that the calling application should write to all addresses within the selected region. Lemmings Revolution is only writing the alpha channel. All-in-all, this is actually a reasonable mistake to make, especially if it seems to work regardless.
  • This worked on Windows 98, which apparently preserved all of the color data when a write-only operation occurred on a texture.
  • This started falling apart on Windows XP, which obviously didn't preserve all of the color data, but just some.
  • This doesn't work at all on Windows 7, which appears to discard the previous contents of the color buffer entirely and resulted in black pixels.
The approach I've taken to correct the problem seems appropriate, as the Lemmings function itself cannot be modified to write all of the pixel data into texture memory during a locked period.

This just goes to show you: pay very close attention to the specification, because just having it work on one system or architecture doesn't mean it's done correctly.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #33 on: April 26, 2012, 01:00:28 AM »
Well, I solved the problem with the multiple builds of the EXE file. The patcher program I'm just about done with will scan the EXE, looking for all of the information it needs to successfully patch it. All of the memory addresses and file offsets are detected automatically, if possible, and used to produce the necessary patch code and DLL file.

Here's what it looks like:



The picture doesn't do the beauty of the thing much justice. The version of the EXE I have on my CD is different from the one in the official patch, and the program still works! It also has a debugging feature that can be activated by command line. Its output will change to look something like this:

Code: [Select]
Lemmings Full Color Revolution!             Windows Vista/7 Compatibility Patch
Written and maintained by Lemmings Forums        http://www.lemmingsforums.com/
  Version 1.0 - April 28, 2012

Analyzing EXE file...   Done
  004A6EEC DirectSoundCreate
  004A6EE0 DirectDrawEnumerateA
  00472F89 LemLoadTexture
  004BDA36 "DDRAW.dll"
  00498B75 Call to DirectSoundCreate
  0058CEA8 Global IDirect3DDevice3
  0058CEA0 Global IDirectDraw4
Configuring DLL file... Done
Patching EXE file...
  Solving the mystery of the missing audio... Done
    04098B75 | 31C0        | XOR   EAX, EAX
  Fixing all those funky/missing colors...    Done
    04072F98 | 51          | PUSH  ECX
    04072F99 | 6A 00       | PUSH  00
    04072F9B | 6A 01       | PUSH  01
    04072F9D | 8E 3E3F0300 | CALL  040A6EE0  ;DirectDrawEnumerateA
    04072FA2 | FFD0        | CALL  NEAR EAX  ;LemLoadTexture (DLL)
    04072FA4 | 90          | NOP
    04072FA5 | 90          | NOP
    04072FA6 | 90          | NOP
    04072FA7 | 83F8 04     | CMP   EAX, 4
  Teaching it to use the DLL we made...       Done

SUCCESS: And there you have it, good as new. Enjoy!

Press any key to continue...

Your eyes don't deceive you: the patcher is auto-assembling machine code based on the information it gleaned from the analyzed EXE file. (-:<

All I have to do now is program a joiner to package the patcher EXE and the DLL together in one file, then make the patcher patch the DLL so it knows how to work with the Lemmings EXE in question. Gimme an hour and I'll have that ready. (-:

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #34 on: April 26, 2012, 02:07:31 AM »
Aaaaand it's ready for testing. This is just a simple EXE file. Using an *original* Lemmings Revolution installation (no modified EXE files), drop this EXE into the installation directory and run it. If all goes well, it won't say there were any problems. (-:

Lemmings Full Color Revolution v1.0 beta is attached to this post. You can access the debugging output by passing -debug on the command line.

EDIT:
Made some updates. I'm happy with it now. Attached is beta 2

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #35 on: April 26, 2012, 10:39:43 AM »
Finally got a chance to try it out.  Works great! :thumbsup:  I even tried it on the demo version for kicks and it works for that too! ;)

Although I have to say I still feel slightly let down with the text not showing on Win7/Vista until after you go into a level.  I know it's not too much a hurdle to playing the game, but certainly it is an very noticeable and ironic first thing to see on something we claim to be "good as new" ;P.  Any clue as to what's up with that?  At first glance, one would think that somehow transparency is not getting enabled until some particular action during level rendering turns it on.  Yet that isn't quite the case, given that the clock icon on the level select screen (top-left, for displaying time limit of the level under the cursor) does have its transparency working. ???

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #36 on: April 26, 2012, 05:28:47 PM »
I even tried it on the demo version for kicks and it works for that too! ;)



Now that's what I like to call a job well done. (-:


Although I have to say I still feel slightly let down with the text not showing on Win7/Vista until after you go into a level.

I plan on looking into the first-launch-menu thing today. I don't want to release the patch until I at least look into it. Only the cursor and text are done with Direct3D and are therefore subject to blending. The level select screen and the Lemmings Revolution splash art are done entirely through DirectDraw, which is why they still work regardless.

Since the text is one of those fancy alpha-mask textures that has to run through the custom DLL, I'm 100% certain blending just isn't being turned on by the time the menu loads the first time. Why it worked on previous versions of Windows, who knows. Maybe it's getting turned off at some point? Maybe it's being turned on incorrectly and, like the texture issue, got released because it Just Plain Worked?

Whatever the case, I went through the trouble to have the patcher pin down the address of the game's global IDirect3DDevice3 object, which is the one responsible for turning on blending. In a worst-case scenario, in the event I can't patch the EXE directly to do it right, it'll just have to call a second custom function in the DLL to flip the switch to the on position. The only real issue at this point is finding exactly where to do that.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #37 on: April 26, 2012, 07:40:55 PM »
I've located the function responsible for enabling transparency in the main menu and... it's working correctly. I'm gonna get some food, then try to find out what else might make transparency not work at all even with blending enabled.


EDIT:
Woo hoo! Got it working!

The problem was actually due to an unconfigured property of the Direct3D device that relates to something called texture stages. This information is initialized going into the level display, but it is NOT initialized going into the menu. And why should it? On Windows 98 and Windows XP, it seemed to work anyway. Buuuuut again, as per the DirectX spec, it should be done before attempting to use a texture with alpha blending.

I think what probably happened was the programmer designed the game from the level display, then after the fact went in and set up the main menu. He forgot to initialize the texture stage information there, but never caught it because it worked without initialization.

The fix is just a couple of lines of code in the DLL using--you guessed it--the global IDirect3DDevice3 address discovered by analyzing the EXE. I'm going to add a message to the patcher indicating that the blending on the main menu is being fixed while patching the EXE, but it's actually all done in the DLL... I just want the user to know it's being fixed.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #38 on: April 26, 2012, 09:33:04 PM »
Lemmings Full Color Revolution!
Version 1.0 (Beta 3)

Attached to this post. Test! Test! Test!

Also, I really want this source code somewhere that we can all get to it.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #39 on: April 27, 2012, 05:22:07 AM »
I'm preparing for a formal release, and have done all sorts of fun stuff! I've got all of the source files trimmed and commented, I crafted an icon for the EXE file using one of the namesake textures from the game that's been loaded improperly for years, and even typed up a nice readme file.

So if you would, please read the readme and let me know what you think:

Code: [Select]
Lemmings Full Color Revolution!             Windows Vista/7 Compatibility Patch
Written and maintained by Lemmings Forums        http://www.lemmingsforums.com/
  Version 1.0 - April 26, 2012


About this program:

As you've probably noticed, Lemmings Revolution has been falling apart over the
years as Windows went through its many updates. It started out innocently
enough on Windows XP: a few of the icons had wonky colors, but it was otherwise
okay. But then, when windows Vista and 7 came about, those icky colors just
turned full-on black. And the main menu became a virtually unusable cluster of
black rectangles. Oh, and the sound stopped working! It's a real mess.

Well, this handy little gadget fixes all of those problems. While the technical
details are beyond the scope of this readme file, the tl;dr version is that the
game program does not conform 100% to the DirectX specification. It was just
fine back on Windows 98 where it worked anyway, but as time marches on, we see
that the game was released with what we have since learned to be show-stopping
bugs!


Things that this gizmo will fix:
 * Restores audio on Windows Vista and 7. It was completely AWOL before.
 * Provides a new texture loading routine. This corrects the messed-up colors.
 * Tweaks the main menu graphics. Solid black rectangles are hard to read.


How to use this bad boy:

 * This is only designed to work with the original Lemmings Revolution EXE
   files (the game has seen various releases), so if you have one with any
   modifications, don't expect it to work. When in doubt, just re-install it
   from the CD. Don't worry: you won't lose your save data.

 * Locate the Lemmings Revolution installation directory on your computer. By
   default, this is "C:\Program Files (x86)\Take 2\Lemmings Revolution\" for
   the North America releases. Believe in yourself; I'm sure you can find it.

 * Make sure "Lemmings Revolution.exe" is not read-only. You can check this by
   right-clicking the file, selecting Properties, then making sure the box next
   to "Attributes" is un-checked.

 * Copy the Full Color EXE file into the Lemmings Revolution installation
   directory and run it. If UAC is enabled, you will have to run it as
   administrator. To do so, right-click the Full Color file and select
   "Run as administrator"

 * The program will do its darnedest to fix up the Lemmings Revolution EXE so
   that it works correctly again. Be sure to read the contents of the window
   that appears for information on what it was able to accomplish. If there was
   a problem, it will let you know what went wrong.


Additional information:

As noted above, there's a few different versions of Lemmings Revolution out
there. In fact, no one's really sure just how many there are. It's not feasible
to track them all down to make a comprehensive list, so this patch is instead
designed to be flexible and figure out exactly what needs to be done by
analyzing the Lemmings Revolution EXE file that it's intended to patch.

Some of the code updates were too large or otherwise too complex to be fitted
into the original EXE file, so they were moved into a DLL file instead. The
Full Color program will produce one such DLL file when it patches Lemmings
Revolution, adding it to the installation directory. The file's name is
"patch.dll" and it is required for the game to run, so don't delete it.

In addition to patching the Lemmings Revolution EXE file, that DLL file itself
is configured to work specifically with the version of Lemmings Revolution
being patched. If you copy a patch DLL from a different installation of
Lemmings Revolution, it will not work. In order to ensure correct
functionality, always run the Full Color program on an un-modified Lemmings
Revolution EXE.


Change log:

 * April 26, 2012 - Original release
   Contained audio fix, new texture loading routine, and a fix for the graphics
   on the main menu.


Credits:
 * Lemmings Revolution is ©2000 Psygnosis/Talonsoft and Take-Two Interactive
 * Lemmings Forums staff (http://www.lemmingsforums.com/)
   - ccexplore, for technical research, ideas and testing support
   - Guy Perfect, for reverse engineering and patch development
   - thick molasses, for testing support



And here's what the final EXE looks like:




The successful user-mode output looks like this:

Code: [Select]
Lemmings Full Color Revolution!             Windows Vista/7 Compatibility Patch
Written and maintained by Lemmings Forums        http://www.lemmingsforums.com/
  Version 1.0 - April 26, 2012

Analyzing EXE file...   Done
Configuring DLL file... Done
Patching EXE file...
  Solving the mystery of the missing audio... Done
  Making those funky/missing colors behave... Done
  Pressing the "Fix Main Menu" button...      Done
  Teaching it how to use the DLL we made...   Done

SUCCESS: And there you have it, good as new. Enjoy!

Press any key to continue...


And the -debug output like so:

Code: [Select]
Lemmings Full Color Revolution!             Windows Vista/7 Compatibility Patch
Written and maintained by Lemmings Forums        http://www.lemmingsforums.com/
  Version 1.0 - April 26, 2012

Analyzing EXE file...   Done
  004A6EEC DirectSoundCreate
  004A6EE0 DirectDrawEnumerateA
  00472F89 LemLoadTexture (EXE)
  000BDA36 "DDRAW.dll"
  00498B75 Call to DirectSoundCreate
  0058CEA8 Global IDirect3DDevice3
  0058CEA0 Global IDirectDraw4
Configuring DLL file... Done
Patching EXE file...
  Solving the mystery of the missing audio... Done
    04098B75 | 31C0        | XOR   EAX, EAX
  Making those funky/missing colors behave... Done
    04072F98 | 51          | PUSH  ECX
    04072F99 | 6A 00       | PUSH  0
    04072F9B | 6A 01       | PUSH  1
    04072F9D | 8E 3E3F0300 | CALL  040A6EE0  ;DirectDrawEnumerateA
    04072FA2 | FFD0        | CALL  NEAR EAX  ;LemLoadTexture (DLL)
    04072FA4 | 90          | NOP
    04072FA5 | 90          | NOP
    04072FA6 | 90          | NOP
    04072FA7 | 83F8 04     | CMP   EAX, 4
  Pressing the "Fix Main Menu" button...      Done
    (This is actually handled by the DLL)
  Teaching it how to use the DLL we made...   Done
    Wrote "patch.dll" to 000BDA36

SUCCESS: And there you have it, good as new. Enjoy!

Press any key to continue...

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #40 on: April 27, 2012, 10:44:12 AM »
Cool.  Other than the patch program not support Beta2->Beta3 (which I half-expected would be the case anyway), it went without a hitch and the game is more or less back to its full glory on my Win7 computer now. :thumbsup:  In fact seeing it like this made me notice quite a few things I didn't even realize or notice were displayed incorrectly when I played a while back on my XP computer, like things in the background in some levels, or the knob color of level switches.

Indeed, now that Win7 is back to not having so many things displayed in black, I actually only start to notice a problem I'm only seeing on my Win7 computer that I didn't notice before.  For some reason a number of things, most noticeably the numbers on the skill buttons and the "over lemming" mouse cursor, exhibits cut-offs and uneven stretchings.  This also happens w/o the patch, and clearly isn't happening on GP's screenshots for Win7 pre-patch nor post-patch, so I guess it must be something specific about the computer, maybe the widescreen dimensions (1280x800 is the native resolution of the LCD)  or the display driver.  Or maybe something about the specific version installed on there (obviously a while since I last installed the game for Win7, and annoyingly I've also misplaced one of the two versions and can't find at the moment).  Oh well, guess you can't always have everything. ;)

Popcorn earned for a job well done! :party:  Didn't expect we'd have understood and solved all those problems in just 2-3 weeks.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #41 on: April 27, 2012, 03:01:53 PM »
I've experienced the "The High Dive" problem that thick molasses brought up, and I think it's an easy fix. If I'm goin' all out, I'm goin' all out. Let me look into that. (-:

Quote
Didn't expect we'd have understood and solved all those problems in just 2-3 weeks.

I didn't start working on it until last Thursday. Today is this Friday. (-:

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #42 on: April 27, 2012, 04:03:34 PM »
"The High Dive" is level 9-6. The game crashes when it tries to load the following file:

Textures\Cylinder\e14_kf_1\OUT_e14_kf_1_7_0Hi.bmp

I took a few minutes to write a BOX extractor and dumped all the files to disk. As it turns out, much to the surprise of ccexplore, these bitmaps do indeed appear to be compressed. However, since the WAV files work out of the box (so to speak), I believe the decompression layer is separate from the archive extraction layer.

The bitmap files contain a 5-byte header:

Code: [Select]
Byte    Version number maybe? Currently set to 0x01
Int16   Packed size, which is the total file size - 5
Int16   Unpacked size

Aaaaaand, I have no idea what algorithm it's using for compression. It's not zlib, though I haven't yet ruled out DEFLATE. Either way, trying to find out why the file isn't working requires some more guesswork and who knows how long that will take.

There's also an OUT_e14_kf_1_7_0.bmp, which is about a fifth of the size. In fact, this seems to be the norm across the board. For each level, there's eight groups of textures (0 through 7), a trio of both INN and OUT textures for each (0 through 2), and each of those with a normal and a HI version. My money's on HI being a higher resolution texture.

So hey, I figured, why not just rename the high-resolution file to the low-resolution file's name? It didn't occur to me until after the fact what the problem with that approach was: if the game's trying to load OUT_e14_kf_1_7_0HI.bmp, then removing it from existence isn't going to solve anything.

But guess what? Somehow or other, renaming the file successfully got the level to load, and I'll be darned if I can't tell what's supposed to look blurrier. A full 360 around the entire level doesn't reveal any inconsistencies whatsoever. |-:

So now I'll just poke into the game and see where the code is that tries to reference that file, then inject a safeguard that will load the other one instead.


Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #43 on: April 27, 2012, 06:31:14 PM »
Aw, man! I thought I was being clever. I found where the resource filename is loaded into memory, and patched it to fix this one filename, and it worked! Except now it crashes when you *close* the level. )-:

Okay, onto plan B. Since editing the BOX file directly doesn't cause any problems, we'll just have to require Lemmings Revolution to be a Typical install rather than Compact. It will patch both the EXE and the BOX file.

EDIT:
Aaaaaaand done. I'm preparing the beta 4 release candidate now.

EDIT2:
Aw, bummer. The update didn't work on XP. Or in Windows 7 with compatibility mode disabled. Back to the drawing board, then.

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #44 on: April 27, 2012, 08:49:03 PM »
much to the surprise of ccexplore

Haha, actually I'm not all that surprised at all.  I think you over-read what I said back when I published the BOX file format.  All I meant is that the BOX format itself does not provide compression, like one would expect with a typical file archive.  The contents of individual files is of course a totally separate matter.  For all I know not only may some of the files themselves be compressed, but so can individual pockets of data within a file.

And as a matter of fact, your recent foray into fixing LR for post-Win98 Windows did get me to take a closer look at the files inside a BOX file, and yes, I found that they compressed the BMP files.  I actually looked enough into it that I have identified the section of code that does the decompression, and can easily hook up debugger commands associated with a breakpoint to dump decompressed data to a file each time the program decompresses a file from BOX.  This is how I got the LR font BMP to post here, except the forum seems to be acting odd when I made replies to that super-old thread, so I don't know if the attachment made it there.

I haven't read what you've done with this, but I do want to note that while I didn't really bother to see exactly what the program does to decompress, I've skimmed enough of it to tell you that the program first explicitly checks for the first two bytes to be 'B' 'M', ie. the "header signature" for a proper BMP file, and will just return data as-is w/o decompression in that case.  So you can replace any compressed BMP textures in a BOX file with a decompressed BMP, you don't actually need to figure out compression for purpose of file replacement.

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: DirectL
« Reply #45 on: April 27, 2012, 08:55:53 PM »
  I actually looked enough into it that I have identified the section of code that does the decompression, and can easily hook up debugger commands associated with a breakpoint to dump decompressed data to a file each time the program decompresses a file from BOX.  This is how I got the LR font BMP to post here, except the forum seems to be acting odd when I made replies to that super-old thread, so I don't know if the attachment made it there.

Geoo said he couldn't see it either. logged in I can't read it, the page takes really long to load and cuts off at minimac's post but not logged in I can see it (of course the picture isn't there)
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #46 on: April 27, 2012, 09:07:08 PM »
Actually I just remember that the font BMP's data mostly comes from the uncompressed ^font.alf file, so that is a poor example of decompression.  But pick any file you want decompressed and I can do it through the debugger, at least from my copy of lemmings.box/patch.box.  So for example I can definitely hook it up again to get Textures\Cylinder\e14_kf_1\OUT_e14_kf_1_7_0Hi.bmp extracted, although it sounds like we think the compressed data itself may be bad to begin with for that file?  Today's Friday though so I still have work to do in real-life (ie. job).

BTW, one quick way you can see what a bitmap looks like (w/o bothering about the actual data, compressed or otherwise), is to make a copy of the EXE, hex-edit to find and replace the string texture\main_logo.bmp with path to the bitmap you want to see, and then run the modified EXE and see what the start-screen logo is replaced with.

The bitmap files contain a 5-byte header:

Code: [Select]
Byte    Version number maybe? Currently set to 0x01
Int16   Packed size, which is the total file size - 5
Int16   Unpacked size

The first byte actually is number of sections.  As you noted, packed and unpacked sizes are limited to Int16 (actually UInt16 I think, IIRC), so to support larger file sizes (like texture\main_logo.bmp which is a full 640x480x24bpp BMP), contents are split into multiple sections whose size fit within UInt16, and compressed separately (I think, not sure if no state data gets carried over from section to section).  That is:

number of sections (packed size of section, unpacked size of section, compressed data), (packed size of section, unpacked size of section, compressed data), ...

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #47 on: April 27, 2012, 09:08:53 PM »
  I actually looked enough into it that I have identified the section of code that does the decompression, and can easily hook up debugger commands associated with a breakpoint to dump decompressed data to a file each time the program decompresses a file from BOX.  This is how I got the LR font BMP to post here, except the forum seems to be acting odd when I made replies to that super-old thread, so I don't know if the attachment made it there.

Geoo said he couldn't see it either. logged in I can't read it, the page takes really long to load and cuts off at minimac's post but not logged in I can see it (of course the picture isn't there)

Yeah, I think my act of posting on that old thread has somehow corrupted the data on it. :-\ :o  The really funny thing is that I can still read the post as guest, so I'm thoroughly confused as to what's going on.  And since it refuses to display my posts when I logged in, I can't delete the post either (although maybe with the damage already done, further modifications might just make things worse).

Let me repost later on a new thread instead.

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #48 on: April 27, 2012, 09:27:59 PM »
Or maybe I can just post here.  The attached is what I got out of the debugger for all BMPs loaded from BOX from launching the game to reaching the start screen.  Numbers are auto-generated (the debugger I used don't have powerful enough scripting support to do anything fancy with the filename of the dump command).  font.png is actually not from any compressed BMPs, it so happens that for the font, the main BMP is just a 256x240 white rectangle, and there is an associated separate .alf file that contains raw bitmap bits for the alpha-channel part of the bitmap.  font.png is derived from the ^font.alf file.  Other "all white" rectangles are probably similarly formatted.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #49 on: April 27, 2012, 11:25:34 PM »
So for example I can definitely hook it up again to get Textures\Cylinder\e14_kf_1\OUT_e14_kf_1_7_0Hi.bmp extracted, although it sounds like we think the compressed data itself may be bad to begin with for that file?

Unfortunately, no. There's nothing wrong with the file. I snagged this as it passed through my texture loader:



I mean, it's fortunate that there's nothing wrong with the file, but unfortunate that the game is crashing for an unrelated reason. Who knows how many hours it took finding that out.

Let me see if I can just tell the game to ignore the error.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #50 on: April 28, 2012, 12:00:56 AM »
Well, I told the game to just ignore the error and it crashed for reals.

Code: [Select]
00450379 | 83F9 03       | CMP     ECX, 3                   |
0045037C | 75 1F         | JNZ     0045039D                 | Initial error is detected here
0045037E | 8B95 B0FEFFFF | MOV     EDX, DWORD PTR [EBP-150] |
00450384 | 83EA 05       | SUB     EDX, 5                   |
00450387 | 52            | PUSH    EDX                      |
00450388 | 8B45 F0       | MOV     EAX, DWORD PTR [EBP-10]  |
0045038B | 50            | PUSH    EAX                      |
0045038C | 8B8D B8FEFFFF | MOV     ECX, DWORD PTR [EBP-148] |
00450392 | 51            | PUSH    ECX                      |
00450393 | E8 48CC0400   | CALL    0049CFE0                 |
00450398 | 83C4 0C       | ADD     ESP, C                   |
0045039B | EB 6A         | JMP     00450407                 |

0045039D | 8B55 F0       | MOV     EDX, DWORD PTR [EBP-10]  |
004503A0 | 33C0          | XOR     EAX, EAX                 |
004503A2 | 8A42 FF       | MOV     AL, BYTE PTR [EDX-1]     |
004503A5 | 83F8 04       | CMP     EAX, 4                   | If this passes, the game will not crash
004503A8 | EB 1A         | JMP     004503C4                 |

004503AA | 8B4D 08       | MOV     ECX, DWORD PTR [EBP+8]   |
004503AD | 51            | PUSH    ECX                      |
004503AE | 6A 3F         | PUSH    3F                       |
004503B0 | 68 78034C00   | PUSH    4C0378                   |
004503B5 | E8 68240300   | CALL    00482822                 | This calls the routine to display the message box
004503BA | 83C4 0C       | ADD     ESP, C                   |
004503BD | 6A 00         | PUSH    0                        |
004503BF | E8 8FCF0400   | CALL    0049D353                 | This presumably has an exit() somewhere.

004503C4 | 8B95 A8FEFFFF | MOV     EDX, DWORD PTR [EBP-158] |

I'm still experimenting seeing if I can get it to pass anyway, since as far as I can tell, the texture is valid by the time it gets here.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #51 on: April 28, 2012, 01:08:58 AM »
Ohohoooooo, they thought they were clever.

I believe I know the source of the problem, and it's an anti-piracy countermeasure. Let me run a couple tests to make sure.


EDIT:
Bahaha! Man, was that ever dumb. To think I wasted a whole day on this.

No, it's not an anti-piracy countermeasure; it's just a big wad of derp. The only users affected are those who chose a Typical install from the original CD. Users with a Compact installation will not crash when loading the level.

The installer writes a different lemmings.box file than is on the CD. I don't know exactly what changed or how, but copying the file from the CD into the installation directory after running a Typical install will fix the level and make it playable.

What a load of crap.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #52 on: April 28, 2012, 01:47:25 AM »
Attached to this post is Full Color v1.0 (Beta 4). This is a release candidate.

The updated Readme is as follows:

Code: [Select]
Lemmings Full Color Revolution!             Windows Vista/7 Compatibility Patch
Written and maintained by Lemmings Forums        http://www.lemmingsforums.com/
  Version 1.0 (Beta 4) - April 27, 2012


About this program:

As you've probably noticed, Lemmings Revolution has been falling apart over the
years as Windows went through its many updates. It started out innocently
enough on Windows XP: a few of the icons had wonky colors, but it was otherwise
okay. But then, when windows Vista and 7 came about, those icky colors just
turned full-on black. And the main menu became a virtually unusable cluster of
black rectangles. Oh, and the sound stopped working! It's a real mess.

Well, this handy little gadget fixes all of those problems. While the technical
details are beyond the scope of this readme file, the tl;dr version is that the
game program does not conform 100% to the DirectX specification. It was just
fine back on Windows 98 where it worked anyway, but as time marches on, we see
that the game was released with what we have since learned to be show-stopping
bugs!


Things that this gizmo will fix:
 * Restores audio on Windows Vista and 7. It was completely AWOL before.
 * Provides a new texture loading routine. This corrects the messed-up colors.
 * Tweaks the main menu graphics. Solid black rectangles are hard to read.


Things you can fix yourself:
 * Level 9-6, The High Dive, has practically never worked for users who
   selected the "Typical" installation option. This can be corrected by copying
   "lemmings.box" from the CD and into the Lemmings Revolution installation
   directory. For real. The installer doesn't copy it right for some reason.


How to use this bad boy:

 * This patch is only designed to work with the original Lemmings Revolution
   EXE files (the game has seen various releases), so if you have one with any
   modifications, don't expect it to work. When in doubt, just re-install it
   from the CD. Don't worry: you won't lose your save data.

 * Locate the Lemmings Revolution installation directory on your computer. By
   default, this is "C:\Program Files (x86)\Take 2\Lemmings Revolution\" for
   the North America releases. Believe in yourself. I'm sure you can find it.

 * Make sure "Lemmings Revolution.exe" is not read-only. You can check this by
   right-clicking the file, selecting Properties, then making sure the box next
   to "Attributes" is un-checked.

 * Copy the Full Color EXE file into the Lemmings Revolution installation
   directory and run it. If UAC is enabled, you will have to run it as
   administrator. To do so, right-click the Full Color file and select
   "Run as administrator"

 * The program will do its darnedest to fix up the Lemmings Revolution EXE so
   that it works correctly again. Be sure to read the contents of the window
   that appears for information on what it was able to accomplish. If there was
   a problem, it will let you know what went wrong.


Additional information:

As noted above, there's a few different versions of Lemmings Revolution out
there. In fact, no one's really sure just how many there are. It's not feasible
to track them all down to make a comprehensive list, so this patch is instead
designed to be flexible and figure out exactly what needs to be done by
analyzing the Lemmings Revolution EXE file that it's intended to patch.

Some of the code updates were too large or otherwise too complex to be fitted
into the original EXE file, so they were moved into a DLL file instead. The
Full Color program will produce one such DLL file when it patches Lemmings
Revolution, adding it to the installation directory. The file's name is
"patch.dll" and it is required for the game to run, so don't delete it.

In addition to patching the Lemmings Revolution EXE file, that DLL file itself
is configured to work specifically with the version of Lemmings Revolution
being patched. If you copy a patch DLL from a different installation of
Lemmings Revolution, it will not work. In order to ensure correct
functionality, always run the Full Color program on an un-modified Lemmings
Revolution EXE.


Change log:

 * April 27, 2012 - Original release
   - Introducing audio fix
   - Introducing texture fix
   - Introducing main menu fix


Credits:
 * Lemmings Revolution is ©2000 Psygnosis/Talonsoft and Take-Two Interactive
 * Lemmings Forums staff (http://www.lemmingsforums.com/)
   - ccexplore, for technical research, ideas and testing support
   - Guy Perfect, for reverse engineering and patch development
   - thick molasses, for bug investigation and testing support


Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #53 on: April 28, 2012, 07:17:55 PM »
Hey ccexplore, since you've already located it, would you be so kind as to post the EXE you're using and the address of the bitmap decompression routine? I'd like to disassemble it to see what it's doing.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #54 on: April 28, 2012, 10:15:38 PM »
Nevermind, I found it.

In the EXE from Download.com linked earlier:

Code: [Select]
00467C28 | 55          | PUSH    EBP                     |
00467C29 | 8BEC        | MOV     EBP, ESP                |
00467C2B | 53          | PUSH    EBX                     |
00467C2C | 51          | PUSH    ECX                     |
00467C2D | 52          | PUSH    EDX                     |
00467C2E | 56          | PUSH    ESI                     |
00467C2F | 57          | PUSH    EDI                     |
00467C30 | 8B75 08     | MOV     ESI, DWORD PTR [EBP+8]  | ;Pointer to seventh byte of the bitmap file
00467C33 | 8B7D 0C     | MOV     EDI, DWORD PTR [EBP+C]  | ;Pointer to the first byte of the output buffer
00467C36 | 8B4D 14     | MOV     ECX, DWORD PTR [EBP+14] | ;Unpacked size of this chunk
00467C39 | 55          | PUSH    EBP                     |
00467C3A | E8 14000000 | CALL    00467C53                |
00467C3F | 5D          | POP     EBP                     |
00467C40 | B8 00000000 | MOV     EAX, 0                  |
00467C45 | 72 05       | JB      00467C4C                |
00467C47 | 8BC7        | MOV     EAX, EDI                |
00467C49 | 2B45 0C     | SUB     EAX, DWORD PTR [EBP+C]  |
00467C4C | 5F          | POP     EDI                     |
00467C4D | 5E          | POP     ESI                     |
00467C4E | 5A          | POP     EDX                     |
00467C4F | 59          | POP     ECX                     |
00467C50 | 5B          | POP     EBX                     |
00467C51 | C9          | LEAVE                           |
00467C52 | C3          | RETN                            |

This function is called to decompress individual chunks in the file, which for small bitmaps is the entire file.

I'm just now diving into 00467C53, which does the heavy lifting. Most of the functions in the program are _cdecl or __stdcall, but this one's loading values into registers without pushing to the stack. It's probably a compiler-defined fastcall.


EDIT:
The cursory examination has failed. Now I get the honor of pulling apart 16-bit code one line at a time. (-:

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #55 on: April 29, 2012, 01:16:31 AM »
I've isolated all of the code responsible for decompressing the chunks in the bitmap file. I'll be looking through it later--not right now. All of the magic happens in the code I've pasted into this post.

The functions seem to be largely 16-bit centric, and do not follow typical calling conventions. My guess is that it was an optimized 16-bit program, possibly written in assembly (as evidenced by its lack of wastefulness), and only linked into Lemmings Revolution. Whatever it is, it wasn't made by the same compiler that made the rest of the program.

Some addresses (004C0F2C and 004C1228 among others) appear to be global variables and are located in static memory. Since Decomp1 reads from these addresses prior to writing to them, it seems like it might be a persistent decoder state across data chunks. Regardless, for the first chunk of each file, these have to be initialized; there's no two ways about that.

Decomp2 does not end with a RETN instruction. The disassembly as I've provided it is correct. This particular function will be the hardest to figure out, but it's the key to the whole deal.

When Decomp1 is called the first time:
  • ESI = Address of seventh byte of BMP file
  • EDI = Address of first byte of output buffer
  • ECX = Unpacked size of the output buffer
  • Memory at 004C0F2C = Zeroes all the way down
  • Memory at 004C1228 = Zeroes all the way down
When Decomp1 returns, the fully decompressed BMP file will be located at [EDI]

Decomp1
Code: [Select]
00467C53 | 51            | PUSH    ECX                     |
00467C54 | 57            | PUSH    EDI                     |
00467C55 | 8D3D 28124C00 | LEA     EDI, DWORD PTR [4C1228] |
00467C5B | 893D 2C0F4C00 | MOV     DWORD PTR [4C0F2C], EDI |
00467C61 | 83C7 11       | ADD     EDI, 11                 |
00467C64 | 893D 300F4C00 | MOV     DWORD PTR [4C0F30], EDI |
00467C6A | 83C7 03       | ADD     EDI, 3                  |
00467C6D | 33DB          | XOR     EBX, EBX                |
00467C6F | E8 83000000   | CALL    00467CF7                | ;Decomp2
00467C74 | 72 16         | JB      00467C8C                |
00467C76 | BB 01000000   | MOV     EBX, 1                  |
00467C7B | E8 77000000   | CALL    00467CF7                | ;Decomp2
00467C80 | 72 0A         | JB      00467C8C                |
00467C82 | BB 02000000   | MOV     EBX, 2                  |
00467C87 | E8 6B000000   | CALL    00467CF7                | ;Decomp2
00467C8C | 5F            | POP     EDI                     |
00467C8D | 59            | POP     ECX                     |
00467C8E | 73 02         | JNB     00467C92                |
00467C90 | F9            | STC                             |
00467C91 | C3            | RETN                            |
00467C92 | 49            | DEC     ECX                     |
00467C93 | B2 80         | MOV     DL, 80                  |
00467C95 | FC            | CLD                             |
00467C96 | 51            | PUSH    ECX                     |
00467C97 | 33DB          | XOR     EBX, EBX                |
00467C99 | E8 8F010000   | CALL    00467E2D                | ;Decomp3
00467C9E | 85C0          | TEST    EAX, EAX                |
00467CA0 | 74 21         | JE      00467CC3                |
00467CA2 | 8BC8          | MOV     ECX, EAX                |
00467CA4 | 8BD8          | MOV     EBX, EAX                |
00467CA6 | B0 01         | MOV     AL, 1                   |
00467CA8 | 8A26          | MOV     AH, BYTE PTR [ESI]      |
00467CAA | 22E2          | AND     AH, DL                  |
00467CAC | D0CA          | ROR     DL, 1                   |
00467CAE | 83D6 00       | ADC     ESI, 0                  |
00467CB1 | 80C4 FF       | ADD     AH, FF                  |
00467CB4 | D0D0          | RCL     AL, 1                   |
00467CB6 | 73 F0         | JNB     00467CA8                |
00467CB8 | AA            | STOSB                           |
00467CB9 | E2 EB         | LOOPD   00467CA6                |
00467CBB | 8BC3          | MOV     EAX, EBX                |
00467CBD | 59            | POP     ECX                     |
00467CBE | 2BC8          | SUB     ECX, EAX                |
00467CC0 | 72 2E         | JB      00467CF0                |
00467CC2 | 51            | PUSH    ECX                     |
00467CC3 | BB 01000000   | MOV     EBX, 1                  |
00467CC8 | E8 60010000   | CALL    00467E2D                | ;Decomp3
00467CCD | 50            | PUSH    EAX                     |
00467CCE | BB 02000000   | MOV     EBX, 2                  |
00467CD3 | E8 55010000   | CALL    00467E2D                | ;Decomp3
00467CD8 | 8BDE          | MOV     EBX, ESI                |
00467CDA | 8BF7          | MOV     ESI, EDI                |
00467CDC | F9            | STC                             |
00467CDD | 1BF0          | SBB     ESI, EAX                |
00467CDF | 59            | POP     ECX                     |
00467CE0 | 83C1 02       | ADD     ECX, 2                  |
00467CE3 | 8BC1          | MOV     EAX, ECX                |
00467CE5 | F3:A4         | REP MOVSB                       |
00467CE7 | 8BF3          | MOV     ESI, EBX                |
00467CE9 | 59            | POP     ECX                     |
00467CEA | 2BC8          | SUB     ECX, EAX                |
00467CEC | 72 02         | JB      00467CF0                |
00467CEE | EB A6         | JMP     00467C96                |
00467CF0 | D0C2          | ROL     DL, 1                   |
00467CF2 | F5            | CMC                             |
00467CF3 | 83D6 00       | ADC     ESI, 0                  |
00467CF6 | C3            | RETN                            |

Decomp2
Code: [Select]
00467CF7 | 8A06          | MOV     AL, BYTE PTR [ESI]          |
00467CF9 | 46            | INC     ESI                         |
00467CFA | A8 0F         | TEST    AL, F                       |
00467CFC | 75 0A         | JNZ     00467D08                    |
00467CFE | 8883 3A0F4C00 | MOV     BYTE PTR [EBX+4C0F3A], AL   |
00467D04 | 3C 01         | CMP     AL, 1                       |
00467D06 | F5            | CMC                                 |
00467D07 | C3            | RETN                                |
00467D08 | 53            | PUSH    EBX                         |
00467D09 | 57            | PUSH    EDI                         |
00467D0A | 8B3D 2C0F4C00 | MOV     EDI, DWORD PTR [4C0F2C]     |
00467D10 | 8AF8          | MOV     BH, AL                      |
00467D12 | 66:83E0 0F    | AND     AX, F                       |
00467D16 | 04 02         | ADD     AL, 2                       |
00467D18 | 8AE8          | MOV     CH, AL                      |
00467D1A | B1 04         | MOV     CL, 4                       |
00467D1C | D2EF          | SHR     BH, CL                      |
00467D1E | 38FC          | CMP     AH, BH                      |
00467D20 | 73 02         | JNB     00467D24                    |
00467D22 | 8AE7          | MOV     AH, BH                      |
00467D24 | 883F          | MOV     BYTE PTR [EDI], BH          |
00467D26 | 47            | INC     EDI                         |
00467D27 | FECD          | DEC     CH                          |
00467D29 | 74 15         | JE      00467D40                    |
00467D2B | 8A1E          | MOV     BL, BYTE PTR [ESI]          |
00467D2D | 46            | INC     ESI                         |
00467D2E | 8AFB          | MOV     BH, BL                      |
00467D30 | 80E3 0F       | AND     BL, F                       |
00467D33 | 38DC          | CMP     AH, BL                      |
00467D35 | 73 02         | JNB     00467D39                    |
00467D37 | 8AE3          | MOV     AH, BL                      |
00467D39 | 881F          | MOV     BYTE PTR [EDI], BL          |
00467D3B | 47            | INC     EDI                         |
00467D3C | FECD          | DEC     CH                          |
00467D3E | 75 DC         | JNZ     00467D1C                    |
00467D40 | A2 340F4C00   | MOV     BYTE PTR [4C0F34], AL       |
00467D45 | 8825 350F4C00 | MOV     BYTE PTR [4C0F35], AH       |
00467D4B | 5F            | POP     EDI                         |
00467D4C | 5B            | POP     EBX                         |
00467D4D | 56            | PUSH    ESI                         |
00467D4E | 8BF3          | MOV     ESI, EBX                    |
00467D50 | 8886 3A0F4C00 | MOV     BYTE PTR [ESI+4C0F3A], AL   |
00467D56 | C1E6 02       | SHL     ESI, 2                      |
00467D59 | 89BE 3E0F4C00 | MOV     DWORD PTR [ESI+4C0F3E], EDI |
00467D5F | 893D 360F4C00 | MOV     DWORD PTR [4C0F36], EDI     |
00467D65 | C607 00       | MOV     BYTE PTR [EDI], 0           |
00467D68 | 47            | INC     EDI                         |
00467D69 | 8B35 300F4C00 | MOV     ESI, DWORD PTR [4C0F30]     |
00467D6F | C606 00       | MOV     BYTE PTR [ESI], 0           |
00467D72 | B6 80         | MOV     DH, 80                      |
00467D74 | B5 01         | MOV     CH, 1                       |
00467D76 | 8B1D 2C0F4C00 | MOV     EBX, DWORD PTR [4C0F2C]     |
00467D7C | 8A0D 340F4C00 | MOV     CL, BYTE PTR [4C0F34]       |
00467D82 | 382B          | CMP     BYTE PTR [EBX], CH          |
00467D84 | 74 1F         | JE      00467DA5                    |
00467D86 | 43            | INC     EBX                         |
00467D87 | FEC9          | DEC     CL                          |
00467D89 | 75 F7         | JNZ     00467D82                    |
00467D8B | 880F          | MOV     BYTE PTR [EDI], CL          |
00467D8D | 47            | INC     EDI                         |
00467D8E | D0CE          | ROR     DH, 1                       |
00467D90 | 83D6 00       | ADC     ESI, 0                      |
00467D93 | 8AC6          | MOV     AL, DH                      |
00467D95 | F6D0          | NOT     AL                          |
00467D97 | 2006          | AND     BYTE PTR [ESI], AL          |
00467D99 | FEC5          | INC     CH                          |
00467D9B | 382D 350F4C00 | CMP     BYTE PTR [4C0F35], CH       |
00467DA1 | 73 D3         | JNB     00467D76                    |
00467DA3 | EB 20         | JMP     00467DC5                    |
00467DA5 | 8A25 340F4C00 | MOV     AH, BYTE PTR [4C0F34]       |
00467DAB | 2AE1          | SUB     AH, CL                      |
00467DAD | B0 00         | MOV     AL, 0                       |
00467DAF | 66:8907       | MOV     WORD PTR [EDI], AX          |
00467DB2 | 47            | INC     EDI                         |
00467DB3 | 47            | INC     EDI                         |
00467DB4 | 8AD5          | MOV     DL, CH                      |
00467DB6 | 8AC5          | MOV     AL, CH                      |
00467DB8 | 8436          | TEST    BYTE PTR [ESI], DH          |
00467DBA | 74 0C         | JE      00467DC8                    |
00467DBC | D0C6          | ROL     DH, 1                       |
00467DBE | 83DE 00       | SBB     ESI, 0                      |
00467DC1 | FEC8          | DEC     AL                          |
00467DC3 | 75 F3         | JNZ     00467DB8                    |
00467DC5 | 5E            | POP     ESI                         |
00467DC6 | F8            | CLC                                 |
00467DC7 | C3            | RETN                                |
00467DC8 | 0836          | OR      BYTE PTR [ESI], DH          |
00467DCA | 53            | PUSH    EBX                         |
00467DCB | B6 80         | MOV     DH, 80                      |
00467DCD | 8B35 300F4C00 | MOV     ESI, DWORD PTR [4C0F30]     |
00467DD3 | 8B1D 360F4C00 | MOV     EBX, DWORD PTR [4C0F36]     |
00467DD9 | 8436          | TEST    BYTE PTR [ESI], DH          |
00467DDB | 75 03         | JNZ     00467DE0                    |
00467DDD | 43            | INC     EBX                         |
00467DDE | EB 2C         | JMP     00467E0C                    |
00467DE0 | 8A03          | MOV     AL, BYTE PTR [EBX]          |
00467DE2 | 66:25 FF00    | AND     AX, FF                      |
00467DE6 | 75 22         | JNZ     00467E0A                    |
00467DE8 | 8BC7          | MOV     EAX, EDI                    |
00467DEA | 2BC3          | SUB     EAX, EBX                    |
00467DEC | 3D 00010000   | CMP     EAX, 100                    |
00467DF1 | 73 22         | JNB     00467E15                    |
00467DF3 | 8803          | MOV     BYTE PTR [EBX], AL          |
00467DF5 | FECA          | DEC     DL                          |
00467DF7 | 74 20         | JE      00467E19                    |
00467DF9 | C607 00       | MOV     BYTE PTR [EDI], 0           |
00467DFC | 47            | INC     EDI                         |
00467DFD | D0CE          | ROR     DH, 1                       |
00467DFF | 83D6 00       | ADC     ESI, 0                      |
00467E02 | 8AC6          | MOV     AL, DH                      |
00467E04 | F6D0          | NOT     AL                          |
00467E06 | 2006          | AND     BYTE PTR [ESI], AL          |
00467E08 | EB EB         | JMP     00467DF5                    |
00467E0A | 03D8          | ADD     EBX, EAX                    |
00467E0C | D0CE          | ROR     DH, 1                       |
00467E0E | 83D6 00       | ADC     ESI, 0                      |
00467E11 | FECA          | DEC     DL                          |
00467E13 | 75 C4         | JNZ     00467DD9                    |
00467E15 | 5B            | POP     EBX                         |
00467E16 | 5E            | POP     ESI                         |
00467E17 | F9            | STC                                 |
00467E18 | C3            | RETN                                |
00467E19 | 5B            | POP     EBX                         |
00467E1A | 43            | INC     EBX                         |
00467E1B | FEC9          | DEC     CL                          |
00467E1D | 75 05         | JNZ     00467E24                    |
00467E1F | E9 67FFFFFF   | JMP     00467D8B                    |
00467E24 | 382B          | CMP     BYTE PTR [EBX], CH          |
00467E26 | 75 F2         | JNZ     00467E1A                    |
00467E28 | E9 78FFFFFF   | JMP     00467DA5                    |

Decomp3
Code: [Select]
00467E2D | 8BCB            | MOV     ECX, EBX                    |
00467E2F | 0FB683 3A0F4C00 | MOVZX   EAX, BYTE PTR [EBX+4C0F3A]  |
00467E36 | 84C0            | TEST    AL, AL                      |
00467E38 | 75 33           | JNZ     00467E6D                    |
00467E3A | B9 00000000     | MOV     ECX, 0                      |
00467E3F | 8416            | TEST    BYTE PTR [ESI], DL          |
00467E41 | 74 09           | JE      00467E4C                    |
00467E43 | FEC1            | INC     CL                          |
00467E45 | D0CA            | ROR     DL, 1                       |
00467E47 | 83D6 00         | ADC     ESI, 0                      |
00467E4A | EB F3           | JMP     00467E3F                    |
00467E4C | D0CA            | ROR     DL, 1                       |
00467E4E | 83D6 00         | ADC     ESI, 0                      |
00467E51 | 33C0            | XOR     EAX, EAX                    |
00467E53 | 84C9            | TEST    CL, CL                      |
00467E55 | 74 15           | JE      00467E6C                    |
00467E57 | 40              | INC     EAX                         |
00467E58 | 8A2E            | MOV     CH, BYTE PTR [ESI]          |
00467E5A | 22EA            | AND     CH, DL                      |
00467E5C | 80C5 FF         | ADD     CH, FF                      |
00467E5F | 66:D1D0         | RCL     AX, 1                       |
00467E62 | D0CA            | ROR     DL, 1                       |
00467E64 | 83D6 00         | ADC     ESI, 0                      |
00467E67 | FEC9            | DEC     CL                          |
00467E69 | 75 ED           | JNZ     00467E58                    |
00467E6B | 48              | DEC     EAX                         |
00467E6C | C3              | RETN                                |
00467E6D | 03D9            | ADD     EBX, ECX                    |
00467E6F | D1E3            | SHL     EBX, 1                      |
00467E71 | 8B9B 3E0F4C00   | MOV     EBX, DWORD PTR [EBX+4C0F3E] |
00467E77 | 8416            | TEST    BYTE PTR [ESI], DL          |
00467E79 | 75 03           | JNZ     00467E7E                    |
00467E7B | 43              | INC     EBX                         |
00467E7C | EB 05           | JMP     00467E83                    |
00467E7E | 0FB603          | MOVZX   EAX, BYTE PTR [EBX]         |
00467E81 | 03D8            | ADD     EBX, EAX                    |
00467E83 | D0CA            | ROR     DL, 1                       |
00467E85 | 83D6 00         | ADC     ESI, 0                      |
00467E88 | 803B 00         | CMP     BYTE PTR [EBX], 0           |
00467E8B | 75 EA           | JNZ     00467E77                    |
00467E8D | 43              | INC     EBX                         |
00467E8E | 8A0B            | MOV     CL, BYTE PTR [EBX]          |
00467E90 | 80F9 02         | CMP     CL, 2                       |
00467E93 | 72 1B           | JB      00467EB0                    |
00467E95 | FEC9            | DEC     CL                          |
00467E97 | B8 01000000     | MOV     EAX, 1                      |
00467E9C | 8A2E            | MOV     CH, BYTE PTR [ESI]          |
00467E9E | 22EA            | AND     CH, DL                      |
00467EA0 | 80C5 FF         | ADD     CH, FF                      |
00467EA3 | 66:D1D0         | RCL     AX, 1                       |
00467EA6 | D0CA            | ROR     DL, 1                       |
00467EA8 | 83D6 00         | ADC     ESI, 0                      |
00467EAB | FEC9            | DEC     CL                          |
00467EAD | 75 ED           | JNZ     00467E9C                    |
00467EAF | C3              | RETN                                |
00467EB0 | 0FB6C1          | MOVZX   EAX, CL                     |
00467EB3 | C3              | RETN                                |

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #56 on: April 29, 2012, 03:26:32 AM »
Ah, the things I do for lem.

The assembly here was definitely done by hand, and it's heavily spaghettified. I think the most reliable and portable way to implement it is to make a sort of miniature x86 emulator to process the bytecode. This makes it so we won't have to pull out our hair just to get the decompression working, and the code can still be moved to other languages and architectures.

Offline ccexplore

  • Posts: 5311
    • View Profile
Re: DirectL
« Reply #57 on: April 29, 2012, 08:48:57 AM »
Hey ccexplore, since you've already located it, would you be so kind as to post the EXE you're using and the address of the bitmap decompression routine? I'd like to disassemble it to see what it's doing.

You caught me at a bad time, I was work-swamped for Friday and away for all of Saturday.  But looks like you managed just fine anyway. ;P

I think the most reliable and portable way to implement it is to make a sort of miniature x86 emulator to process the bytecode.

I guess that would be a more portable approach, albeit seems like just as much work as deciphering the decompression?

My plan was to take a version of the game EXE (the demo version might be best as it doesn't require CD-ROM drive, assuming there aren't any changes to decompression between demo and non-demo), and just hack it so that instead of running the game, we short-circuit it into just decompressing some data we set up in memory.  An approach like this:

1) somewhere near the start of the game (preferably before the DirectX video mode switch, and not too early as to avoid skipping any potential necessary initialization of C runtime etc.), have it call our own DLL function.

2) The DLL function handles user input, and loads the user-specified data to be decompressed into some memory buffer.  It then jumps back into the point in the game EXE's code where, normally, it's just after the game loads something from BOX to be decompressed.  Except we've set things up for the code to process our data instead.

3) At the point further down in the game EXE's code, where it finishes decompression and is prepping to return the data, we call our own DLL function again, passing in things such as size of decompressed data and pointer to it.  The DLL function handles user input and saves the decompressed data to wherever the user wants, then calls ExitProcess() to shut everything down.

=============

Below's what I had jotted/copied down earlier in the week to help with above approach (based on my own copy of game EXE, non-demo):

Code: [Select]
0045015a 55              push    ebp
0045015b 8bec            mov     ebp,esp
0045015d 6aff            push    0FFFFFFFFh
0045015f 687ccb4a00      push    offset Lemmings_Revolution+0xacb7c (004acb7c)
00450164 64a100000000    mov     eax,dword ptr fs:[00000000h]
0045016a 50              push    eax
0045016b 64892500000000  mov     dword ptr fs:[0],esp
00450172 81ec5c010000    sub     esp,15Ch
<snip>
004501ea 8985a4feffff    mov     dword ptr [ebp-15Ch],eax
004501f0 8b9598feffff    mov     edx,dword ptr [ebp-168h]
004501f6 8b85a4feffff    mov     eax,dword ptr [ebp-15Ch]
004501fc 894204          mov     dword ptr [edx+4],eax
004501ff 8b8d98feffff    mov     ecx,dword ptr [ebp-168h]
00450205 8b11            mov     edx,dword ptr [ecx]
00450207 52              push    edx
00450208 8b8598feffff    mov     eax,dword ptr [ebp-168h]
0045020e 8b4804          mov     ecx,dword ptr [eax+4]
00450211 51              push    ecx
00450212 8d8dbcfeffff    lea     ecx,[ebp-144h]
00450218 e893b3feff      call    Lemmings_Revolution+0x3b5b0 (0043b5b0)
0045021d 8d8dbcfeffff    lea     ecx,[ebp-144h]
00450223 e80ae60200      call    Lemmings_Revolution+0x7e832 (0047e832) // load from BOX file?

// at this point, [ebp-168h] = address to an 8-byte struct {UInt32 numBytes; Byte *ptrData};
// [[ebp-168h]+4] = address to compressed data

00450228 8b9598feffff    mov     edx,dword ptr [ebp-168h]
0045022e 8b4204          mov     eax,dword ptr [edx+4]
00450231 33c9            xor     ecx,ecx
00450233 8a08            mov     cl,byte ptr [eax]
00450235 83f942          cmp     ecx,42h  // 'B'
00450238 752a            jne     Lemmings_Revolution+0x50264 (00450264)
0045023a 8b9598feffff    mov     edx,dword ptr [ebp-168h]
00450240 8b4204          mov     eax,dword ptr [edx+4]
00450243 33c9            xor     ecx,ecx
00450245 8a4801          mov     cl,byte ptr [eax+1]
00450248 83f94d          cmp     ecx,4Dh  // 'M'
0045024b 7517            jne     Lemmings_Revolution+0x50264 (00450264)
0045024d c745fcffffffff  mov     dword ptr [ebp-4],0FFFFFFFFh
00450254 8d8dbcfeffff    lea     ecx,[ebp-144h]
0045025a e8b9d90200      call    Lemmings_Revolution+0x7dc18 (0047dc18)
0045025f e933020000      jmp     Lemmings_Revolution+0x50497 (00450497)
00450264 8b9598feffff    mov     edx,dword ptr [ebp-168h]
<snip>
00450427 8b8db0feffff    mov     ecx,dword ptr [ebp-150h]
0045042d 8b55f0          mov     edx,dword ptr [ebp-10h]
00450430 8d440afb        lea     eax,[edx+ecx-5]
00450434 8945f0          mov     dword ptr [ebp-10h],eax
00450437 8b8db8feffff    mov     ecx,dword ptr [ebp-148h]
0045043d 038da8feffff    add     ecx,dword ptr [ebp-158h]
00450443 898db8feffff    mov     dword ptr [ebp-148h],ecx
00450449 e9edfeffff      jmp     Lemmings_Revolution+0x5033b (0045033b)

// when we reach 45044e, [ebp-14c] = address to decompressed data,
// [[ebp-168h]] = size of decompressed data

0045044e 8b9598feffff    mov     edx,dword ptr [ebp-168h]

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: DirectL
« Reply #58 on: April 29, 2012, 03:01:06 PM »
That looks like the code I was picking through yesterday. By the time that function returns, [EBP-14C] contains the address of the decompressed bitmap, copied from [[EBP-168]+4].

I just woke up to a decompressed bitmap in Skype, so I'll have to wait for my associate to show up so he can tell me how he did it. O-:


EDIT:
For what it's worth, I don't like the idea of hijacking the Lemmings EXE to make it do decompression for us. I like to keep my utilities cross-platform when possible, and I prefer to make general things like archive managers in Java to make sure nigh-on everybody can use it. Restricting support to 32-bit x86 code isn't really the best way to achieve that goal.


EDIT2:
Looks like all he did was execute the code I posted. At least now we know for sure it works. (-:

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #59 on: April 29, 2012, 08:39:44 PM »
Well, the other guy was able to point out that the code reads the input data one bit at a time, and that the uncompressed "BM" file identifier is visible in the data if you shift it a few times. Looking at the data myself, I was able to see that all the literal byte values for the file we're working with (^OUT.BMP) are in fact in the data, just not always on a byte boundary. Strings of repeated bytes are encoded differently, which reeks of LZ77 or one of its variants.

I'm still investigating, but starting at offset 00000006 in the file, the following bit strings are known:

Code: [Select]
No output:
0010011000110011001100110100001100000100000000000110101101010000011001010110011100110010001000110111001110001
First byte of output:
01000010 01001101 11110110 00001001 00000000    42 4D F6 09 00
11000111100010                                  (Encoded) 00 00 00 00 00 - Distance 1 Length 5
00110110                                        36
100111                                          (Encoded) 00 00 00 - Distance 4 or 7, Length 3
00101000                                        28
101000100111001010                              (Encoded) 00 00 00 - Distance 6 or 11, Length 3
00011010                                        1A
100111001010001000001001110010111               (Encoded) 00 00 00 - Distance 6 or 14, Length 3
00000001 00000000 00011000                      01 00 18
11001111111010000011111000001111100111010110    (Encoded) 00 * 40d - Distance... uh... Probably at least two distance/length pairs here.
00100100 00101100 00111000                      24 2C 38...

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #60 on: April 30, 2012, 03:06:13 AM »
Still don't know the details of the algorithm in whole, but still looking into it.

We made a C program that can decode single-chunk compressed .bmp files from Lemmings Revolution using the code from its EXE file. It requires an x86 architecture to work, but that's how it goes.

Usage: lrdecomp <inputfile> <outputfile>

A compiled version is attached to this post, while the source code is this:

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PRG_SIZE    609
#define PRG_BASE    0x00467C53

// Codewalker's hax
char staticmemory[0x100000];
int len;
char *outbuf;
void *decp1dst = (void*)0x00467c53;
unsigned char *out_bmp;

// The mystery program data
static unsigned char PRG_ROM[PRG_SIZE] = {
0x51,0x57,0x8D,0x3D,0x28,0x12,0x4C,0x00,0x89,0x3D,0x2C,0x0F,0x4C,0x00,0x83,0xC7,
0x11,0x89,0x3D,0x30,0x0F,0x4C,0x00,0x83,0xC7,0x03,0x33,0xDB,0xE8,0x83,0x00,0x00,
0x00,0x72,0x16,0xBB,0x01,0x00,0x00,0x00,0xE8,0x77,0x00,0x00,0x00,0x72,0x0A,0xBB,
0x02,0x00,0x00,0x00,0xE8,0x6B,0x00,0x00,0x00,0x5F,0x59,0x73,0x02,0xF9,0xC3,0x49,
0xB2,0x80,0xFC,0x51,0x33,0xDB,0xE8,0x8F,0x01,0x00,0x00,0x85,0xC0,0x74,0x21,0x8B,
0xC8,0x8B,0xD8,0xB0,0x01,0x8A,0x26,0x22,0xE2,0xD0,0xCA,0x83,0xD6,0x00,0x80,0xC4,
0xFF,0xD0,0xD0,0x73,0xF0,0xAA,0xE2,0xEB,0x8B,0xC3,0x59,0x2B,0xC8,0x72,0x2E,0x51,
0xBB,0x01,0x00,0x00,0x00,0xE8,0x60,0x01,0x00,0x00,0x50,0xBB,0x02,0x00,0x00,0x00,
0xE8,0x55,0x01,0x00,0x00,0x8B,0xDE,0x8B,0xF7,0xF9,0x1B,0xF0,0x59,0x83,0xC1,0x02,
0x8B,0xC1,0xF3,0xA4,0x8B,0xF3,0x59,0x2B,0xC8,0x72,0x02,0xEB,0xA6,0xD0,0xC2,0xF5,
0x83,0xD6,0x00,0xC3,0x8A,0x06,0x46,0xA8,0x0F,0x75,0x0A,0x88,0x83,0x3A,0x0F,0x4C,
0x00,0x3C,0x01,0xF5,0xC3,0x53,0x57,0x8B,0x3D,0x2C,0x0F,0x4C,0x00,0x8A,0xF8,0x66,
0x83,0xE0,0x0F,0x04,0x02,0x8A,0xE8,0xB1,0x04,0xD2,0xEF,0x38,0xFC,0x73,0x02,0x8A,
0xE7,0x88,0x3F,0x47,0xFE,0xCD,0x74,0x15,0x8A,0x1E,0x46,0x8A,0xFB,0x80,0xE3,0x0F,
0x38,0xDC,0x73,0x02,0x8A,0xE3,0x88,0x1F,0x47,0xFE,0xCD,0x75,0xDC,0xA2,0x34,0x0F,
0x4C,0x00,0x88,0x25,0x35,0x0F,0x4C,0x00,0x5F,0x5B,0x56,0x8B,0xF3,0x88,0x86,0x3A,
0x0F,0x4C,0x00,0xC1,0xE6,0x02,0x89,0xBE,0x3E,0x0F,0x4C,0x00,0x89,0x3D,0x36,0x0F,
0x4C,0x00,0xC6,0x07,0x00,0x47,0x8B,0x35,0x30,0x0F,0x4C,0x00,0xC6,0x06,0x00,0xB6,
0x80,0xB5,0x01,0x8B,0x1D,0x2C,0x0F,0x4C,0x00,0x8A,0x0D,0x34,0x0F,0x4C,0x00,0x38,
0x2B,0x74,0x1F,0x43,0xFE,0xC9,0x75,0xF7,0x88,0x0F,0x47,0xD0,0xCE,0x83,0xD6,0x00,
0x8A,0xC6,0xF6,0xD0,0x20,0x06,0xFE,0xC5,0x38,0x2D,0x35,0x0F,0x4C,0x00,0x73,0xD3,
0xEB,0x20,0x8A,0x25,0x34,0x0F,0x4C,0x00,0x2A,0xE1,0xB0,0x00,0x66,0x89,0x07,0x47,
0x47,0x8A,0xD5,0x8A,0xC5,0x84,0x36,0x74,0x0C,0xD0,0xC6,0x83,0xDE,0x00,0xFE,0xC8,
0x75,0xF3,0x5E,0xF8,0xC3,0x08,0x36,0x53,0xB6,0x80,0x8B,0x35,0x30,0x0F,0x4C,0x00,
0x8B,0x1D,0x36,0x0F,0x4C,0x00,0x84,0x36,0x75,0x03,0x43,0xEB,0x2C,0x8A,0x03,0x66,
0x25,0xFF,0x00,0x75,0x22,0x8B,0xC7,0x2B,0xC3,0x3D,0x00,0x01,0x00,0x00,0x73,0x22,
0x88,0x03,0xFE,0xCA,0x74,0x20,0xC6,0x07,0x00,0x47,0xD0,0xCE,0x83,0xD6,0x00,0x8A,
0xC6,0xF6,0xD0,0x20,0x06,0xEB,0xEB,0x03,0xD8,0xD0,0xCE,0x83,0xD6,0x00,0xFE,0xCA,
0x75,0xC4,0x5B,0x5E,0xF9,0xC3,0x5B,0x43,0xFE,0xC9,0x75,0x05,0xE9,0x67,0xFF,0xFF,
0xFF,0x38,0x2B,0x75,0xF2,0xE9,0x78,0xFF,0xFF,0xFF,0x8B,0xCB,0x0F,0xB6,0x83,0x3A,
0x0F,0x4C,0x00,0x84,0xC0,0x75,0x33,0xB9,0x00,0x00,0x00,0x00,0x84,0x16,0x74,0x09,
0xFE,0xC1,0xD0,0xCA,0x83,0xD6,0x00,0xEB,0xF3,0xD0,0xCA,0x83,0xD6,0x00,0x33,0xC0,
0x84,0xC9,0x74,0x15,0x40,0x8A,0x2E,0x22,0xEA,0x80,0xC5,0xFF,0x66,0xD1,0xD0,0xD0,
0xCA,0x83,0xD6,0x00,0xFE,0xC9,0x75,0xED,0x48,0xC3,0x03,0xD9,0xD1,0xE3,0x8B,0x9B,
0x3E,0x0F,0x4C,0x00,0x84,0x16,0x75,0x03,0x43,0xEB,0x05,0x0F,0xB6,0x03,0x03,0xD8,
0xD0,0xCA,0x83,0xD6,0x00,0x80,0x3B,0x00,0x75,0xEA,0x43,0x8A,0x0B,0x80,0xF9,0x02,
0x72,0x1B,0xFE,0xC9,0xB8,0x01,0x00,0x00,0x00,0x8A,0x2E,0x22,0xEA,0x80,0xC5,0xFF,
0x66,0xD1,0xD0,0xD0,0xCA,0x83,0xD6,0x00,0xFE,0xC9,0x75,0xED,0xC3,0x0F,0xB6,0xC1,
0xC3};

// Calculates the total unpacked size of a file and returns the length
int lrdGetSize(unsigned char *data, int size) {
    int chunks, packed, unpacked = 0, x, off = 1;

    // Error checking
    if (data == NULL || size < 6) return 0;

    // Get the number of chunks in the file
    chunks = (int) data[0];
    if (chunks < 1) return 0;

    // Read the unpacked sizes for all chunks
    for (x = 0; x < chunks; x++) {
        if (off + 4 > size) return 0;
        packed    = (int) data[off + 1] << 8 | (int) data[off];
        if (off + packed > size) return 0;
        unpacked += (int) data[off + 3] << 8 | (int) data[off + 2];
        off += packed;
    }

    return unpacked;
}

// Decompresses a Lemmings Revolution bitmap file
int lrdDecompress(unsigned char *src, int srclen,
                  unsigned char *dst, int dstlen) {

    // Error checking
    if (src == NULL || srclen < 6 || dst == NULL || dstlen < 1) return 1;

    //memset(staticmemory, 0, 0x100000);
    memcpy((void *) PRG_BASE, PRG_ROM, PRG_SIZE);

       out_bmp = src;
   outbuf = dst;
   len = (int) dstlen;
   memset(outbuf, 0, len);

   asm("movl _out_bmp, %esi\n"
      "add $6, %esi\n"
      "movl _outbuf, %edi\n"
      "movl _len, %ecx\n"
      "call *_decp1dst");

    return 0;
}

// Program entry point
int main(int argc, char **argv) {
    FILE *fPtr;
    int fLen, uLen;
    unsigned char *fData, *uData;

    if (argc != 3) {
        printf("Usage: %s <inputfile> <outputfile>\n", argv[0]);
        return 0;
    }

    fPtr = fopen(argv[1], "rb");
    if (fPtr == NULL) {
        printf("Could not open %s\n", argv[1]);
        return 1;
    }

    fseek(fPtr, 0, SEEK_END);
    fLen = ftell(fPtr);
    if (fLen < 6) {
        fclose(fPtr);
        printf("Invalid data in %s\n", argv[1]);
        return 1;
    }

    fData = malloc(fLen);
    fseek(fPtr, 0, SEEK_SET);
    uLen = fread(fData, 1, fLen, fPtr);
    fclose(fPtr);
    if (uLen != fLen) {
        printf("Could not read data from %s\n", argv[1]);
        return 1;
    }

    uLen = lrdGetSize(fData, fLen);
    if (!uLen) {
        free(fData);
        printf("Invalid data in %s\n", argv[1]);
        return 1;
    }

    printf("File size: %04X\n", uLen);
    uData = malloc(uLen);
    fLen = lrdDecompress(fData, fLen, uData, uLen);

    fPtr = fopen(argv[2], "wb");
    if (fPtr == NULL) {
        printf("Error writing %s\n", argv[2]);
    } else {
        fwrite(uData, 1, uLen, fPtr);
        fclose(fPtr);
        printf("Wrote %s\n", argv[2]);
    }

    free(fData);
    free(uData);
    return 0;
}

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #61 on: April 30, 2012, 08:03:56 AM »
Okay, making some slow but tangible progress.

The first however many bytes of the compressed chunk initialize some state variables in static memory. How this happens and by what logic is unknown, as well as how many of them there are. What is known is that there are at least three in all cases, because Decomp2() is called 3 times to initialize the aforementioned state variables. The variables are located at 4C1228 (in the code that I posted, as well as in the kludgy C program in the previous post), and if the lower 4 bits of a byte are zero when Decomp2() is called, it will immediately return without altering the data in the variables.

The data stream itself is processed one bit at a time, pulling values for decompressing the data. The setup is fully suitable for chunked input, which appears to be the case with larger files anyway. I don't know all the specifics yet, but there's a catch: if the state variables are initialized, the exact size and format of the values becomes unknown. Only in files that don't initialize the state variables do we know the format of the data at this time.

The decoder alternates between states: first is raw data, and the other is distance/length pair. Every time data for one state is processed, the decoder flips to the other state.
  • Raw data reads one number from the data, which represents the number of 8-bit bytes to copy to the output.
  • Distance/length pair reads two numbers from the data: first for length, then for distance.
    • The value read for length gets 2 added implicitly after decoding.
    • The value read for distance gets 1 added implicitly after decoding.
The numbers themselves are stored in a variable-size data format:
  • Read bits for as long as they are 1
  • When a 0 is encountered, count how many 1s there were and read that many additional bits
  • The value of the number is the value of the 1s bits plus the value of the additional bits, both in high-to-low order
For example:
  • Bit sequence 11111010010
  • There are 5 contiguous 1s, which comes out to 31
  • There is a zero separating the two fields
  • The next 5 bits, 10010, comes out to 18
  • The value of the number is 31 + 18 = 49
It is worth noting that if the first bit in a number sequence is a 0, it effectively produces 0 as the result because there are no 1s on the left and no additional bits on the right. 0 + 0 = 0. This value is used in situations where multiple distance/length pairs need to exist back-to-back, because the decoder will flip into the raw data state after each one.
__________

Most of what I've been doing comes from TEXTURES\^WATER_GLOW.BMP from lemmings.box.

This is the compressed file as extracted from the BOX:
Code: [Select]
00000000  01 22 00 F6 00 04 00 00  00 CA 12 6F B0 06 50 DA
00000010  62 14 4C 40 8D 63 00 20  03 1A F5 3C 2C 72 CD A6
00000020  7F 3C A0

And this is the decompressed file:
Code: [Select]
00000000  42 4D F6 00 00 00 00 00  00 00 36 00 00 00 28 00
00000010  00 00 08 00 00 00 08 00  00 00 01 00 18 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00 00 E5 9B  4C E5 9B 4C E5 9B 4C E5
00000040  9B 4C E5 9B 4C E5 9B 4C  E5 9B 4C E5 9B 4C E5 9B
00000050  4C E5 9B 4C E5 9B 4C E5  9B 4C E5 9B 4C E5 9B 4C
00000060  E5 9B 4C E5 9B 4C E5 9B  4C E5 9B 4C E5 9B 4C E5
00000070  9B 4C E5 9B 4C E5 9B 4C  E5 9B 4C E5 9B 4C E5 9B
00000080  4C E5 9B 4C E5 9B 4C E5  9B 4C E5 9B 4C E5 9B 4C
00000090  E5 9B 4C E5 9B 4C E5 9B  4C E5 9B 4C E5 9B 4C E5
000000A0  9B 4C E5 9B 4C E5 9B 4C  E5 9B 4C E5 9B 4C E5 9B
000000B0  4C E5 9B 4C E5 9B 4C E5  9B 4C E5 9B 4C E5 9B 4C
000000C0  E5 9B 4C E5 9B 4C E5 9B  4C E5 9B 4C E5 9B 4C E5
000000D0  9B 4C E5 9B 4C E5 9B 4C  E5 9B 4C E5 9B 4C E5 9B
000000E0  4C E5 9B 4C E5 9B 4C E5  9B 4C E5 9B 4C E5 9B 4C
000000F0  E5 9B 4C E5 9B 4C

This, on the other hand, is the compressed file expressed in binary:
Code: [Select]
00000000  00000001 00100010 00000000 11110110
00000004  00000000 00000100 00000000 00000000
00000008  00000000 11001010 00010010 01101111
0000000C  10110000 00000110 01010000 11011010
00000010  01100010 00010100 01001100 01000000
00000014  10001101 01100011 00000000 00100000
00000018  00000011 00011010 11110101 00111100
0000001C  00101100 01110010 11001101 10100110
00000020  01111111 00111100 10100000

An analysis of the file is as follows:

File Header
  * 00000001                   Chunks      = 1
  * 00100010 00000000  ChunkSize = 0x0022
  * 11110110 00000000  DataSize    = 0x00F6
  * 00000100                   (Unknown) = 4

Stream Chunk Header
  * 00000000  These three bytes are all 0x00. Decomp2() is called once for each
  * 00000000  of them, and promptly returns because their lower 4 bits are all
  * 00000000  0. No data is written to 4C1228 for this file.

Begin output stream

11001 = 4 bytes
  * 01000010 = 42 = 'B'
  * 01001101 = 4D = 'M'
  * 11110110 = F6
  * 00000000 = 00

11001 = Length = 4 + (2) = 6
0 = Distance = 0 + (1) = 1
  * 00 00 00 00 00 00

100 = 1 byte
  * 00110110 = 36

100 = Length = 1 + (2) = 3
11000 = Distance = 3 + (1) = 4
  * 00 00 00

100 = Raw data, 1 byte
  * 00101000 = 28

100 = Length = 1 + (2) = 3
11000 = Distance = 3 + (1) = 4
  * 00 00 00

100 = 1 byte
  * 00001000 = 08

11010 = Length = 5 + (2) = 7
11000 = Distance = 3 + (1) = 4
  * 00 00 00 08 00 00 00

11000 = 3 bytes
  * 00000001 = 01
  * 00000000 = 00
  * 00011000 = 18

11010 = Length = 5 + (2) = 7
111101010 = Distance = 25 + (1) = 26
  * 00 00 00 00 00 00 00

0 = 0 bytes

111100001 = Length = 16 + (2) = 18
0 = Distance = 0 + (1) = 1
  * 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
     00 00

11000 = 3 bytes
  * 11100101 = E5
  * 10011011 = 9B
  * 01001100 = 4C

111111100111100 = Length = 187 + (2) = 189
101 = Distance = 2 + (1) = 3
  * E5 9B 4C E5 9B 4C... you get the idea

00000 = Spare bits at the end of the stream, padded onto the last byte

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #62 on: April 30, 2012, 10:42:36 PM »
Crawling along, I still don't know exactly how the chunk header bits affect data input, but I at least know what values they represent now.

Indeed, there are at least 3 bytes at the beginning of every chunk. The lower 4 bits of these specifies a number of additional data units to read, where a value of 0 indicates there are no additional values. However, if the value is non-zero, then 2 is added to it to get the total number of units to read. Units are then read 4 bits each, starting with the high nibble of the current byte (the one that contained the count value), then the low nibble of the next byte and so-on until all of the specified units are read. If there is an even number of nibbles to read, the upper 4 bits of the last byte only exist as padding so that the next data begins on a byte boundary.

Decomp2() processes these nibble units, parsing them into bytes of their own and temporarily storing them at 4C1228 for further processing. As per the specification, there can be anywhere from 3 to 17 bytes written starting at that address. However, it's that "further processing" I'm still not clear on.

The first group of units affects how raw data byte count numbers are read from the stream. The second and third affect the distance/length numbers, presumably length for the second and distance for the third. I'll still need to verify that once I get the protocol down, but the magic 8 ball seems to think that's how it will end up.

Example:
  • Byte sequence 12 34 05 70 61 89
  • 12 = *2 = 4 nibbles for raw data: 1, 4, 3, 5, and then the 0 is junk
  • 70 = *0 = no nibbles for length data, so the 7 is junk
  • 61 = *1 = 3 nibbles for distance data: 6, 9, 8

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #63 on: May 02, 2012, 12:23:40 AM »
Got it!

The nibbles prior to the encoded data stream are parsed in the method I described in detail in the previous post, so I won't review.

What those nibbles represent are A) values to be added to a binary tree and B) the depth within that tree where each value occurs.
__________

For the uninitiated, a binary tree consists of nodes, where each node is either a value or branches out to 2 more nodes. If a node branches out, it has two paths: 0 and 1. At the top of the tree is a single node, called the root node, which ALWAYS branches. The nodes it branches to are called child nodes and, to those nodes, the node that branched to them is their parent node.

A quick example:

Code: [Select]
Level 0      root
            0/  \1
Level 1     a    b
          0/ \1
Level 2   c   d

In this example, the root node branches into 0=a and 1=b. a in turn branches into 0=c and 1=d. b, c and d, however, do not branch. They are terminal nodes in this particular tree. a is the parent node of c and d, and root is the parent node of a and b.
__________

Imagine the list of nibbles as an array with 0 as the first index. The index of each nibble will find its way into the tree as a terminal node. The value of the nibble represents how many levels down into the tree that the index appears. If the value of a nibble is 0, then its index will not appear in the  tree.

So as an example from a file I was working with last night:

Nibbles:  4
Values:   2, 1, 3, 3
Indexes: 0, 1, 2, 3

As shown, the nibble at (for instance) index 2 is a 3, meaning that a 2 will appear in level 3 of the binary tree.

I tried to express the algorithm, but it was taking too long. So let's just process the example. The tree starts out in the following state:

Code: [Select]
Level 0    root
          0/  \1
Level 1   ?    ?

Nibbles: 2 1 3 3
Indexes: 0 1 2 3

It always starts on the 0 side and tries to fill in the question marks by looking for nibbles that have values equal to the current level of depth. We start at level 1, so it looks for a nibble with value 1. It finds one at index 1, so it writes that into the tree and marks the nibble as used. It now looks like this:

Code: [Select]
Level 0    root
          0/  \1
Level 1  (1)   ?

Nibbles: 2 X 3 3
Indexes: 0 1 2 3

When it tries to find a second nibble for level 1, it fails and turns that node into a branching node instead:

Code: [Select]
Level 0    root
          0/  \1
Level 1  (1)   @
             0/ \1
Level 2      ?   ?

Nibbles: 2 X 3 3
Indexes: 0 1 2 3

It finds a 2 to assign to the 0 side, but there isn't a 2 for the 1 side and it thus makes another branching node:

Code: [Select]
Level 0    root
          0/  \1
Level 1  (1)   @
             0/ \1
Level 2     (0)  @
               0/ \1
Level 3        ?   ?

Nibbles: X X 3 3
Indexes: 0 1 2 3

This time, it does have enough nibbles for the current level of depth, so it writes those both into the tree, which makes all of its nodes terminal:

Code: [Select]
Level 0    root
          0/  \1
Level 1  (1)   @
             0/ \1
Level 2     (0)  @
               0/ \1
Level 3       (2) (3)

Nibbles: X X X X
Indexes: 0 1 2 3
__________

As practice, here's another list of nibbles from another file:

3, 4, 3, 2, 3, 3, 3, 4

The output should look something like this if you did it correctly:

Code: [Select]
Level 0            root
             0/            \1
Level 1      @              @
           0/ \1        0/     \1
Level 2   (3)  @        @       @
             0/ \1    0/ \1   0/ \1
Level 3     (0) (2)  (4) (5) (6)  @
                                0/ \1
Level 4                        (1) (7)

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #64 on: May 02, 2012, 12:34:43 AM »
The next part is important, so I didn't want it to get lost in the mess of illustrations up there.

As mentioned before, three binary trees are processed before decoding begins. The first is for raw byte counts, the second is for distance/length lengths and the third is for distance length distances. After those bytes are processed, the encoded input begins. If there are 0 nibbles to process for the current binary tree, then no binary tree is generated and instead, numbers are read directly from the input data using the format I described in an earlier post.

In the event a binary tree is present for the type of number that needs to be read, there's a small algorithm used to produce the final value:
  • Step down the binary tree one input bit at a time to locate a number
  • If the number is 0 or 1, use it
  • If the number is 2 or greater
    • Subtract 1 from the number
    • Read the resulting number additional bits from the input data
    • Process a number using the bits read, along with an additional 1 as the highest bit
For example, let's use that binary tree from the last post:

Code: [Select]
Level 0            root
             0/            \1
Level 1      @              @
           0/ \1        0/     \1
Level 2   (3)  @        @       @
             0/ \1    0/ \1   0/ \1
Level 3     (0) (2)  (4) (5) (6)  @
                                0/ \1
Level 4                        (1) (7)

And let's say our input bits are 1010011.
  • As we step down the binary tree, 1, 0, 1, we wind up at 5
  • 5 is >= 2, so we don't return it as-is
  • We subtract 1 to make 4
  • The next 4 bits in the data are 0011
  • We stick a 1 on the front, making 10011, or 19 in decimal, which is the number to use
Numbers read either from the data or from the binary tree are still subject to modification when processing distance/length pairs: namely, you still add 2 for length or 1 for distance depending on context.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #65 on: May 02, 2012, 01:42:16 AM »
Revisiting ^OUT.BMP from earlier, I can actually decode it now. (-: Sing along at home!


Partial input file (hex):
Code: [Select]
Source (hex)
00000000  01 36 08 36 0A 04 26 33  33 43 04 00 6B 50 65 67
00000010  32 23 73 8A 12 6F B0 48  06 3C 46 D3 94 51 39 43
00000020  53 94 41 39 70 10 01 8C  FE 83 E0 F9 D6 24 2C 38
00000030  97 B6 BA 5F 7D 9D 5B 7F  BB 64 8B CE 54 72 C6 46
00000040  5E A7 50 69 A1 53 67 92  36 47 6F 49 68 9D 5D 85
00000050  C4 53 73 C6 45 5C AC 35  48 81 36 49 85 23 30 56
00000060  05 07 0C E1 F7 9B 37 37  B0 7F 58 44 50 59 CE 2E
00000070  4E AB 3F 63 3F F3 FB 37  F7 F6 B7 6B FA 3A C7 C5
00000080  ...

Partial output file (hex):
Code: [Select]
00000000  42 4D F6 09 00 00 00 00  00 00 36 00 00 00 28 00
00000010  00 00 1A 00 00 00 20 00  00 00 01 00 18 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000040  00 00 00 00 00 24 2C 38  97 B6 BA 5F 7D 9D 5B 7F
00000050  BB 64 8B CE 54 72 C6 46  5E A7 50 69 A1 53 67 92
00000060  36 47 6F 49 68 9D 5D 85  C4 53 73 C6 45 5C AC 35
00000070  48 81 36 49 85 23 30 56  05 07 0C 00 00 00 00 00
00000080  ...

Partial input file (binary):
Code: [Select]
00000000 00000001 00110110 00001000 00110110
00000004 00001010 00000100 00100110 00110011
00000008 00110011 01000011 00000100 00000000
0000000C 01101011 01010000 01100101 01100111
00000010 00110010 00100011 01110011 10001010
00000014 00010010 01101111 10110000 01001000
00000018 00000110 00111100 01000110 11010011
0000001C 10010100 01010001 00111001 01000011
00000020 01010011 10010100 01000001 00111001
00000024 01110000 00010000 00000001 10001100
00000028 11111110 10000011 11100000 11111001
0000002C 11010110 00100100 00101100 00111000
00000030 10010111 10110110 10111010 01011111
00000034 01111101 10011101 01011011 01111111
00000038 10111011 01100100 10001011 11001110
0000003C 01010100 01110010 11000110 01000110
00000040 01011110 10100111 01010000 01101001
00000044 10100001 01010011 01100111 10010010
00000048 00110110 01000111 01101111 01001001
0000004C 01101000 10011101 01011101 10000101
00000050 11000100 01010011 01110011 11000110
00000054 01000101 01011100 10101100 00110101
00000058 01001000 10000001 00110110 01001001
0000005C 10000101 00100011 00110000 01010110
00000060 00000101 00000111 00001100 11100001
00000064 11110111 10011011 00110111 00110111
00000068 10110000 01111111 01011000 01000100
0000006C 01010000 01011001 11001110 00101110
00000070 01001110 10101011 00111111 01100011
00000074 00111111 11110011 11111011 00110111
00000078 11110111 11110110 10110111 01101011
0000007C 11111010 00111010 11000111 11000101
00000080 ...


File Header

00000001 = 1 chunk


Chunk Header

00110110 00001000 = Chunk size = 0x0836
00110110 00001010 = Data size  = 0x0A36
00000100                  = 4 (unknown)

Raw Binary Tree Header
0010[0110] = 6 + (2) = 8 nibbles = 2,
0011 0011  = 3, 3
0011 0011  = 3, 3
0100 0011  = 3, 4
0000 0100  = 4 (, padding)

Produces the following tree with nibbles 2 3 3 3 3 3 4 4:
Code: [Select]
Level 0            root
             0/            \1
Level 1      @              @
           0/ \1        0/     \1
Level 2   (0)  @        @       @
             0/ \1    0/ \1   0/ \1
Level 3     (1) (2)  (3) (4) (5)  @
                                0/ \1
Level 4                        (6) (7)

Length Binary Tree Haader
0000[0000] = 0 = No binary tree for Length

Distance Binary Tree Header
0110[1011] = 11 + (2) = 13 nibbles = 6,
0101 0000  = 0, 5
0110 0101  = 5, 6
0110 0111  = 7, 6
0011 0010  = 2, 3
0010 0011  = 3, 2
0111 0011  = 3, 7

Produces the following tree with nibbles 6 0 5 5 6 7 6 2 3 3 2 3 7:
Code: [Select]
Level 0          root
             0/        \1
Level 1      @          @
           0/ \1   0/       \1
Level 2   (7) (A)  @         @
                 0/ \1   0/     \1
Level 3         (8) (9) (B)      @
                            0/       \1
Level 4                     @         @
                          0/ \1   0/     \1
Level 5                  (2) (3)  @       @
                                0/ \1   0/ \1
Level 6                        (0) (4) (6)  @
                                          0/ \1
Level 7                                  (5) (C)


Begin Output Stream

100 (1)01 = 5 bytes
 * 01000010 = 42 = 'B'
 * 01001101 = 4D = 'M'
 * 11110110 = F6
 * 00001001 = 09
 * 00000000 = 00

11000 = Length 3 + (2) = 5
111100 = Distance 0 + (1) = 1
 * 00 00 00 00 00

010 = 1 byte
 * 00110110 = 36

100 = Length 1 + (2) = 3
11100 (1)1 = Distance = 3 + (1) = 4
 * 00 00 00

010 = 1 byte
 * 00101000 = 28

100 = Length 1 + (2) = 3
11100 (1)1 = Distance 3 + (1) = 4
 * 00 00 00

010 = 1 byte
 * 00011010 = 1A

100 = Length 1 + (2) = 3
11100 (1)1 = Distance 3 + (1) = 4
 * 00 00 00

010 = 1 byte
 * 00100000 = 20

100 = Length 1 + (2) = 3
11100 (1)1 = Distance 3 + (1) = 4
 * 00 00 00

011 (1)1 = 3 bytes
 * 00000001 = 01
 * 00000000 = 00
 * 00011000 = 18

11001 = Length 4 + (2) = 6
1111110 (1)1000 = 24 + (1) = 25
 * 00 00 00 00 00 00

00 = 0 bytes

11111000001 = Length 32 + (2) = 34
111100 = Distance 0 + (1) = 1
 * 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
   00 00

1110 (1)10110 = 54 bytes
 * 00100100 = 24
 * 00101100 = 2C
 * 00111000 = 38
 * 10010111 = 97
 * 10110110 = B6
 * 10111010 = BA
 * 01011111 = 5F
 * ...

...

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #66 on: May 02, 2012, 08:55:29 PM »
I didn't want to post this in the glitches thread because it's not exactly a glitch. But maybe you can get something out of it. I found it interesting.

I took a screencap with "Screenhunter6" while playing the game, and this is the picture that came from it (see attachment)

this never happened before (I've taken quite a few pics now).
However, I noticed every time I take a picture, Revolution 'flashes' or blacks out for a split second. (this doesn't normally happen with this program).

-(this is the level 'Lone Ranger') most of the objects are gone, like the teleporters and acid but the "light" from the acid is still there. also the lemmings are gone (they were there in reality. ...that sounds odd :-\)
plus you can see through to the background decoration.

I should mention I also attempted to take a video of the game awhile ago with Camstudio and a somewhat similar anomaly happened. [The video was mostly black and the whole thing appeared to be misplaced up and to the left so all you saw was a small portion of the game happening in the upper corner of the screen.]

At least this let me see the different parts of the graphics and the way they're rendered in a way
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline ccexplore

  • Posts: 5311
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #67 on: May 02, 2012, 09:50:36 PM »
In general, screen capture types of program aren't guaranteed to play well with programs that outputs video through DirectX and similar means.  The price of being able to output video faster is that other programs occasionally can't accurately read back what is currently being displayed.

That said, I think for the CamStudio issue, I suspect you simply failed to correctly set up CamStudio to capture full-screen instead of a specific region of the screen.  Either that or CamStudio is buggy and fails to correctly calculate the screen size.

Offline Leo

  • Posts: 125
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #68 on: May 28, 2012, 02:38:55 AM »
This is not really related to this subject, but it's sort of the game settings and maybe can be the start of some new game settings program. As I can see GuyPerfect is certainly capable to make one.

There are 3 possible ways of pointer behaving at the gameplay, but I don't see it's mention in the manual or selectable in the game itself.

One, of course, is default settings. It's, lets say, 'Manual rotation'. Right mouse button must be hold to rotate cylinder.

Other one is 'Automatic rotation'. Rotation follows any mouse movement, and right mouse button is switch between the play area and 'skill icons'.

Last one is 'Old style' with rotation when pointer touch the playfield edges.

Settings to that three styles are just metter of changing one number in the game registry entries. So, it's all what we have here, three reg files, one for each setting. Just doubleclick on any and try for yourself.

But, I have some other ideas what can be included in some nice settings utility.
Switching On/Off animation, all together, or separate for each one. Start animations are really annoying, who want's to watch that every time before the game? Animation after the end of a level also start to be boring after some time. It's enough to change the names of the animations in the EXE file (change any letter in the names) and animations files will be considered missing and animation will be skipped. It's easy to change that 'manualy' with an hex editor, but that's not something what 'normal' gamer do.
And there is one more thing that be nice to have. At the 'Old style' rotation, pointer can't reach 'skill icons' area normally, so must be switched with right mouse button. It's OK for the 'Automatic rotation' settings, but for the 'Old style' is stupid. Would be nice if that can be 'fixed'.

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #69 on: May 28, 2012, 03:57:10 AM »
hey you didn't give up on this did you Guy?

good ideas there Leo.  Guy has already discovered a number of things in the game that were not documented or in the manual.

There are 3 possible ways of pointer behaving at the gameplay, but I don't see it's mention in the manual or selectable in the game itself.

Other one is 'Automatic rotation'. Rotation follows any mouse movement, and right mouse button is switch between the play area and 'skill icons'.

so in other words; the cursor always remains horizontally in the center of the screen and when you move the mouse right the cylinder rotates right? Sounds like it might be a very cool concept, but it would be cool to be able to switch easily. thanx for those  :)

As far as ideas for the game I have a few as well but was holding off on mentioning them, but I might as well while I remember them. It would be nice for blockers to turn builders like in previous lemmings games.
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline Minim

  • Posts: 1724
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #70 on: May 30, 2012, 08:13:24 AM »
good ideas there Leo.  Guy has already discovered a number of things in the game that were not documented or in the manual.

I agree. Both registration entries do work quite well (Although one of them made me dizzy. :sick:). However, I'm getting a slight problem with both of them. I am unable to fast forward. When I try to click on that button the pointer moves back to the middle whether it's a left click or a right click (Unless it's me not knowing which key is to fast forward). I wonder how that can be solved...
Level Solving Contest creator. Anybody bored and looking for a different challenge? Try these levels!

Neolemmix: #1 #4 #5 #6
Lix: #2  #7
Both Engines: #3

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #71 on: May 30, 2012, 04:56:01 PM »
I imagine the functionality is leftovers from A) the PlayStation version of the game and B) an early Windows approach to rotation. On PlayStation, I imagine you could use shoulder buttons to rotate, and a couple other buttons to select skills, so all you needed to do was move the cursor to select Lemmings and not use it for rotation. The first Windows build may have used the classic edge-of-screen paradigm used by other Lemmings games, but they settled on the right-hold solution because frankly, it's more intuitive.

Very nice finds, Leo. It's fun to see that this stuff is still in the game without modifying anything.

As for adjusting the program to make it work with whatever enhancements, it's certainly possible. I personally would love to tweak the screen size to get the game to run at a higher resolution, and my poking around in the programming suggests that there are actual variables containing 640 for width and 480 for height that might be able to be simply changed to modify the size the game runs at. Having said that, I wanted to keep such enhancements out of the "fix" patch, since they're not "fix" related.

Offline Leo

  • Posts: 125
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #72 on: May 30, 2012, 11:21:07 PM »
All the keyboard controls I know of (some of them are not documented in the manual).

Esc. . . . . . . . . . . . .options (in game)
                              exit to windows (in menus)
Space, Control . . . zoom in, zoom out
Backspace. . . . . . . rotate 180 degrees
Cursor left. . . . . . . (hold) select only left walking lemmings
Cursor right. . . . . . (hold) select only right walking lemmings
Cursor up, A . . . . . change one skill up
Cursor down, Z . . .change one skill down
P. . . . . . . . . . . . . . .pause
O. . . . . . . . . . . . . . options (in pause)
Num pad left . . . . . move cursor left (rotation left)
Num pad right. . . . .move cursor right (rotation right)

At the default mouse settings Num pad left/right rotate screen only when Right mouse button is hold down. On the other two settings these buttons can rotate screen without a mouse.

There isn't 'fast forward' key on the keyboard, that's strange. And it is annoying that 'fast forward' is not available if mouse is not in the default mode.

Offline lem

  • Posts: 1
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #73 on: July 15, 2012, 08:55:04 PM »
Possible New Idea

I was thinking that this game would be ideal to play on a touchscreen and would likely become one of the best touchscreen games available. The interface is really perfect for it and it doesn't necessarily require any mouse motion like when played on PC as it has a simple point and click input.

However when touchscreen is used, the mouse cursor (ie the in-game green crosshair) mostly circles the outer edge of the gameplay area. It does float quickly over the gameplay area when touching the center of the screen, but is quickly dragged to the outer edge closest to where the screen is touched. Is there a reason why this is happening? Or is there a fix that would allow Lemmings Revolution to work on a touchscreen.

Thanks

Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #74 on: July 16, 2012, 01:33:25 PM »
Wow guys, just found out about this custom patch today and it is great!  :thumbsup:

Anyhow, I read a couple of people asking if Lemmings Revolution could be played in a window or at different resolutions. I found that we could use DXWind and posted about it here http://www.lemmingsforums.com/index.php?topic=646.0

Unfortunately DXWind doesn't play nicely with your custom patch.

Just wondering, is it possible to make the custom patch play nicely with DXWind.
Or, from trying DXWind can you get any hints for how to make your custom patch work in a window or at different resolutions without using DXWind?

At the very least you might have a good idea of what DXWind settings might work better with Lemmings Revolution.
In particular so that [Alt][Tab] or clicking outside of game window doesn't crash, etc..
To keep this thread clean; if you do find some good settings for DXWind please post in that thread http://www.lemmingsforums.com/index.php?topic=646.0

PS: really impressed with your custom patch and really enjoyed reading through this thread!

Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #75 on: July 20, 2012, 01:25:33 PM »
Hey GuyPerfect could this help or be of interest at all?

DirectDrawWrapper v0.1 sources from here: http://sol.gfxile.net/code.html
or also DirectDrawHack binary/source: http://sol.gfxile.net/ddhack/ or here: https://code.google.com/p/ddhack/
Might give some insight or ideas?  ???

He also has some interesting tutorials etc: http://sol.gfxile.net/dxtut/index.html
May or may not be useful.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #76 on: July 20, 2012, 03:17:04 PM »
DirectX in all its forms uses Microsoft's typical COM interface, and I have a collection of header files for reference courtesy of the Wine project. Even in its current state, the patch.dll is manipulating DirectX even though it's written in C (rather than C++), which is practically unheard of. (-:

Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #77 on: July 20, 2012, 03:48:23 PM »
I think his DirectDrawHack might have been transfering the DirectDraw data through to OpenGL. Was wondering if doing something like that might be beneficial with your patch.dll?

I think the 'DDraw Emulate' option under the 'Window Mode' tab of D3DWindower also transfers the DirectDraw data out to OpenGL.

From what I gathered, bonuses would be OpenGL is faster and also may allow some form of filtering to improve image quality.

Unfortunately neither of those work for me because my ATI cards drivers are very troublesome with OpenGL. If the OpenGL program is not made how the ATI drivers like then it results in a BSOD. Annoyed the hell out of me for a couple of years but ATI have got the drivers atleast half way fixed now so I can play most OpenGL games.

Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #78 on: July 21, 2012, 02:28:13 AM »
Is it possible to improve the number font beside the lemmings type selectors; floater, climber, etc...
I notice it looks quite bad using the official Lemmings Revolution version as well. Any ideas?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Edit1:
I see you had the number font looking real nice back here;
http://www.lemmingsforums.com/index.php?topic=615.msg13694#msg13694

How come the font doesn't look that crisp on my machine? Did you change the 'number' font .bmp files or something?

See on my end the number font on the lefthand side of the screen looks bad.
Screenshot taken playing with the Custom Hack Patch in normal fullscreen 640x480.
(The same problem with the 'number' font occurs playing in windowed mode as well)

Edit2:
Also, notice my 'speedup' double arrow button icon doesn't look as sharp either.  ???
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


I will see if I can get Lemmings Revolution running on an old PC to see what it originally looked like back in the day and report back.

Edit2:
The number font looks really crisp on my old PC: PIII 600MHZ + Voodoo3 + W98SE

Maybe the problem is just with ATI graphic cards, GuyPerfect are you using a NVIDIA graphic card by chance?

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #79 on: July 22, 2012, 10:30:37 PM »
Again, I apologize if I go over anything already mentioned.

I took a screen shot (using both PrintScreen and a program called screen hunter) and both times the “full screen” picture ends up looking no larger than this (see attachment).

I don’t know if this has anything to do with Lemmings Revolution or it’s just the way this works but in any case; my game doesn’t look like this or yours (played normally with Guy’s patch). The numbers are smooth and good. I’m using NVIDIA graphics (I think, I can’t find the documentation  ><img src=" title="Angry" class="smiley" />)
Mine looks basically like Guy’s from the link you posted. Idk why it doesn’t come out that way when I take screen shots. Are you saying yours looks like that picture at full screen?
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #80 on: July 22, 2012, 11:51:40 PM »
First I will just check that I have understood you right.

You say that when you play the game it looks like GuyPefrect screenshot. But when you take a screenshot it looks like picture you posted (obviously) which looks like my screenshot (the number '1' looks terrible for example).

A) GuyPerfect = plays good and screenshots good. [Fullscreen?] (Unknown graphic card at this stage)
B) ThickMolasses = plays good and screenshots bad. [Fullscreen] (ATI HD4350 and Win7)
C) JClampy = plays bad and screenshots bad. [Fullscreen or Window] (ATI HD4660 using latest DX9 and WinXP)
D) JClampy = plays good and haven't taken screenshot yet. [Fullscreen] (3DFX Voodoo3 2000 AGP using latest DX9 and Win98SE)

So, still not enough information to know what problem is. Could guess that maybe it is an issue with ATI graphic cards, but without trialing with different cards or getting more info we are only speculating.

I will test on another computer with an ATI HD4650 later today if I can.

Thick Molasses are you sure you can't find what graphic card you are using:
from windows 'start button', 'settings', 'control panel', 'system', 'hardware', 'device manager', then 'display adapters'.
or from from windows 'start button', 'settings', 'control panel', 'display', 'settings', 'advanced', then 'adapter'.

Also, what directx version and operating system are you using?

DirectX version = windows 'start button', 'run', type dxdiag

Operating System = windows 'start button', 'settings', 'control panel', 'system'

Edit:
Updated ThickMolasses graphic card and operating system information

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #81 on: July 23, 2012, 01:14:15 AM »
edit: yes your right about all that.
Idk if this screen shot problem really has anything to do with Revolution but.... What I should try is taking a screen shot of another full screen program! That's what I'll do and get back to you.
Btw, "screen hunter plus" is a very good program, only thing is it costs money and the trail doesn't last real long.

EDIT:
I just took a screenshot using PrintScreen of another fullscreen but much different program and it was a lot different! It still wasn't full size though  ??? (compared to the real game) see attached.
At least now we know that this does have something to do with the game (or game mechanics).
--
In another note, once I tried using CamStudio to record my playing of Revolution and some really odd happened: The video turned out totally distorted; the colors were way off and the whole screen appeared to be displaced up and to the left so far only a small portion of the game screen was visible in the video. the rest of the video was black.

----------
thanx for the help. I have Windows 7 home edition so locating this stuff if is pain because you have to first work around all the ‘dumb people protection bullcrap’ to prevent non-computer savvy people from accidentally ruining their computer.  ><img src=" title="Angry" class="smiley" /> (not that I'm extremely computer savvy but apparently I'm better than the people they designed this for).

Mine is a HP, 64 bit, AMD Phenom™ II 925 Processor 2.80 GHz, (6.1, build 7601)

Apparently I was wrong—I don’t have Nvidia (I must have been thinking of my old computer) I have ATI Radeon HD 4350

DirectX 11

--------
If you ever wanna discuss stuff at length or quickly visit this chat room for this site here:
http://webchat.quakenet.org/?channels=lix
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #82 on: July 23, 2012, 02:00:42 AM »
Ok, just to clarify a few things.

Although you have DirectX11 installed there should also be a DirectX9 in there somewhere. It maybe called DirectX9L or simlar from memory as I don't have Vista or Win7 myself.

Basically unless a game is made to use DirectX10 or DirectX11 it will instead be using DirectX9 or in Vista & Win7 case, DirectX9L. Unfortuantely I wouldn't know whether DirectX9L would cause a visual difference when compared to DirecX9 or not.

Secondly, if the 64bit is just refering to your CPU or if you are using a 64bit operating system may or may not cause differences, especially when running 32bit software.

Although, it could also be a difference between WinXP and WinVista or Win7 as maybe I am only one running WinXP?  :scared:

Lastly, it is interesting you have a similar graphic card to mine being same chipset maker but of a different family.
Still, it is conceivable that they could display the images the same on a hardware level, although drivers could throw a spanner in the works.

I am using ATI driver CAT 12.3 which is a few months old now. It appears they are on 12.6 or 12.7 now.

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #83 on: July 23, 2012, 10:04:32 PM »
I should point out a few things; I may not be the best person to be testing things out considering for one; my monitor is larger than normal it’s 1680x1050 resolution. Secondly in the past I did a lot of messing around with DirectX and other video codecs which I downloaded in an attempt to try and get this other program working called Virtual Dub. Consequently I think I may have changed things to the point where I'd need somebody else to get my computer to it's original state, (or how it *should* be)
Besides that when checking my PC’s stats it tells me “Windows has a problem detecting all of your information” … so something is wrong, but no idea what. In any case I don’t see DirectX9 or any other version listed anywhere so far.

I have a 64bit operating system. (not CPU) and yes that can cause major problems, one major one that I know is that you can not run anything smaller than 32 bit programs at all. But beyond that I don’t know.
My computer is about 2 years old now I think. Windows update also recently stopped working for me for yet unknown reasons so…. yeah. (I'll stop complaining now ;P)

Anyway… I’ve just been testing out D3Dwindower and I can’t it to work at all. No matter what changes I make to the options the game just plays normally (full screen). I tried moving different files around as well.
Now, for some reason my game has reverted to the ‘bad’ look; the numbers aren’t as defined. (it looks like your picture here *see below) I don’t know what I did to change that though.
--Also I've only been using Guy's patched version to do all this, maybe I'll try using the old version but I don't really want to. Guy went to a lot of work to get the colors back and I can't stand playing it the bad way anymore. (unless you need me to test it for testing purposes)

A question; when using D3Dwindoer are you able to have Revolution run in the background fine while having another program open like a music player?



Just out of curiosity I might try screen capping afew other programs. Half life (and most Steam games actually) have most of their files stored on the Steam server so stuff isn't even on your PC. I'll try something closer to Revolution.

EDIT-- I tested three other games with all different results. My theory is that (I believe Guy might have mentioned this somewhere) the game ‘screen’ has a certain size then gets stretched to your screen during game play. What I don’t know understand is why you’re not able to screen-capture that properly. It's capturing the screen as it's created initially. (I don't know how to put it)

here are two separate screen caps (both using screen hunter as you can see) and you can clearly see the difference. (the latter is a screen cap of my desktop and I just cut it down to make it smaller but the 'size' (resolution size) was correct. It was the size of my desktop.
I wish I had something more useful to bring to this.
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #84 on: July 24, 2012, 09:47:01 AM »
Ok, I will wittle down your message a bit so we don't get caught up talking about Micro$hit operating systems and hardware or we will probably be here till xmas and banging our heads against brick walls.

Anyway… I’ve just been testing out D3Dwindower and I can’t it to work at all. No matter what changes I make to the options the game just plays normally (full screen). I tried moving different files around as well.

Answer1:
If it was me I would try this; in D3DWindower settings try ticking 'background resize' see if that works. If not, then maybe try unticking 'use foreground control' and/or unticking 'use direct input'. Although, now I think about it, if you already tried running D3DWindower with Lemmings Revolution before actually modifying any D3DWindower settings and it didn't work then things do not bode well.

Answer2:
Just did a google search on D3DWindower and Windows 7 or 64bit. One website mentions that although the game was running fullscreen, it was now running at their computers native resolution. For example, if your native resolution was 1280x960 then Lemmings Revolution would be running at 1280x960.
Can you please check this by pressing a button on your monitor if possible. There should be a menu display you can bring up and hopefully an information section where your monitor can tell you what resolution and refresh rate it is currently using. That way, while you are playing Lemmings Revolution your monitor can tell you what resolution you are in. If it says 640x480 or similar then you know D3DWindower is not working.
http://forum.shrapnelgames.com/showthread.php?t=45099

Honestly, don't know if what is on that website really works. I think his widescreen monitor is automatically filling the screen as I will explain at the end of this post.
The problem is more likely D3DWindower is not Windows 7 compatible, especially if it originally was released in 2004. If you still have no luck, then we may have to research on google some more. I will try and have a look later but I am in the process of backing up a couple of large HDDs, of which one is supposedly failing, but I'll try and do a factory format to rescue it. This will keep me busy for a little while.

Now, for some reason my game has reverted to the ‘bad’ look; the numbers aren’t as defined. (it looks like your picture here *see below) I don’t know what I did to change that though.

This is interesting. This would propose that the font problem is correctable. Did you change graphic card driver? Did you change any of your graphic card settings? Did you change your desktop resolution or colorspace 16bit/24bit/32bit? Did you re-install Lemmings Revolution? (I wonder if difference between typical or compact install could cause this?) Would be good if we could get to the bottom of this problem.

--Also I've only been using Guy's patched version to do all this, maybe I'll try using the old version but I don't really want to. Guy went to a lot of work to get the colors back and I can't stand playing it the bad way anymore. (unless you need me to test it for testing purposes)

No, keep using Guy's patched version.

A question; when using D3Dwindoer are you able to have Revolution run in the background fine while having another program open like a music player?

Yes, just tried a level with mission impossible music playing in the background.

EDIT-- I tested three other games with all different results. My theory is that (I believe Guy might have mentioned this somewhere) the game ‘screen’ has a certain size then gets stretched to your screen during game play. What I don’t know understand is why you’re not able to screen-capture that properly. It's capturing the screen as it's created initially. (I don't know how to put it)

here are two separate screen caps (both using screen hunter as you can see) and you can clearly see the difference. (the latter is a screen cap of my desktop and I just cut it down to make it smaller but the 'size' (resolution size) was correct. It was the size of my desktop.
I wish I had something more useful to bring to this.

Hmm, no I'm pretty sure the original game is 640x480 as that is how it displays both on my old computer with Voodoo3 and this computer with ATI HD4660. The thing you might not realise is that both my computers are displayed on a 4:3 ratio monitor, which is exactly the ratio that this game was made to be displayed at.

I assume you are using a widescreen display. If so you may want to investigate how your widescreen displays resolutions that it is not made for. For example most widescreen displays have an option where you can choose whether the monitor should automatically make whatever size resolution it receives fill the screen. This has the effect of distorting the picture if it is the wrong resolution. IE; if video footage; make people look short/fat or tall/skinny, etc...

If you can access your monitors setup menu as discussed earlier. Look for something like 'manual image adjust', then 'aspect ratio', now what you want to do is choose 1:1 if it is available. What this will do is display all resolution's as they are suppose to be seen. If a picture is suppose to be square then you will see black borders etc...

With 1:1 selected you will definately see the truth about what Lemmings Revolution is doing.

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #85 on: July 25, 2012, 02:10:00 AM »
First: D3DWindower;
By the looks of it (without much research) I’m getting the feeling that (as you said might be the case) D3DWindower is not compatible with Windows 7. There’s just no change what-so-ever, and the same with that other program, if it had any kind of impact, I’d think it would at least do something or crash. But it’s like it’s not doing anything at all. Today it just stopped responding for no apparent reason. And I checked my monitor’s resolution while it was active and there was no change to what it normally would do. (see below for what it normally would do.) I'll try to tinker around some more.
In the end; if I can’t get it to play in a window I won’t be real upset. I’d rather spend time on making an editor for the game. But that’s another story.
---------------------
Now; I didn’t have time yet to try all those things out but I can tell you some things;
---I may have confused 'Definition' for 'Resolution' in previous posts. :-[
first of all; Idk whether it’s important but I forgot to mention my computer is an HP but I’m using an older Gateway monitor which originally came with Nvidia. But now I have a different adapter (ATI Radeon)

I assume you are using a widescreen display. If so you may want to investigate how your widescreen displays resolutions that it is not made for. For example most widescreen displays have an option where you can choose whether the monitor should automatically make whatever size resolution it receives fill the screen. This has the effect of distorting the picture if it is the wrong resolution. IE; if video footage; make people look short/fat or tall/skinny, etc...

Yeah, that’s what I meant earlier. My monitor is 8 inches by 11 ½ inches and it’s default desktop resolution is 1680x1050. Most older full screen games I play either looked stretched or they’re “boxed” because of this. However, now that you mentioned it Revolution must be looking different; I just never realized it. 1680x1050 aren’t divisible by 640x480 but they are fairly close; both by 2.XXX which means my picture is much larger but only stretched lengthwise so little it’s hardly noticeable.
Also I checked a picture of the game using Photoshop. It’s exactly 640x480 pixels. (man is that how small screens used to be? I’m spoiled) I just can’t figure out why I can’t get a screen-cap of the stretched version which is what I (the user) see.
I can confirm my monitor does revert to 640x480 while Revolution is active. So no higher definition for me right now. 
I’ll try your recommendations later. Don’t have time now.

Now, for some reason my game has reverted to the ‘bad’ look; the numbers aren’t as defined. (it looks like your picture here *see below) I don’t know what I did to change that though.

This is interesting. This would propose that the font problem is correctable. Did you change graphic card driver? Did you change any of your graphic card settings? Did you change your desktop resolution or colorspace 16bit/24bit/32bit? Did you re-install Lemmings Revolution? (I wonder if difference between typical or compact install could cause this?) Would be good if we could get to the bottom of this problem.

I’ll look into this sometime this week but I’ve been very busy. As of now, the only thing I can think of is I hit the “auto-processing” button on my monitor which does… something. I haven’t pressed that button in years. It kinda burns me up because my game was looking good now all of a sudden it doesn't look right.

Guy has a Linux (similar to Ubuntu) and I used to use Ubuntu and I specifically remember the graphics being really nice and smooth on that. It may have to do with the OS. (I’ve never played Revolution on it though but I know Guy has).
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #86 on: July 25, 2012, 03:08:05 AM »
Ok, try this;

First go to Microsoft website and download DirectX9 for your operating system (know that what you may download is a 'downloader' and then you use that 'downloader' to do an 'online download installation' of the DirectX9 package. If it only takes a few seconds then you know you have not installed DirectX9, you have only downloaded the 'downloader'. This will not overwrite your DirectX11 so don't worry about that. This will install DirectX9 beside DirectX11 so you will have both and your windows operating should automatically choose which one to use depending on game you are running.

After you have done that go to D3DWindower settings where it says 'DLL' and click [browse] button and select the D3DHook.dll file and press [open] button. Then click [ok] button to close out of settings window.

Now run the game and see if that works.


Edit:
Also, If after the above it still doesn't work. Then does your Operating System have a 'Windows XP mode' or similar? There is a chance that may work.

Offline Lomax

  • Posts: 15
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #87 on: August 11, 2012, 11:57:25 PM »
Works well for me, but I also have a problem with the font.

 :thumbsup:

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #88 on: August 12, 2012, 03:46:39 AM »
what kind of computer are you using? Your screencap looks really nice. I mean the graphics (aside from the font) look higher definition. also the top and bottom of the column is flat. It's supposed to come out at an angle.  ???

----
I'm currently fixing a Gateway\Windows 98 computer so I'll be able to run Revolution on the machine I originally did!
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline Lomax

  • Posts: 15
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #89 on: August 12, 2012, 05:32:15 AM »
I have a Dell XPS running Windows XP SP 3. My graphics card is an ATI Radeon HD 4800 Series.

Re: Hacking Lemmings Revolution
« Reply #90 on: August 20, 2012, 08:11:10 PM »
Attached to this post is Full Color v1.0 (Beta 4). This is a release candidate.

The updated Readme is as follows:

Code: [Select]
Lemmings Full Color Revolution!             Windows Vista/7 Compatibility Patch
Written and maintained by Lemmings Forums        http://www.lemmingsforums.com/
  Version 1.0 (Beta 4) - April 27, 2012


About this program:

As you've probably noticed, Lemmings Revolution has been falling apart over the
years as Windows went through its many updates. It started out innocently
enough on Windows XP: a few of the icons had wonky colors, but it was otherwise
okay. But then, when windows Vista and 7 came about, those icky colors just
turned full-on black. And the main menu became a virtually unusable cluster of
black rectangles. Oh, and the sound stopped working! It's a real mess.

Well, this handy little gadget fixes all of those problems. While the technical
details are beyond the scope of this readme file, the tl;dr version is that the
game program does not conform 100% to the DirectX specification. It was just
fine back on Windows 98 where it worked anyway, but as time marches on, we see
that the game was released with what we have since learned to be show-stopping
bugs!


Things that this gizmo will fix:
 * Restores audio on Windows Vista and 7. It was completely AWOL before.
 * Provides a new texture loading routine. This corrects the messed-up colors.
 * Tweaks the main menu graphics. Solid black rectangles are hard to read.


Things you can fix yourself:
 * Level 9-6, The High Dive, has practically never worked for users who
   selected the "Typical" installation option. This can be corrected by copying
   "lemmings.box" from the CD and into the Lemmings Revolution installation
   directory. For real. The installer doesn't copy it right for some reason.


How to use this bad boy:

 * This patch is only designed to work with the original Lemmings Revolution
   EXE files (the game has seen various releases), so if you have one with any
   modifications, don't expect it to work. When in doubt, just re-install it
   from the CD. Don't worry: you won't lose your save data.

 * Locate the Lemmings Revolution installation directory on your computer. By
   default, this is "C:\Program Files (x86)\Take 2\Lemmings Revolution\" for
   the North America releases. Believe in yourself. I'm sure you can find it.

 * Make sure "Lemmings Revolution.exe" is not read-only. You can check this by
   right-clicking the file, selecting Properties, then making sure the box next
   to "Attributes" is un-checked.

 * Copy the Full Color EXE file into the Lemmings Revolution installation
   directory and run it. If UAC is enabled, you will have to run it as
   administrator. To do so, right-click the Full Color file and select
   "Run as administrator"

 * The program will do its darnedest to fix up the Lemmings Revolution EXE so
   that it works correctly again. Be sure to read the contents of the window
   that appears for information on what it was able to accomplish. If there was
   a problem, it will let you know what went wrong.


Additional information:

As noted above, there's a few different versions of Lemmings Revolution out
there. In fact, no one's really sure just how many there are. It's not feasible
to track them all down to make a comprehensive list, so this patch is instead
designed to be flexible and figure out exactly what needs to be done by
analyzing the Lemmings Revolution EXE file that it's intended to patch.

Some of the code updates were too large or otherwise too complex to be fitted
into the original EXE file, so they were moved into a DLL file instead. The
Full Color program will produce one such DLL file when it patches Lemmings
Revolution, adding it to the installation directory. The file's name is
"patch.dll" and it is required for the game to run, so don't delete it.

In addition to patching the Lemmings Revolution EXE file, that DLL file itself
is configured to work specifically with the version of Lemmings Revolution
being patched. If you copy a patch DLL from a different installation of
Lemmings Revolution, it will not work. In order to ensure correct
functionality, always run the Full Color program on an un-modified Lemmings
Revolution EXE.


Change log:

 * April 27, 2012 - Original release
   - Introducing audio fix
   - Introducing texture fix
   - Introducing main menu fix


Credits:
 * Lemmings Revolution is ©2000 Psygnosis/Talonsoft and Take-Two Interactive
 * Lemmings Forums staff (http://www.lemmingsforums.com/)
   - ccexplore, for technical research, ideas and testing support
   - Guy Perfect, for reverse engineering and patch development
   - thick molasses, for bug investigation and testing support


Any light on when the final release is ready?

Also, is it advisable to run the patch when running the game on Windows 98, XP and/or Wine?

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #91 on: August 20, 2012, 09:31:42 PM »
as far as I know, it's been tested on XP and 7. I'm not sure about Wine.
On Wine the game wasn't too bad but had some problems. It don't think it was not playable though.

If you have a Windows 98, you don't need it; the game works correctly on that version. I don't know what it would do if you tested it out...
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #92 on: August 22, 2012, 01:25:18 AM »
It's ready to go if we have a site to put it on. With a username like "The Lemmings Encyclopedia", I'm suddenly hopeful. (-:

The fix corrects some code in the game that didn't conform to the DirectX specification. It should run fine on any version of Windows as well as Wine.

EDIT:
If you're aiming to put this up online, let me know and I'll make a formal v1.0 release with the host included in the credits.

Re: Hacking Lemmings Revolution
« Reply #93 on: August 23, 2012, 05:46:33 PM »
It's ready to go if we have a site to put it on. With a username like "The Lemmings Encyclopedia", I'm suddenly hopeful. (-:

The fix corrects some code in the game that didn't conform to the DirectX specification. It should run fine on any version of Windows as well as Wine.

EDIT:
If you're aiming to put this up online, let me know and I'll make a formal v1.0 release with the host included in the credits.

You can e-mail it to me, I'll add a new section under Downloads named 'patches' and link to the file on page http://tle.vaarties.nl/revolution/

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #94 on: August 24, 2012, 08:23:34 PM »
No need for an e-mail. I've attached the .zip file to this post, so if you're logged in you can download it. It's all ready to go, tested, and TLE is in the credits file.

Re: Hacking Lemmings Revolution
« Reply #95 on: August 25, 2012, 09:21:20 AM »
The patch is hosted now: http://tle.vaarties.nl/patches/

Re: Hacking Lemmings Revolution
« Reply #96 on: August 25, 2012, 10:19:56 AM »
Has someone been able to play this game properly on Wine? On my version, 1.5.11 on Ubuntu 12.04, the mouse cursor behaves as if it's drunk. Can some confirm this behaviour? Here's a movie of what Í'm describing, in the movie I'm trying to start a new game and select a level (which I'm unable to do this time): http://vergaarbak.vaarties.nl/drunk-cursor.ogv

@GuyPerfect: I know of this official patch: http://download.cnet.com/Lemmings-Revolution-patch/3000-2121_4-10236700.html . Do you know what that patch does and if it's still needed after applying your Full color patch?

Note: attached is my version of Lemmings Revolution.exe (CD label = 'Lemmings Rev'). The CD cover says (c) 2004. DCG 902350 | Dice Multimedia

Offline mobius

  • Posts: 2752
  • relax.
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #97 on: August 25, 2012, 05:33:07 PM »
@GuyPerfect: I know of this official patch: http://download.cnet.com/Lemmings-Revolution-patch/3000-2121_4-10236700.html . Do you know what that patch does and if it's still needed after applying your Full color patch?

Note: attached is my version of Lemmings Revolution.exe (CD label = 'Lemmings Rev'). The CD cover says (c) 2004. DCG 902350 | Dice Multimedia

that patch was to fix an issue in which the fall height which made a few levels impossible. it's glitchy though, I have the patch and still once and a while it doesn't work correctly. If you bought revolution after some date (some time in 2000) it comes with the patch already.
Supposedly; If you bought the game before that you would need the patch. You can see what goes wrong in a video posted in this thread below; at a certain height there is a chance that either lemmings will survive or die.

you can find some more info about that mysterious patch in this thread:
http://www.lemmingsforums.com/index.php?topic=585.15

(sorry I keep answering Guy's questions for him ;P)
everything by me: https://www.lemmingsforums.net/index.php?topic=5982.msg96035#msg96035

"Not knowing how near the truth is, we seek it far away."
-Hakuin Ekaku

"I have seen a heap of trouble in my life, and most of it has never come to pass" - Mark Twain


Re: Hacking Lemmings Revolution
« Reply #98 on: August 25, 2012, 06:29:51 PM »
@GuyPerfect: I know of this official patch: http://download.cnet.com/Lemmings-Revolution-patch/3000-2121_4-10236700.html . Do you know what that patch does and if it's still needed after applying your Full color patch?

Note: attached is my version of Lemmings Revolution.exe (CD label = 'Lemmings Rev'). The CD cover says (c) 2004. DCG 902350 | Dice Multimedia

that patch was to fix an issue in which the fall height which made a few levels impossible. it's glitchy though, I have the patch and still once and a while it doesn't work correctly. If you bought revolution after some date (some time in 2000) it comes with the patch already.
Supposedly; If you bought the game before that you would need the patch. You can see what goes wrong in a video posted in this thread below; at a certain height there is a chance that either lemmings will survive or die.

you can find some more info about that mysterious patch in this thread:
http://www.lemmingsforums.com/index.php?topic=585.15

(sorry I keep answering Guy's questions for him ;P)

Thanks for that answer, I don't know if mine is patched already. Will find out when I can play the game with wine and reach the specific levels.

For the drunk mouse, I made a bug report: http://bugs.winehq.org/show_bug.cgi?id=31545

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #99 on: August 25, 2012, 07:16:18 PM »
The official patches address some game program bugs and should be applied before the Full Color compatibility fix.

I've had mouse issues on Wine as well. It's definitely something to bring to their attention.

Offline jclampy

  • Posts: 23
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #100 on: September 06, 2012, 02:31:04 AM »
Ok, while reading about font problems in another game I noticed a solution had been found.

I have only tested this with ATI so have no idea what Nvidia users can do sorry.  ;P

Anyhow, if your in game font looks like a dog's breakfast then try this;
ATI users have an option called "Alternate Pixel Centers", if you activate that then font issues
in Lemmings Revolution are solved.

I personally use ATI Tray Tools which I know has this option and it is also easy to setup a profile
just for Lemmings Revolution, incase it causes problems for other games. (or not?)

Just writing up some instructions which I'll post here:
http://www.lemmingsforums.com/index.php?topic=646.msg14732#msg14732

Unfortunately no idea whether Nvidia has an option like this or how a Nvidia user would use it.

Offline LemSteven

  • Posts: 559
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #101 on: September 09, 2012, 10:30:39 PM »
I got a new computer last month with Windows 7, and I have many of the same graphical bugs mentioned earlier in the thread.  However when I tried to run the patch, I got an error that read:

ERROR: Unrecognized EXE File
This Lemmings Revolution EXE file contains unknown data and cannot be patched. Try re-installing the game from the CD.


Apparently the patch is not recognizing my version of the EXE file.  My Lemmings Revolution.exe file is 921,600 bytes, with a modified date of July 14, 2000, 7:49:40 AM; however when I install it on the hard drive, the modified date there is July 10, 2000, 2:23:56 PM (the file size is the same).  I've tried running the patch on both files without success.  I don't have problems with the splat height and High Dive glitches, and the music works fine.

Any assistance on this issue would be appreciated.  :)

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #102 on: September 18, 2012, 05:43:53 PM »
Any assistance on this issue would be appreciated.  :)

You first. (-:

You realize that all I can do from here is guess, right? How about a copy of that mysterious EXE file?

Offline LemSteven

  • Posts: 559
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #103 on: September 19, 2012, 01:47:38 AM »
Thanks for looking into it!  Here's the .exe file.

Offline GuyPerfect

  • Posts: 363
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #104 on: September 19, 2012, 08:00:45 PM »
Found the issue. In every version of the EXE we've encountered so far, the call to DirectSoundCreate() looks like this:

Code: [Select]
8B 00             MOV  EAX, DWORD PTR [EAX]
50                PUSH EAX
E8 xx xx xx xx    CALL xxxxxxxx ;DirectSoundCreate(), exact address varies

In that EXE file you just posted, however, it looks like this:

Code: [Select]
8B 04 02          MOV  EAX, DWORD PTR [EDX+EAX]
50                PUSH EAX
E8 xx xx xx xx    CALL xxxxxxxx ;DirectSoundCreate()

The patcher looks for the following byte pattern to locate the call to DirectSoundCreate(): 8B 00 50 E8 ** ** ** **. However, the code in your EXE doesn't start with 8B 00, but with 8B 04 02. At some point, Take 2 either changed the code that starts up DirectSound, or built it with a different compiler, and that's why the patcher is failing.
__________

I have modified the patcher program and have attached a v1.1 release candidate to this post. Note that this is not a formal release, so don't point people to it just yet.

What it does differently is that if it can't find the first DirectSoundCreate() call, it will search for the second one. If it finds either, it writes the following instruction to the "MOV EAX" instruction:

Code: [Select]
31 C0    XOR EAX, EAX
This forces EAX to be equal to zero, effectively passing NULL as the device ID to DirectSoundCreate(), which in turn informs the subsystem to use the default audio device. This is how the game should have been doing it all along. |-:

In the event the patcher located the second form, which has an additional byte, it will overwrite that byte with this:

Code: [Select]
90       NOP
NOP literally has no function, so it allows the number of bytes to remain the same while honoring our reprogramming of it.

So hey, LemSteven, check the attachment and see if it works for you. Everyone else, check the attachment and make sure it works for you as well. I want to make sure I didn't break anything while implementing this fix. (-:
__________

As for the EXE, I did notice one change in particular: the language-selection option on the main menu is missing:



This was either an early US-only release, or a late US-only release. I can't decide which is more likely. (-:

Offline LemSteven

  • Posts: 559
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #105 on: September 20, 2012, 12:09:38 AM »
The new patch appears to work fine now!  Thank you!  :thumbsup:

I'm guessing I had a relatively late US-only release, because I never had any of the issues with the early releases (e.g. the fall distance and High Dive glitches).  If I remember correctly, I originally got the game as a Christmas present back in 2000.

Offline Lomax

  • Posts: 15
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #106 on: September 28, 2012, 11:33:12 PM »
Ok, while reading about font problems in another game I noticed a solution had been found.

I have only tested this with ATI so have no idea what Nvidia users can do sorry.  ;P

Anyhow, if your in game font looks like a dog's breakfast then try this;
ATI users have an option called "Alternate Pixel Centers", if you activate that then font issues
in Lemmings Revolution are solved.

I personally use ATI Tray Tools which I know has this option and it is also easy to setup a profile
just for Lemmings Revolution, incase it causes problems for other games. (or not?)

Just writing up some instructions which I'll post here:
http://www.lemmingsforums.com/index.php?topic=646.msg14732#msg14732

Unfortunately no idea whether Nvidia has an option like this or how a Nvidia user would use it.
Interestingly, I don't seem to have that option.

Re: Hacking Lemmings Revolution
« Reply #107 on: January 28, 2013, 07:40:04 PM »
@GuyPerfect: Is you're 1.1 version ready for release? If so, could you package it so I can place it on TLE. Thanks!

Offline Duranu

  • Posts: 1
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #108 on: February 14, 2013, 09:31:53 PM »
Excellent work Guy, made an account just for this patch. Now I can play the lemmings again  :thumbsup:

Offline Pooty

  • Posts: 359
    • View Profile
Re: Hacking Lemmings Revolution
« Reply #109 on: April 23, 2013, 09:32:00 PM »
Seems like I have another freaky EXE of Lemmings Revolution. I couldn't get either version of the patch to work, and the byte patterns you posted above don't appear to be in it.
SEGA Master System version
100% on 110/120 levels (92%). Other levels [Lemmings lost]:
Fun 03 [3], 06 [2], 18 [5]   
Taxing 19 [5], 27 [1], 28 [3]
Tricky 15 [5], 17 [2]
Mayhem 19 [7], 26 [10]