What's new

NRage Input Plugin V2.00 BETA (an overhaul)

Poobah

New member
squall_leonhart said:
hmm... im pretty sure the latest Redist is required for Visual studio... as it contains the latest MDX...
I doubt that this input plug-in requires MDX. My point was that MS's DX SDK is over 75% bloated junk such as documentation and sample code and data files, but you can't compile this plug-in without the SDK.
 
Last edited:
OP
R

rabiddeity

Plugin Hacker
Poobah said:
I doubt that this input plug-in requires MDX. My point was that MS's DX SDK is over 75% bloated junk such as documentation and sample code and data files, but you can't compile this plug-in without the SDK.

You're right, there is a lot of bloat, but the DX documentation is very very important. And the API stuff is all available online, for free. Hell, they even TELL you when you go to download VS Express that you need to download the Windows API separately, along with any other stuff. I'm pretty sure you can choose not to install sample code, even if you probably still have to download it.

Hey, it was just a suggestion, and only because it's free. If you don't like it, use a copy of Borland or gcc or what have you. Myself, I use an old copy of VS .NET (7) with the latest directx9 sdk. Now THAT is a bloated piece of crap; it takes an hour just to install.

"stringconv.cpp" and "databufferclass.cpp" are leftovers from an old version of the plugin. Don't open the VC6 file; in fact, you can safely delete the files NRage.dsw, NRage.dsp, NRage.opt . You want to open the VC7 project, either the NRage.vcproj file or preferably the NRage.sln file. My fault, I should make that clearer. I've fixed the source.

A bit of warning about the current source. I'm fiddling with internationalization routines, so I've included a partially modified "language" folder with some resource files. As the project is set up right now, it will compile these extra resources into the stock plugin and you'll get a bigger plugin file than you normally would. It shouldn't break anything, but it's bigger than it should be.

Very shortly, I'm going to pull that into a separate language DLL to start testing. So hang in there.
 
Last edited by a moderator:

Poobah

New member
GCC is my compiler of choice, and the Allegro website has a 500KB DX8 SDK available for it. :)

