Update: Check out my wiki page for the latest download of WinROTT.
I've completed the port of all c files to c++ for WinROTT. I'm in the process of making a release for download on the wiki. However, testing showed a subtle bug in the c++ code. The bug manifested itself by automatically loading the first saved game in the list of saved games. (I'll try to get some screen shots, but it's difficult to grab a DirectX screen in full screen mode.) I was able to track the problem down to a function that was cast to a different type of function pointer. (Yes, c++ will allow this, so you have to be careful when casting method pointers.)
As the following code shows, WinROTT makes extensive use of structs and arrays of structs that contain method pointers. The bug was caused because CP_LoadGame was cast to a function type void (* menuptr)(void) while the function signature is int CP_LoadGame (int quick, int dieload). WinROTT uses an index into an array and calls the function without any parameters. In the c version of the code, the stack was cleared and the two integer values can be read as 0 (zero). In c++, the stacks appears to be setup correctly, but the values are not cleared. This meant that the parameter quick was almost always true, causing a quick load action. (Quick load is meant to quickly reload game 0 if a character is killed.) As it turns out, the solution to the problem was trivial. Tracking downthe source of the problem was not trivial.
typedef void (* menuptr)(void);
typedef struct
{
int active;
char texture[10];
char letter;
void (* routine)(void);
} CP_itemtype;
CP_itemtype MainMenu[] =
{
{ CP_CursorLocation, "mm_opt1\0", 'N', CP_NewGame },
{ CP_Active, "battle\0", 'C', CP_BattleModes },
{ CP_Active, "mm_opt2\0", 'R', CP_LoadGame },
{ CP_Inactive, "mm_opt3\0", 'S', (menuptr)CP_SaveGame },
{ CP_Active, "mm_opt5\0", 'O', CP_ControlMenu },
{ CP_Active, "ordrinfo\0", 'O', CP_OrderInfo },
{ CP_Active, "mm_opt7\0", 'V', CP_ViewScores },
{ CP_Active, "mm_opt8\0", 'B', (menuptr)NULL },
{ CP_Active, "mm_opt9\0", 'Q', (menuptr)CP_Quit }
};
// In c, the two parameters are set to 0 if the function is called
// as CP_LoadGame(void). In c++, the values are undefined,
// and generally not 0.
int CP_LoadGame (int quick, int dieload)
{
//
// QUICKLOAD?
//
if (quick)
.... rest of method
}
I was able to correct the problem by declaring an overloaded method that fit the correct signature and called the parameterized method with the correct integer values. This is one simple way that c++ is assisting me with the code cleanup. By defining the overloaded method, I did not take need to make any additional changes to the code.
void CP_LoadGame (void)
{
CP_LoadGame(0, 0);
}