You are currently viewing our site as a guest which gives you limited access to view most discussions and access our other features. By joining our free community you will have access to post topics, communicate privately with other members (PM), respond to polls, upload content and access many other special features. Registration is fast, simple and absolutely free so please, join our community today!

If you have any problems with the registration process or your account login, please contact contact us.

I recently dug out LBA for the first time in a few years... and a few minutes in, my laptop fan was going nuts and my battery was fading fast. It was so annoying I had to crank the sound up to mask it! For a game engine from the mid-'90s this seemed like something was a bit wrong. Given that I actually wanted to be able to play more than 20 minutes on a charge, I did a bit of reverse engineering to figure out how to calm it down a bit. Here's what I did and what came out, I'd be interested to hear if anyone else finds this useful. I know "here I patched it" can mean all sorts of things, so I'm going to explain exactly what I changed and you can decide how you feel about it

As with most software of the era, LbaWin uses 100% of the CPU regardless of how busy it is; it spends all its time checking for new input a squillion times a second. With those computers it wasn't a big deal, but now that so many of us have moved to mobile devices, it's a little troublesome for the user experience.

Interestingly, LbaWin already has an FPS limiter: according to the change notes, the FPS was limited to 500 to avoid problems with collision detection. Here's the FPS limiter code in LbaWin.exe:
It loops over and over, checking the inputs, until it's time for the next frame - using 100% CPU. Then it sets the next time 2ms in the future, to get that 500FPS limit.

This is easy to fix: we just need a little sleep in that loop. Even a sleep of just 1ms would do the job. Of course, there's no empty space here to insert some code, so it's got to go elsewhere; and perhaps more importantly, this isn't the only place the game spins in a tight loop.
It turns out that this loop governs the main rendering when you're running around in the world, but there are other loops that take over during dialogue, for example. If we just patch this loop, the fan still cranks up while you're listening to people talk! Also annoying.

Luckily, the answer lies in the polling routine sub_4034A0. This is called from most places where the game spins waiting for timers or input. It looks like this:
sub_4036D0 does housekeeping related to FPS calculation and timers (and FPS display if you press F).
sub_4033E0 handles input from Windows' event system (so keyboard input, Alt+F4, et cetera). And it returns a flag indicating if the game has been asked to quit: if so, it calls into sub_403480, which exits the game.

As it happens, sub_403480, the exit routine, is placed just before this code:

Conveniently, this gives us a little space to work in. The exit routine calls PostQuitMessage before calling _exit, but this doesn't actually achieve anything, because _exit exits the process immediately.
So by cutting that out and moving the _exit call up a bit, we score a few free bytes of space to build something in...

So here's what I did: I replaced the call to sub_4036D0 to call the new empty space. There, I wrote a new function which calls Sleep() to sleep a few milliseconds, and then calls sub_4036D0 itself. (I also changed a few sub names on the way to this pic.)

In the end, I decided that running at 500FPS was also over the top, so I changed the FPS limit to 60FPS (waiting 16ms instead of 2ms between frames). This seems like an entirely reasonable limit for all purposes, but feel free to let me know if you have a strong opinion! It drops CPU usage by about 8x so that's pretty big.
Thus I chose to set the sleep in the loop to 4ms, so it should poll for input 3-4 times on every frame. Again, that should be more than enough for any usage, right?

Now the CPU usage is comfortably at 5-10% while playing on my laptop, the fan never runs, and I can enjoy the game properly

(I also had a problem with Wine; it was burning up another CPU in wined3d_cs_run() and I had to disable CSMT using regedit... not sure if that's a Wine bug or an LbaWin bug.)

Anyway, this scratches my itch; I'd be curious to hear if it's useful for anyone else.

how on earth u managed to dig and discover all those things is beyond me ... the level of interpretation you were able to give to all those ASM routines is wtf-level. Hats down man, u are truly a wizard, go grab your tunic, u've earned it!!!

__________________ "Because we don't know when we will die, we get to think of life as an inexhaustible well, yet everything happens only a certain number of times, and a very small number, really. How many more times will you remember a certain afternoon of your childhood, some afternoon that's so deeply a part of your being that you can't even conceive of your life without it? Perhaps four or five times more, perhaps not even that. How many more times will you watch the full moon rise? Perhaps twenty. And yet it all seems limitless." --- Paul Bowles