musicfreak
Warlord
- Joined
- Nov 30, 2007
- Messages
- 274
Hey guys, long time. I'm back, and with lots of suggestions to improve the speed of this mod. I was looking at the Python code recently and the reason it's so slow is because there are many big loops that are either completely unneeded or can be slimmed down a lot. I'll go through all the suggestions I can think of, but you get the idea. Most of these have to do with UHV conditions.
Persia
Control 8% of world territory in 600 AD (Turn 151)
This is more of a fix than an optimization, but it says "in" 600 AD, not "by" 600 AD, but the code checks for the condition every turn until 600 AD. One of those should be fixed.
Control 7 world wonders in 700 AD (Turn 161)
Instead of looping through every wonder and every city, every turn, use events. Just increment the counter when Persia builds a wonder (onBuildingBuilt, and onCityAquired for cities with wonders in them), and decrement it when a wonder is lost (onCityLost). Then you wouldn't have to do any calculations or loops every turn, only when wonders are built/lost. You already do this with the Maya, the only difference here is you have to keep count, which is easy with pickle.
Rome
Build 5 Barracks, 5 Aqueducts and 5 Amphitheatres by 450 AD (Turn 143)
Again, use the onBuildingBuilt event instead of looping through each city every turn and checking the number of each building.
Russia
The Power of General Winter: Enemy units in Russia take damage every turn
This is just a small thing, but how about skipping the loop if Russia is not at war with anyone? I don't know how easy this is to check though...if it requires looping through each civilization and checking, then maybe it's not worth it.
Custom events
This is a fairly big suggestion, so bear with me. What I'm proposing is to make custom events using the Civ SDK (CvGameCoreDLL.dll). For example, for all the "...control...by..." objectives, you could make a plotOwnerChange event that fires whenever the owner of a plot changes. This could be easily done by just adding a couple lines of code to CvPlot::updateCulture or CvPlot::doCulture (probably the latter) to fire the event if the new owner is different. My reasoning for this is that plot owners are not changed every turn, and even if they were, you wouldn't have to loop through a bunch of plots in a region, which would (theoretically) increase the speed of the mod substantially. This would help especially with RFC RAND, since there are no static coordinate-based "regions"; everything is dynamic, which makes it slower (theoretically...I haven't played long enough to find out).
I'm not an expert on this stuff, and I'm pretty new to the Civ SDK, so let me know if there are any problems in doing this, or if, with the way Civ implemented events, this would actually be slower, etc. I am a programmer, but I've never really studied Civ's algorithms before, so like I said, I'm not an expert.
Here are some examples:
Carthage
Secure through trade or take control of 3 dye resources by 350 AD (Turn 138)
Create the events resourceAquired and resourceLost, and have a counter that increments every time Carthage aquires a source of die, and decrements every time they lose one. This isn't really that big, since the current check is pretty fast, but it's a speed improvement either way.
Arabia
Control or make vassal states of Egypt, Spain and Carthage by 1300 AD
There is already a vassalState event, so use that together with the onPlotOwnerChange event I mentioned above. When one of the Civs is either controlled or vassalized, check it off using pickle, and stop checking it in the future. Then, when Arabia gains a plot, check against the remaining Civs and see if another can be "checked off". For example, if you've already vassalized Spain, there's no need to check its territory, so you only need to check if the plot you gained is in Charthage or Egypt.
Mongolia
Control China by 1300 AD
Control 10% of world territory by 1500 AD
Use the onPlotOwnerChange event mentioned above. When Mongolia gains a plot, calculate the land percent and store it using pickle. If it becomes 10%, Mongolia completes the objective and the check can be skipped in the future.
The Netherlands
Secure or get by trade 7 spices resources by 1775 AD
Same thing as Carthage, but Spices instead of Dye.
America
Secure 10 oil resources by 2000 AD
Same thing as well.
I hope this helps in making the mod faster. Please note that I've never tried using custom events and am unable to, as I don't have Visual Studio on my computer, and am not planning on getting it. (Is there a "lighter" version of it somewhere? Preferably free? I'm not talking about VS Express.) I have, however, tried a couple of the Python optimizations, and they've helped noticeably. Unfortunately, my changes accidentally got overwritten when I updated the mod, so I am unable to share the exact code differences with you.
Cheers.
EDIT: I'll attach the latest version of my little "RFC Optimized" project here so it's easily accessible.
Persia
Control 8% of world territory in 600 AD (Turn 151)
This is more of a fix than an optimization, but it says "in" 600 AD, not "by" 600 AD, but the code checks for the condition every turn until 600 AD. One of those should be fixed.
Control 7 world wonders in 700 AD (Turn 161)
Instead of looping through every wonder and every city, every turn, use events. Just increment the counter when Persia builds a wonder (onBuildingBuilt, and onCityAquired for cities with wonders in them), and decrement it when a wonder is lost (onCityLost). Then you wouldn't have to do any calculations or loops every turn, only when wonders are built/lost. You already do this with the Maya, the only difference here is you have to keep count, which is easy with pickle.
Rome
Build 5 Barracks, 5 Aqueducts and 5 Amphitheatres by 450 AD (Turn 143)
Again, use the onBuildingBuilt event instead of looping through each city every turn and checking the number of each building.
Russia
The Power of General Winter: Enemy units in Russia take damage every turn
This is just a small thing, but how about skipping the loop if Russia is not at war with anyone? I don't know how easy this is to check though...if it requires looping through each civilization and checking, then maybe it's not worth it.
Custom events
This is a fairly big suggestion, so bear with me. What I'm proposing is to make custom events using the Civ SDK (CvGameCoreDLL.dll). For example, for all the "...control...by..." objectives, you could make a plotOwnerChange event that fires whenever the owner of a plot changes. This could be easily done by just adding a couple lines of code to CvPlot::updateCulture or CvPlot::doCulture (probably the latter) to fire the event if the new owner is different. My reasoning for this is that plot owners are not changed every turn, and even if they were, you wouldn't have to loop through a bunch of plots in a region, which would (theoretically) increase the speed of the mod substantially. This would help especially with RFC RAND, since there are no static coordinate-based "regions"; everything is dynamic, which makes it slower (theoretically...I haven't played long enough to find out).
I'm not an expert on this stuff, and I'm pretty new to the Civ SDK, so let me know if there are any problems in doing this, or if, with the way Civ implemented events, this would actually be slower, etc. I am a programmer, but I've never really studied Civ's algorithms before, so like I said, I'm not an expert.
Here are some examples:
Carthage
Secure through trade or take control of 3 dye resources by 350 AD (Turn 138)
Create the events resourceAquired and resourceLost, and have a counter that increments every time Carthage aquires a source of die, and decrements every time they lose one. This isn't really that big, since the current check is pretty fast, but it's a speed improvement either way.
Arabia
Control or make vassal states of Egypt, Spain and Carthage by 1300 AD
There is already a vassalState event, so use that together with the onPlotOwnerChange event I mentioned above. When one of the Civs is either controlled or vassalized, check it off using pickle, and stop checking it in the future. Then, when Arabia gains a plot, check against the remaining Civs and see if another can be "checked off". For example, if you've already vassalized Spain, there's no need to check its territory, so you only need to check if the plot you gained is in Charthage or Egypt.
Mongolia
Control China by 1300 AD
Control 10% of world territory by 1500 AD
Use the onPlotOwnerChange event mentioned above. When Mongolia gains a plot, calculate the land percent and store it using pickle. If it becomes 10%, Mongolia completes the objective and the check can be skipped in the future.
The Netherlands
Secure or get by trade 7 spices resources by 1775 AD
Same thing as Carthage, but Spices instead of Dye.
America
Secure 10 oil resources by 2000 AD
Same thing as well.
I hope this helps in making the mod faster. Please note that I've never tried using custom events and am unable to, as I don't have Visual Studio on my computer, and am not planning on getting it. (Is there a "lighter" version of it somewhere? Preferably free? I'm not talking about VS Express.) I have, however, tried a couple of the Python optimizations, and they've helped noticeably. Unfortunately, my changes accidentally got overwritten when I updated the mod, so I am unable to share the exact code differences with you.

Cheers.
EDIT: I'll attach the latest version of my little "RFC Optimized" project here so it's easily accessible.