コード例 #1
0
ファイル: _HarmonyPatches.cs プロジェクト: lbmaian/JecsTools
 public void Remove(PawnAbilityPointsEntry entry)
 {
     if (list?.Remove(entry) ?? false)
     {
         count--;
         points -= entry.points;
     }
 }
コード例 #2
0
ファイル: _HarmonyPatches.cs プロジェクト: lbmaian/JecsTools
 public void Add(PawnAbilityPointsEntry entry, bool addToList = true)
 {
     if (addToList)
     {
         list ??= new List <PawnAbilityPointsEntry>();
         list.Add(entry);
     }
     count++;
     points += entry.points;
 }
コード例 #3
0
ファイル: _HarmonyPatches.cs プロジェクト: lbmaian/JecsTools
        private static void RebalanceGeneratedPawns(PawnGroupMakerParms parms, List <Pawn> pawns)
        {
            // PawnGroupKindWorker does not guaranteed that the sum of pawn points (pawn.kindDef.combatPower) <= parms.points.
            // Chattel pawns (slaves and animals) are not included in parms.points yet are in __result.
            // Also, PawnGroupKindWorker_Trader decrements parms.points for trader pawns, effectively likewise excluding them.
            var targetPoints = parms.points; // parms.points + special trader points (see below)
            var targetCount  = 0;            // debug only, represents the pawns contributing to targetPoints
            var origCount    = 0;            // debug only, represents the pawns contributing to parms.points

            // Partition into special and normal pawns, calculating combat points for each.
            // Note: entry lists are allocated only if necessary.
            var specials = new PawnAbilityPointsEntries();
            var normals  = new PawnAbilityPointsEntries();
            var excluded = new PawnAbilityPointsEntries(); // debug only

            foreach (var pawn in pawns)
            {
                var entry = PawnAbilityPointsEntry.For(pawn);
                // parms.points is not used for slaves and animals, so exclude them.
                // Using GetTraderCaravanRole() for this, since Humanoid Alien Races patches this method to account for alienslavekinds.
                var traderCaravanRole = pawn.GetTraderCaravanRole();
                if (traderCaravanRole == TraderCaravanRole.Chattel || traderCaravanRole == TraderCaravanRole.Carrier)
                {
                    DebugAdd(ref excluded, entry);
                }
                // Not using TraderCaravanRole.Trader for determining traders - non-null pawn.traders is the authoritative source.
                else if (pawn.trader == null)
                {
                    if (entry.IsSpecial)
                    {
                        specials.Add(entry);
                    }
                    else
                    {
                        normals.Add(entry);
                    }
                    DebugAdd(ref origCount, 1);
                    DebugAdd(ref targetCount, 1);
                }
                else
                {
                    // PawnGroupKindWorker_Trader reduces parms.points by trader's cost, so exclude them as well.
                    if (entry.IsSpecial)
                    {
                        // Not excluding 'special' traders yet, to allow them to be disabled into normal traders in below rebalancing loop.
                        specials.Add(entry);
                        // Since they're not excluded yet, include them in targetPoints (and targetCount);
                        // this will be "undone" if disabled in below rebalancing loop.
                        DebugAdd(ref targetCount, 1);
                        targetPoints += entry.basePoints;
                    }
                    else
                    {
                        DebugAdd(ref excluded, entry, isDebugLog);
                    }
                }
            }

            if (specials.count > 0)
            {
                DebugMessage(rgpMsgPrefix + "Target: " + (targetCount != origCount
                    ? $"#pawns = {origCount} orig + {targetCount - origCount} special trader = {targetCount}, " +
                                                          $"points = {parms.points} orig + {targetPoints - parms.points} special trader = {targetPoints}"
                    : $"#pawns = {targetCount}, points = {targetPoints}"));
                DebugMessage(rgpMsgPrefix + "Special: " + specials);
                DebugMessage(rgpMsgPrefix + "Normal: " + normals);
                DebugMessage(rgpMsgPrefix + "Excluded: " + excluded);

                // Rebalancing loop:
                // Until # special pawns = 0 or # pawns <= 1 or special pawn + normal pawn points <= target points:
                //   If # special pawns > # normal pawns or special pawn points > normal pawn points:
                //     Try to disable a random special pawn into a normal pawn.
                //     If this fails, remove the special pawn instead.
                //     Except if the special pawn being disabled is a trader, just exclude them like normal traders even if disabling fails.
                //   Else:
                //     Remove a random normal pawn.
                var iterCount = 0;                              // debug only
                var destroyed = new PawnAbilityPointsEntries(); // debug only
                while (true)
                {
                    var condition = specials.count > 0 && specials.count + normals.count > 1 &&
                                    specials.points + normals.points > targetPoints;
                    DebugMessage(rgpMsgPrefix + (condition ? $"Rebalance iteration {++iterCount}" : "Final"));
                    DebugMessage(rgpMsgPrefix + "#pawns: " + (targetCount != origCount
                            ? $"{origCount} orig + {targetCount - origCount} special trader = {targetCount}"
                            : $"{targetCount} orig") +
                                 $", {specials.count} special + {normals.count} normal = {specials.count + normals.count}, " +
                                 $"{excluded.count} excluded, {destroyed.count} destroyed");
                    DebugMessage(rgpMsgPrefix + "points: " + (targetPoints != parms.points
                            ? $"{parms.points} orig + {targetPoints - parms.points} special trader = {targetPoints}"
                            : $"{targetPoints} orig") +
                                 $", {specials.points} special + {normals.points} normal = {specials.points + normals.points}, " +
                                 $"{excluded.points} excluded, {destroyed.points} destroyed");
                    if (!condition)
                    {
                        break;
                    }

                    if (specials.count >= normals.count || specials.points >= normals.points)
                    {
                        var entry = specials.list.RandomElement();
                        var pawn  = entry.pawn;
                        specials.Remove(entry);
                        var newEntry = entry.DisableAbilityUser();
                        if (pawn.trader != null)
                        {
                            if (newEntry.IsSpecial)
                            {
                                Log.Warning(rgpMsgPrefix + "DisableAbilityUser on 'special' trader pawn {entry} into " +
                                            $"'normal' trader pawn {newEntry} may not have worked, but keeping this pawn due to trader status");
                                // Even if disabling didn't work, exclude them like normal trader pawns from more rebalancing, but do NOT
                                // "undo" their inclusion in targetPoints, so that rebalancing still has to account for their base points.
                            }
                            else
                            {
                                DebugMessage(rgpMsgPrefix + "Disabled special trader pawn {entry} into normal trader pawn {newEntry}");
                                // Once disabled, exclude them like normal trader pawns from more rebalancing,
                                // and "undo" their inclusion in targetPoints (and targetCount).
                                targetPoints -= newEntry.basePoints;
                                DebugAdd(ref targetCount, -1);
                            }
                            DebugAdd(ref excluded, newEntry, addToList: false);
                        }
                        else
                        {
                            if (newEntry.IsSpecial)
                            {
                                Log.Warning(rgpMsgPrefix + "DisableAbilityUser on 'special' pawn {entry} into 'normal' pawn {newEntry} " +
                                            "may not have worked, so destroying this pawn");
                                pawn.DestroyOrPassToWorld();
                                pawns.Remove(pawn);
                                DebugAdd(ref destroyed, newEntry, addToList: false);
                            }
                            else
                            {
                                DebugMessage(rgpMsgPrefix + "Disabled special non-trader pawn {entry} into normal non-trader pawn {newEntry}");
                                normals.Add(newEntry);
                            }
                        }
                    }
                    else
                    {
                        // Note: Since specCount < avgCount, there's at least one normal pawn.
                        var entry = normals.list.RandomElement();
                        var pawn  = entry.pawn;
                        DebugMessage(rgpMsgPrefix + "Destroyed normal non-trader pawn {entry}");
                        normals.Remove(entry);
                        pawn.DestroyOrPassToWorld();
                        pawns.Remove(pawn);
                        DebugAdd(ref destroyed, entry, addToList: false);
                    }
                }
                DebugMessage(rgpMsgPrefix + "Result: #pawns = {pawns.Count}" +
                             pawns.Join(pawn => $"\n\t{PawnAbilityPointsEntry.For(pawn)}", ""));
            }
        }
コード例 #4
0
ファイル: _HarmonyPatches.cs プロジェクト: lbmaian/JecsTools
 private static void DebugAdd(ref PawnAbilityPointsEntries entries, PawnAbilityPointsEntry entry, bool addToList = true) =>
 entries.Add(entry, addToList);