BrokenRegistry / Rotp-Fusion

Other
22 stars 4 forks source link

Display correct expected growth in Eco slider when transports are incoming #5

Closed dHannasch closed 1 year ago

dHannasch commented 1 year ago

https://github.com/BrokenRegistry/Rotp-Fusion/commit/200a69a61348035b809a084687ad1f8903b88f07 is very cool. I think we can go further, for the case when transports are one turn out.

Currently, when there are transports arriving this year, the next turn's actual natural population growth will be different from what the EmpireColonySpendingPane predicted. Lower, if the incoming transports moved the colony further from half-full (that is, if the colony was already half-full); higher, if the incoming transports moved the colony closer to half-full (as in the case of a just-starting-out colony receiving its first transports).

This changes the EmpireColonySpendingPane display to show the correct, transport-aware growth. It also bites the bullet and includes the incoming transports in the growth number, which seems consistent if the outgoing transports are subtracted from the growth number (as they currently are).

This makes the displayed growth match the actual next turn's population for the most common cases. For example, when just starting out with autotransport enabled, the first colony shows population growth of -23 from sending transports to the second (and then calculating natural population growth with its new, lower population); with this change, the second shows, when those transports are due to arrive this year, a population growth of +25, matching that the population will in fact increase from 2 to 27 over the course of the year.

Obviously the EmpireColonySpendingPane shouldn't display information that the player is not privy to, but the player of course does know about their own transports.

There is, of course, a catch. When we have outgoing transports, those pops are definitely going to leave. When there are incoming transports, those transports are going to land...unless they're shot down.

I do think displaying the transports is one step more sophisticated than not; it's going to be more commonly correct. But I think there's a sliding scale of sophistication that we could proceed further along, but I wanted to gauge your reaction before getting at all fancy with that.

  1. Take no account of incoming transports at all. (This is what it currently does.)

  2. Always assume incoming transports will arrive. (What this change does.)

  3. Always assume incoming transports will arrive, unless the colony is underSiege(), in which case always assume that none of the incoming transports will arrive.

  4. Check for orbitingEnemyShips() and reduce the number of incoming transports by the number the orbiting enemy ships will shoot down. Conveniently, the player always gets a scan of any enemy ships in orbit around their colony, even if the colony has zero missile bases. So the firepower of the enemy fleet can be calculated using only information already available to the player.

5*. Check for enemy ships arriving next turn and reduce the number of incoming transports by the number those enemy ships will shoot down. Conveniently, this is never needed at all, because friendly transports are always assumed to win the race to the colony; Galaxy.moveShipsInTransit() moves transports before fleets, and StarSystem.acceptTransport() pointedly has friendly transports (but not enemy transports) land immediately instead of going into orbit with the other arriving ships. https://github.com/BrokenRegistry/Rotp-Fusion/blob/main/src/rotp/model/galaxy/StarSystem.java#L399

    public Transport acceptTransport(Transport tr) {
        // friendly transports always immediately land
        Colony col = colony();
        if ((col != null) && (col.empire() == tr.empire())) {
            if (!colony().inRebellion()) {
                colony().acceptTransport(tr);
                return null;
            }
        }
        ...
    }

6. Check for orbitingEnemyShips() and reduce the number of incoming transports by the number the orbiting enemy ships will shoot down, unless the player has a fleet enroute, in which case assume the player knows what they're doing and is going to win the battle, so assume that all* incoming transports will land. Conveniently, this too is not needed at all, because Galaxy.moveShipsInTransit() moves transports before fleets, and StarSystem.acceptTransport() pointedly has friendly transports (but not enemy transports) land immediately instead of going into orbit with the other arriving ships, so friendly war fleets will not arrive in time to save the transports. (From the player's perspective, the "friendly transports are assumed to arrive first" rule giveth and the "friendly transports are assumed to arrive first" rule taketh away.)

7*. Perhaps you see where this is going: And of course ships and missile bases built at the colony also will not finish in time to save the transports: just as transports are assumed to arrive over the course of the year in time to affect natural population growth, the transports arrive before ship and missile base production. In other words, once the enemy ships are in orbit and the transports are arriving, it's too late and there's nothing the player can do to save them, so we really can make a prediction about next turn's population growth based solely on the transports and the firepower of the orbiting fleet.

8. We could take account of detected enemy transports as well, but I don't think there's any real reason to, since enemy transports, unlike friendly transports, are assumed to land at the end of the year. Natural population growth is calculated before* enemy transports land, so it's unaffected, and ground battles are a pretty different thing from arriving friendly transports. (For one thing, they're nondeterministic.)

The starred levels would be more trouble than this is worth anyway; I bring them up only to point out that, with the way the game actually works, 4 would actually be literally exactly correct (based on the information available to the player at the time, ignoring things the player doesn't know about, such as earthquakes). (Which doesn't necessarily mean it would be a good idea, UI-wise, or that it would be something you'd want.)

Obviously the main thing I'm thinking about is just getting the displayed number right in the most common cases (with autotransport enabled, it's very common to have incoming transports). Most colonies at most times are not under siege. But I thought I'd lay out the options just in case your reaction is "Wait, but who says the transports are going to land?"

BrokenRegistry commented 1 year ago

Very good analysis, I like this improvement. Trying to predict war result could be fun to do, but I don't think colony growth will be so important for the player facing an attack! :-)

dHannasch commented 1 year ago

Oh, incidentally, there's something this doesn't fix: sometimes (not always), when transporting out the maximum number of colonists (using the new right-click functionality, for example), the slider will incorrectly show "Growth -1". (That is, next turn the population will be max, just as the transport helper predicted.) I have not been able to figure out why this happens. Since it doesn't always happen and it doesn't reliably correlate with planet size, I assume it has to do with rounding, but all the int-casts in https://github.com/BrokenRegistry/Rotp-Fusion/blob/main/src/rotp/model/colony/ColonyEcology.java#L285 look correct. Most baffling of all, the Colony.upcomingPopGrowth() function that controls the helper literally calls the same upcomingResult() function anyway. The only difference is that Colony.upcomingPopGrowth() actually subtracts from population instead of just leaving it to workingPopulation(), and I don't see how that could matter, since totalProductionIncome() and wasteCleanupCost() and whatnot all use workingPopulation() anyway. https://github.com/BrokenRegistry/Rotp-Fusion/blob/main/src/rotp/model/colony/Colony.java#L1889

Anyway, I just kind of ignored that. This change doesn't make the erroneous "Growth -1" appear in any situations when it didn't already.

BrokenRegistry commented 1 year ago

Yes, this is a very strange behaviour! The difference could be due to the small rounding in the float operations folowed by the "floor" function of int-cast... But this difference should definitly not favor the transport helper predictions! Some very subtle error correlations perhaps!