lurker's comment:
The theoretical brick wall I've run into is that I haven't thought of a way to allocate new memory for the running process. So, I could update existing structures just fine, and look for certain triggers to do so. Doing that is limited primarily by the fact that it would take a lot of time, which so far I've put towards other things. But what if you wanted to add a new unit to the map? How to add that memory and have it be added in a way that Civ (1 or 3) would recognize it seems like a very difficult problem to me. Not that you can't do interesting things even without that, but if you have ideas as to how to get around that, I'd be curious to hear them.
For Civ 1 it is pretty clear: most of the necessary memory to run the game is allocated once and then its size and shape almost never change.
At least the main game data is always at the same place in memory.
For example, the entire memory necessary to store 8*128 units is statically preallocated (at ds:90F4), with empty values (00 or FF), so if you want to add a new unit, all you have to do is modify those values in the right place.
I don't how Civ 3 is coded: newer programming languages, especially OOP who rely a lot on object instantiation, must create a significant mess in memory, but I also know that relying a lot on object instantiation is usually a bad practice performance-wise, so maybe Civ3 still has some static anchors to help...
Anyhow, the main problem is to locate the base address of CIV.EXE (or DOSBox) in memory - from this address, all individual offsets to atomic CIV data elements are always the same.
In fact I have played around with
ProcessHacker and DOSBox+CIV1 (in Win7) and I could successfully change which CIV I was playing, right in the middle of the game (as well as some text strings here and there).
With ProcessHacker, I was able to locate the address segments used by DOSBox, and then in DOSBox's memory, I looked up the string "
MS Run-Time Library - Copyright (c) 1988, Microsoft Corp" which is at the beginning of CIV.EXE's data segment (ds:0x8).
Besides this, I have some working samples of Java code (using JNA) to read and write an external process memory in Windows (user32 + kernel32) and in Linux (ptrace).
So the whole thing is setting in place, but that doesn't resolve the core issue: how to find the base memory address?