In MinGW, however, all sorts of odd errors occur when trying to compile it, because it's too MSVC-specific. In order to make it more compatible with GCC, you'll want to fix up the
Code:
DirectInput.cpp:245: pasting "/" and "/" does not give a valid preprocessing token
DirectInput.cpp:245: error: expected primary-expression before '/' token
errors. They occur with every DebugWriteA call, but I'm not sure what's wrong there. You should also change all the
Code:
for( int i = 0
to have the i declared outside of the for() header, because most non-MSVC compilers complain about that. (I think it's against one of the ISO standards.) PakIO.h should have
Code:
#ifndef _LPCBYTE_DEFINED
#define _LPCBYTE_DEFINED
typedef const BYTE *LPCBYTE;
#endif
in it at the beginning, because LPCBYTE doesn't seem to be defined anywhere else.

The __asm things are also MSVC specific, so some CPP stuff would be necessary to make the ASM stuff more portable.
 
Last edited:
OP
R

rabiddeity

Plugin Hacker
Poobah said:
GCC is my compiler of choice, and the Allegro website has a 500KB DX8 SDK available for it. :)

In MinGW, however, all sorts of odd errors occur when trying to compile it, because it's too MSVC-specific. In order to make it more compatible with GCC, you'll want to fix up the
Code:
DirectInput.cpp:245: pasting "/" and "/" does not give a valid preprocessing token
DirectInput.cpp:245: error: expected primary-expression before '/' token
errors. They occur with every DebugWriteA call, but I'm not sure what's wrong there. You should also change all the
Code:
for( int i = 0
to have the i declared outside of the for() header, because most non-MSVC compilers complain about that. (I think it's against one of the ISO standards.) PakIO.h should have
Code:
#ifndef _LPCBYTE_DEFINED
#define _LPCBYTE_DEFINED
typedef const BYTE *LPCBYTE;
#endif
in it at the beginning, because LPCBYTE doesn't seem to be defined anywhere else.

The __asm things are also MSVC specific, so some CPP stuff would be necessary to make the ASM stuff more portable.

Yup, that __asm thing in particular made me cringe when I saw it, but I never got around to fixing it. There's no reason for it to even be there. Hmph.

LPCBYTE: quirky, I thought that was defined in one of the <windows.h> headers. I'll just replace it with const LPBYTE.

The DebugWriteA is using some weird MS macro to replace DebugWriteA with an empty implementation if _DEBUG isn't defined... see Debug.h, around line 47. I'll figure out how to do it better.

Updated source, debug, release.

OK, I've cleaned up the dialog boxes a bit. Source will be cleaned up more by tomorrow. Last real bug I know about (that I can potentially fix) is the Conker's/Worms rumble. I'm taking a look at that one tonight, but I have a pretty good idea of what the issue is.

Plugin is ready for translation. Do we have any native speakers of languages other than English?
 
Last edited by a moderator:

Legend

New member
If it helps you here's a couple more that I could find that should rumble. I'm sure there's more.

Castlevania: Legacy of Darkness
Virtual Pool 64
 

en24

Emunews 24
rabiddeity said:
Do we have any native speakers of languages other than English?
Yes, if you want a german translation please send me the language file to webmaster_at_emunews24.com.
 
OP
R

rabiddeity

Plugin Hacker
en24 said:
Yes, if you want a german translation please send me the language file to webmaster_at_emunews24.com.

Emailed.

If anyone else is interested, I'm posting the .rc files up here as well. There's a text file inside that gives instructions on how to translate. Sorry that you have to deal with this .rc file, but it's the quickest way for me to get it into the format it needs to be in.

http://www.randomwisdom.com/files/NRage_DInput8_Lang_SDK.zip

While I was digging around trying to fix the rumble pak issue, I found a very serious memory leak issue involving shortcuts. It seems if you switched between paks, the old pak wouldn't get closed and the new pak wouldn't get properly initialized. I have no idea why this didn't cause a crash or problem somewhere, but I fixed it.

Somewhere in there, a version of the source got uploaded that won't compile. If yours doesn't, grab the latest.

Poobah:
I removed the asm crap. (Why didn't he just use sqrtf in the first place?) Also cleaned up the precompiler quirkiness. I think much of it had to do with the fact that the MS precompiler uses C99 by default. Edited header files to move // comments and fixed that empty implementation... which only worked due to a quirk in the MS precompiler. Also fixed LPCBYTE (which is const BYTE * and not const LPBYTE).

As for definitions within for loops, and mixed declarations (declaring a variable after a statement was illegal in older versions of C), try compiling with -std=c99 to remove the warnings.

I ran Conker and it seems to rumble OK, despite the "Insert Rumble Pak" message when you start. Thing is, Conker doesn't rumble all that much anyway; I found just two places so far. The first one is in the tutorial area where you blow up the boulder blocking your way (rumbles twice) and the other is in the multiplayer game type, where firing guns makes the controller rumble.

As for Worms: Armageddon, it doesn't seem to access the controller pak port at all. No rumble support there.

I'll take a look at Castlevania and Virtual Pool.
 
Last edited by a moderator:

NaSeR

Spanish Member
I´m translating it to spanish (around 60% done) It´s easy but there´s some words that makes me spend more time than the rest of the translation, let´s wait to see what´s the final result :bouncy:
 

Legend

New member
Yeah, Conker's weird because it DOES rumble when shooting guns perfectly BUT when your opponent blows your head off with a bazooka, NO RUMBLE. That can't be right...

Worms should have rumble however. I get most of my rumble info from here:http://www.emutalk.net/showthread.php?t=13867&highlight=rumble+pak+support
And looking at tech info online about this game, it says it does support mem paks and rumble paks. Here's a link to one of many talking about Worms: http://www.mobygames.com/game/n64/worms-armageddon/techinfo

And yes you are on a freaken' roll. Thanks.
 
Last edited:
OP
R

rabiddeity

Plugin Hacker
Legend said:
Yeah, Conker's weird because it DOES rumble when shooting guns perfectly BUT when your opponent blows your head off with a bazooka, NO RUMBLE. That can't be right...

Worms should have rumble however. I get most of my rumble info from here:http://www.emutalk.net/showthread.php?t=13867&highlight=rumble+pak+support
And looking at tech info online about this game, it says it does support mem paks and rumble paks. Here's a link to one of many talking about Worms: http://www.mobygames.com/game/n64/worms-armageddon/techinfo

And yes you are on a freaken' roll. Thanks.

Fantastic, that's just the list of games I've been looking for.

I'm going back through the code for rawmode rumblepak detection at the moment... but I don't have much documentation to go from. If someone had an adaptoid and a rumble pak, I could use the raw data modes as a trace between the emulator and the adaptoid....
 

squall_leonhart

The Great Gunblade Wielder
this isn't right this is very not right..

Fixed ROM read - RAW
TPak Read:
Address: C120
Cart Read: Bank:0
Address:0120
Fixed ROM read - RAW
TPak Read:
Address: C140
Cart Read: Bank:0
Address:0140
Fixed ROM read - RAW
TPak Read:
Address: 8000...

pokemon yellow uses the same format as Pokemon blue and red, theres no differences to the way the battery is loaded or the saves work...

its wierd.
i can load a pokemon yellow save in pokeblue..
but pokemon yellow itself isn't loading its save properly

GAH! its not loading the cartridge properly!!!

every section that reads as RAW is supposed to be MBC3!!!


hmm its something in this section... maybe something is missing...

PHP:
// Done
bool ReadCartMBC3(LPGBCART Cart, DWORD dwAddress, BYTE *Data)
{
    int i;

    if ((dwAddress >= 0) && (dwAddress <= 0x3FFF)) {
        for (i=0; i<32; i++) Data[i] = Cart->RomData[dwAddress + i];
        DebugWriteA("Fixed ROM read - MBC3\n");
    }
    if ((dwAddress >= 0x4000) && (dwAddress <= 0x7FFF)) {
        if (Cart->iCurrentRomBankNo >= Cart->iNumRomBanks) {
            for (i=0; i<32; i++) Data[i] = 0;
            DebugWriteA("Banked ROM read: (Banking Error)");
            DebugWriteByte(Cart->iCurrentRomBankNo);
            DebugWriteA("\n");
        } else {
            for (i=0; i<32; i++) Data[i] = Cart->RomData[(dwAddress - 0x4000) + i + (Cart->iCurrentRomBankNo * 0x4000)];
            DebugWriteA("Banked ROM read: Bank=");
            DebugWriteByte(Cart->iCurrentRomBankNo);
            DebugWriteA("\n");
        }
    }
    if ((dwAddress >= 0xA000) && (dwAddress <= 0xBFFF)) {
        if (Cart->bHasTimer && (Cart->iCurrentRamBankNo >= 0x08 && Cart->iCurrentRamBankNo <= 0x0c)) {
            // w00t! the Timer was just read!! Now, if only the timer actualy existed...
             UpdateRTC(Cart);
            if (Cart->TimerDataLatched) {
                for (i=0; i<32; i++) Data[i] = Cart->LatchedTimerData[Cart->iCurrentRamBankNo - 0x08];
            } else {
                for (i=0; i<32; i++) Data[i] = Cart->TimerData[Cart->iCurrentRamBankNo - 0x08];
            }
            return true;
        }
        if (Cart->bHasRam) {
            if (Cart->iCurrentRamBankNo >= Cart->iNumRamBanks) {
                for (i=0; i<32; i++) Data[i] = 0;
                DebugWriteA("Failed RAM read: (Banking Error)");
                DebugWriteByte(Cart->iCurrentRamBankNo);
                DebugWriteA("\n");
            } else {
                for (i=0; i<32; i++) Data[i] = Cart->RamData[(dwAddress - 0xA000) + i + (Cart->iCurrentRamBankNo * 0x2000)];
                DebugWriteA("RAM read: Bank=");
                DebugWriteByte(Cart->iCurrentRamBankNo);
                DebugWriteA("\n");
            }
        } else {
            for (i=0; i<32; i++) Data[i] = 0;
            DebugWriteA("Failed RAM read: (RAM Not Present)\n");
        }
    }
    return true;
}

// Done
bool WriteCartMBC3(LPGBCART Cart, DWORD dwAddress, BYTE *Data)
{
    int i;

    if ((dwAddress >= 0) && (dwAddress <= 0x1FFF)) { // RAM enable (Don't know what this does... Doesn't seem to affect a GB Rom cartrige)
        DebugWriteA("Set Ram Enable:");
        DebugWriteByte(Data[0]);
        DebugWriteA("\n");
    }

    if ((dwAddress >= 0x2000) && (dwAddress <= 0x3FFF)) { // ROM bank select
        Cart->iCurrentRomBankNo = Data[0] & 0x03F;
        if (Cart->iCurrentRomBankNo == 0) {
            Cart->iCurrentRomBankNo = 1;
        }
        DebugWriteA("Set Rom Bank:");
        DebugWriteByte(Cart->iCurrentRomBankNo);
        DebugWriteA("\n");
    }
    if ((dwAddress >= 0x6000) && (dwAddress <= 0x7FFF)) { // Latch timer data
        for (i=0; i<6; i++) Cart->LatchedTimerData[i] = Cart->TimerData[i];
        if (Data[0] & 1) {
            // Latch
            Cart->TimerDataLatched = true;
            DebugWriteA("Timer Data Latch: Enable\n");
        } else {
            Cart->TimerDataLatched = false;
            DebugWriteA("Timer Data Latch: Disable\n");
        }
    }
    if (Cart->bHasRam) {
        if ((dwAddress >= 0x4000) && (dwAddress <= 0x5FFF)) { // RAM/Clock bank select
            Cart->iCurrentRamBankNo = Data[0] & 0x03;
            DebugWriteA("Set Ram Bank=");
            DebugWriteByte(Cart->iCurrentRamBankNo);
            DebugWriteA("\n");
            if (Cart->bHasTimer && (Data[0] >= 0x08 && Data[0] <= 0x0c)) {
                // Set the bank for the timer
                Cart->iCurrentRamBankNo = Data[0];
            }
        }
        if ((dwAddress >= 0xA000) && (dwAddress <= 0xBFFF)) { // Write to RAM
            if (Cart->iCurrentRamBankNo >= 0x08 && Cart->iCurrentRamBankNo <= 0x0c) {
                // Write to the timer
                Cart->TimerData[Cart->iCurrentRamBankNo - 0x08] = Data[0];
            } else {
                DebugWriteA("RAM write: Bank=");
                DebugWriteByte(Cart->iCurrentRamBankNo);
                DebugWriteA("\n");
                for (i=0; i<32; i++) Cart->RamData[(dwAddress - 0xA000) + i + (Cart->iCurrentRamBankNo * 0x2000)] = Data[i];
            }
        }
    }
    return true;
}
 
Last edited by a moderator:
OP
R

rabiddeity

Plugin Hacker
squall_leonhart said:
this isn't right this is very not right..

Fixed ROM read - RAW
TPak Read:
Address: C120
Cart Read: Bank:0
Address:0120
Fixed ROM read - RAW
TPak Read:
Address: C140
Cart Read: Bank:0
Address:0140
Fixed ROM read - RAW
TPak Read:
Address: 8000...

pokemon yellow uses the same format as Pokemon blue and red, theres no differences to the way the battery is loaded or the saves work...

its wierd.
i can load a pokemon yellow save in pokeblue..
but pokemon yellow itself isn't loading its save properly

GAH! its not loading the cartridge properly!!!

every section that reads as RAW is supposed to be MBC3!!!


hmm its something in this section... maybe something is missing...

Bzzzt! Sorry, but according to my sources, Pokemon Red/Blue are MBC3, but Pokemon Yellow is MBC5!
http://uk.geocities.com/gameboycartsuk/GameBoyCartridges.html

This tells me the MBC5 interface is screwing up somewhere... and look, hey, the 1.83 source doesn'thave MBC5 support!

...tinkers...
 

Poobah

New member
Squall, you might want to use [code] tags to retain spacing when posting code. Or even better, [php] tags for syntax highlighting.
 
Last edited:

squall_leonhart

The Great Gunblade Wielder
ahh i see something missing!

PHP:
bool ReadCart(LPGBCART Cart, DWORD dwAddress, BYTE *Data)
{
#ifdef ENABLE_GBCART_READS_WRITES_DEBUG
    DebugWriteA("Cart Read: Addy=");
    DebugWriteWord(dwAddress);
    DebugWriteA("\n");
#endif

    switch (Cart->iCartType) {
    case 0x00: // Raw cartridge
        return ReadCartNorm(Cart, dwAddress, Data);
        break;
    case 0x01: // MBC1
        return ReadCartMBC1(Cart, dwAddress, Data);
        break;
    case 0x02: // MBC2
        return ReadCartMBC2(Cart, dwAddress, Data);
        break;
    case 0x04: // MBC3
        return ReadCartMBC3(Cart, dwAddress, Data);
        break;
    default: // Currently unsupported... Pretend it's a normal ROM-only cart
        return ReadCartNorm(Cart, dwAddress, Data);
        break;
    }
    return true;
}

bool WriteCart(LPGBCART Cart, DWORD dwAddress, BYTE *Data)
{
#ifdef ENABLE_GBCART_READS_WRITES_DEBUG
    DebugWriteA("Cart Write: Addy=");
    DebugWriteWord(dwAddress);
    DebugWriteA("\n");
#endif

    switch (Cart->iCartType) {
    case 0x00: // Raw cartridge
        return WriteCartNorm(Cart, dwAddress, Data);
        break;
    case 0x01: // MBC1
        return WriteCartMBC1(Cart, dwAddress, Data);
        break;
    case 0x02: // MBC2
        return WriteCartMBC2(Cart, dwAddress, Data);
        break;
    case 0x04: // MBC3
        return WriteCartMBC3(Cart, dwAddress, Data);
        break;
    case 0x05: // MBC5
        return WriteCartMBC5(Cart, dwAddress, Data);
        break;
    default: // Currently unsupported... Pretend it's a normal ROM-only cart
        return WriteCartNorm(Cart, dwAddress, Data);
        break;
    }
    return true;
}


should be

PHP:
bool ReadCart(LPGBCART Cart, DWORD dwAddress, BYTE *Data)
{
#ifdef ENABLE_GBCART_READS_WRITES_DEBUG
    DebugWriteA("Cart Read: Addy=");
    DebugWriteWord(dwAddress);
    DebugWriteA("\n");
#endif

    switch (Cart->iCartType) {
    case 0x00: // Raw cartridge
        return ReadCartNorm(Cart, dwAddress, Data);
        break;
    case 0x01: // MBC1
        return ReadCartMBC1(Cart, dwAddress, Data);
        break;
    case 0x02: // MBC2
        return ReadCartMBC2(Cart, dwAddress, Data);
        break;
    case 0x04: // MBC3
        return ReadCartMBC3(Cart, dwAddress, Data);
        break;
    case 0x05: // MBC5
        return ReadCartMBC5(Cart, dwAddress, Data);
        break;
    default: // Currently unsupported... Pretend it's a normal ROM-only cart
        return ReadCartNorm(Cart, dwAddress, Data);
        break;
    }
    return true;
}

bool WriteCart(LPGBCART Cart, DWORD dwAddress, BYTE *Data)
{
#ifdef ENABLE_GBCART_READS_WRITES_DEBUG
    DebugWriteA("Cart Write: Addy=");
    DebugWriteWord(dwAddress);
    DebugWriteA("\n");
#endif

    switch (Cart->iCartType) {
    case 0x00: // Raw cartridge
        return WriteCartNorm(Cart, dwAddress, Data);
        break;
    case 0x01: // MBC1
        return WriteCartMBC1(Cart, dwAddress, Data);
        break;
    case 0x02: // MBC2
        return WriteCartMBC2(Cart, dwAddress, Data);
        break;
    case 0x04: // MBC3
        return WriteCartMBC3(Cart, dwAddress, Data);
        break;
    case 0x05: // MBC5
        return WriteCartMBC5(Cart, dwAddress, Data);
        break;
    default: // Currently unsupported... Pretend it's a normal ROM-only cart
        return WriteCartNorm(Cart, dwAddress, Data);
        break;
    }
    return true;
}
:) this is why its reading the cart as raw

it can't read it as a mbc5 coz mbc5 isn't in the readcart list.
 
Last edited:
OP
R

rabiddeity

Plugin Hacker
squall_leonhart said:
ahh i see something missing!

PHP:
... snip


should be

PHP:
... snip
:) this is why its reading the cart as raw

it can't read it as a mbc5 coz mbc5 isn't in the readcart list.

Yup, you caught the main reason. If you dig deeper you'll also find that the MBC5 mapper isn't quite finished; there's a problem buried deep within; the ROM reads will return reads from the wrong page of ROM (using iCurrentRamBankNo instead of iCurrentRomBankNo, an easy thing to miss). Also, ROM bank 0 reads through the mapper should work OK on a real MBC5, but they're disabled here. Any of these problems might have broken TPak reads. My guess is that MadManMarkAu just got tired, or moved on to another project. Fixed up.

I went through and double checked each bank select routine (and fixed a truncation issue in a couple of them). Props to MadManMark, he really did his homework, and the documentation for the mappers is all right there in the source file. Did some optimization with else ifs, condensed a lot of the DebugWriteA calls into one call, and replaced most of his copying code with system calls (ZeroMemory, CopyMemory). That should give a significant speed boost, assuming I didn't break anything along the way.

MBC1 support is still not quite finished. There's a mode select feature that isn't implemented, that affects how ROM and RAM are accessed. If there's an MBC1 TPak game, it probably uses this...

Also, I implemented a "RAM lock" feature that the MBC chips all have, which prevents reads/writes from RAM unless a certain address is written to first. If this breaks any games, then those games shouldn't have worked with a real GB pak anyway.

RTC support is still untested. Do any Tpak games use this?

Dammit, I said I wasn't gonna touch this code. Now look at what you made me do, squall. :evil:

Final feature to be added: language SELECTION menu, and saving (currently it just picks based on what your OS is set to).

Other things that might need fixing: only return the requested number of bytes to the emulator with tpak (I think it almost always reads 32 bytes, but if I'm wrong...)

Everything updated!
 
OP
R

rabiddeity

Plugin Hacker
OK, language stuff.

I've updated the plugin so it has a Language select box. It should load and save your language settings as well.

Harlay and aTomIC, I've received both of your translations. As for the language DLLs, I'll release them tomorrow. I need to fix the width on some buttons in the dialog boxes. A note: if you change the language from English, the config dialog changes to the release version. This is because the DLLs are compiled in Release mode. In the final release, it won't matter because the English config dialog will also be from the Release version. Also, the language won't change for real until you hit "Save" in the config box and reopen it. I did this on purpose; trust me, it's simpler this way.

I'm not making any sense. I need to go home and sleep.

OK, so all the files are updated. Again.
 

Top