@miauw62
You misunderstood me, the problem is not the performance, the problem are solely the crashes and broken safefiles. A mature fortress will crash around twice per real-life hour, and every few days a safefile gets corrupted, and if you safe it may crash too. So the most important thing in your mind while playing is typically, "Should I safe and risk a crash on saving, or should I play on, and risk a random crash", and you have to back up safefiles everyday, and run "tweak fixmigrants" and "clean all" every five minutes. I is also odd, that DFHack is absolutely mandatory to really play the game, and Toady even banned the guy who created DFHack (hireing him would have been better).
Videogames are always more than just art. If you make a graphics heavy game, like a first.-preson-shooter, you should spend a lot of time on performance, writing graphics functions in assembly, and when you make a deep game like dwarf fortress, you should spend a lot of time on stability, writing failsafe funtions in C.
Verifying, if a pointer existst is usually done with NULL pointers, but if a pointer contains garbage, it will still crash. Also I read every single dumplog from Dr. Watson when DF crashes, and most crashes are actual access to NULL pointers. (If you see something like wrtiting to adress 50 it are usually instructions like MOV EBX,[EBP+10], MOV EAX,[EBX+50], there 50 is the offset inside a NULL structure, and EBX the NULL pointer, read from a parameter on the stack, acessed with EBP.) So appearently some functions assume to always get valid pointers.
It is possible to intercept garbage pointers with arrays :
struct dwarf{
bla; bla; bla;
};
struct dwarf *dwarves; /* Array allocated at load time */
int max_dwarves; /* Maximum number of Dwarves, set at load time */
void build_consturction( struct job *j, blabla)
{
struct dwarf *worker;
blabla;
blabla;
worker=job->worker; /* load a pointer from the job */
if(worker<dwarves) return; /* pointer too small */
if(worker>=(dwarves+sizeof(struct dwarf)*max_dwarves)) return; /* pointer too large*/
blablabla(worker);
blabla;
}
If job was thrashed by a growing tree, or watever, we load an invalid pointer in worker. Accessing this pointer with blablabla() will cause a segfault or damage data, but the two lines before using it check if the pointer is out of range, so you wont get a segfault.
For extra proofing, you can even check, if the pointer is misaligned with "if((worker-dwarves)%sizeof(struct dwarf)) return;"
If you use a storage-class from the C++ library istead of an array, you don't have acces at this low level, and the library functions will happyly crash. The only workaround is, to rewrite all the strorage classes yourself, and even then the functions using the classes must handle the error, so you have even more work, than in standart-C.
The Key is defensive programming. If you look at the source code at NetHack, you see haw it works. Problems that can be fixed, call the function impossible() that displays a "Programe in disorder" message, and if it can't be fixed, it is at least anounced with panic(), before trying to safe, and aborting. This shows, that the Dev Team thought about the problem.
---
Limits don't mean, what the limits are fixed for everybody. You just set the number in an init file.
Lets say your session has slots for 200 dwarves, and you have 200 dwarves. A birth times out, you get a Message :
THE CHEESE MAKER URIST BLABLA IS PREGNANT : ABORT (G)AME ABORT (B)ABY
You pick ABORT (G)AME, and your game IS SAFED normally. You edit the init file and set the Dwarf limit to 201. You restart. During loading, the game shows, that it is actually loading in the moment (instead of freezing with a black screen), and suddendly you see the message OUT OF MEMORY, LOADING FAILED (good programmers actually check if alloc() returns a NULL pointer). You now see, that the game can't handle the baby, set the limit back to 200 and choose (A)BORT BABY.
Another player in the same situation might have enough memory and can continue with the limit of 201.
Windows, Linux and DPMIs have virtual memory, so you can actually allocate gigabytes on a 486er, but everything is slowed down by writing the PAGEFILE.SYS . Then Dwarf Fortress crashes from too much stuff, it usually hits a boundary of the adress space or the operation system. Yes, your game can need multiple GIGABYTES on a 2x2 Embark, because everything is covered in blood, and everytime you safe unused data isn't free()ed, so quitting, restarting and running clean all will let the memory usage drop to 50MB
There is nothing bad abouts limits. Other videogames have limits, CAD programes have limits and file systems have limits. The only important thing is, to know the limits and safely fail if the limit is hit, instead of crashing for the sake of freedom.