Ok, there are a few issues I can see.
First of all, Player.Scientists() returns the total number of scientists, not the available number of scientists. You could still be trying to assign too many.
Secondly, lift the check for Scientists() > 0 out of that mess, since it's common to all. It would make the code much more readable.
Replace your rather sick looking nested if statements with something simpler. Generally you should use { } to disambiguate things, rather than "else;". What you can do is use (or create) a "min(int a, int b )" type of function. Better yet, if the library you're using allows you to quesry a tech for the max number of scientists for a research, is to combine this with a min function and wrap all that into a "DoResearch" type function.
Ex:
// Note I'm using some fake/nonexistent function names in here
lab.DoResearch(int techID)
{
int availableScientists, maxAssignableScientists, numScientists;
// Get available scientists
availableScientists = Player[lab.ownerNum].GetAvailableScientists();
// Get max scientists for research
maxAssignableScientists = Technology.GetMaxScientists(techNum);
numScientists = min(availableScientists, maxAssignableScientists)
lab.Research(techID, numScientists);
}
My next suggestion is to get rid of the cascaded if statements all together. Use an array of some kind, and a global counter variable that tells you how far into the list you've researched. (Put it in a global struct that gets saved by GetSaveRegions). Then, use the same function as the callback for all research being completed. Each time it's called, it increments the index of the research being completed, and if it's not passed the end of the list, it'll start the next research.
Ex:
// Global AI research order array
// Note: I STRONGLY suggest using symbolic names here,
// such as those listed in OP2Helper\EnumTechID.h,
// or something equivalent for tech files that you wrote.
// (But, here is a numeric exmaple instead)
int AIResearchList[] = {
2701,
2702,
2703,
...
};
// Trigger callback function
SCRIPT_API void AIResearchCallback()
{
if (scriptGlobal.AI.researchIndex < SizeOfResearchList)
{
lab.DoResearch(AIResearchList[scriptGlobal.AI.researchIndex]);
scriptGlobal.AI.researchIndex++;
}
}
Ideally however, you should make sure the DoResearch was actually successful before incrementing the researchIndex. If no scientists were available or the lab is destroyed or disabled or whatever, then the AI will stop researching. You may need to design something to jump start research again if it ever stops. Remember that just because you order a lab to start researching something, it doesn't mean it will necessarily finish. Prime example is if the player destroys their lab. In which case the research callback will never get called to start the AI on it's next research, so all the research will just hang.
Also, you'll need to start off the first research somewhere outside of the callback. (You should probably also initialize the researchIndex to 1, and have the initialization research element 0 in the list).
As for the crash, I suspect maybe the enumerator failed to find the lab. I have no idea what sort of error checking is done on the lab functions from that library you're using. It might just assume that it's always passed a valid lab. If it's not, then it could probably crash the game. There are two possible problems I see with your code for finding the lab. The first one is, it doesn't loop, so if it finds another unit first, then it won't check again for the lab. This could happen if the rect you're using to check in is too big, and another unit moves into that rect. The other problem, is there is no error reporting if it doesn't find a lab. It could be that your rect is wrong, or the lab is destroyed, and no unit at all is ever found. In which case the if is never executed, and your bLab variable is never properly initialized.