public override void Run(RunPayload payload) { Main.Logger.Log($"[AddExtraLanceSpawnPoints] Adding lance spawn points to match contract override data"); Contract contract = MissionControl.Instance.CurrentContract; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; ContractOverride contractOverride = contract.Override; lanceSpawners = new List <LanceSpawnerGameLogic>(encounterLayerData.gameObject.GetComponentsInChildren <LanceSpawnerGameLogic>()); TeamOverride targetTeamOverride = contractOverride.targetTeam; TeamOverride employerTeamOverride = contractOverride.employerTeam; IncreaseLanceSpawnPoints(contractOverride, targetTeamOverride); IncreaseLanceSpawnPoints(contractOverride, employerTeamOverride); state.Set("ExtraLanceSpawnKeys", spawnKeys); }
public override void Run(RunPayload payload) { Main.LogDebug("[DialogTrigger] Setting up trigger"); EncounterLayerData encounterData = MissionControl.Instance.EncounterLayerData; SmartTriggerResponse triggerDialogue = new SmartTriggerResponse(); triggerDialogue.inputMessage = onMessage; triggerDialogue.designName = $"Initiate dialogue on {triggerDialogue}"; triggerDialogue.conditionalbox = new EncounterConditionalBox(conditional); DialogResult dialogueResult = ScriptableObject.CreateInstance <DialogResult>(); dialogueResult.dialogueRef.EncounterObjectGuid = dialogueGuid; dialogueResult.isInterrupt = this.isInterrupt; triggerDialogue.resultList.contentsBox.Add(new EncounterResultBox(dialogueResult)); encounterData.responseGroup.triggerList.Add(triggerDialogue); }
public override void Run(RunPayload payload) { Main.LogDebug("[ShowObjectiveTrigger] Setting up trigger"); EncounterLayerData encounterData = MissionControl.Instance.EncounterLayerData; SmartTriggerResponse trigger = new SmartTriggerResponse(); trigger.inputMessage = onMessage; trigger.designName = $"Show objective on {onMessage}"; trigger.conditionalbox = new EncounterConditionalBox(conditional); ShowObjectiveResult showObjectiveResult = ScriptableObject.CreateInstance <ShowObjectiveResult>(); showObjectiveResult.ObjectiveGuid = this.objectiveGuid; showObjectiveResult.IsContractObjective = this.isContractObjective; trigger.resultList.contentsBox.Add(new EncounterResultBox(showObjectiveResult)); encounterData.responseGroup.triggerList.Add(trigger); }
public override void Run(RunPayload payload) { Main.Logger.Log($"[AddCustomPlayerLanceSpawnChunk] Adding encounter structure"); EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; EmptyCustomChunkGameLogic emptyCustomChunk = ChunkFactory.CreateEmptyCustomChunk("Chunk_Lance"); emptyCustomChunk.encounterObjectGuid = System.Guid.NewGuid().ToString(); emptyCustomChunk.notes = debugDescription; // Auto select Player or Employer based on the lance configurator if (teamGuid == null) { SpawnableUnit[] lanceUnits = MissionControl.Instance.CurrentContract.Lances.GetLanceUnits(EncounterRules.PLAYER_TEAM_ID); if (lanceUnits.Length > 4) { teamGuid = EncounterRules.PLAYER_TEAM_ID; } else { teamGuid = EncounterRules.EMPLOYER_TEAM_ID; } } // Guard: Don't do anything if there are no employer units and employer mode is on SpawnableUnit[] employerLanceUnits = MissionControl.Instance.CurrentContract.Lances.GetLanceUnits(EncounterRules.EMPLOYER_TEAM_ID); Main.Logger.Log($"[AddCustomPlayerLanceExtraSpawnPoints] '{employerLanceUnits.Length}' employer lance units are being sent to Mission Control by Bigger Drops."); if (employerLanceUnits.Length <= 0) { return; } bool spawnOnActivation = true; CustomPlayerLanceSpawnerGameLogic lanceSpawner = LanceSpawnerFactory.CreateCustomPlayerLanceSpawner( emptyCustomChunk.gameObject, spawnerName, lanceGuid, teamGuid, spawnOnActivation, SpawnUnitMethodType.ViaLeopardDropship, unitGuids ); lanceSpawner.transform.position = Vector3.zero; }
public void InitSceneData() { CombatGameState combat = UnityGameInstance.BattleTechGame.Combat; if (!EncounterLayerParentGameObject) { EncounterLayerParentGameObject = GameObject.Find("EncounterLayerParent"); } EncounterLayerParent = EncounterLayerParentGameObject.GetComponent <EncounterLayerParent>(); EncounterLayerData = GetActiveEncounter(); EncounterLayerGameObject = EncounterLayerData.gameObject; EncounterLayerData.CalculateEncounterBoundary(); if (HexGrid == null) { HexGrid = ReflectionHelper.GetPrivateStaticField(typeof(WorldPointGameLogic), "_hexGrid") as HexGrid; } }
protected List <GameObject> GetInvalidLanceMemberSpawns(GameObject lance, Vector3 checkTarget) { CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; List <GameObject> invalidLanceSpawns = new List <GameObject>(); List <GameObject> spawnPoints = lance.FindAllContains("SpawnPoint"); Vector3 checkTargetPosition = checkTarget.GetClosestHexLerpedPointOnGrid(); foreach (GameObject spawnPoint in spawnPoints) { // Vector3 spawnPointPosition = spawnPoint.transform.position.GetClosestHexLerpedPointOnGrid(); Vector3 spawnPointPosition = GetClosestValidPathFindingHex(spawnPoint, spawnPoint.transform.position, $"GetInvalidLanceMemberSpawns.{spawnPoint.name}", IsLancePlayerLance(lance.name) ? checkTargetPosition : Vector3.zero, 2); Main.LogDebug($"[SpawnLanceLogic.GetInvalidLanceMemberSpawns] Spawn point's closest hex lerped point on grid for '{spawnPoint.name}' is '{spawnPointPosition}'"); if (!encounterLayerData.IsInEncounterBounds(spawnPointPosition)) { Main.LogDebugWarning("[SpawnLanceLogic.GetInvalidLanceMemberSpawns] Lance member spawn is outside of the boundary. Select a new lance spawn point."); invalidLanceSpawns.Add(spawnPoint); continue; } // Ensure the lance member's spawn's closest valid point isn't on another spawn point's closest valid point if (IsPointTooCloseToOtherPointsClosestPointOnGrid(spawnPointPosition, spawnPoints.Where(sp => spawnPoint.name != sp.name).ToList())) { Main.LogDebugWarning("[SpawnLanceLogic.GetInvalidLanceMemberSpawns] Lance member spawn is too close to the other spawns when snapped to the grid"); invalidLanceSpawns.Add(spawnPoint); continue; } if (!PathFinderManager.Instance.IsSpawnValid(spawnPoint, spawnPointPosition, checkTargetPosition, UnitType.Mech, spawnPoint.name)) { Main.LogDebugWarning($"[SpawnLanceLogic.GetInvalidLanceMemberSpawns] Lance member spawn '{spawnPoint.name}' path to check target '{checkTarget}' is blocked. Select a new lance spawn point"); invalidLanceSpawns.Add(spawnPoint); continue; } spawnPoint.transform.position = spawnPointPosition; } return(invalidLanceSpawns); }
public static EncounterLayerData CreateEncounterLayer(Contract contract) { EncounterLayer_MDD encounterLayerMDD = MissionControl.Instance.EncounterLayerMDD; GameObject encounterLayerGo = new GameObject(encounterLayerMDD.Name); EncounterLayerData encounterLayer = encounterLayerGo.AddComponent <EncounterLayerData>(); encounterLayer.encounterObjectGuid = contract.encounterObjectGuid; encounterLayer.encounterName = MissionControl.Instance.CurrentContractTypeValue.Name; encounterLayer.encounterDescription = MissionControl.Instance.EncounterLayerMDD.Description; encounterLayer.EDITOR_SetSupportedContractTypeID(MissionControl.Instance.CurrentContractTypeValue.Name); encounterLayer.version = MissionControl.Instance.CurrentContractTypeValue.Version; // Need to dump the serialised binary data into a mock EncounterLayerData then throw it away to get the important bits GameObject mockGo = new GameObject("MockGo"); EncounterLayerData mockLayer = mockGo.AddComponent <EncounterLayerData>(); List <EncounterLayerIdentifier> layerIdList = UnityGameInstance.BattleTechGame.Combat.MapMetaData.encounterLayerIdentifierList; mockLayer.LoadMapData(layerIdList[0], UnityGameInstance.BattleTechGame.DataManager); encounterLayer.mapEncounterLayerDataCells = mockLayer.mapEncounterLayerDataCells; encounterLayer.inclineMeshData = mockLayer.inclineMeshData; MonoBehaviour.Destroy(mockLayer); // Clear out all old regions from copied encounter layer data for (int j = 0; j < encounterLayer.mapEncounterLayerDataCells.GetLength(1); j++) { for (int k = 0; k < encounterLayer.mapEncounterLayerDataCells.GetLength(0); k++) { List <string> regionGuidList = encounterLayer.mapEncounterLayerDataCells[j, k].regionGuidList; if (regionGuidList != null) { regionGuidList.Clear(); } } } CreateContractObjectives(encounterLayerGo); encounterLayerGo.AddComponent <PlotOverride>(); return(encounterLayer); }
public static MapEncounterLayerDataCell[,] GetMapEncounterLayerDataCells(this EncounterLayerData layerData) { if (layerData.mapEncounterLayerDataCells != null) { return(layerData.mapEncounterLayerDataCells); } Transform parent = layerData.gameObject.transform.parent; foreach (Transform t in parent) { EncounterLayerData siblingEncounterLayer = t.GetComponent <EncounterLayerData>(); if (siblingEncounterLayer.mapEncounterLayerDataCells != null) { return(siblingEncounterLayer.mapEncounterLayerDataCells); } } return(null); }
public override void Run(RunPayload payload) { Main.Logger.Log($"[AddObjectiveToAutocompleteTrigger] Adding objective '{objectiveId}' to AutocompleteGameLogic"); EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; AutoCompleteGameLogic autoCompleteGameLogic = encounterLayerData.GetComponent <AutoCompleteGameLogic>(); if (autoCompleteGameLogic != null) { TriggeringObjectiveStatus triggeringObjectiveStatus = new TriggeringObjectiveStatus(); ObjectiveRef objectiveRef = new ObjectiveRef(); objectiveRef.EncounterObjectGuid = objectiveId; triggeringObjectiveStatus.objective = objectiveRef; triggeringObjectiveStatus.objectiveStatus = ObjectiveStatusEvaluationType.Complete; autoCompleteGameLogic.triggeringObjectiveList.Add(triggeringObjectiveStatus); } else { Main.LogDebugWarning($"[AddObjectiveToAutocompleteTrigger] Contract type '{MissionControl.Instance.CurrentContractType}' has no Autocomplete logic. Unable to add objective '{objectiveId}' to triggers"); } }
public static List <MapEncounterLayerDataCell> GetMapEncounterLayerDataCellsWithinCollider(GameObject regionGo) { MeshCollider collider = regionGo.GetComponent <MeshCollider>(); RegionGameLogic regionGameLogic = regionGo.GetComponent <RegionGameLogic>(); List <MapEncounterLayerDataCell> cells = new List <MapEncounterLayerDataCell>(); Vector3 colliderExtents = collider.bounds.extents; Vector3 colliderCenter = collider.bounds.center; EncounterLayerData encounterLayerData = MissionControl.MissionControl.Instance.EncounterLayerData; int cellX = encounterLayerData.GetXIndex(colliderCenter.x); int cellZ = encounterLayerData.GetZIndex(colliderCenter.z); // Add center MapEncounterLayerDataCell layerDataCell = GetOrCreateEncounterLayerDataCell(cellX, cellZ); cells.Add(layerDataCell); float bottom = colliderCenter.x - colliderExtents.x; float top = colliderCenter.x + colliderExtents.x; float left = colliderCenter.z - colliderExtents.z; float right = colliderCenter.z + colliderExtents.z; for (float i = bottom; i < top; i += 0.5f) { for (float j = left; j < right; j += 0.5f) { cellX = encounterLayerData.GetXIndex(i); cellZ = encounterLayerData.GetZIndex(j); layerDataCell = GetOrCreateEncounterLayerDataCell(cellX, cellZ); if (layerDataCell != null) { cells.Add(layerDataCell); } } } return(cells); }
public override void Run(RunPayload payload) { Main.Logger.Log($"[AddLanceSpawnChunk] Adding encounter structure"); EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; EmptyCustomChunkGameLogic emptyCustomChunk = ChunkFactory.CreateEmptyCustomChunk("Chunk_Lance"); emptyCustomChunk.encounterObjectGuid = System.Guid.NewGuid().ToString(); emptyCustomChunk.notes = debugDescription; bool spawnOnActivation = true; LanceSpawnerGameLogic lanceSpawner = LanceSpawnerFactory.CreateLanceSpawner( emptyCustomChunk.gameObject, spawnerName, lanceGuid, teamGuid, spawnOnActivation, SpawnUnitMethodType.InstantlyAtSpawnPoint, unitGuids ); lanceSpawner.transform.position = Vector3.zero; }
public override void Run(RunPayload payload) { Main.LogDebug("[IssueFollowLanceOrderTrigger] Setting up trigger"); EncounterLayerData encounterData = MissionControl.Instance.EncounterLayerData; SmartTriggerResponse onEncounterLoadIssueOrder = new SmartTriggerResponse(); onEncounterLoadIssueOrder.inputMessage = MessageCenterMessageType.OnEncounterBegin; onEncounterLoadIssueOrder.designName = "Issue Follow Lance AI order on Encounter Start"; onEncounterLoadIssueOrder.conditionalbox = new EncounterConditionalBox(ScriptableObject.CreateInstance <AlwaysTrueConditional>()); FollowLanceOrder followOrder = new FollowLanceOrder(); followOrder.TargetEncounterTags.AddRange(this.targetTags); IssueCustomAIOrderResult issueOrder = ScriptableObject.CreateInstance <IssueCustomAIOrderResult>(); issueOrder.issueAIOrderTo = this.receiverType; issueOrder.requiredReceiverTags.AddRange(this.receiverTags); issueOrder.aiOrder = followOrder; onEncounterLoadIssueOrder.resultList.contentsBox.Add(new EncounterResultBox(issueOrder)); encounterData.responseGroup.triggerList.Add(onEncounterLoadIssueOrder); }
public override void Run(RunPayload payload) { Main.Logger.Log($"[AddExtraLanceSpawnPoints] Adding lance spawn points to match contract override data"); Contract contract = MissionControl.Instance.CurrentContract; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; ContractOverride contractOverride = contract.Override; lancesToSkip = (List <string>)state.GetObject("LancesToSkip"); lanceSpawners = new List <LanceSpawnerGameLogic>(encounterLayerData.gameObject.GetComponentsInChildren <LanceSpawnerGameLogic>()); TeamOverride targetTeamOverride = contractOverride.targetTeam; TeamOverride employerTeamOverride = contractOverride.employerTeam; if (Main.Settings.ActiveContractSettings.Has(ContractSettingsOverrides.ExtendedLances_EnemyLanceSizeOverride)) { int lanceSizeOverride = Main.Settings.ActiveContractSettings.GetInt(ContractSettingsOverrides.ExtendedLances_EnemyLanceSizeOverride); Main.Logger.Log($"[AddExtraLanceSpawnPoints] Using contract-specific settings override for contract '{MissionControl.Instance.CurrentContract.Name}'. Enemy lance size will be '{lanceSizeOverride}'."); IncreaseLanceSpawnPoints(contractOverride, targetTeamOverride, lanceSizeOverride); } else { IncreaseLanceSpawnPoints(contractOverride, targetTeamOverride); } if (Main.Settings.ActiveContractSettings.Has(ContractSettingsOverrides.ExtendedLances_AllyLanceSizeOverride)) { int lanceSizeOverride = Main.Settings.ActiveContractSettings.GetInt(ContractSettingsOverrides.ExtendedLances_AllyLanceSizeOverride); Main.Logger.Log($"[AddExtraLanceSpawnPoints] Using contract-specific settings override for contract '{MissionControl.Instance.CurrentContract.Name}'. Ally lance size will be '{lanceSizeOverride}'."); IncreaseLanceSpawnPoints(contractOverride, employerTeamOverride, lanceSizeOverride); } else { IncreaseLanceSpawnPoints(contractOverride, employerTeamOverride); } state.Set("ExtraLanceSpawnKeys", spawnKeys); }
private GameObject CheckAllPlotsForValidPlot(GameObject plotsParent, Vector3 origin, string name) { GameObject closestPlot = null; float closestDistance = -1; foreach (Transform t in plotsParent.transform) { Vector3 plotPosition = t.position; if (EncounterLayerData.IsInEncounterBounds(plotPosition)) { if (IsPlotValidForEncounter(t, name)) { float distance = Vector3.Distance(t.position, origin); if (closestDistance == -1 || closestDistance < distance) { closestDistance = distance; closestPlot = t.gameObject; } } } } return(closestPlot); }
public static void SpawnAmbush(Vector3 ambushOrigin, AmbushType ambushType) { // Determine how many units we're spawning int minSpawns = 0, maxSpawns = 0; if (ambushType == AmbushType.BattleArmor) { if (!Mod.Config.BattleArmorAmbush.Enabled) { return; } minSpawns = ModState.BattleArmorAmbushDefForContract.MinSpawns; maxSpawns = ModState.BattleArmorAmbushDefForContract.MaxSpawns; } else if (ambushType == AmbushType.Mech) { if (!Mod.Config.MechAmbush.Enabled) { return; } minSpawns = ModState.MechAmbushDefForContract.MinSpawns; maxSpawns = ModState.MechAmbushDefForContract.MaxSpawns; } else if (ambushType == AmbushType.Vehicle) { if (!Mod.Config.VehicleAmbush.Enabled) { return; } minSpawns = ModState.VehicleAmbushDefForContract.MinSpawns; maxSpawns = ModState.VehicleAmbushDefForContract.MaxSpawns; } int actorsToSpawn = Mod.Random.Next(minSpawns, maxSpawns); Mod.Log.Debug?.Write($"Spawning {actorsToSpawn} actors as part of this ambush."); // Starting with the closest building, look through the buildings and determine how many locations can support a unit. List <BattleTech.Building> candidates = CandidateBuildingsHelper.ClosestCandidatesToPosition(ambushOrigin, Mod.Config.Ambush.SearchRadius); if (candidates.Count < minSpawns) { Mod.Log.Debug?.Write($"Insufficient candidate buildings for a spawn ambush. Skipping."); return; } // Create a new lance in the target team Lance ambushLance = TeamHelper.CreateAmbushLance(ModState.AmbushTeam); ModState.CurrentSpawningLance = ambushLance; EncounterLayerData encounterLayerData = ModState.Combat.EncounterLayerData; List <BattleTech.Building> buildingsToLevel = new List <BattleTech.Building>(); List <AbstractActor> spawnedActors = new List <AbstractActor>(); foreach (BattleTech.Building building in candidates) { if (actorsToSpawn == 0) { break; // nothing more to do, end processing. } // Spawn one unit at the origin of the building buildingsToLevel.Add(building); Mod.Log.Debug?.Write("Spawning actor at building origin."); AbstractActor spawnedActor = null; if (ambushType == AmbushType.BattleArmor) { spawnedActor = SpawnAmbushMech(ModState.AmbushTeam, ambushLance, ambushOrigin, building.CurrentPosition, building.CurrentRotation, ModState.BattleArmorAmbushDefForContract.SpawnPool); } else if (ambushType == AmbushType.Mech) { spawnedActor = SpawnAmbushMech(ModState.AmbushTeam, ambushLance, ambushOrigin, building.CurrentPosition, building.CurrentRotation, ModState.MechAmbushDefForContract.SpawnPool); } else if (ambushType == AmbushType.Vehicle) { spawnedActor = SpawnAmbushVehicle(ModState.AmbushTeam, ambushLance, ambushOrigin, building.CurrentPosition, building.CurrentRotation); } spawnedActors.Add(spawnedActor); actorsToSpawn--; // Iterate through adjacent hexes to see if we can spawn more units in the building List <Vector3> adjacentHexes = ModState.Combat.HexGrid.GetGridPointsAroundPointWithinRadius(ambushOrigin, 3); // 3 hexes should cover most large buidlings foreach (Vector3 adjacentHex in adjacentHexes) { if (actorsToSpawn == 0) { break; } Point cellPoint = new Point(ModState.Combat.MapMetaData.GetXIndex(adjacentHex.x), ModState.Combat.MapMetaData.GetZIndex(adjacentHex.z)); Mod.Log.Debug?.Write($" Evaluating point {cellPoint.X}, {cellPoint.Z} for potential ambush."); if (encounterLayerData.mapEncounterLayerDataCells[cellPoint.Z, cellPoint.X].HasSpecifiedBuilding(building.GUID)) { Mod.Log.Debug?.Write($"Spawning actor at adjacent hex at position: {adjacentHex}"); AbstractActor additionalSpawn = null; if (ambushType == AmbushType.BattleArmor) { additionalSpawn = SpawnAmbushMech(ModState.AmbushTeam, ambushLance, ambushOrigin, adjacentHex, building.CurrentRotation, ModState.BattleArmorAmbushDefForContract.SpawnPool); } else if (ambushType == AmbushType.Mech) { additionalSpawn = SpawnAmbushMech(ModState.AmbushTeam, ambushLance, ambushOrigin, adjacentHex, building.CurrentRotation, ModState.MechAmbushDefForContract.SpawnPool); } else if (ambushType == AmbushType.Vehicle) { additionalSpawn = SpawnAmbushVehicle(ModState.AmbushTeam, ambushLance, ambushOrigin, adjacentHex, building.CurrentRotation); } spawnedActors.Add(additionalSpawn); actorsToSpawn--; } else { Mod.Log.Debug?.Write($" Hex {adjacentHex} is outside of the main building, skipping."); } } } // Remove any buildings that are part of this ambush from candidates ModState.CandidateBuildings.RemoveAll(x => buildingsToLevel.Contains(x)); // Determine the targets that should be prioritized by the enemies List <ICombatant> targets = new List <ICombatant>(); foreach (ICombatant combatant in ModState.Combat.GetAllCombatants()) { if (!combatant.IsDead && !combatant.IsFlaggedForDeath && combatant.team != null && ModState.Combat.HostilityMatrix.IsLocalPlayerFriendly(combatant.team)) { if (Vector3.Distance(ambushOrigin, combatant.CurrentPosition) <= Mod.Config.Ambush.SearchRadius) { targets.Add(combatant); } } } bool applyAttacks = false; if (ambushType == AmbushType.BattleArmor && Mod.Config.BattleArmorAmbush.FreeAttackEnabled) { applyAttacks = true; } if (ambushType == AmbushType.Mech && Mod.Config.MechAmbush.FreeAttackEnabled) { applyAttacks = true; } if (ambushType == AmbushType.Vehicle && Mod.Config.VehicleAmbush.FreeAttackEnabled) { applyAttacks = true; } Mod.Log.Info?.Write($"Adding SpawnAmbushSequence for {spawnedActors.Count} actors and {buildingsToLevel.Count} buildings to be leveled."); try { SpawnAmbushSequence ambushSequence = new SpawnAmbushSequence(ModState.Combat, ambushOrigin, spawnedActors, buildingsToLevel, targets, applyAttacks); ModState.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(ambushSequence)); } catch (Exception e) { Mod.Log.Error?.Write(e, "Failed to create AES sequence due to error!"); } }
public bool IsSpawnValid(GameObject spawnGo, Vector3 position, Vector3 validityPosition, UnitType type, string identifier) { CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; MapTerrainDataCell cellData = combatState.MapMetaData.GetCellAt(position); Main.LogDebug($""); Main.LogDebug($"-------- [PFM.IsSpawnValid] [{identifier}] --------"); if (position.IsTooCloseToAnotherSpawn(spawnGo)) { Main.LogDebug($"[PFM] Position '{position}' is too close to another spawn point. Not a valid location."); return(false); } if (cellData.cachedSteepness > MAX_SLOPE_FOR_PATHFINDING) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Spawn point of '{cellData.cachedSteepness}' is too steep (> {MAX_SLOPE_FOR_PATHFINDING}). Not a valid spawn"); return(false); } if (IsCellImpassableOrDeepWater(cellData)) { return(false); } if (!encounterLayerData.IsInEncounterBounds(position)) { return(false); } if (cellData.cachedHeight > (cellData.terrainHeight + 50f)) { return(false); } float pathFindingZoneRadius = 25f; AbstractActor pathfindingActor = GetPathFindingActor(type); SetupPathfindingActor(position, pathfindingActor); PathNode positionPathNode = null; try { PathNodeGrid pathfinderPathGrid = pathfindingActor.Pathing.CurrentGrid; positionPathNode = pathfinderPathGrid.GetValidPathNodeAt(position, pathfindingActor.Pathing.MaxCost); if (positionPathNode == null) { Reset(); return(false); } } catch (Exception e) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Caught error in 'pathfinderPathGrid.GetValidPathNodeAt' chunk. Flagging as invalid spawn. Select a new spawn point. {e.Message}, {e.StackTrace}"); WasABadPathfindTest(validityPosition); return(false); } if (positionPathNode == null) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] PositionPathNode not set from 'pathfinderPathGrid.GetValidPathNodeAt'. No valid path found so not a valid spawn."); WasABadPathfindTest(validityPosition); return(false); } List <Vector3> path = null; try { DynamicLongRangePathfinder.PointWithCost pointWithCost = new DynamicLongRangePathfinder.PointWithCost(combatState.HexGrid.GetClosestHexPoint3OnGrid(positionPathNode.Position), 0, (validityPosition - positionPathNode.Position).magnitude); path = DynamicLongRangePathfinder.GetDynamicPathToDestination(new List <DynamicLongRangePathfinder.PointWithCost>() { pointWithCost }, validityPosition, float.MaxValue, pathfindingActor, false, new List <AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); } catch (Exception e) { // TODO: Sometimes this gets triggered in very large amounts. It's usually because the SpawnLogic.GetClosestValidPathFindingHex is increasing // the radius larger and larger and the checks keep going off the map // I need a way to hard abort out of this and either use the original origin of the focus or trigger the rule logic again (random, around a position etc) Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Caught error in 'DynamicLongRangePathfinder' chunk. Flagging as invalid spawn. Select a new spawn point. {e.Message}, {e.StackTrace}"); WasABadPathfindTest(validityPosition); return(false); } if (path == null) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Path not set from DynamicLongRangePathfinder so not a valid spawn."); WasABadPathfindTest(validityPosition); return(false); } Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); // GUARD: Against deep water and other impassables that have slipped through if (HasPathImpassableOrDeepWaterTiles(combatState, path)) { return(false); } if (path != null && path.Count > 1 && (path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Last point is '{path[path.Count - 1]}', Validity position is '{validityPosition}'"); Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Distance from last path to valdity position is: '{(path[path.Count - 1].DistanceFlat(validityPosition))}' and is it within zone radius? '{(path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)}'"); Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Has valid long range path finding"); if (HasValidNeighbours(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Has at least two valid neighbours"); if (HasValidLocalPathfinding(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Has a valid path"); Reset(); Main.LogDebug($"-------- END [PFM.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); return(true); } else { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Does NOT have a valid path"); } } else { Main.LogDebug($"[PFM.IsSpawnValid] [{identifier}] Does not have two valid neighbours"); } } Main.LogDebug($"-------- END [PFM.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); Reset(); return(false); }
private Vector3 PathfindFromPointToSpawn(GameObject originGo, Vector3 origin, int radius, string identifier, Vector3 pathfindingTarget) { EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; Vector3 originOnGrid = origin.GetClosestHexLerpedPointOnGrid(); // TODO: If the SpawnerPlayerLanceGo's closest hex point is in an inaccessible location - this will cause infinite loading issues // TODO: Need to find a reliably accessible location (hard to do in a proc-genned setup) Vector3 pathfindingPoint = (pathfindingTarget == Vector3.zero) ? EncounterRules.SpawnerPlayerLanceGo.transform.position.GetClosestHexLerpedPointOnGrid() : pathfindingTarget.GetClosestHexLerpedPointOnGrid(); Main.LogDebug($"[PathfindFromPointToPlayerSpawn] Using pathfinding point '{pathfindingPoint}'"); if (!PathFinderManager.Instance.IsSpawnValid(originGo, originOnGrid, pathfindingPoint, UnitType.Mech, identifier)) { List <Vector3> adjacentPointsOnGrid = combatState.HexGrid.GetGridPointsAroundPointWithinRadius(originOnGrid, radius); Main.LogDebug($"[PathfindFromPointToPlayerSpawn] Adjacent point count is '{adjacentPointsOnGrid.Count}'"); adjacentPointsOnGrid = adjacentPointsOnGrid.Where(point => { return(!checkedAdjacentPoints.Contains(point) && encounterLayerData.IsInEncounterBounds(point)); }).ToList(); Main.LogDebug($"[PathfindFromPointToPlayerSpawn] Removed already checked points & out of bounds points. Adjacent point count is now '{adjacentPointsOnGrid.Count}'"); adjacentPointsOnGrid.Shuffle(); int count = 0; foreach (Vector3 point in adjacentPointsOnGrid) { if (count > ADJACENT_NODE_LIMITED) { Main.LogDebug($"[PathfindFromPointToPlayerSpawn] Adjacent point count limited exceeded (random selection of {ADJACENT_NODE_LIMITED} / {adjacentPointsOnGrid.Count}). Bailing."); break; } Vector3 validPoint = point.GetClosestHexLerpedPointOnGrid(); Main.LogDebug($"[PathfindFromPointToPlayerSpawn] Testing an adjacent point of '{validPoint}'"); if (PathFinderManager.Instance.IsSpawnValid(originGo, validPoint, pathfindingPoint, UnitType.Mech, identifier)) { return(validPoint); } bool isBadPathfindTest = PathFinderManager.Instance.IsProbablyABadPathfindTest(pathfindingPoint); if (isBadPathfindTest) { Main.LogDebug($"[PathfindFromPointToPlayerSpawn] Estimated this is a bad pathfind setup so trying something new."); radius = 100; count = ADJACENT_NODE_LIMITED; } checkedAdjacentPoints.Add(point); count++; } return(Vector3.zero); } else { Main.LogDebug($"[PathfindFromPointToPlayerSpawn] Spawn has been found valid by pathfinding '{originOnGrid}'"); } return(originOnGrid); }
public static AbstractActor SpawnAmbushTurret(Team team, Lance ambushLance, BattleTech.Building building, Vector3 ambushOrigin) { // Randomly determine one of the spawnpairs from the current ambushdef List <TurretAndPilotDef> shuffledSpawns = new List <TurretAndPilotDef>(); shuffledSpawns.AddRange(ModState.InfantryAmbushDefForContract.SpawnPool); shuffledSpawns.Shuffle(); TurretAndPilotDef ambushDef = shuffledSpawns[0]; PilotDef pilotDef = ModState.Combat.DataManager.PilotDefs.Get(ambushDef.PilotDefId); TurretDef turretDef = ModState.Combat.DataManager.TurretDefs.GetOrCreate(ambushDef.TurretDefId); turretDef.Refresh(); // determine a position somewhere up the building's axis EncounterLayerData encounterLayerData = ModState.Combat.EncounterLayerData; Point cellPoint = new Point( ModState.Combat.MapMetaData.GetXIndex(building.CurrentPosition.x), ModState.Combat.MapMetaData.GetZIndex(building.CurrentPosition.z)); MapEncounterLayerDataCell melDataCell = encounterLayerData.mapEncounterLayerDataCells[cellPoint.Z, cellPoint.X]; float buildingHeight = melDataCell.GetBuildingHeight(); float terrainHeight = ModState.Combat.MapMetaData.GetLerpedHeightAt(building.CurrentPosition, true); float heightDelta = (buildingHeight - terrainHeight) * 0.7f; float adjustedY = terrainHeight + heightDelta; Mod.Log.Debug?.Write($"At building position, terrain height is: {terrainHeight} while buildingHeight is: {buildingHeight}. " + $" Calculated 70% of building height + terrain as {adjustedY}."); Vector3 newPosition = building.GameRep.transform.position; newPosition.y = adjustedY; Mod.Log.Debug?.Write($"Changing transform position from: {building.GameRep.transform.position} to {newPosition}"); /// Rotate to face the ambush origin Vector3 spawnDirection = Vector3.RotateTowards(building.CurrentRotation.eulerAngles, ambushOrigin, 1f, 0f); Quaternion spawnRotation = Quaternion.LookRotation(spawnDirection); // Create the turret Turret turret = ActorFactory.CreateTurret(turretDef, pilotDef, team.EncounterTags, ModState.Combat, team.GetNextSupportUnitGuid(), "", null); turret.Init(newPosition, spawnRotation.eulerAngles.y, true); turret.InitGameRep(null); if (turret == null) { Mod.Log.Error?.Write($"Failed to spawn turretDefId: {ambushDef.TurretDefId} + pilotDefId: {ambushDef.PilotDefId} !"); } Mod.Log.Debug?.Write($" Spawned trap turret, adding to team."); team.AddUnit(turret); turret.AddToTeam(team); turret.AddToLance(ambushLance); turret.BehaviorTree = BehaviorTreeFactory.MakeBehaviorTree(ModState.Combat.BattleTechGame, turret, BehaviorTreeIDEnum.CoreAITree); Mod.Log.Debug?.Write("Updated turret behaviorTree"); ModState.AmbushBuildingGUIDToTurrets.Add(building.GUID, turret); ModState.AmbushTurretGUIDtoBuilding.Add(turret.GUID, building); // Associate the building withe the team building.AddToTeam(team); building.BuildingRep.IsTargetable = true; building.BuildingRep.SetHighlightColor(ModState.Combat, team); building.BuildingRep.RefreshEdgeCache(); // Increase the building's health to the current value + turret structure float combinedStructure = (float)Math.Ceiling(building.CurrentStructure + turret.GetCurrentStructure(BuildingLocation.Structure)); Mod.Log.Debug?.Write($"Setting ambush structure to: {combinedStructure} = building.currentStructure: {building.CurrentStructure} + " + $"turret.currentStructure: {turret.GetCurrentStructure(BuildingLocation.Structure)}"); building.StatCollection.Set <float>("Structure", combinedStructure); // Finally notify others UnitSpawnedMessage message = new UnitSpawnedMessage("CJ_TRAP", turret.GUID); ModState.Combat.MessageCenter.PublishMessage(message); // Finally force the turret to be fully visible turret.OnPlayerVisibilityChanged(VisibilityLevel.LOSFull); return(turret); }
static void Postfix(EncounterLayerData __instance) { Main.LogDebug($"[EncounterLayerData.Postfix] Running..."); EncounterDataManager.Instance.HandleCustomContractType(); }
static void Postfix(LineOfSight __instance, Point p0, float height0, Point p1, float height1, string targetedBuildingGuid, ref Point collisionWorldPos, ref bool __result, CombatGameState ___Combat) { if (ModState.CurrentTurretForLOF == null) { return; } Mod.Log.Trace?.Write($"Recalculating LOF from {CombatantUtils.Label(ModState.CurrentTurretForLOF)} due to collision on building shell. " + $"CollisonWorldPos=> x={collisionWorldPos.X} z={collisionWorldPos.Z}"); collisionWorldPos = p1; // If the origin and target points are the same, there is a collision if (p0.X == p1.X && p0.Z == p1.Z) { __result = true; return; } // If the origin or target points are outsie the bounds of the map, there is no collision (because how could there be) if (!___Combat.MapMetaData.IsWithinBounds(p0) || !___Combat.MapMetaData.IsWithinBounds(p1)) { __result = false; return; } MapMetaData mapMetaData = ___Combat.MapMetaData; EncounterLayerData encounterLayerData = ___Combat.EncounterLayerData; bool targetIsABuilding = !string.IsNullOrEmpty(targetedBuildingGuid); string shellBuildingGUID = ModState.AmbushTurretGUIDtoBuilding[ModState.CurrentTurretForLOF.GUID].GUID; List <Point> bresenhamLinePoints = BresenhamLineUtil.BresenhamLine(p0, p1); float heightDeltaPerPoint = (height1 - height0) / (float)bresenhamLinePoints.Count; float collisionPointHeight = height0; // Walk the bresenham Line, evaluation collision at a speciifc height as we go. for (int i = 0; i < bresenhamLinePoints.Count; i++) { collisionPointHeight += heightDeltaPerPoint; Point point = bresenhamLinePoints[i]; if (encounterLayerData.mapEncounterLayerDataCells[point.Z, point.X].HasSpecifiedBuilding(shellBuildingGUID)) { Mod.Log.Trace?.Write($" Point x={point.X} z={point.Z} is inside the shell building, continuing."); continue; } if (targetIsABuilding && encounterLayerData.mapEncounterLayerDataCells[point.Z, point.X].HasSpecifiedBuilding(targetedBuildingGuid)) { Mod.Log.Trace?.Write($" Building {targetedBuildingGuid} conflicts with the LoS, collision at x={collisionWorldPos.X} z={collisionWorldPos.Z}"); collisionWorldPos = bresenhamLinePoints[i]; __result = true; return; } if (mapMetaData.mapTerrainDataCells[point.Z, point.X].cachedHeight > collisionPointHeight) { Mod.Log.Trace?.Write($" Collision on terrain at position x={collisionWorldPos.X} z={collisionWorldPos.Z}"); collisionWorldPos = bresenhamLinePoints[i]; __result = false; return; } } Mod.Log.Trace?.Write($"No collision detected, changing LoF to true. CollisonWorldPos => x ={ collisionWorldPos.X} z ={ collisionWorldPos.Z}"); __result = true; return; }
static void Postfix(LineOfSight __instance, Point p0, float height0, Point p1, float height1, Vector3 unitDelta, string targetGuid, ref float __result, CombatGameState ___Combat) { if (ModState.CurrentTurretForLOS == null) { return; } if (p0.X == p1.X && p0.Z == p1.Z) { __result = 0f; return; } if (!___Combat.MapMetaData.IsWithinBounds(p0) || !___Combat.MapMetaData.IsWithinBounds(p1)) { __result = float.MaxValue; return; } float numCellsX = Mathf.Abs(unitDelta.x) * (float)MapMetaDataExporter.cellSize; float numCellsY = Mathf.Abs(unitDelta.z) * (float)MapMetaDataExporter.cellSize; float lineDeltaX = (float)(p1.X - p0.X); float lineDeltaZ = (float)(p1.Z - p0.Z); float greatestDivisor = Mathf.Max(Mathf.Abs(lineDeltaX), Mathf.Abs(lineDeltaZ)); float stepHeight = (height1 - height0) / greatestDivisor; float sumVisionCost = 0f; Traverse projectedHeightAtT = Traverse.Create(__instance).Method("getProjectedHeightAt", new Type[] { typeof(Point), typeof(float), typeof(Point), typeof(float) }); Traverse visCostOfCellT = Traverse.Create(__instance).Method("visCostOfCell", new Type[] { typeof(MapTerrainDataCell), typeof(float) }); string shellBuildingGUID = ModState.AmbushTurretGUIDtoBuilding[ModState.CurrentTurretForLOS.GUID].GUID; EncounterLayerData encounterLayerData = ___Combat.EncounterLayerData; List <Point> list = BresenhamLineUtil.BresenhamLine(p0, p1); for (int i = 1; i < list.Count; i++) { float stepDelta; if (list[i].X != list[i - 1].X) { stepDelta = numCellsX; } else { stepDelta = numCellsY; } // Increment vision cost only slightly if it's inside our shell building if (encounterLayerData.mapEncounterLayerDataCells[list[i].Z, list[i].X].HasSpecifiedBuilding(shellBuildingGUID)) { Mod.Log.Trace?.Write($" Point x={list[i].X} z={list[i].Z} is inside the shell building, adding vision cost normally."); sumVisionCost += stepDelta; } else { float projectedHeightAt = projectedHeightAtT.GetValue <float>(new object[] { p0, height0, list[i], stepHeight }); MapTerrainDataCell mapTerrainDataCell = ___Combat.MapMetaData.mapTerrainDataCells[list[i].Z, list[i].X]; if (mapTerrainDataCell.cachedHeight > projectedHeightAt) { if (mapTerrainDataCell.MapEncounterLayerDataCell.HasBuilding) { for (int j = 0; j < mapTerrainDataCell.MapEncounterLayerDataCell.buildingList.Count; j++) { if (ObstructionGameLogic.GuidsMatchObjectOrRep(mapTerrainDataCell.MapEncounterLayerDataCell.buildingList[j].buildingGuid, targetGuid)) { __result = sumVisionCost; return; } } } __result = float.MaxValue; return; } sumVisionCost += visCostOfCellT.GetValue <float>(new object[] { mapTerrainDataCell, projectedHeightAt }) * stepDelta; } } __result = sumVisionCost; return; }
public bool IsGoodFaithEffort() { EncounterLayerData encounterLayerData = UnityEngine.Object.FindObjectOfType <EncounterLayerData>(); return(encounterLayerData.IsGoodFaithEffort); }
public bool IsSpawnValid(Vector3 position, Vector3 validityPosition, UnitType type, string identifier) { CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; MapTerrainDataCell cellData = combatState.MapMetaData.GetCellAt(position); Main.LogDebug($""); Main.LogDebug($"-------- [PathFinderManager.IsSpawnValid] [{identifier}] --------"); if (cellData.cachedSteepness > MAX_SLOPE_FOR_PATHFINDING) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Spawn point of '{cellData.cachedSteepness}' is too steep (> {MAX_SLOPE_FOR_PATHFINDING}). Not a valid spawn"); return(false); } if (IsCellImpassableOrDeepWater(cellData)) { return(false); } if (!encounterLayerData.IsInEncounterBounds(position)) { return(false); } if (cellData.cachedHeight > (cellData.terrainHeight + 50f)) { return(false); } float pathFindingZoneRadius = 25f; AbstractActor pathfindingActor = GetPathFindingActor(type); SetupPathfindingActor(position, pathfindingActor); try { PathNodeGrid pathfinderPathGrid = pathfindingActor.Pathing.CurrentGrid; PathNode positionPathNode = pathfinderPathGrid.GetValidPathNodeAt(position, pathfindingActor.Pathing.MaxCost); if (positionPathNode == null) { Reset(); return(false); } DynamicLongRangePathfinder.PointWithCost pointWithCost = new DynamicLongRangePathfinder.PointWithCost(combatState.HexGrid.GetClosestHexPoint3OnGrid(positionPathNode.Position), 0, (validityPosition - positionPathNode.Position).magnitude) { pathNode = positionPathNode }; List <Vector3> path = DynamicLongRangePathfinder.GetDynamicPathToDestination(new List <DynamicLongRangePathfinder.PointWithCost>() { pointWithCost }, validityPosition, float.MaxValue, pathfindingActor, false, new List <AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); // List<Vector3> path = DynamicLongRangePathfinder.GetPathToDestination(position, float.MaxValue, pathfindingActor, true, pathFindingZoneRadius); // List<Vector3> path = DynamicLongRangePathfinder.GetDynamicPathToDestination(position, float.MaxValue, pathfindingActor, true, new List<AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); // GUARD: Against deep water and other impassables that have slipped through if (HasPathImpassableOrDeepWaterTiles(combatState, path)) { return(false); } if (path != null && path.Count > 1 && (path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Path count is: '{path.Count}', Current position is: '{position}'"); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Last point is '{path[path.Count - 1]}', Validity position is '{validityPosition}'"); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Distance from last path to valdity position is: '{(path[path.Count - 1].DistanceFlat(validityPosition))}' and is it within zone radius? '{(path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)}'"); Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Has valid long range path finding"); if (HasValidNeighbours(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Has at least two valid neighbours"); if (HasValidLocalPathfinding(positionPathNode, validityPosition, type)) { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Has a valid path"); Reset(); Main.LogDebug($"-------- END [PathFinderManager.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); return(true); } else { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Does NOT have a valid path"); } } else { Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Does not have two valid neighbours"); } } /* // Failed attempt to improve spawn checks * List<Vector3> path = DynamicLongRangePathfinder.GetDynamicPathToDestination(validityPosition, float.MaxValue, pathfindingActor, true, new List<AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, pathFindingZoneRadius); * if (path != null && (path[path.Count - 1].DistanceFlat(validityPosition) <= pathFindingZoneRadius)) { * if (path.Count > 4) { // very strong pathfinding location * return true; * } else { * Main.Logger.Log($"[PathFinderManager] Spawn point is valid due to proximity but is not strong enough success for pathing. Attempting to confirm."); * CombatGameState combatState = UnityGameInstance.BattleTechGame.Combat; * List<Vector3> pointsAroundPosition = combatState.HexGrid.GetGridPointsAroundPointWithinRadius(position, 3, 5); * * foreach (Vector3 point in pointsAroundPosition) { * List<Vector3> secondaryPath = DynamicLongRangePathfinder.GetDynamicPathToDestination(point, float.MaxValue, pathfindingActor, true, new List<AbstractActor>(), pathfindingActor.Pathing.CurrentGrid, 2); * if (path != null && path.Count > 2) { * Main.Logger.Log($"[PathFinderManager] Spawn point is valid. It is close to the validation point but can be moved away from. Success."); * return true; * } * } * } * } */ } catch (Exception e) { // TODO: Sometimes this gets triggered in very large amounts. It's usually because the SpawnLogic.GetClosestValidPathFindingHex is increasing // the radius larger and larger and the checks keep going off the map // I need a way to hard abort out of this and either use the original origin of the focus or trigger the rule logic again (random, around a position etc) Main.LogDebug($"[PathFinderManager.IsSpawnValid] [{identifier}] Array out of bounds detected in the path finding code. Flagging as invalid spawn. Select a new spawn point. {e.Message}, {e.StackTrace}"); } Main.LogDebug($"-------- END [PathFinderManager.IsSpawnValid] [{identifier}] END --------"); Main.LogDebug($""); Reset(); return(false); }
public static void EncounterLayerData_Constructor(EncounterLayerData __instance) { eld_cache = eld_cache.Where(c => c != null).ToList(); eld_cache.Add(__instance); }
private void SetBoundarySizeToCustom(EncounterLayerData encounterLayerData, float size) { EncounterBoundaryChunkGameLogic encounterBoundaryChunk = encounterLayerData.GetComponentInChildren <EncounterBoundaryChunkGameLogic>(); if (encounterBoundaryChunk != null) { Main.Logger.Log($"[MaximiseBoundarySize.SetBoundarySizeToCustom] Increasing Boundary Size by '{size * 100}%'"); List <RectHolder> encounterBoundaryRectList = new List <RectHolder>(); EncounterObjectGameLogic[] childEncounterObjectGameLogicList = encounterBoundaryChunk.childEncounterObjectGameLogicList; float mapBorderSize = 50f; float mapSize = 2048f; int mapSide = (int)(mapSize - mapBorderSize); for (int i = 0; i < childEncounterObjectGameLogicList.Length; i++) { EncounterBoundaryRectGameLogic encounterBoundaryRectGameLogic = childEncounterObjectGameLogicList[i] as EncounterBoundaryRectGameLogic; int sizeFactor = (int)(encounterBoundaryRectGameLogic.width * (1f + size)); int movementFactor = (int)(encounterBoundaryRectGameLogic.width * size); if (sizeFactor > mapSide) { Main.Logger.Log($"[MaximiseBoundarySize.SetBoundarySizeToCustom] Custom size would be greater than map size. Using map size.'"); MatchBoundarySizeToMapSize(encounterLayerData); } else { if (encounterBoundaryRectGameLogic != null) { Vector3 position = encounterBoundaryRectGameLogic.transform.position; Main.Logger.Log($"[MaximiseBoundarySize.SetBoundarySizeToCustom] Boundary [X,Z] originally was [{position.x}, {position.z}]"); float xPosition = 0; if (position.x > 0) { xPosition = position.x - movementFactor; // (movementFactor / 2f); if (xPosition < 0) { xPosition = 0; } } else if (position.x < 0) { xPosition = position.x + movementFactor; // (movementFactor / 2f); if (xPosition > 0) { xPosition = 0; } } float zPosition = 0; if (position.z > 0) { zPosition = position.z - movementFactor; // (movementFactor / 2f); if (zPosition < 0) { zPosition = 0; } } else if (position.z < 0) { zPosition = position.z + movementFactor; // (movementFactor / 2f); if (zPosition > 0) { zPosition = 0; } } encounterBoundaryRectGameLogic.width = (int)sizeFactor; encounterBoundaryRectGameLogic.height = (int)sizeFactor; encounterBoundaryRectGameLogic.transform.position = new Vector3(xPosition, encounterBoundaryRectGameLogic.transform.position.y, zPosition); Main.Logger.Log($"[MaximiseBoundarySize.SetBoundarySizeToCustom] Boundary [X,Z] is now [{xPosition}, {zPosition}]"); encounterLayerData.CalculateEncounterBoundary(); } else { Main.Logger.Log($"[MaximiseBoundarySize] This encounter has no boundary to maximise."); } } } } }
public void GenerateEncounterLayerBuildingData() { Main.Logger.LogDebug($"[EncounterDataManager.GenerateEncounterLayerBuildingData] Generating building data"); Terrain terrain = Terrain.activeTerrain; float terrainZSize = terrain.terrainData.size.z; float terrainXSize = terrain.terrainData.size.x; Vector3 terrainPosition = terrain.transform.position; float halfMapCellSize = (float)MapMetaDataExporter.cellSize / 2f; int halfMapCellSizeInt = MapMetaDataExporter.cellSize / 2; EncounterLayerParent encounterLayerParent = MissionControl.Instance.EncounterLayerParent; EncounterLayerData encounterLayerData = MissionControl.Instance.EncounterLayerData; MapMetaDataExporter mapMetaExporter = encounterLayerParent.GetComponent <MapMetaDataExporter>(); MapMetaData mapMetaData = UnityGameInstance.BattleTechGame.Combat.MapMetaData; Vector3 raycastOrigin = new Vector3(0f, 1000f, 0f); // Lookups Dictionary <string, int> regionRaycastHits = new Dictionary <string, int>(); List <RegionGameLogic> regionGameObjectList = new List <RegionGameLogic>(); List <ObstructionGameLogic> obstructionGameObjectList = new List <ObstructionGameLogic>(); // Marks only the ObstructionGameLogic objects for ray tracing for performance reasons AccessTools.Method(typeof(MapMetaDataExporter), "MarkCellsForRaycasting").Invoke(mapMetaExporter, new object[] { mapMetaData.mapTerrainDataCells, (int)terrain.transform.position.x, (int)terrain.transform.position.z }); // TODO: Maybe wipe region building lists. Not sure if I really need/want this yet RegionGameLogic[] componentsInChildren = encounterLayerData.GetComponentsInChildren <RegionGameLogic>(); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].InitRegionForRayCasting(); } // Iterate over the Z cell range for (float i = halfMapCellSize; i < terrainZSize; i += (float)MapMetaDataExporter.cellSize) { int zCellIndex = (int)i / MapMetaDataExporter.cellSize; // Iterate over the X cell range for (float j = halfMapCellSize; j < terrainXSize; j += (float)MapMetaDataExporter.cellSize) { int xCellIndex = (int)j / MapMetaDataExporter.cellSize; MapEncounterLayerDataCell mapEncounterLayerDataCell = new MapEncounterLayerDataCell(); if (mapMetaData.mapTerrainDataCells[zCellIndex, xCellIndex].doRayCast) { int hitIndex = 0; regionRaycastHits.Clear(); regionGameObjectList.Clear(); obstructionGameObjectList.Clear(); for (int k = -halfMapCellSizeInt; k < halfMapCellSizeInt; k++) { raycastOrigin.z = i + (float)k + terrainPosition.z; for (int l = -halfMapCellSizeInt; l < halfMapCellSizeInt; l++) { raycastOrigin.x = j + (float)l + terrainPosition.x; RaycastHit[] raycastHits = Physics.RaycastAll(raycastOrigin, Vector3.down); List <ObstructionGameLogic> list3 = new List <ObstructionGameLogic>(); // Go through all the raycasts at Z,X of the terrain by cell size (middle of cell) // Then find any regions hit, record the number of hits/cells the region has for (int m = 0; m < raycastHits.Length; m++) { RegionGameLogic regionGameLogic = raycastHits[m].transform.GetComponent <RegionGameLogic>(); if (regionGameLogic != null) { if (!regionRaycastHits.ContainsKey(regionGameLogic.encounterObjectGuid)) { regionRaycastHits[regionGameLogic.encounterObjectGuid] = 1; } else { string encounterObjectGuid = regionGameLogic.encounterObjectGuid; regionRaycastHits[encounterObjectGuid]++; } // Cache the region in the lookup if (!regionGameObjectList.Contains(regionGameLogic)) { regionGameObjectList.Add(regionGameLogic); } } ObstructionGameLogic obstructionGameLogicInParent = raycastHits[m].transform.GetComponentInParent <ObstructionGameLogic>(); if (obstructionGameLogicInParent != null && raycastHits[m].point.y > mapMetaData.mapTerrainDataCells[zCellIndex, xCellIndex].terrainHeight) { if (obstructionGameLogicInParent.IsBuildingHitAddWorthy) { if (!obstructionGameObjectList.Contains(obstructionGameLogicInParent)) { obstructionGameObjectList.Add(obstructionGameLogicInParent); } } Vector3 normal = raycastHits[m].normal; BuildingRaycastHit buildingRaycastHit = new BuildingRaycastHit { buildingSteepness = 90f - 57.29578f * Mathf.Atan2(normal.y, Mathf.Sqrt(normal.x * normal.x + normal.z * normal.z)), buildingHeight = raycastHits[m].point.y, buildingGuid = obstructionGameLogicInParent.encounterObjectGuid, hitIndex = hitIndex }; mapEncounterLayerDataCell.AddBuildingHit(buildingRaycastHit); } } hitIndex++; } } // For all the regions detected, if it exists in 10 or more cells - add the region to the map encounter layer data (this is vanilla... why?!) // And all all obstruction games logics to the region foreach (RegionGameLogic regionGameLogic in regionGameObjectList) { if (regionRaycastHits[regionGameLogic.encounterObjectGuid] >= 10) { mapEncounterLayerDataCell.AddRegion(regionGameLogic); foreach (ObstructionGameLogic obstructionGameLogic in obstructionGameObjectList) { regionGameLogic.AddBuildingGuidToRegion(obstructionGameLogic.encounterObjectGuid); } } } mapEncounterLayerDataCell.AverageTheBuildingHits(); mapEncounterLayerDataCell.SortBuildingListByHeight(); } encounterLayerData.mapEncounterLayerDataCells[zCellIndex, xCellIndex] = mapEncounterLayerDataCell; encounterLayerData.mapEncounterLayerDataCells[zCellIndex, xCellIndex].relatedTerrainCell = mapMetaData.mapTerrainDataCells[zCellIndex, xCellIndex]; mapMetaData.mapTerrainDataCells[zCellIndex, xCellIndex].MapEncounterLayerDataCell = mapEncounterLayerDataCell; } } }