private bool CheckForLanceSkips(TeamOverride teamOverride, LanceOverride lanceOverride)
        {
            if (lancesToSkip.Contains(lanceOverride.GUID))
            {
                Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected a lance to skip. Skipping.");
                return(true);
            }

            if (lanceOverride.IsATurretLance())
            {
                Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected a turret lance Ignoring for Extended Lances.");
                return(true);
            }

            return(false);
        }
        private bool CheckForLanceOverrideSkips(LanceOverride lanceOverride, TeamOverride teamOverride, string lanceGUID)
        {
            Main.LogDebug($"[AddExtraLanceMembersIndividualSecondPass] [{teamOverride.faction}] Checking first pass skips in second pass...");

            if (lancesToSkip.Contains(lanceOverride.GUID))
            {
                Main.LogDebug($"[AddExtraLanceMembersIndividualSecondPass] [Faction:{teamOverride.faction}] Detected a lance to skip. Skipping.");
                return(true);
            }

            if (lanceOverride.IsATurretLance())
            {
                Main.LogDebug($"[AddExtraLanceMembersIndividualSecondPass] [Faction:{teamOverride.faction}] Detected a turret lance Ignoring for Extended Lances.");
                return(true);
            }

            return(false);
        }
        private void IncreaseLanceSpawnPoints(ContractOverride contractOverride, TeamOverride teamOverride)
        {
            List <LanceOverride> lanceOverrides = teamOverride.lanceOverrideList;
            int           factionLanceSize      = Main.Settings.ExtendedLances.GetFactionLanceSize(teamOverride.faction.ToString());
            List <string> lancesToDelete        = new List <string>();

            for (int i = 0; i < lanceOverrides.Count; i++)
            {
                LanceOverride lanceOverride        = lanceOverrides[i];
                bool          isManualLance        = lanceOverride.lanceDefId == "Manual";
                int           numberOfUnitsInLance = lanceOverride.unitSpawnPointOverrideList.Count;

                if (lancesToSkip.Contains(lanceOverride.GUID))
                {
                    Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected a lance to skip. Skipping.");
                    continue;
                }

                if (lanceOverride.IsATurretLance())
                {
                    Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected a turret lance Ignoring for Extended Lances.");
                    continue;
                }

                if (isManualLance && numberOfUnitsInLance <= 0)
                {
                    Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected a lance that is set to manual but no units were manually specified. This is a bad contract json setup. Fix it! Ignoring for Extended Lances");
                    continue;
                }

                if ((numberOfUnitsInLance < factionLanceSize) && numberOfUnitsInLance > 0)
                {
                    // This is usually from a 'tagged' lance being selected which has less lance members than the faction lance size
                    if (Main.Settings.ExtendedLances.Autofill)
                    {
                        Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Populated lance '{lanceOverride.name}' has fewer units than the faction requires. Autofilling the missing units");

                        // GUARD: If an AdditionalLance lance config has been set to 'supportAutoFill' false, then don't autofill
                        if (lanceOverride is MLanceOverride)
                        {
                            MLanceOverride mLanceOverride = (MLanceOverride)lanceOverride;
                            if (!mLanceOverride.SupportAutofill)
                            {
                                Main.LogDebug($"[AddExtraLanceSpawnPoints] Lance Override '{mLanceOverride.GUID}' has 'autofill' explicitly turned off in MC lance '{mLanceOverride.LanceKey}'");
                                continue;
                            }
                        }

                        AddNewLanceMembers(contractOverride, teamOverride, lanceOverride, numberOfUnitsInLance, factionLanceSize);
                    }
                    else
                    {
                        Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Populated lance '{lanceOverride.name}' has fewer units than the faction requires. Allowing as a valid setup as 'Autofill' is false");
                    }
                }

                LanceSpawnerGameLogic lanceSpawner = lanceSpawners.Find(spawner => spawner.GUID == lanceOverride.lanceSpawner.EncounterObjectGuid);
                if (lanceSpawner != null)
                {
                    List <GameObject> unitSpawnPoints = lanceSpawner.gameObject.FindAllContains("UnitSpawnPoint");
                    numberOfUnitsInLance = lanceOverride.unitSpawnPointOverrideList.Count;

                    if (numberOfUnitsInLance > unitSpawnPoints.Count)
                    {
                        Main.Logger.Log($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected lance '{lanceOverride.name}' has more units than lance spawn points. Creating new lance spawns to accommodate.");
                        string     spawnerName     = lanceSpawner.gameObject.name;
                        GameObject orientationUnit = unitSpawnPoints[0].gameObject;
                        string     orientationKey  = $"{spawnerName}.{orientationUnit.name}";
                        encounterRules.ObjectLookup[orientationKey] = orientationUnit;

                        for (int j = unitSpawnPoints.Count; j < numberOfUnitsInLance; j++)
                        {
                            Vector3 randomLanceSpawn = unitSpawnPoints.GetRandom().transform.localPosition;
                            Vector3 spawnPositon     = SceneUtils.GetRandomPositionFromTarget(randomLanceSpawn, 24, 100);
                            spawnPositon = spawnPositon.GetClosestHexLerpedPointOnGrid();

                            // Ensure spawn position isn't on another unit spawn. Give up if one isn't possible.
                            int failSafe = 0;
                            while (spawnPositon.IsTooCloseToAnotherSpawn())
                            {
                                spawnPositon = SceneUtils.GetRandomPositionFromTarget(randomLanceSpawn, 24, 100);
                                spawnPositon = spawnPositon.GetClosestHexLerpedPointOnGrid();
                                if (failSafe > 20)
                                {
                                    break;
                                }
                                failSafe++;
                            }

                            Main.Logger.Log($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Creating lance '{lanceOverride.name}' spawn point 'UnitSpawnPoint{j + 1}'");
                            UnitSpawnPointGameLogic unitSpawnGameLogic = LanceSpawnerFactory.CreateUnitSpawnPoint(lanceSpawner.gameObject, $"UnitSpawnPoint{j + 1}", spawnPositon, lanceOverride.unitSpawnPointOverrideList[j].unitSpawnPoint.EncounterObjectGuid);

                            string spawnKey = $"{spawnerName}.{unitSpawnGameLogic.gameObject.name}";
                            encounterRules.ObjectLookup[spawnKey] = unitSpawnGameLogic.gameObject;
                            spawnKeys.Add(new string[] { spawnKey, orientationKey });
                        }
                    }
                }
                else
                {
                    Main.Logger.LogWarning($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Spawner is null for {lanceOverride.lanceSpawner.EncounterObjectGuid}. This is probably data from a restarted contract that hasn't been cleared up. It can be safely ignored.");
                    lancesToDelete.Add(lanceOverride.lanceSpawner.EncounterObjectGuid);
                }
            }

            for (int i = (lanceOverrides.Count - 1); i >= 0; i--)
            {
                LanceOverride lanceOverride = lanceOverrides[i];

                foreach (string lanceToDeleteByGuid in lancesToDelete)
                {
                    if (lanceOverride.lanceSpawner.EncounterObjectGuid == lanceToDeleteByGuid)
                    {
                        Main.Logger.LogWarning($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Removing old lance data from contract. Deleting lance '{lanceToDeleteByGuid}'");
                        lanceOverrides.Remove(lanceOverride);
                    }
                }
            }
        }
        private void IncreaseLanceSpawnPoints(ContractOverride contractOverride, TeamOverride teamOverride)
        {
            List <LanceOverride> lanceOverrides = teamOverride.lanceOverrideList;
            List <string>        lancesToDelete = new List <string>();

            for (int i = 0; i < lanceOverrides.Count; i++)
            {
                LanceOverride lanceOverride = lanceOverrides[i];
                bool          isManualLance = lanceOverride.lanceDefId == "Manual";

                if (lanceOverride.IsATurretLance())
                {
                    Main.Logger.LogDebug($"[AddExtraLanceSpawnPoints] Detected a turret lance. Skipping.");
                    continue;
                }

                // At this point the number of units in a lance should be the expected amount.
                // The unitSpawnPointOverrides will be up to the EL limit set. They will be either:
                //  - Empty, Null, MechDef_None, Vehicle_None, Turret_None (Because they were a non-inheriting unit, manually entered as such or the LanceDef didn't have enough units to fill up the UnitOverride slots)
                //  - Filled resolved units (Because they were resolved by the LanceOverride LanceDef, or manually entered into the Contract Override)
                //  - 'Tagged', 'UseLance' or 'Manual' slots (Because they were not filled up by the LanceOverride LanceDef selection or Autofilled in Pass 1)
                int numberOfUnitsInLance = lanceOverride.unitSpawnPointOverrideList.Count;

                if (CheckForLanceSkips(teamOverride, lanceOverride))
                {
                    Main.Logger.LogDebug($"[AddExtraLanceSpawnPoints] Detected a skip for this Lance. Skipping.");
                    continue;
                }

                LanceSpawnerGameLogic lanceSpawner = lanceSpawners.Find(spawner => spawner.GUID == lanceOverride.lanceSpawner.EncounterObjectGuid);
                if (lanceSpawner != null)
                {
                    AddSpawnPoints(lanceSpawner, teamOverride, lanceOverride, numberOfUnitsInLance);
                }
                else
                {
                    Main.Logger.LogWarning($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Spawner is null for {lanceOverride.lanceSpawner.EncounterObjectGuid}. This is probably data from a restarted contract that hasn't been cleared up. It can be safely ignored.");
                    lancesToDelete.Add(lanceOverride.lanceSpawner.EncounterObjectGuid);
                }


                if (Main.Settings.ExtendedLances.IsAutofillAllowed(contractOverride))
                {
                    // GUARD: If an AdditionalLance lance config has been set to 'supportAutoFill' false, then don't autofill
                    if (lanceOverride is MLanceOverride)
                    {
                        MLanceOverride mLanceOverride = (MLanceOverride)lanceOverride;
                        if (!mLanceOverride.SupportAutofill)
                        {
                            Main.LogDebug($"[AddExtraLanceSpawnPoints] Lance Override '{lanceOverride.name} - {mLanceOverride.GUID}' has 'autofill' explicitly turned off in MC lance '{mLanceOverride.LanceKey}'");
                            continue;
                        }
                    }

                    bool lanceOverrideForced = this.state.GetBool($"LANCE_OVERRIDE_FORCED_{lanceOverride.GUID}");
                    bool lanceDefForced      = this.state.GetBool($"LANCE_DEF_FORCED_{lanceOverride.GUID}");
                    if (lanceOverrideForced || lanceDefForced)
                    {
                        Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected that lance '{lanceOverride.name} - {lanceOverride.GUID}' was forced using a LanceOverride or LanceDef EL enforcement. Skipping autofill.");
                        continue;
                    }

                    List <GameObject> unitSpawnPoints = lanceSpawner.gameObject.FindAllContains("UnitSpawnPoint");

                    if (unitSpawnPoints.Count <= 0)
                    {
                        Main.Logger.LogError($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Lance '{lanceOverride.name} - {lanceOverride.GUID}' has no UnitSpawnPoints. A Lance must have at least one unit spawn point to be valid");
                    }

                    List <string> unitSpawnPointGameLogicGUIDs = (List <string>)unitSpawnPoints.Select(unitSpawnPointGO => unitSpawnPointGO.GetComponent <UnitSpawnPointGameLogic>().GUID).ToList();

                    // Only replace unresolved unit overrides if autofill is on
                    int        originalLanceOverrideSize = this.state.GetInt($"LANCE_ORIGINAL_UNIT_OVERRIDE_COUNT_{lanceOverride.GUID}");
                    List <int> unresolvedIndexes         = lanceOverride.GetUnresolvedUnitIndexes(originalLanceOverrideSize);
                    Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Detected '{unresolvedIndexes.Count}' unresolved unit spawn overrides. Will resolve them before building spawn points.");
                    if (unresolvedIndexes.Count > 0)
                    {
                        LanceDef loadedLanceDef = null;

                        if (!isManualLance)
                        {
                            loadedLanceDef = (LanceDef)AccessTools.Field(typeof(LanceOverride), "loadedLanceDef").GetValue(lanceOverride);
                            Main.LogDebug($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Loaded LanceDef is '{loadedLanceDef.Description.Id}'");
                        }

                        ReplaceUnresolvedUnitOverride(unitSpawnPointGameLogicGUIDs, teamOverride, lanceOverride, loadedLanceDef, unresolvedIndexes);
                    }

                    // Fix any unmatching UnitSpawnPointOverrideGUIDs-to-UnitSpawnPointGameLogicGUIDs
                    FixMisMatchedGUIDs(unitSpawnPointGameLogicGUIDs, teamOverride, lanceOverride);
                }
            }

            for (int i = (lanceOverrides.Count - 1); i >= 0; i--)
            {
                LanceOverride lanceOverride = lanceOverrides[i];

                foreach (string lanceToDeleteByGuid in lancesToDelete)
                {
                    if (lanceOverride.lanceSpawner.EncounterObjectGuid == lanceToDeleteByGuid)
                    {
                        Main.Logger.LogWarning($"[AddExtraLanceSpawnPoints] [Faction:{teamOverride.faction}] Removing old lance data from contract. Deleting lance '{lanceToDeleteByGuid}'");
                        lanceOverrides.Remove(lanceOverride);
                    }
                }
            }
        }