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); }