I already tested this using different code, but the same patching method, and it does work perfectly in-game.
Why didn't you release this?
It makes me feel bad, that I unintentionally stole your idea/work ...
Nah, it's all cool. It's part of the TobEx utility still in development. So really, "you got there first".
There is one issue to make it perfectly compatible with scripting: the PlaySong() function only allows a unsigned word for specifying the songlist entry. You'll need to adjust that, otherwise PlaySong(128) will wrap over to PlaySong(-127), which won't crash the game, but will have no effect for entry #128 in sognlist.2da.
I don't understand this.
The script compiler should store this value as an dword in the bcs. The PlaySong() action extracts the lower word and passes it to the relevant function in CSoundMixer. So the upper boundary should be 2^15 = 32767. (which is an non-issue for a songlist with max. 500 entries)
Here's a snippet of the code I used to implement the patches (very messy, and uses collections). Looks like I got confused and what I meant was the engine functions for starting and stopping a song takes the lower byte, which is treated as signed (look at the fifth test patch part near the bottom).
//make a fourth test patch
char oldChar2[] = {0x3C, 0x67};
char newChar2[] = {0x60, 0xCE};
dataList.push_back( Data(0x009E20B4, 2, oldChar2, newChar2) ); //stack size for local vars (673C)
oldChar2[0] = 0xB8; oldChar2[1] = 0x98;
newChar2[0] = 0x94; newChar2[1] = 0x31;
dataList.push_back( Data(0x009E20BF, 2, oldChar2, newChar2) ); //this pointer (98B8)
dataList.push_back( Data(0x009E20C5, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E20DB, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E212A, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E2140, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E216F, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E21D3, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E2221, 2, oldChar2, newChar2) );
char oldChar5[] = {0xE8, 0x49, 0xCF, 0xFC, 0xFF};
char newChar5[] = {0x90, 0x90, 0x90, 0x90, 0x90};
dataList.push_back( Data(0x009E211E, 5, oldChar5, newChar5) ); //assertion error call
oldChar2[0] = 0x50; oldChar2[1] = 0x9A;
newChar2[0] = 0xBC; newChar2[1] = 0x34;
dataList.push_back( Data(0x009E214A, 2, oldChar2, newChar2) ); //object pointer (9A50)
dataList.push_back( Data(0x009E2216, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E2241, 2, oldChar2, newChar2) );
oldChar2[0] = 0x5C; oldChar2[1] = 0x9A;
newChar2[0] = 0xC8; newChar2[1] = 0x34;
dataList.push_back( Data(0x009E2180, 2, oldChar2, newChar2) ); //for loop count (9A5C)
dataList.push_back( Data(0x009E218C, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E2195, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E219B, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E21A6, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E21B9, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E21C6, 2, oldChar2, newChar2) );
dataList.push_back( Data(0x009E21E5, 2, oldChar2, newChar2) );
oldChar2[0] = 0x60; oldChar2[1] = 0x9A;
newChar2[0] = 0xCC; newChar2[1] = 0x34;
dataList.push_back( Data(0x009E21B3, 2, oldChar2, newChar2) ); //area for CString musName (9A60)
dataList.push_back( Data(0x009E21F2, 2, oldChar2, newChar2) );
oldChar2[0] = 0xC0; oldChar2[1] = 0x98;
newChar2[0] = 0x9C; newChar2[1] = 0x31;
dataList.push_back( Data(0x009E21C0, 2, oldChar2, newChar2) ); //area for CString* (98C0)
dataList.push_back( Data(0x009E2207, 2, oldChar2, newChar2) );
oldChar2[0] = 0xBC; oldChar2[1] = 0x98;
newChar2[0] = 0x98; newChar2[1] = 0x31;
dataList.push_back( Data(0x009E2230, 2, oldChar2, newChar2) ); //returnVal (98BC)
dataList.push_back( Data(0x009E224C, 2, oldChar2, newChar2) );
patchList.push_back( Patch("Double size limit of SONGLIST.2DA (entry treated as signed byte, so 128+ won't play)", dataList) );
dataList.clear();
//make a fifth test patch
//section that stops the music
oldChar[0] = 0x88;
newChar[0] = 0x89;
dataList.push_back( Data(0x004CC6F7, 1, oldChar, newChar) );
char oldChar15[] = {0xA8, 0x8A, 0x4D, 0xA8, 0x88, 0x4D, 0xF4, 0x0F, 0xBE, 0x55, 0xFC, 0x0F, 0xBE, 0x45, 0xF4};
char newChar15[] = {0xF4, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8B, 0x55, 0xFC, 0x90, 0x8B, 0x45, 0xF4, 0x90};
dataList.push_back( Data(0x004CC708, 15, oldChar15, newChar15) );
char oldChar4[] = {0x0F, 0xBE, 0x45, 0xF4};
char newChar4[] = {0x8B, 0x45, 0xF4, 0x90};
dataList.push_back( Data(0x004CC735, 4, oldChar4, newChar4) );
//section that starts the music
oldChar[0] = 0x88;
newChar[0] = 0x89;
dataList.push_back( Data(0x004D4892, 1, oldChar, newChar) );
oldChar4[0] = 0x0F; oldChar4[1] = 0xBE; oldChar4[2] = 0x45; oldChar4[3] = 0xF8;
newChar4[0] = 0x8B; newChar4[1] = 0x45; newChar4[2] = 0xF8; newChar4[3] = 0x90;
dataList.push_back( Data(0x004D489D, 4, oldChar4, newChar4) );
patchList.push_back( Patch("Treat song entries as DWORD instead of BYTE", dataList) );
dataList.clear();
Edited by Ascension64, 27 May 2009 - 06:02 AM.