Moff Jerjerrod
Deity
Has anyone here experience members of a locked alliance declaring war on each other? I believe this has something to do with my game freezing up playing a user created scenario and the flintlock mod.
This can happen when one of the civs signs a mutual protection pact with a third party, and then the other civ attacks that third party. It isn't caused by this mod.Has anyone here experience members of a locked alliance declaring war on each other? I believe this has something to do with my game freezing up playing a user created scenario and the flintlock mod.
This can happen when one of the civs signs a mutual protection pact with a third party, and then the other civ attacks that third party. It isn't caused by this mod.
Awesome work!Big update time. R17 Preview 1 is finally ready, download it from GitHub here. What was holding it up was that I was tinkering with the code for calculating trade networks, and ended up replacing most of it from the base game. I had a feeling that the base game's implementation was way too slow, that calculating the trade network is not that complicated, and especially that it shouldn't have to blow up in the late game. My feeling was right! I was able to get my reimplementation of the trade network to run ~35x faster than the original in an extreme test case. It's enough to make maps like Monstrosity playable all the way to the end.
My extreme test case is a late industrial era Monstrosity game with many wars going on. Previously (*) trade net calculations between turns would take 894 sec out of a total turn time of 958 sec. My custom trade net code runs in only 24.9 sec, reducing the total turn time to 93.4 sec. This is an extreme case since ~90% of the turn time is spent computing trade networks, usually it's less than that. I also measured times on an earlier save from that same game, in the early industrial era without many wars. In that more typical case, trade net calculations previously took 86 sec of an overall 153 sec turn. The custom code reduces that to just 3.85 sec, bringing the overall turn time down to 74 sec.
(*) Aside: "previously" here means with C3X R16, so including the improvement loop optimization. Out of curiosity, I turned that off and found it increased the trade net time to 943 sec and overall turn time to 1008 sec. So optimizing the improv. loops is worth about 5% in that case. That is not surprising since the Monstrosity scenario doesn't add any city improvements and the trade net calculations take so long they dwarf everything else. Optimizing the trade net makes the improv. loop optimization look better. With the trade net optimized and the improv. loops not, the trade net takes 50.0 sec of an overall 117 sec turn time, so the improv. loop optimization further reduces that by about 20%.
As for what the optimizations entail, by far the biggest improvement comes from preserving pathfinding info across jobs. Basically, when computing sea trade, the game loops over all pairs of cities with harbors that are not already connected by roads and tries to find a path between them. It processes the pairs independently, clearing the pathfinder's internal state before each search. That's extremely wasteful. For example, trying to path from city A to city B is done by crawling outward from A building up a set of reachable tiles in the direction of B (Wikipedia has a good illustration). Either you eventually reach B, and so there is a path, or you run out of reachable tiles, and can conclude no path exists. If next you want to check for a path between cities A and C, you can get a big head start by reusing the results from the search from A to B, since those results already include many tiles reachable from A. In the extreme case where there is no path from A to B, you've already done the work of searching for a path from A to C. That's because the only way to conclude there is no path is to visit every tile reachable from A, so either you've already visited C and there is a path A->C or you haven't and there isn't.
In fact, you can do even better than that. Imagine you've searched for paths connecting A->B, A->C, A->D, etc., building up a set of reachable tiles along the way. Next you're asked if there's a path B->C. If B is in the set of tiles reachable from A, you can again reuse the pathfinder state since A and B are in the same set of reachable tiles.
Reusing the pathfinder state is not the only optimization I've done. Since I reimplemented the pathfinder logic for the trade network entirely I had the opportunity to make many improvements. Two more notable ones:
In terms of final performance, it's the reusing of the pathfinder's state that's responsible for almost all of the speed up. The above two improvements I mentioned only speed up trade net calculations by about 30%. I also replaced the calculation of the road network and managed to speed that up by about 2x. That sounds good but it really doesn't matter since road network computations take up 0.1% or less of the overall turn time.
- The game's data structures make very poor use of the CPU cache. The game was written in a typical unoptimized object-oriented fashion meaning all the data that makes up a tile has been piled into a tile object and then the game map is an array of tile objects. The problem with that is when the CPU checks, for example, the terrain of a tile, it pulls into its cache many unrelated parts of the tile object which it will not use. That stuff gets pulled in simply because it's what close in memory. If soon after the CPU needs to check the terrain of the surrounding tiles, as it does while pathfinding, that data will probably not already be in the cache. It would be faster to store the terrain data separately and arrange it so that data for nearby tiles is kept nearby in memory. The replacement logic can't replace the original tile or map layout but what it can do is stash the relevant tile data in a cache-efficient structure after it's accessed once, so all later accesses to the same tile's data are done in a cache-efficient manner.
- The logic for checking sea trade accessibility at a tile level has been simplified so it only runs once per tile. The base game is inefficient here in that it checks accessibility between tiles, not per-tile, even though when you boil down the rules they only matter per-tile. For example, say you want to know if a sea route can pass between tiles T and U, and then later between tiles T and V. The base game will make four checks here, two for tiles T & U, and another for tiles T & V. However, you only need to make three checks here, one for each tile, since a sea route can pass between any two adjacent accessible tiles.
By the way, you might be wondering if that's really true, if any two adjacent, passable sea tiles can have a sea trade route passed between them. What about tiles separated by an isthmus? For example, imagine four tiles in a diamond shape, where the left and right tiles are land and the top and bottom are water. In that case, you can't pass naval units between the top and bottom tiles (unless you've activated the C3X land-sea intersections option) but you actually can pass a sea trade route between them. That's an odd little aspect of the game rules, and I'm not sure why the game is programmed that way. It may have been done for performance reasons, or maybe the devs simply never thought of it.
To get reliable numbers for the turn times, I added the ability to measure them in-game, the option is named measure_turn_times (duh). If activated, you'll get a popup at the end of every interturn reporting how long it took, including specifically how long it took to recalculate the trade networks. Some of you might find this interesting, for example if you have a very slow save and want to know how much of the slowdown is due to the trade network.
There's a lot more in R17 Preview 1 than that. It also contains many extensions to zone of control and defensive bombard. Thanks to Vaughn for commissioning those. Here's the full list of changes:
Here's a little preview of what defensive bombard and zone of control can now do. I could have posted this version a day sooner if I hadn't taken the time to make these, so be sure to appreciate them:
- Optimize computation of trade networks
- For details, see the info text file in the Trade Net X folder
- Option to measure turn times
- Zone of control changes
- Allow land-to-sea and sea-to-land attacks, only using bombard stat
- May be lethal
- May be exerted by air units
- Show attack animation even when attacker is not at the top of its stack
- Defensive bombard changes
- May be lethal
- May be performed by air units
- Invisible, undetected units may be made immune
- May be performed multiple times per turn with blitz
- Naval units in a city may perform defensive bombard vs land attackers
- Allow precision strikes to target tile improvements
- Option not to end a unit's turn after it bombards a barricade
- Option to allow bombardment of other improvements on a tile with an occupied airfield
- Option to boost OCN increase from forbidden palaces in non-communal governments
- Fix graphical issues when running on Wine
- Option to allow defensive retreat on water tiles
- Overhaul implementation of shared visibility for simplicity and correctness
- Display total city count (disabled by default, appears on demographics screen)
View attachment 677787
Land units can exert ZoC over passing sea units & vice versa.
View attachment 677788
Air units can exert ZoC.
View attachment 677789
And they can perform defensive bombardment as well.
View attachment 677790
Defensive bombard & ZoC can be made lethal.
That's it! Please report any bugs if you find them. I'm 99% sure that my reimplementation of the trade network calculations will give exactly the same results as the original game, but it's always possible I missed something.
It would. I've identified the game function that computes combat odds but I haven't looked into modifying it yet. Even if there's no convenient way to modify it, I could replace the whole since it's relatively short.Flintlock, will it ever be possible to make damaged unit weaker than the same unit in full health? I.e. damaged artillery delievering weaker bombardment.
It would be possible with enough effort. The awkward thing about zone of control is that it's all integrated into one big function that's called whenever a unit moves between tiles. That function also includes the logic for coastal fortresses as they exert a form of ZoC. The logic for CFs and unit ZoC is tangled together since the way ZoC works is the strongest attacker gets to take the shot. I don't see any convenient way to change only how CFs work. One thing I could do is cut out the original CF logic then insert some code at the end to damage units by CFs based on the tile they end up in, but then units could be hit twice by ZoC, first by a unit then again by a CF. Also if you want to make the CF sound effect louder, the easiest way would be to edit its WAV file.Since you are addressing a lot of Zone of Control and defensive bombard issues in this release, would it be possible to fix Coastal Fortresses too?
When I tested this it worked properly for me. Can you share more details about how you have things configured? Ideally if you could post a small scenario that isn't worked as expected, I could look into that.From what I've tested and played the Charm unique command on the units combined with the configuration sheet at the moment converts these units back to C3C targeting instead of the intended PTW targeting. Only when I manually added the names of my artillery and naval units onto the manual PTW style targeting list did they target PTW style.
It's the same mod just a newer version. The only difference with the preview versions versus the regular versions is the previews are uploaded to GitHub instead of CFC and haven't been as thoroughly bug tested.How can I update it to this version? I have the latest one before this one but I've been very busy and I don't remember how to do it, it's the same mod, I understand, right? C3X but improved.
Sorry for hijacking the thread but I know what scenario is being referenced to and it has no MPPs enabled. What it does have is the Spy Missions and AI civs declaring war on locked ally for spying on them. How do people handle such situations in their scenarios?Thank you for pointing that out to me! That makes total sense. I will try disabling MPP in the scenario and see if that fixes my problem.![]()
Another small issue is that the sound that plays when the CF fires is quite faint, it would be nice if it was more obvious.
I had thought about editing the WAV file, but I hadn't looked hard enough to find it. But I have now, it is called City Fortress.wav in the original Civ 3 Sounds folder. Sorry for bringing up something I could fix easily myself.Also if you want to make the CF sound effect louder, the easiest way would be to edit its WAV file.
Originally the CF follows the ZoC rule: If a ship already adjacent to the Fortress moves to another adjacent tile, then the CF will (attempt to) shoot at it. This means that a CF inside a bay (where there is only 1 coastal tile adjacent) will never fire at enemy ships. Furthermore, the AI tends to move their warships in from deeper waters, bombard, then pull their ship straight out to sea again. Which doesn't allow for the ZoC rule to trigger, and renders the CF's attack mostly useless. In my opinion it would be better and more logical if the CF would shoot immediately, every time an enemy ship enters a tile within reach.
I think that is a good idea and it would solve the problem.I don't see any convenient way to change only how CFs work. One thing I could do is cut out the original CF logic then insert some code at the end to damage units by CFs based on the tile they end up in, but then units could be hit twice by ZoC, first by a unit then again by a CF.
Yeah, on second thought a unit being hit by ZoC and a CF at the same time isn't really much of a problem. It would very rare anyway. I'm more concerned that the AI wouldn't understand the new rules and would end up taking a lot of damage. I don't think the AI understands ZoC at all, and the only reason that isn't a problem is that ZoC is so weak. Anyway, it's worth trying out.I think that is a good idea and it would solve the problem.Whenever an enemy ship enters a tile adjacent to a Coastal Fortress, the fortress attempts to shoot at it. That's what a real fortress would do. No need for Zone of Control logic. The fact that both a unit and a CF might take one shot each I don't see as a problem.
...
By the way, this may be interesting to know for modders using Coastal Fortresses in their mod: I did some extensive testing a couple of years ago, and proved statistically that the number you input as a Naval combat value in the Editor needs to be 20 times stronger than what you are aiming for. At least on my system. So, if you want the CF to actually shoot with a strength of 8 and have a 50/50 chance of hitting a ship with 8 defense, you need to input a Naval combat value of 160.
Honestly I haven't thought about it since. Though looking over the unit maintenance code again, it should be easy to increase maintenance for certain types. The game has a function that counts a player's maintenance-free units. It's a short function that simply counts how many units in the game are owned by the player and either have the king flag or are of a foreign race (e.g. slave workers). I could replace that function but modify it so it reduces the count or not for each unit depending on its type. It's fine if the maintenance-free unit count is negative since it's subtracted off the player's total unit count to determine how many units they have that require maintenance.About modifying the unit base maintenance for units and enabling arbitrary limits based in things like the amount of buildings/cities. I asked this quite a few moons ago and at the time you replied that limits looked somewhat easy and that maintenance cost might be workable too. Have you gave this any thoughts in the meantime?
If you could code shield-weight-based unit costs into the patch-framework, that would be awesome. And it would be even more awesome if the modder could specify the threshold-increment for the maintenance-cost increase.Would it be sufficient to tie the additional maintenance to the unit's shield cost? Like for every 100 shields a unit costs to build, it costs an additional unit's worth of maintenance?
I agree that the AI seems to not have a clue and totally disregard ZoC. I don't think there's any AI logic to avoid it. But, knowing the formula, modders can regulate how powerful the Coastal Fortress will be in practice by inputting higher or lower Naval combat values. Looking at the formula, it seems the correct number to multiply by is 16, not 20 as I thought. To sum up the formula in simpler words, just multiply the number you actually want with 16. For example, to get a Coastal Fortress with attack strength of 8, input 128 as a Naval combat value (8 x 16 = 128).I'm more concerned that the AI wouldn't understand the new rules and would end up taking a lot of damage. I don't think the AI understands ZoC at all, and the only reason that isn't a problem is that ZoC is so weak. Anyway, it's worth trying out.
Those numbers check out based on the formula I worked out by reading the game code. A CF with strength 8 attacking a ship with defense 8 would deal damage 5.9% of the time and if boosted to strength 160, it would do damage 55.6% of the time. The formula for the chance to do damage by ZoC is: 1 - (D*16 / (D*16 + A)), where D is the moving unit's defense and A is the ZoC attack/bombard strength. This also applies to coastal fortresses. A ZoC attack is much less dangerous to the defender than one round of combat.
Would it be sufficient to tie the additional maintenance to the unit's shield cost? Like for every 100 shields a unit costs to build, it costs an additional unit's worth of maintenance?
Being able to give EXP Civs some half-price buildings (Gran? Duct?) would certainly help buff that currently weak trait a little.1) Discount for buildings flagged as expansionist and industrious. As I see, it doesn't work in stock game now.
Being able to give EXP Civs some half-price buildings (Gran? Duct?) would certainly help buff that currently weak trait a little.
The COMM building-flag also does not give half-price buildings -- but it does at least allow all the COMM-buildings to be made maintenance-free with a Smiths-equivalent GW.
But IND...? Unless the IND flag was also removed from Factories, or the modder restricted where they could be built (e.g. only near rivers, or only where Iron is in the BFC), having them cost only 120 shields would likely make them OP for the IND Civs -- just like having half-price 'Ducts is yet another OP-making factor for the AGRI Civs (I removed that AGRI building-flag in my personal mod, but I also made Ducts require Freshwater in the BFC, 80s to build, and 2GPT to maintain...)
That is possible and should be relatively easy. I recently discovered that the game already maintains a count of how many units of each type each player has in production, so that simplifies things. I'd probably have the limits defined by a list of pairs of unit types and numbers, for example [Missionary: 3, Spy: 3, "Corporate Executive": 5]. That should be the easiest way unless you want many unit types to have the same limit.And about unit limits, having them as a property for each unit could work or it would be better defined in a list? Or is it possible at all?
Welcome! Glad to hear you're enjoying the mod. About your list:BTW, hello everyone! I joined right now, but I read this forum for a long time. Flintlock patch really makes a big deal and I'm looking forward for further updates. I got some ideas and I wonder is it ever possible or maybe even you might implement it once.
It would be easy to limit paratroopers to one airdrop per turn, except the catch is I still don't have a way to pack extra data into save files so the record of which units have already airdropped would be lost when saving & reloading. I thought about making airdrops cost one move but then paratroopers would need to be 2+ move units to take advantage of that. Maybe the best solution is to make airdrops free only if they target enemy territory. That's a weird rule from a realism standpoint, but hey, if it works...