diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8a496a72..9ae8238e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -11,7 +11,7 @@ { "label": "copy (assets)", "type": "shell", - "command": "copy-assets.sh" + "command": "./copy-assets.sh" } ] } diff --git a/config/Contracts/My_FP_Contract_ID_Example.json b/config/Contracts/My_FP_Contract_ID_Example.json index 85136efa..4b4dd02f 100644 --- a/config/Contracts/My_FP_Contract_ID_Example.json +++ b/config/Contracts/My_FP_Contract_ID_Example.json @@ -9,7 +9,9 @@ "AdditionalLances": { "Enable": true, "EnemyLanceCount": 2, - "AllyLanceCount": 1 + "EnemyLances": ["Damaged_Assault_Battle_Lance", "lancedef_vehicle_d10_dynamic_convoy"], + "AllyLanceCount": 1, + "AllyLances": ["Generic_Light_Battle_Lance"] }, "ExtendedLances": { "Enable": true, diff --git a/contractTypeBuilds/Blackout/common.jsonc b/contractTypeBuilds/Blackout/common.jsonc index 14493995..f5c484eb 100644 --- a/contractTypeBuilds/Blackout/common.jsonc +++ b/contractTypeBuilds/Blackout/common.jsonc @@ -21,7 +21,6 @@ }, "Team": "Player1", "Guid": "76b654a6-4f2c-4a6f-86e6-d4cf868335fe", // Must be this Guid and the contract .json must have this specific. It's hardcoded in BT for PlayerLance. - "SpawnPoints": 4, "SpawnPointGuids": [ "ec9d2280-ca9a-4d90-8a20-963d8a4c0a39", "5df48a48-1840-49b0-84e9-126847053afa", @@ -53,7 +52,6 @@ }, "Team": "Target", "Guid": "c13c63a1-95ba-460a-af07-4096cfc6ff06", - "SpawnPoints": 4, "SpawnPointGuids": [ "2407c766-aa2e-440b-8118-a70b1a4679ed", "625aa0ff-2c5b-48a4-becb-621c1bbaccd3", @@ -101,7 +99,6 @@ "Team": "NeutralToAll", "Guid": "223fd528-c333-4367-883c-a817acf24360", "Tags": ["turrets_1b"], - "SpawnPoints": 4, "SpawnPointGuids": [ "6826832c-83d5-4287-b349-33008dc1fac5", "0329e03f-9d9c-4a5d-99df-ccdb6afe2bb5", @@ -135,7 +132,6 @@ "Team": "NeutralToAll", "Guid": "98fc619a-28f5-4a29-ae7f-5f42576cd0bc", "Tags": ["turrets_3x"], - "SpawnPoints": 3, "SpawnPointGuids": [ "38538181-1208-4cd1-bad9-7469f2cb9478", "6552d0c2-b705-49b8-a4f8-5205e537db05", @@ -287,7 +283,6 @@ }, "Team": "Target", "Guid": "b60da416-495c-474d-8b58-1678966835df", // Must match the spawner guids in the contract .json - "SpawnPoints": 4, "SpawnPointGuids": [ "9405bf60-db6c-4ae9-95b0-3c26a6e9fd88", "8f1a8422-917c-47c4-ada9-01eaa94499ee", @@ -448,7 +443,6 @@ }, "Team": "Target", "Guid": "f5714221-5fc6-41e5-a369-c8aa2b6d1bcf", // Must match the spawner guids in the contract .json - "SpawnPoints": 4, "SpawnPointGuids": [ "ec9b2fd0-15a0-488c-8190-64cea5cce242", "993b100b-dc76-44c2-85ac-e50beb0dc9ed", @@ -567,7 +561,6 @@ }, "Team": "Target", "Guid": "f426f0dc-969d-477d-81a9-d02f9e1eff79", // Must match the spawner guids in the contract .json - "SpawnPoints": 4, "SpawnPointGuids": [ "6cd3107e-0f9d-4809-ab8c-fb30faf4cd80", "14c58a13-96a6-4f91-a1e5-47b5d02b81d1", @@ -803,7 +796,7 @@ ] }, { - "Name": "Trigger_Emable_Chunk_Post_1c", + "Name": "Trigger_Enable_Chunk_Post_1c", "TriggerOn": "OnObjectiveUpdated", "Description": "Complete the destroy lance objective", "Conditionals": [ diff --git a/contractTypeBuilds/Blackout/mountainhold_lunar.jsonc b/contractTypeBuilds/Blackout/mountainhold_lunar.jsonc index f05c404c..03a2642a 100644 --- a/contractTypeBuilds/Blackout/mountainhold_lunar.jsonc +++ b/contractTypeBuilds/Blackout/mountainhold_lunar.jsonc @@ -72,7 +72,7 @@ "Path": "Chunks[?(@.Name == 'Chunk_Alpha_Base_Turrets')].Children[?(@.Name == 'Spawner_Alpha_Turrets')]", "Action": "ObjectMerge", "Value": { - "Name": "Spawner_Alpha_Turredts", + "Name": "Spawner_Alpha_Turrets", "Position": { "Type": "World", "Value": { "x": -700, "y": 0, "z": 160 } diff --git a/contractTypeBuilds/DuoDuel/common.jsonc b/contractTypeBuilds/DuoDuel/common.jsonc index 2b2a8493..e3674800 100644 --- a/contractTypeBuilds/DuoDuel/common.jsonc +++ b/contractTypeBuilds/DuoDuel/common.jsonc @@ -20,7 +20,6 @@ }, "Team": "Player1", "Guid": "76b654a6-4f2c-4a6f-86e6-d4cf868335fe", // Must be this Guid and the contract .json must have this specific. It's hardcoded in BT for PlayerLance. - "SpawnPoints": 2, "SpawnPointGuids": [ "ec9d2280-ca9a-4d90-8a20-963d8a4c0a39", "5df48a48-1840-49b0-84e9-126847053afa" @@ -52,7 +51,6 @@ }, "Team": "Target", "Guid": "f426f0dc-969d-477d-81a9-d02f9e1eff79", // Must match the spawner guids in the contract .json - "SpawnPoints": 2, "SpawnPointGuids": [ "6cd3107e-0f9d-4809-ab8c-fb30faf4cd80", "14c58a13-96a6-4f91-a1e5-47b5d02b81d1" diff --git a/contractTypeBuilds/SoloDuel/common.jsonc b/contractTypeBuilds/SoloDuel/common.jsonc index d663f46e..8505385a 100644 --- a/contractTypeBuilds/SoloDuel/common.jsonc +++ b/contractTypeBuilds/SoloDuel/common.jsonc @@ -20,7 +20,6 @@ }, "Team": "Player1", "Guid": "76b654a6-4f2c-4a6f-86e6-d4cf868335fe", // Must be this Guid and the contract .json must have this specific. It's hardcoded in BT for PlayerLance. - "SpawnPoints": 1, "SpawnPointGuids": ["ec9d2280-ca9a-4d90-8a20-963d8a4c0a39"], // Must match the unit spawn guids in the contract .json "SpawnType": "Instant" // Leopard, DropPod, Instant } @@ -49,7 +48,6 @@ }, "Team": "Target", "Guid": "f426f0dc-969d-477d-81a9-d02f9e1eff79", // Must match the spawner guids in the contract .json - "SpawnPoints": 1, "SpawnPointGuids": ["6cd3107e-0f9d-4809-ab8c-fb30faf4cd80"], // Must match the unit spawn guids in the contract .json "SpawnType": "Instant", // Leopard, DropPod, Instant "AI": [ diff --git a/overrides/contracts/duoduel/DuoDuel_FestiveCouple.json b/overrides/contracts/duoduel/DuoDuel_FestiveCouple.json index c77dad34..bff0f943 100644 --- a/overrides/contracts/duoduel/DuoDuel_FestiveCouple.json +++ b/overrides/contracts/duoduel/DuoDuel_FestiveCouple.json @@ -57,19 +57,11 @@ "objectiveGuids": ["a0b9c5b2-c594-4c5a-be1d-028a51c51519"] }, { - "Name": "Chunk_DisablePilotDeath", - "Type": "Chunk", - "SubType": "Container", - "ControlledByContract": true, - "Guid": "953a5930-06d0-4a2d-9840-e9a70c2a63ea", - "Children": [ - { - "Name": "CombatState_DisablePilotDeath", - "Type": "CombatState", - "SubType": "DisablePilotDeath", - "DisableInjuries": false - } - ] + "name": "Chunk_DisablePilotDeath", + "encounterChunk": { + "EncounterObjectGuid": "953a5930-06d0-4a2d-9840-e9a70c2a63ea" + }, + "enableChunkFromContract": true } ], "objectiveList": [ diff --git a/overrides/contracts/duoduel/DuoDuel_YearlyTussle.json b/overrides/contracts/duoduel/DuoDuel_YearlyTussle.json index 3145e78f..b3a3e1b9 100644 --- a/overrides/contracts/duoduel/DuoDuel_YearlyTussle.json +++ b/overrides/contracts/duoduel/DuoDuel_YearlyTussle.json @@ -82,19 +82,11 @@ "enableChunkFromContract": true }, { - "Name": "Chunk_DisablePilotDeath", - "Type": "Chunk", - "SubType": "Container", - "ControlledByContract": true, - "Guid": "953a5930-06d0-4a2d-9840-e9a70c2a63ea", - "Children": [ - { - "Name": "CombatState_DisablePilotDeath", - "Type": "CombatState", - "SubType": "DisablePilotDeath", - "DisableInjuries": false - } - ] + "name": "Chunk_DisablePilotDeath", + "encounterChunk": { + "EncounterObjectGuid": "953a5930-06d0-4a2d-9840-e9a70c2a63ea" + }, + "enableChunkFromContract": true } ], "cameraFocusHelperList": [ diff --git a/settings.json b/settings.json index cfccffce..f96dacf8 100644 --- a/settings.json +++ b/settings.json @@ -48,6 +48,8 @@ "MatchAllyLanceCountToEnemy": false, "DropWeightInfluence": { "Enable": false, + "EnemySpawnInfluenceMax": 0.9, + "AllySpawnInfluenceMax": 0.9, "EnemySpawnInfluencePerHalfSkullAbove": 0.1, "AllySpawnInfluencePerHalfSkullAbove": -0.1, "EnemySpawnInfluencePerHalfSkullBelow": -0.1, diff --git a/src/Core/ContractTypeBuilders/NodeBuilders/DialogueBuilder.cs b/src/Core/ContractTypeBuilders/NodeBuilders/DialogueBuilder.cs index 66186d83..a9a04a71 100644 --- a/src/Core/ContractTypeBuilders/NodeBuilders/DialogueBuilder.cs +++ b/src/Core/ContractTypeBuilders/NodeBuilders/DialogueBuilder.cs @@ -5,6 +5,7 @@ using MissionControl.Trigger; using MissionControl.Rules; using MissionControl.EncounterFactories; +using MissionControl.Messages; using Newtonsoft.Json.Linq; @@ -42,9 +43,18 @@ public override void Build() { private void BuildSimpleDialogue() { DialogueFactory.CreateDialogLogic(this.parent, this.name, this.guid, this.showOnlyOnce); + MessageCenterMessageType messageType; if (this.trigger != null) { - MessageCenterMessageType triggerMessageType = (MessageCenterMessageType)Enum.Parse(typeof(MessageCenterMessageType), this.trigger); - DialogTrigger dialogueTrigger = new DialogTrigger(triggerMessageType, this.guid); + if (!Enum.TryParse(this.trigger, out messageType)) { + MessageTypes customMessageType; + if (!Enum.TryParse(this.trigger, out customMessageType)) { + Main.Logger.LogError("[DialogueBuilder] Invalid 'Trigger' provided."); + } else { + messageType = (MessageCenterMessageType)customMessageType; + } + } + + DialogTrigger dialogueTrigger = new DialogTrigger(messageType, this.guid); dialogueTrigger.Run(); } } diff --git a/src/Core/Data/Deserialisation/MLanceOverride.cs b/src/Core/Data/Deserialisation/MLanceOverride.cs index aec408c3..69c9e9e2 100644 --- a/src/Core/Data/Deserialisation/MLanceOverride.cs +++ b/src/Core/Data/Deserialisation/MLanceOverride.cs @@ -28,6 +28,7 @@ public MLanceOverride(MLanceOverrideData lanceOverrideData) { } public MLanceOverride(LanceDef lanceDef) { + this.LanceKey = lanceDef.Description.Id; this.lanceDefId = lanceDef.Description.Id; this.lanceTagSet = lanceDef.LanceTags; @@ -48,6 +49,7 @@ public MLanceOverride(LanceDef lanceDef) { } public MLanceOverride(LanceOverride lanceOverride) { + this.LanceKey = lanceOverride.lanceDefId; this.lanceDefId = lanceOverride.lanceDefId; this.lanceTagSet = new TagSet(lanceOverride.lanceTagSet); this.lanceExcludedTagSet = new TagSet(lanceOverride.lanceExcludedTagSet); @@ -59,6 +61,7 @@ public MLanceOverride(LanceOverride lanceOverride) { public MLanceOverride(string lanceDefId, TagSet lanceTagSet, TagSet lanceExcludedTagSet, TagSet spawnEffectTags, int lanceDifficultyAdjustment, List unitSpawnOverrides) { + this.LanceKey = lanceDefId; this.lanceDefId = lanceDefId; this.lanceTagSet = lanceTagSet; this.lanceExcludedTagSet = lanceExcludedTagSet; diff --git a/src/Core/Data/SceneManipulationLogic.cs b/src/Core/Data/SceneManipulationLogic.cs index c42d62e7..e248498a 100644 --- a/src/Core/Data/SceneManipulationLogic.cs +++ b/src/Core/Data/SceneManipulationLogic.cs @@ -117,14 +117,8 @@ public Vector3 GetRandomPositionWithinBounds(Vector3 target, float maxDistance) } public Vector3 GetRandomPositionWithinBounds() { - MissionControl EncounterManager = MissionControl.Instance; - GameObject chunkBoundaryRect = MissionControl.Instance.EncounterLayerGameObject.transform.Find("Chunk_EncounterBoundary")?.gameObject; - if (chunkBoundaryRect == null) { - chunkBoundaryRect = MissionControl.Instance.EncounterLayerGameObject.transform.Find("Gen_EncounterBoundary").gameObject; - } - GameObject boundary = chunkBoundaryRect.transform.Find("EncounterBoundaryRect").gameObject; - EncounterBoundaryChunkGameLogic chunkBoundary = chunkBoundaryRect.GetComponent(); - EncounterBoundaryRectGameLogic boundaryLogic = boundary.GetComponent(); + EncounterBoundaryChunkGameLogic chunkBoundary = MissionControl.Instance.EncounterLayerGameObject.GetComponentInChildren(); + EncounterBoundaryRectGameLogic boundaryLogic = chunkBoundary.GetComponentInChildren(); Rect boundaryRec = chunkBoundary.GetEncounterBoundaryRectBounds(); Vector3 randomRecPosition = boundaryRec.GetRandomPosition(); diff --git a/src/Core/DataManager.cs b/src/Core/DataManager.cs index 8cc0a60f..d1dec775 100644 --- a/src/Core/DataManager.cs +++ b/src/Core/DataManager.cs @@ -107,26 +107,30 @@ private void LoadSettingsOverrides() { private void LoadCustomContractTypeBuilds() { foreach (string directory in Directory.GetDirectories($"{ModDirectory}/contractTypeBuilds/")) { - string contractTypeBuildCommonSource = File.ReadAllText($"{directory}/common.jsonc"); - JObject contractTypeCommonBuild = JsonConvert.DeserializeObject(contractTypeBuildCommonSource, serialiserSettings); - string contractTypeName = (string)contractTypeCommonBuild["Key"]; - Main.LogDebug($"[DataManager.LoadCustomContractTypeBuilds] Loading contract type build '{contractTypeName}'"); - - Dictionary contractTypeMapBuilds = new Dictionary(); - AvailableCustomContractTypeBuilds.Add(contractTypeCommonBuild["Key"].ToString(), contractTypeMapBuilds); - - foreach (string file in Directory.GetFiles(directory, "*.json*", SearchOption.AllDirectories)) { - string contractTypeBuildMapSource = File.ReadAllText(file); - JObject contractTypeMapBuild = JsonConvert.DeserializeObject(contractTypeBuildMapSource, serialiserSettings); - string fileName = Path.GetFileNameWithoutExtension(file.Substring(file.LastIndexOf("/"))); - - if (fileName == "common" || contractTypeMapBuild.ContainsKey("EncounterLayerId")) { - string encounterLayerId = (fileName == "common") ? fileName : (string)contractTypeMapBuild["EncounterLayerId"]; - Main.LogDebug($"[DataManager.LoadCustomContractTypeBuilds] Loaded contract type map build '{contractTypeName}/{fileName}' with encounterLayerId '{encounterLayerId}'"); - contractTypeMapBuilds.Add(encounterLayerId, contractTypeMapBuild); - } else { - Main.Logger.LogError($"[DataManager.LoadCustomContractTypeBuilds] Unable to load contract type map build file '{fileName}' for contract type '{contractTypeName}' because no 'EncounterLayerId' exists"); + if (File.Exists($"{directory}/common.jsonc")) { + string contractTypeBuildCommonSource = File.ReadAllText($"{directory}/common.jsonc"); + JObject contractTypeCommonBuild = JsonConvert.DeserializeObject(contractTypeBuildCommonSource, serialiserSettings); + string contractTypeName = (string)contractTypeCommonBuild["Key"]; + Main.LogDebug($"[DataManager.LoadCustomContractTypeBuilds] Loading contract type build '{contractTypeName}'"); + + Dictionary contractTypeMapBuilds = new Dictionary(); + AvailableCustomContractTypeBuilds.Add(contractTypeCommonBuild["Key"].ToString(), contractTypeMapBuilds); + + foreach (string file in Directory.GetFiles(directory, "*.json*", SearchOption.AllDirectories)) { + string contractTypeBuildMapSource = File.ReadAllText(file); + JObject contractTypeMapBuild = JsonConvert.DeserializeObject(contractTypeBuildMapSource, serialiserSettings); + string fileName = Path.GetFileNameWithoutExtension(file.Substring(file.LastIndexOf("/"))); + + if (fileName == "common" || contractTypeMapBuild.ContainsKey("EncounterLayerId")) { + string encounterLayerId = (fileName == "common") ? fileName : (string)contractTypeMapBuild["EncounterLayerId"]; + Main.LogDebug($"[DataManager.LoadCustomContractTypeBuilds] Loaded contract type map build '{contractTypeName}/{fileName}' with encounterLayerId '{encounterLayerId}'"); + contractTypeMapBuilds.Add(encounterLayerId, contractTypeMapBuild); + } else { + Main.Logger.LogError($"[DataManager.LoadCustomContractTypeBuilds] Unable to load contract type map build file '{fileName}' for contract type '{contractTypeName}' because no 'EncounterLayerId' exists"); + } } + } else { + Main.Logger.LogWarning($"[DataManager.LoadCustomContractTypeBuilds] Directory exists for contract type but no common.jsonc exists. Probably bad data or WIP contract type build - {directory}"); } } } @@ -227,7 +231,7 @@ private void LoadLanceOverrides() { } */ } else { - Main.Logger.LogError($"[DataManager] Json format is wrong. Read the documentation on the lance override format."); + Main.Logger.LogError($"[DataManager] Json format is wrong for file '{file}'. Read the documentation on the lance override format."); } } } @@ -255,7 +259,7 @@ public MLanceOverride GetLanceOverride(string key) { if (LanceOverrides.ContainsKey(key)) { Main.Logger.Log($"[GetLanceOverride] Found a lance override for '{key}'"); - return LanceOverrides[key]; + return LanceOverrides[key].Copy(); } LanceDef lanceDef = null; @@ -263,10 +267,22 @@ public MLanceOverride GetLanceOverride(string key) { if (lanceDef != null) { MLanceOverride lanceOverride = new MLanceOverride(lanceDef); LanceOverrides.Add(lanceOverride.lanceDefId, lanceOverride); - Main.Logger.Log($"[GetLanceOverride] Found a lance def for '{key}', creating and caching a lance override for it. Using defaults of 'adjustedDifficulty - 0' and no 'spawnEffectTags'"); - return lanceOverride; + Main.Logger.Log($"[GetLanceOverride] Found a lance def for '{key}', creating and caching a lance override for it. Using defaults of 'adjustedDifficulty' of '0' and no 'spawnEffectTags'"); + return lanceOverride.Copy(); + } else { + Main.Logger.Log($"[GetLanceOverride] No loaded LanceDef was found for '{key}'. Attempting to load the LanceDef."); + lanceDef = BattleTechResourceLoader.LoadDefFromId(key, BattleTechResourceType.LanceDef); + DataManager.Instance.RequestResourcesAndProcess(BattleTechResourceType.LanceDef, key); + + if (lanceDef != null) { + MLanceOverride lanceOverride = new MLanceOverride(lanceDef); + LanceOverrides.Add(lanceOverride.lanceDefId, lanceOverride); + Main.Logger.Log($"[GetLanceOverride] Load succeeded. Found a lance def for '{key}', creating and caching a lance override for it. Using defaults of 'adjustedDifficulty' of '0' and no 'spawnEffectTags'"); + return lanceOverride.Copy(); + } } + Main.Logger.LogError($"[GetLanceOverride] No MC Lance or LanceDef found with key '{key}'. This is a case sensitive search.'"); return null; } diff --git a/src/Core/EncounterDataManager.cs b/src/Core/EncounterDataManager.cs index 3c6c08b5..45b34ce8 100644 --- a/src/Core/EncounterDataManager.cs +++ b/src/Core/EncounterDataManager.cs @@ -61,17 +61,22 @@ public void SetMountOnPosition(GameObject target, string mountTargetPath) { Main.LogDebug($"[EncounterDataManager.SetMountOnPositions] Target '{mountTargetPath}' found with '{go.name}'"); } - Vector3 pos = go.transform.position; - Collider col = go.GetComponentInChildren(); + GameObject copyGo = GameObject.Instantiate(go); + copyGo.transform.position = go.transform.position; + Vector3 pos = copyGo.transform.position; + Collider col = copyGo.GetComponentInChildren(); + Vector4 colliderPos = col.transform.position; - RaycastHit[] hits = Physics.RaycastAll(new Vector3(pos.x, pos.y + 500f, pos.z), go.transform.TransformDirection(Vector3.down), 1000f); + RaycastHit[] hits = Physics.RaycastAll(new Vector3(colliderPos.x, colliderPos.y + 500f, colliderPos.z), go.transform.TransformDirection(Vector3.down), 1000f); foreach (RaycastHit hit1 in hits) { if (hit1.collider.gameObject.name == col.gameObject.name) { pos.y = hit1.point.y; + break; } } target.transform.position = pos; + GameObject.Destroy(copyGo); } public void GenerateEncounterLayerBuildingData() { diff --git a/src/Core/EncounterLogic/BatchedLogic/AddEmployerLanceBatch.cs b/src/Core/EncounterLogic/BatchedLogic/AddEmployerLanceBatch.cs index 4944dd20..f68c626a 100644 --- a/src/Core/EncounterLogic/BatchedLogic/AddEmployerLanceBatch.cs +++ b/src/Core/EncounterLogic/BatchedLogic/AddEmployerLanceBatch.cs @@ -2,39 +2,40 @@ using System; using System.Collections.Generic; +using MissionControl.Data; using MissionControl.Rules; using MissionControl.Trigger; namespace MissionControl.Logic { public class AddEmployerLanceBatch { public AddEmployerLanceBatch(EncounterRules encounterRules, string orientationTargetKey, - SpawnLogic.LookDirection lookDirection, float minDistance, float maxDistance) { + SpawnLogic.LookDirection lookDirection, float minDistance, float maxDistance, MLanceOverride manuallySpecifiedLance = null) { - int numberOfUnitsInLance = 4; - string lanceGuid = Guid.NewGuid().ToString(); - List unitGuids = encounterRules.GenerateGuids(numberOfUnitsInLance); - string employerTeamGuid = EncounterRules.EMPLOYER_TEAM_ID; - string spawnerName = $"Lance_Ally_SupportingForce_{lanceGuid}"; + int numberOfUnitsInLance = 4; + string lanceGuid = Guid.NewGuid().ToString(); + List unitGuids = encounterRules.GenerateGuids(numberOfUnitsInLance); + string employerTeamGuid = EncounterRules.EMPLOYER_TEAM_ID; + string spawnerName = $"Lance_Ally_SupportingForce_{lanceGuid}"; - encounterRules.EncounterLogic.Add(new AddLanceToAllyTeam(lanceGuid, unitGuids)); - encounterRules.EncounterLogic.Add(new AddLanceSpawnChunk(employerTeamGuid, lanceGuid, unitGuids, spawnerName, - "Spawns a non-objective related ally supporting lance")); - encounterRules.EncounterLogic.Add(new SpawnLanceMembersAroundTarget(encounterRules, spawnerName, orientationTargetKey, - lookDirection, minDistance, maxDistance)); + encounterRules.EncounterLogic.Add(new AddLanceToAllyTeam(lanceGuid, unitGuids, manuallySpecifiedLance)); + encounterRules.EncounterLogic.Add(new AddLanceSpawnChunk(employerTeamGuid, lanceGuid, unitGuids, spawnerName, + "Spawns a non-objective related ally supporting lance")); + encounterRules.EncounterLogic.Add(new SpawnLanceMembersAroundTarget(encounterRules, spawnerName, orientationTargetKey, + lookDirection, minDistance, maxDistance)); - if (Main.Settings.AdditionalLanceSettings.UseDialogue && !MissionControl.Instance.ContractStats.ContainsKey(ContractStats.DIALOGUE_ADDITIONAL_LANCE_ALLY_START)) { - MissionControl.Instance.ContractStats.Add(ContractStats.DIALOGUE_ADDITIONAL_LANCE_ALLY_START, true); - encounterRules.EncounterLogic.Add(new AddDialogueChunk( - ChunkLogic.DIALOGUE_ADDITIONAL_LANCE_ALLY_START_GUID, - "AdditionalLanceAllyStart", - "Start Conversation For Additional Lance Ally", - lanceGuid - // "DialogBucketDef_Universal_KillConfirmed" - )); - encounterRules.EncounterLogic.Add(new DialogTrigger(MessageCenterMessageType.OnEncounterIntroComplete, ChunkLogic.DIALOGUE_ADDITIONAL_LANCE_ALLY_START_GUID)); - } + if (Main.Settings.AdditionalLanceSettings.UseDialogue && !MissionControl.Instance.ContractStats.ContainsKey(ContractStats.DIALOGUE_ADDITIONAL_LANCE_ALLY_START)) { + MissionControl.Instance.ContractStats.Add(ContractStats.DIALOGUE_ADDITIONAL_LANCE_ALLY_START, true); + encounterRules.EncounterLogic.Add(new AddDialogueChunk( + ChunkLogic.DIALOGUE_ADDITIONAL_LANCE_ALLY_START_GUID, + "AdditionalLanceAllyStart", + "Start Conversation For Additional Lance Ally", + lanceGuid + // "DialogBucketDef_Universal_KillConfirmed" + )); + encounterRules.EncounterLogic.Add(new DialogTrigger(MessageCenterMessageType.OnEncounterIntroComplete, ChunkLogic.DIALOGUE_ADDITIONAL_LANCE_ALLY_START_GUID)); + } - encounterRules.ObjectReferenceQueue.Add(spawnerName); + encounterRules.ObjectReferenceQueue.Add(spawnerName); } } } \ No newline at end of file diff --git a/src/Core/EncounterLogic/BatchedLogic/AddTargetLanceWithDestroyObjectiveBatch.cs b/src/Core/EncounterLogic/BatchedLogic/AddTargetLanceWithDestroyObjectiveBatch.cs index 013f79c6..ee09a085 100644 --- a/src/Core/EncounterLogic/BatchedLogic/AddTargetLanceWithDestroyObjectiveBatch.cs +++ b/src/Core/EncounterLogic/BatchedLogic/AddTargetLanceWithDestroyObjectiveBatch.cs @@ -1,16 +1,15 @@ -using UnityEngine; using System; using System.Collections.Generic; +using MissionControl.Data; using MissionControl.Rules; using MissionControl.Trigger; -using MissionControl.Messages; namespace MissionControl.Logic { public class AddTargetLanceWithDestroyObjectiveBatch { public AddTargetLanceWithDestroyObjectiveBatch(EncounterRules encounterRules, string orientationTargetKey, SpawnLogic.LookDirection lookDirection, float mustBeBeyondDistance, float mustBeWithinDistance, string objectiveName, int priority, - bool isPrimaryObjective, bool displayToUser, bool showObjectiveOnLanceDetected, bool excludeFromAutocomplete) { + bool isPrimaryObjective, bool displayToUser, bool showObjectiveOnLanceDetected, bool excludeFromAutocomplete, MLanceOverride manuallySpecifiedLance = null) { int numberOfUnitsInLance = 4; string lanceGuid = Guid.NewGuid().ToString(); @@ -20,7 +19,7 @@ public AddTargetLanceWithDestroyObjectiveBatch(EncounterRules encounterRules, st string targetTeamGuid = EncounterRules.TARGET_TEAM_ID; string spawnerName = $"Lance_Enemy_OpposingForce_{lanceGuid}"; - encounterRules.EncounterLogic.Add(new AddLanceToTargetTeam(lanceGuid, unitGuids)); + encounterRules.EncounterLogic.Add(new AddLanceToTargetTeam(lanceGuid, unitGuids, manuallySpecifiedLance)); encounterRules.EncounterLogic.Add(new AddDestroyWholeUnitChunk(encounterRules, targetTeamGuid, lanceGuid, unitGuids, spawnerName, objectiveGuid, objectiveName, priority, isPrimaryObjective, displayToUser)); if (!excludeFromAutocomplete) encounterRules.EncounterLogic.Add(new AddObjectiveToAutocompleteTrigger(objectiveGuid)); diff --git a/src/Core/EncounterLogic/LanceLogic/AddLanceToAllyTeam.cs b/src/Core/EncounterLogic/LanceLogic/AddLanceToAllyTeam.cs index 31d702d9..164859c0 100644 --- a/src/Core/EncounterLogic/LanceLogic/AddLanceToAllyTeam.cs +++ b/src/Core/EncounterLogic/LanceLogic/AddLanceToAllyTeam.cs @@ -1,23 +1,19 @@ -using UnityEngine; -using System; -using System.Collections; using System.Collections.Generic; -using BattleTech; -using BattleTech.Designed; using BattleTech.Framework; -using MissionControl.Rules; -using MissionControl.Utils; +using MissionControl.Data; namespace MissionControl.Logic { public class AddLanceToAllyTeam : LanceLogic { private string lanceGuid; private List unitGuids; + private MLanceOverride manuallySpecifiedLance; - public AddLanceToAllyTeam(string lanceGuid, List unitGuids) { + public AddLanceToAllyTeam(string lanceGuid, List unitGuids, MLanceOverride manuallySpecifiedLance = null) { this.lanceGuid = lanceGuid; this.unitGuids = unitGuids; + this.manuallySpecifiedLance = manuallySpecifiedLance; } public override void Run(RunPayload payload) { @@ -26,7 +22,7 @@ public override void Run(RunPayload payload) { TeamOverride teamOverride = contractOverride.employerTeam; TeamOverride targetTeamOverride = contractOverride.targetTeam; - LanceOverride lanceOverride = SelectAppropriateLanceOverride("allies").Copy(); + LanceOverride lanceOverride = (manuallySpecifiedLance == null) ? SelectAppropriateLanceOverride("allies").Copy() : manuallySpecifiedLance.Copy(); lanceOverride.name = $"Lance_Ally_Force_{lanceGuid}"; if (unitGuids.Count > 4) { @@ -42,7 +38,7 @@ public override void Run(RunPayload payload) { unitSpawnRef.EncounterObjectGuid = unitGuid; lanceOverride.unitSpawnPointOverrideList[i].unitSpawnPoint = unitSpawnRef; } - + LanceSpawnerRef lanceSpawnerRef = new LanceSpawnerRef(); lanceSpawnerRef.EncounterObjectGuid = lanceGuid; lanceOverride.lanceSpawner = lanceSpawnerRef; diff --git a/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayer2Team.cs b/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayer2Team.cs index 94a96291..3cd8febb 100644 --- a/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayer2Team.cs +++ b/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayer2Team.cs @@ -1,15 +1,7 @@ -using UnityEngine; -using System; -using System.Collections; using System.Collections.Generic; -using BattleTech; -using BattleTech.Designed; using BattleTech.Framework; -using MissionControl.Rules; -using MissionControl.Utils; - namespace MissionControl.Logic { public class AddLanceToPlayer2Team : LanceLogic { private string lanceGuid; @@ -41,7 +33,7 @@ public override void Run(RunPayload payload) { unitSpawnRef.EncounterObjectGuid = unitGuid; lanceOverride.unitSpawnPointOverrideList[i].unitSpawnPoint = unitSpawnRef; } - + LanceSpawnerRef lanceSpawnerRef = new LanceSpawnerRef(); lanceSpawnerRef.EncounterObjectGuid = lanceGuid; lanceOverride.lanceSpawner = lanceSpawnerRef; diff --git a/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayerTeam.cs b/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayerTeam.cs index 60eeb09f..0f1ad618 100644 --- a/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayerTeam.cs +++ b/src/Core/EncounterLogic/LanceLogic/AddLanceToPlayerTeam.cs @@ -1,15 +1,7 @@ -using UnityEngine; -using System; -using System.Collections; using System.Collections.Generic; -using BattleTech; -using BattleTech.Designed; using BattleTech.Framework; -using MissionControl.Rules; -using MissionControl.Utils; - namespace MissionControl.Logic { public class AddLanceToPlayerTeam : LanceLogic { private string lanceGuid; @@ -46,7 +38,7 @@ public override void Run(RunPayload payload) { unitSpawnRef.EncounterObjectGuid = unitGuid; lanceOverride.unitSpawnPointOverrideList[i].unitSpawnPoint = unitSpawnRef; } - + LanceSpawnerRef lanceSpawnerRef = new LanceSpawnerRef(); lanceSpawnerRef.EncounterObjectGuid = lanceGuid; lanceOverride.lanceSpawner = lanceSpawnerRef; diff --git a/src/Core/EncounterLogic/LanceLogic/AddLanceToTargetTeam.cs b/src/Core/EncounterLogic/LanceLogic/AddLanceToTargetTeam.cs index f4c9a170..043c94cc 100644 --- a/src/Core/EncounterLogic/LanceLogic/AddLanceToTargetTeam.cs +++ b/src/Core/EncounterLogic/LanceLogic/AddLanceToTargetTeam.cs @@ -7,6 +7,7 @@ using BattleTech.Designed; using BattleTech.Framework; +using MissionControl.Data; using MissionControl.Rules; using MissionControl.Utils; @@ -14,10 +15,12 @@ namespace MissionControl.Logic { public class AddLanceToTargetTeam : LanceLogic { private string lanceGuid; private List unitGuids; + private MLanceOverride manuallySpecifiedLance; - public AddLanceToTargetTeam(string lanceGuid, List unitGuids) { + public AddLanceToTargetTeam(string lanceGuid, List unitGuids, MLanceOverride manuallySpecifiedLance = null) { this.lanceGuid = lanceGuid; this.unitGuids = unitGuids; + this.manuallySpecifiedLance = manuallySpecifiedLance; } public override void Run(RunPayload payload) { @@ -25,7 +28,7 @@ public override void Run(RunPayload payload) { ContractOverride contractOverride = ((ContractOverridePayload)payload).ContractOverride; TeamOverride teamOverride = contractOverride.targetTeam; - LanceOverride lanceOverride = SelectAppropriateLanceOverride("enemy").Copy(); + LanceOverride lanceOverride = (manuallySpecifiedLance == null) ? SelectAppropriateLanceOverride("enemy").Copy() : manuallySpecifiedLance.Copy(); lanceOverride.name = $"Lance_Enemy_OpposingForce_{lanceGuid}"; if (unitGuids.Count > 4) { @@ -41,7 +44,7 @@ public override void Run(RunPayload payload) { unitSpawnRef.EncounterObjectGuid = unitGuid; lanceOverride.unitSpawnPointOverrideList[i].unitSpawnPoint = unitSpawnRef; } - + LanceSpawnerRef lanceSpawnerRef = new LanceSpawnerRef(); lanceSpawnerRef.EncounterObjectGuid = lanceGuid; lanceOverride.lanceSpawner = lanceSpawnerRef; diff --git a/src/Core/EncounterLogic/SpawnLogic/SpawnLanceAtEdgeBoundary.cs b/src/Core/EncounterLogic/SpawnLogic/SpawnLanceAtEdgeBoundary.cs index 0b97a4c8..d0d0bfdd 100644 --- a/src/Core/EncounterLogic/SpawnLogic/SpawnLanceAtEdgeBoundary.cs +++ b/src/Core/EncounterLogic/SpawnLogic/SpawnLanceAtEdgeBoundary.cs @@ -103,11 +103,9 @@ public override void Run(RunPayload payload) { Init(); CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; - MissionControl EncounterManager = MissionControl.Instance; - GameObject chunkBoundaryRect = EncounterManager.EncounterLayerGameObject.transform.Find("Chunk_EncounterBoundary").gameObject; - GameObject boundary = chunkBoundaryRect.transform.Find("EncounterBoundaryRect").gameObject; - EncounterBoundaryChunkGameLogic chunkBoundary = chunkBoundaryRect.GetComponent(); - EncounterBoundaryRectGameLogic boundaryLogic = boundary.GetComponent(); + EncounterBoundaryChunkGameLogic chunkBoundary = MissionControl.Instance.EncounterLayerGameObject.GetComponentInChildren(); + EncounterBoundaryRectGameLogic boundaryLogic = chunkBoundary.GetComponentInChildren(); + GameObject boundary = boundaryLogic.gameObject; Rect boundaryRec = chunkBoundary.GetEncounterBoundaryRectBounds(); Rect usableBounds = boundaryRec.GenerateUsableBoundary(); diff --git a/src/Core/EncounterRules/EncounterRules.cs b/src/Core/EncounterRules/EncounterRules.cs index e85a4232..95d57a6c 100644 --- a/src/Core/EncounterRules/EncounterRules.cs +++ b/src/Core/EncounterRules/EncounterRules.cs @@ -1,14 +1,12 @@ using UnityEngine; -using UnityEngine.SceneManagement; using System; using System.Linq; -using System.Collections; using System.Collections.Generic; using BattleTech; -using BattleTech.Framework; +using MissionControl.Data; using MissionControl.Logic; using MissionControl.Trigger; using MissionControl.Config; @@ -101,10 +99,10 @@ public static string GetPlayerLanceSpawnerName() { Main.Logger.LogWarning($"[MC 1.2+ DEPRECATION] 'EncounterRules.GetPlayerLanceSpawnerName()' IS DEPRECATED. USE 'EncounterRules.GetPlayerSpawnerGameObject(GameObject encounterLayerGo)' INSTEAD. IT WILL BE REMOVED IN A FUTURE UPDATE."); Main.Logger.LogWarning($"[MC 1.2+ DEPRECATION] 'EncounterRules.GetPlayerLanceSpawnerName()' IS DEPRECATED. USE 'EncounterRules.GetPlayerSpawnerGameObject(GameObject encounterLayerGo)' INSTEAD. IT WILL BE REMOVED IN A FUTURE UPDATE."); Main.Logger.LogWarning($"[MC 1.2+ DEPRECATION] 'EncounterRules.GetPlayerLanceSpawnerName()' IS DEPRECATED. USE 'EncounterRules.GetPlayerSpawnerGameObject(GameObject encounterLayerGo)' INSTEAD. IT WILL BE REMOVED IN A FUTURE UPDATE."); - + GameObject encounterLayerGo = MissionControl.Instance.EncounterLayerGameObject; GameObject chunkPlayerLanceGo = EncounterRules.GetPlayerLanceChunkGameObject(encounterLayerGo); - GameObject SpawnerPlayerLanceGo = GetPlayerSpawnerGameObject(chunkPlayerLanceGo); + GameObject SpawnerPlayerLanceGo = GetPlayerSpawnerGameObject(chunkPlayerLanceGo); return SpawnerPlayerLanceGo.name; } @@ -137,7 +135,7 @@ private void RunSceneManipulationLogic(IEnumerable logicBlocks, RunP EncounterLayerData = MissionControl.Instance.EncounterLayerData; ChunkPlayerLanceGo = GetPlayerLanceChunkGameObject(EncounterLayerGo); - SpawnerPlayerLanceGo = GetPlayerSpawnerGameObject(ChunkPlayerLanceGo); + SpawnerPlayerLanceGo = GetPlayerSpawnerGameObject(ChunkPlayerLanceGo); ObjectLookup["ChunkPlayerLance"] = ChunkPlayerLanceGo; ObjectLookup["SpawnerPlayerLance"] = SpawnerPlayerLanceGo; @@ -255,6 +253,7 @@ protected void BuildAdditionalLances(string enemyOrientationTargetKey, SpawnLogi int numberOfAdditionalEnemyLances = 0; if (MissionControl.Instance.AreAdditionalLancesAllowed("enemy")) { + List manuallySpecifiedLances = new List(); bool isPrimaryObjective = MissionControl.Instance.CurrentContractType.In(Main.Settings.AdditionalLanceSettings.IsPrimaryObjectiveIn.ToArray()); bool displayToUser = !Main.Settings.AdditionalLanceSettings.HideObjective; bool excludeFromAutocomplete = MissionControl.Instance.CurrentContractType.In(Main.Settings.AdditionalLanceSettings.ExcludeFromAutocomplete.ToArray()); @@ -277,22 +276,35 @@ protected void BuildAdditionalLances(string enemyOrientationTargetKey, SpawnLogi Main.Logger.Log($"[{this.GetType().Name}] Using contract-specific settings override for contract '{MissionControl.Instance.CurrentContract.Name}'. Enemy lance count will be '{numberOfAdditionalEnemyLances}'."); } - bool showObjectiveOnLanceDetected = Main.Settings.AdditionalLanceSettings.ShowObjectiveOnLanceDetected; + if (Main.Settings.ActiveContractSettings.Has(ContractSettingsOverrides.AdditionalLances_EnemyLancesOverride)) { + manuallySpecifiedLances = Main.Settings.ActiveContractSettings.GetList(ContractSettingsOverrides.AdditionalLances_EnemyLancesOverride); + Main.Logger.Log($"[{this.GetType().Name}] Using contract-specific settings override for contract '{MissionControl.Instance.CurrentContract.Name}'. Enemy lances will be '{string.Join(",", manuallySpecifiedLances)}'."); + } + bool showObjectiveOnLanceDetected = Main.Settings.AdditionalLanceSettings.ShowObjectiveOnLanceDetected; int objectivePriority = -10; - for (int i = 0; i < numberOfAdditionalEnemyLances; i++) { + for (int i = 1; i <= numberOfAdditionalEnemyLances; i++) { if (MissionControl.Instance.CurrentContractType == "ArenaSkirmish") { new AddPlayer2LanceWithDestroyObjectiveBatch(this, enemyOrientationTargetKey, enemyLookDirection, mustBeBeyondDistanceOfTarget, mustBeWithinDistanceOfTarget, $"Destroy Enemy Support Lance {i + 1}", objectivePriority--, isPrimaryObjective, displayToUser, showObjectiveOnLanceDetected, excludeFromAutocomplete); } else { - new AddTargetLanceWithDestroyObjectiveBatch(this, enemyOrientationTargetKey, enemyLookDirection, mustBeBeyondDistanceOfTarget, mustBeWithinDistanceOfTarget, - $"Destroy {{TEAM_TAR.FactionDef.Demonym}} Support Lance {i + 1}", objectivePriority--, isPrimaryObjective, displayToUser, showObjectiveOnLanceDetected, excludeFromAutocomplete); + if (manuallySpecifiedLances.Count >= i) { + string lanceKey = manuallySpecifiedLances[i - 1]; + MLanceOverride lanceOverride = DataManager.Instance.GetLanceOverride(lanceKey); + Main.Logger.Log($"[{this.GetType().Name}] Using contract-specific settings override for contract '{MissionControl.Instance.CurrentContract.Name}'. Resolved Enemy lance will be '{lanceOverride.LanceKey}'."); + new AddTargetLanceWithDestroyObjectiveBatch(this, enemyOrientationTargetKey, enemyLookDirection, mustBeBeyondDistanceOfTarget, mustBeWithinDistanceOfTarget, + $"Destroy {{TEAM_TAR.FactionDef.Demonym}} Support Lance {i + 1}", objectivePriority--, isPrimaryObjective, displayToUser, showObjectiveOnLanceDetected, excludeFromAutocomplete, lanceOverride); + } else { + new AddTargetLanceWithDestroyObjectiveBatch(this, enemyOrientationTargetKey, enemyLookDirection, mustBeBeyondDistanceOfTarget, mustBeWithinDistanceOfTarget, + $"Destroy {{TEAM_TAR.FactionDef.Demonym}} Support Lance {i + 1}", objectivePriority--, isPrimaryObjective, displayToUser, showObjectiveOnLanceDetected, excludeFromAutocomplete); + } } } } if (MissionControl.Instance.AreAdditionalLancesAllowed("allies")) { + List manuallySpecifiedLances = new List(); FactionDef faction = MissionControl.Instance.GetFactionFromTeamType("allies"); int numberOfAdditionalAllyLances = Main.Settings.ActiveAdditionalLances.Allies.SelectNumberOfAdditionalLances(faction, "allies"); @@ -306,8 +318,20 @@ protected void BuildAdditionalLances(string enemyOrientationTargetKey, SpawnLogi numberOfAdditionalAllyLances = numberOfAdditionalEnemyLances; } - for (int i = 0; i < numberOfAdditionalAllyLances; i++) { - new AddEmployerLanceBatch(this, allyOrientationKey, allyLookDirection, mustBeBeyondDistance, mustBeWithinDistance); + if (Main.Settings.ActiveContractSettings.Has(ContractSettingsOverrides.AdditionalLances_AllyLancesOverride)) { + manuallySpecifiedLances = Main.Settings.ActiveContractSettings.GetList(ContractSettingsOverrides.AdditionalLances_AllyLancesOverride); + Main.Logger.Log($"[{this.GetType().Name}] Using contract-specific settings override for contract '{MissionControl.Instance.CurrentContract.Name}'. Ally lances provided are '{string.Join(",", manuallySpecifiedLances)}'."); + } + + for (int i = 1; i <= numberOfAdditionalAllyLances; i++) { + if (manuallySpecifiedLances.Count >= i) { + string lanceKey = manuallySpecifiedLances[i - 1]; + MLanceOverride lanceOverride = DataManager.Instance.GetLanceOverride(lanceKey); + Main.Logger.Log($"[{this.GetType().Name}] Using contract-specific settings override for contract '{MissionControl.Instance.CurrentContract.Name}'. Resolved Ally lance will be '{lanceOverride.LanceKey}'."); + new AddEmployerLanceBatch(this, allyOrientationKey, allyLookDirection, mustBeBeyondDistance, mustBeWithinDistance, lanceOverride); + } else { + new AddEmployerLanceBatch(this, allyOrientationKey, allyLookDirection, mustBeBeyondDistance, mustBeWithinDistance); + } } } } diff --git a/src/Core/Settings/AdditionalLances/DropWeightInfluenceSettings.cs b/src/Core/Settings/AdditionalLances/DropWeightInfluenceSettings.cs index 58d5bf25..f3fd8e22 100644 --- a/src/Core/Settings/AdditionalLances/DropWeightInfluenceSettings.cs +++ b/src/Core/Settings/AdditionalLances/DropWeightInfluenceSettings.cs @@ -7,6 +7,12 @@ public class DropWeightInfluenceSettings { [JsonProperty("Enable")] public bool Enable { get; set; } = false; + [JsonProperty("EnemySpawnInfluenceMax")] + public float EnemySpawnInfluenceMax { get; set; } = 0.9f; + + [JsonProperty("AllySpawnInfluenceMax")] + public float AllySpawnInfluenceMax { get; set; } = 0.9f; + [JsonProperty("EnemySpawnInfluencePerHalfSkullAbove")] public float EnemySpawnInfluencePerHalfSkullAbove { get; set; } = 0.1f; @@ -18,5 +24,16 @@ public class DropWeightInfluenceSettings { [JsonProperty("AllySpawnInfluencePerHalfSkullBelow")] public float AllySpawnInfluencePerHalfSkullBelow { get; set; } = -0.1f; + + public float GetSpawnInfluenceMax(string team) { + if (team == "Enemy") { + return EnemySpawnInfluenceMax; + } else if (team == "Allies") { + return AllySpawnInfluenceMax; + } + + Main.Logger.LogError($"[GetSpawnInfluenceMax] Team '{team}' is invalid. Must be 'Enemy' or 'Allies'. Returning 0.9"); + return 0.9f; + } } } \ No newline at end of file diff --git a/src/Core/Settings/ContractSettingsOverrides/ContractSettingsOverrides.cs b/src/Core/Settings/ContractSettingsOverrides/ContractSettingsOverrides.cs index 889ff646..7234adaf 100644 --- a/src/Core/Settings/ContractSettingsOverrides/ContractSettingsOverrides.cs +++ b/src/Core/Settings/ContractSettingsOverrides/ContractSettingsOverrides.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + using Newtonsoft.Json.Linq; namespace MissionControl.Config { @@ -5,6 +7,8 @@ public class ContractSettingsOverrides { public static string AdditionalLances_Enable = "AdditionalLances.Enable"; public static string AdditionalLances_AllyLanceCountOverride = "AdditionalLances.AllyLanceCount"; public static string AdditionalLances_EnemyLanceCountOverride = "AdditionalLances.EnemyLanceCount"; + public static string AdditionalLances_AllyLancesOverride = "AdditionalLances.AllyLances"; + public static string AdditionalLances_EnemyLancesOverride = "AdditionalLances.EnemyLances"; public static string ExtendedLances_Enable = "ExtendedLances.Enable"; public static string ExtendedLances_AllyLanceSizeOverride = "ExtendedLances.AllyLanceSize"; @@ -41,5 +45,10 @@ public int GetInt(string path) { JToken token = Properties.SelectToken(path); return (int)token; } + + public List GetList(string path) { + JToken token = Properties.SelectToken(path); + return token.ToObject>(); + } } } \ No newline at end of file diff --git a/src/Core/Settings/Lance.cs b/src/Core/Settings/Lance.cs index 6d346acb..489b3274 100644 --- a/src/Core/Settings/Lance.cs +++ b/src/Core/Settings/Lance.cs @@ -59,11 +59,25 @@ public int SelectNumberOfAdditionalLances(FactionDef faction, string teamType) { float spawnInfluenceModifier = absDifficultyDifference * ((TeamType == "Enemy") ? dropWeightSettings.EnemySpawnInfluencePerHalfSkullAbove : dropWeightSettings.AllySpawnInfluencePerHalfSkullAbove); + if (Math.Abs(spawnInfluenceModifier) > dropWeightSettings.GetSpawnInfluenceMax(TeamType)) { + spawnInfluenceModifier = (TeamType == "Enemy") ? dropWeightSettings.GetSpawnInfluenceMax(TeamType) : dropWeightSettings.GetSpawnInfluenceMax(TeamType) * -1; + Main.LogDebug($"[SelectNumberOfAdditionalLances] [{TeamType}] Calculated '{TeamType}' drop weight influence is above SpawnInfluenceMax. Clamping to: '{spawnInfluenceModifier}'"); + } + + Main.LogDebug($"[SelectNumberOfAdditionalLances] [{TeamType}] SpawnInfluenceModifier is: '{spawnInfluenceModifier}'"); + rawChanceToSpawn = rawChanceToSpawn + spawnInfluenceModifier; } else if (difficultyDifference < 0) { // Player is sending a weaker lance than the contract difficulty requires. Add more influence to AL ally lances spawning. float spawnInfluenceModifier = absDifficultyDifference * ((TeamType == "Enemy") ? dropWeightSettings.EnemySpawnInfluencePerHalfSkullBelow : dropWeightSettings.AllySpawnInfluencePerHalfSkullBelow); + if (Math.Abs(spawnInfluenceModifier) > dropWeightSettings.GetSpawnInfluenceMax(TeamType)) { + spawnInfluenceModifier = (TeamType == "Enemy") ? dropWeightSettings.GetSpawnInfluenceMax(TeamType) * -1 : dropWeightSettings.GetSpawnInfluenceMax(TeamType); + Main.LogDebug($"[SelectNumberOfAdditionalLances] [{TeamType}] Calculated '{TeamType}' drop weight influence is above SpawnInfluenceMax. Clamping to: '{spawnInfluenceModifier}'"); + } + + Main.LogDebug($"[SelectNumberOfAdditionalLances] [{TeamType}] SpawnInfluenceModifier is: '{spawnInfluenceModifier}''"); + rawChanceToSpawn = rawChanceToSpawn + spawnInfluenceModifier; } diff --git a/src/Core/Settings/SettingsOverride.cs b/src/Core/Settings/SettingsOverride.cs index f607b6c5..c2e4334a 100644 --- a/src/Core/Settings/SettingsOverride.cs +++ b/src/Core/Settings/SettingsOverride.cs @@ -60,6 +60,8 @@ public class SettingsOverride { public static string AdditionalLances_MatchAllyLanceCountToEnemy = "AdditionalLances.MatchAllyLanceCountToEnemy"; public static string AdditionalLances_DropWeightInfluence_Enable = "AdditionalLances.DropWeightInfluence.Enable"; + public static string AdditionalLances_DropWeightInfluence_EnemySpawnInfluenceMax = "AdditionalLances.DropWeightInfluence.EnemySpawnInfluenceMax"; + public static string AdditionalLances_DropWeightInfluence_AllySpawnInfluenceMax = "AdditionalLances.DropWeightInfluence.AllySpawnInfluenceMax"; public static string AdditionalLances_DropWeightInfluence_EnemySpawnInfluencePerHalfSkullAbove = "AdditionalLances.DropWeightInfluence.EnemySpawnInfluencePerHalfSkullAbove"; public static string AdditionalLances_DropWeightInfluence_AllySpawnInfluencePerHalfSkullAbove = "AdditionalLances.DropWeightInfluence.AllySpawnInfluencePerHalfSkullAbove"; public static string AdditionalLances_DropWeightInfluence_EnemySpawnInfluencePerHalfSkullBelow = "AdditionalLances.DropWeightInfluence.EnemySpawnInfluencePerHalfSkullBelow"; @@ -247,6 +249,8 @@ private void LoadAdditionalLances(Settings settings) { if (Has(AdditionalLances_MatchAllyLanceCountToEnemy)) settings.AdditionalLanceSettings.MatchAllyLanceCountToEnemy = GetBool(AdditionalLances_MatchAllyLanceCountToEnemy); if (Has(AdditionalLances_DropWeightInfluence_Enable)) settings.AdditionalLanceSettings.DropWeightInfluenceSettings.Enable = GetBool(AdditionalLances_DropWeightInfluence_Enable); + if (Has(AdditionalLances_DropWeightInfluence_EnemySpawnInfluenceMax)) settings.AdditionalLanceSettings.DropWeightInfluenceSettings.EnemySpawnInfluenceMax = GetFloat(AdditionalLances_DropWeightInfluence_EnemySpawnInfluenceMax); + if (Has(AdditionalLances_DropWeightInfluence_AllySpawnInfluenceMax)) settings.AdditionalLanceSettings.DropWeightInfluenceSettings.AllySpawnInfluenceMax = GetFloat(AdditionalLances_DropWeightInfluence_AllySpawnInfluenceMax); if (Has(AdditionalLances_DropWeightInfluence_EnemySpawnInfluencePerHalfSkullAbove)) settings.AdditionalLanceSettings.DropWeightInfluenceSettings.EnemySpawnInfluencePerHalfSkullAbove = GetFloat(AdditionalLances_DropWeightInfluence_EnemySpawnInfluencePerHalfSkullAbove); if (Has(AdditionalLances_DropWeightInfluence_AllySpawnInfluencePerHalfSkullAbove)) settings.AdditionalLanceSettings.DropWeightInfluenceSettings.AllySpawnInfluencePerHalfSkullAbove = GetFloat(AdditionalLances_DropWeightInfluence_AllySpawnInfluencePerHalfSkullAbove); if (Has(AdditionalLances_DropWeightInfluence_EnemySpawnInfluencePerHalfSkullBelow)) settings.AdditionalLanceSettings.DropWeightInfluenceSettings.EnemySpawnInfluencePerHalfSkullBelow = GetFloat(AdditionalLances_DropWeightInfluence_EnemySpawnInfluencePerHalfSkullBelow); diff --git a/src/Main.cs b/src/Main.cs index a6ed488a..89fcc3d3 100644 --- a/src/Main.cs +++ b/src/Main.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Net; -using System.Threading; +using System.Linq; using System.Globalization; using System.Collections.Generic; @@ -90,11 +90,13 @@ private static void LoadSettings(string modDirectory) { Settings.AdditionalLances[0] = JsonConvert.DeserializeObject(additionalLancesJsonString, serialiserSettings); string difficultyFileName = "Difficulty"; - for (int i = 1; i <= 10; i++) { - if (File.Exists($"{alPath}{difficultyFileName}{i}.json")) { - string skullAdditionalLanceJsonString = File.ReadAllText($"{alPath}{difficultyFileName}{i}.json"); - Settings.AdditionalLances[i] = JsonConvert.DeserializeObject(skullAdditionalLanceJsonString, serialiserSettings); - } + var filePaths = Directory.GetFiles(alPath).Where(filePath => System.IO.Path.GetFileNameWithoutExtension(filePath).StartsWith(difficultyFileName)); + + foreach (string filePath in filePaths) { + string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath); + int difficultyLevel = int.Parse(fileName.Replace(difficultyFileName, "")); + string additionalLanceJsonString = File.ReadAllText(filePath); + Settings.AdditionalLances[difficultyLevel] = JsonConvert.DeserializeObject(additionalLanceJsonString, serialiserSettings); } } diff --git a/src/Patches/CustomContractTypes/SimGameStateFilterActiveMapsPatch.cs b/src/Patches/CustomContractTypes/SimGameStateFilterActiveMapsPatch.cs index be00a5f8..a95e6486 100644 --- a/src/Patches/CustomContractTypes/SimGameStateFilterActiveMapsPatch.cs +++ b/src/Patches/CustomContractTypes/SimGameStateFilterActiveMapsPatch.cs @@ -17,6 +17,7 @@ static void Postfix(SimGameState __instance, ref WeightedList FilterOnMapsWithEncountersWithValidContractRequirements(__instance, activeMaps, currentContracts); if (activeMaps.Count <= 0) HandleLackOfContractsSituation(__instance, activeMaps, currentContracts); + if (activeMaps.Count <= 0) HandleLackOfContractsSituation(__instance, activeMaps, currentContracts, false); } private static void FixActiveMapWeights(WeightedList activeMaps) { @@ -48,7 +49,6 @@ private static void FixActiveMapWeights(WeightedList activeMap private static void FilterOnMapsWithEncountersWithValidContractRequirements(SimGameState simGameState, WeightedList activeMaps, List currentContracts) { List mapsToRemove = new List(); - StarSystem system = MissionControl.Instance.System; var validParticipants = AccessTools.Method(typeof(SimGameState), "GetValidParticipants").Invoke(simGameState, new object[] { system }); MethodInfo GetValidFactionMethod = AccessTools.Method(typeof(SimGameState), "GetValidFaction"); @@ -56,36 +56,57 @@ private static void FilterOnMapsWithEncountersWithValidContractRequirements(SimG for (int i = 0; i < activeMaps.Count; i++) { MapAndEncounters level = activeMaps[i]; + List checkedContractTypeIds = new List(); bool removeMap = true; + // Main.LogDebug($""); + // Main.LogDebug($"--- PROCESSING MAP '{level.Map.MapName}' ---"); + // Main.LogDebug($""); + foreach (EncounterLayer_MDD encounterLayerMDD in level.Encounters) { int contractTypeId = (int)encounterLayerMDD.ContractTypeRow.ContractTypeID; + // Main.LogDebug($""); + // Main.LogDebug($"--- PROCESSING CONTRACT TYPE {contractTypeId} ---"); + // Main.LogDebug($""); + // If the encounter ContractTypeID exists in the potential contracts list, continue - if (MissionControl.Instance.PotentialContracts.ContainsKey(contractTypeId)) { - // If the contract overrides in the potential contracts by ContractTypeID has a `DoesContractMeetRequirements` sucess, mark remove = false + if (MissionControl.Instance.PotentialContracts.ContainsKey(contractTypeId) && !checkedContractTypeIds.Contains(contractTypeId)) { + checkedContractTypeIds.Add(contractTypeId); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' is within potential contracts."); + + // If the contract overrides in the potential contracts by ContractTypeID has a `DoesContractMeetRequirements` success, mark remove = false List contractOverrides = MissionControl.Instance.PotentialContracts[contractTypeId]; - // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] '{contractTypeId}' - contractOverrides count is: {contractOverrides.Count}"); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - There are '{contractOverrides.Count}' ContractOverrides (contracts)"); for (int j = contractOverrides.Count; j > 0; j--) { ContractOverride contractOverride = contractOverrides[j - 1]; - // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] '{contractTypeId}' - contractOverride is: {contractOverride.ID}"); - // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] '{contractTypeId}' - validParticipants is: {validParticipants}"); + // Main.LogDebug(""); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Encounter '{encounterLayerMDD.Name}' Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - ContractOverride is: {contractOverride.ID}"); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - ValidParticipants is: {validParticipants}. Cannot extract factions/participants due to BT intern restrictions."); + bool doesContractHaveValidFactions = (bool)GetValidFactionMethod.Invoke(simGameState, new object[] { system, validParticipants, contractOverride.requirementList, null }); - // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] '{contractTypeId}' - Contract '{contractOverride.ID}' has valid fations?: {doesContractHaveValidFactions}"); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - Contract '{contractOverride.ID}' has valid fations?: {doesContractHaveValidFactions}"); if (!doesContractHaveValidFactions) { - // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] '{contractTypeId}' - Removing Contract '{contractOverride.ID}' from potential list"); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - Removing Contract '{contractOverride.ID}' from potential list due to not having any valid factions/participants on the contract."); contractOverrides.RemoveAt(j - 1); continue; } bool doesContractMeetReqs = (bool)DoesContractMeetRequirementsMethod.Invoke(simGameState, new object[] { system, level, contractOverride }); - if (doesContractMeetReqs) { - // At least one contract override meets the requirements to prevent the infinite spinner so ignore this logic now and continue to the next map/encounter combo - // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] '{contractTypeId}' - Level '{level.Map.MapName}.{encounterLayerMDD.Name}' has at least one valid contract override"); - removeMap = false; - break; + if (!doesContractMeetReqs) { + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - Contract '{contractOverride.ID}' FAILS requirements with level '{level.Map.MapName}.{encounterLayerMDD.Name}'. Removing Contract '{contractOverride.ID}' from potential list due to not having met requirements on the contract."); + contractOverrides.RemoveAt(j - 1); + continue; } + + // At least one contract override meets the requirements to prevent the infinite spinner so ignore this logic now and continue to the next map/encounter combo + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - Contract '{contractOverride.ID}' MEETS requirements with level '{level.Map.MapName}.{encounterLayerMDD.Name}' and has at least one valid contract override. Will keep as a possible 'active map' for selection on."); + removeMap = false; } + } else if (checkedContractTypeIds.Contains(contractTypeId)) { + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Skipping checks for Encounter '{encounterLayerMDD.Name}' because already checked Contract Type '{encounterLayerMDD.ContractTypeRow.Name}'"); + } else { + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Contract Type '{encounterLayerMDD.ContractTypeRow.Name}' - Doesn't exist in the potential contracts."); } } @@ -102,20 +123,20 @@ private static void FilterOnMapsWithEncountersWithValidContractRequirements(SimG } // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] There are '{activeMaps.Count}' active maps/encounter combos to use. These are:"); - /* for (int k = 0; k < activeMaps.Count; k++) { MapAndEncounters level = activeMaps[k]; - Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] - '{level.Map.MapName}' with '{level.Encounters.Length}' encounters"); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] '{level.Map.MapName}' with '{level.Encounters.Length}' encounters"); foreach (EncounterLayer_MDD encounterLayerMDD in level.Encounters) { - Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] - Encounter '{encounterLayerMDD.Name}'"); + // Main.LogDebug($"[FilterOnMapsWithEncountersWithValidContractRequirements] Encounter '{encounterLayerMDD.Name}'"); } } - */ } - private static void HandleLackOfContractsSituation(SimGameState simGameState, WeightedList activeMaps, List currentContracts) { + private static void HandleLackOfContractsSituation(SimGameState simGameState, WeightedList activeMaps, List currentContracts, bool filterOutRepeats = true) { // If there are no more active maps, reset the biomes/maps list - Main.Logger.LogWarning($"[FilterOnMapsWithEncountersWithValidContractRequirements] No valid map/encounter combinations. Handling lack of map/encounter situation."); + // Main.Logger.LogWarning($"[HandleLackOfContractsSituation] No valid map/encounter combinations. Handling lack of map/encounter situation."); + // if (!filterOutRepeats) Main.Logger.LogWarning($"[HandleLackOfContractsSituation] Since previous runs that filter out used maps didn't produce results. Filtering will not happen on this run."); + StarSystem system = MissionControl.Instance.System; List mapDiscardPile = (List)AccessTools.Field(typeof(SimGameState), "mapDiscardPile").GetValue(simGameState); mapDiscardPile.Clear(); @@ -126,10 +147,10 @@ private static void HandleLackOfContractsSituation(SimGameState simGameState, We activeMaps.AddRange(weightedList); - Main.Logger.LogWarning($"[FilterOnMapsWithEncountersWithValidContractRequirements] Running fresh map list over post processing to ensure no contracts screen freezes"); - HandleContractRepeats(simGameState, activeMaps); - FilterOnMapsWithEncountersWithValidContractRequirements(simGameState, activeMaps, currentContracts); + // Main.Logger.LogWarning($"[HandleLackOfContractsSituation] Running fresh map list over post processing to ensure no contracts screen freezes"); + if (filterOutRepeats) HandleContractRepeats(simGameState, activeMaps); FixActiveMapWeights(activeMaps); + FilterOnMapsWithEncountersWithValidContractRequirements(simGameState, activeMaps, currentContracts); } private static void HandleContractRepeats(SimGameState simGameState, WeightedList activeMaps) { diff --git a/src/Util/SceneUtils.cs b/src/Util/SceneUtils.cs index 0a7bd7d7..7838f38f 100644 --- a/src/Util/SceneUtils.cs +++ b/src/Util/SceneUtils.cs @@ -8,10 +8,8 @@ public static class SceneUtils { public static Vector3 GetRandomPositionWithinBounds(Vector3 target, float maxDistance) { - GameObject chunkBoundaryRect = MissionControl.MissionControl.Instance.EncounterLayerGameObject.transform.Find("Chunk_EncounterBoundary").gameObject; - GameObject boundary = chunkBoundaryRect.transform.Find("EncounterBoundaryRect").gameObject; - EncounterBoundaryChunkGameLogic chunkBoundary = chunkBoundaryRect.GetComponent(); - EncounterBoundaryRectGameLogic boundaryLogic = boundary.GetComponent(); + EncounterBoundaryChunkGameLogic chunkBoundary = MissionControl.MissionControl.Instance.EncounterLayerGameObject.GetComponentInChildren(); + EncounterBoundaryRectGameLogic boundaryLogic = chunkBoundary.GetComponentInChildren(); Rect boundaryRec = chunkBoundary.GetEncounterBoundaryRectBounds(); Vector3 randomRecPosition = boundaryRec.GetRandomPositionFromTarget(target, maxDistance);