private void CreateChest(List <IGraphNode> openNodes, ISector sector, IDropTableScheme[] trashDropTables, IDropTableScheme[] treasuresDropTable) { // Выбрать из коллекции доступных узлов var rollIndex = _chestGeneratorRandomSource.RollNodeIndex(openNodes.Count); var map = sector.Map; var containerNode = MapRegionHelper.FindNonBlockedNode(openNodes[rollIndex], map, openNodes); if (containerNode == null) { // в этом случае будет сгенерировано на один сундук меньше. // узел, с которого не удаётся найти подходящий узел, удаляем, // чтобы больше его не анализировать, т.к. всё равно будет такой же исход. openNodes.Remove(openNodes[rollIndex]); return; } // Проверка, что сундук не перегораживает проход. var isValid = CheckMap(sector, (HexNode)containerNode); if (!isValid) { // в этом случае будет сгенерировано на один сундук меньше. // узел, с которого не удаётся найти подходящий узел, удаляем, // чтобы больше его не анализировать, т.к. всё равно будет такой же исход. openNodes.Remove(openNodes[rollIndex]); return; } openNodes.Remove(containerNode); var staticObject = CreateChestStaticObject(trashDropTables, treasuresDropTable, containerNode); sector.StaticObjectManager.Add(staticObject); }
public void CreateCitizens(ISector sector, IBotPlayer botPlayer, IEnumerable <MapRegion> citizenRegions) { var map = sector.Map; foreach (var region in citizenRegions) { // 1 к 9, потому что это наиболее удобное соотношение // для размещения неподвижных блокирующих объектов // без преграждения выходов. var citizenCount = region.Nodes.Count() / 9f; var availableNodes = from node in region.Nodes where !map.Transitions.Keys.Contains(node) select node; var openNodes = new List <IMapNode>(availableNodes); for (var i = 0; i < citizenCount; i++) { //TODO Объединить этот блок с генератором сундуков, как дубликат // Выбрать из коллекции доступных узлов var rollIndex = _citizenGeneratorRandomSource.RollNodeIndex(openNodes.Count); var objectNode = MapRegionHelper.FindNonBlockedNode(openNodes[rollIndex], map, openNodes); if (objectNode == null) { // В этом случае будет сгенерировано на одного жителя меньше. // Узел, с которого не удаётся найти подходящий узел, удаляем, // Чтобы больше его не анализировать, т.к. всё равно будет такой же неудачный исход. openNodes.Remove(openNodes[rollIndex]); continue; } openNodes.Remove(objectNode); var traderDropTable = _schemeService.GetScheme <IDropTableScheme>("trader"); var rollCitizenType = _citizenGeneratorRandomSource.RollCitizenType(); switch (rollCitizenType) { case CitizenType.Unintresting: CreateCitizen(objectNode, botPlayer); break; case CitizenType.Trader: CreateCitizen(traderDropTable, objectNode, botPlayer); break; case CitizenType.QuestGiver: CreateCitizen(DialogFactory.Create(), objectNode, botPlayer); break; default: //TODO Завести тип исключения на генерацию персонажей мирных жителей. throw new System.Exception(); } } } }
/// <summary> /// Создать сундуки в секторе. /// </summary> /// <param name="map">Карта сектора. Нужна для определения доступного места для сундука.</param> /// <param name="sectorSubScheme">Схема сектора. По сути - настройки для размещения сундуков.</param> /// <param name="regions">Регионы, в которых возможно размещение сундуков.</param> public void CreateChests(ISectorMap map, ISectorSubScheme sectorSubScheme, IEnumerable <MapRegion> regions) { var dropTables = GetDropTables(sectorSubScheme); var chestCounter = sectorSubScheme.TotalChestCount; //TODO В схемах хранить уже приведённое значение пропорции. var countChestRatioNormal = 1f / sectorSubScheme.RegionChestCountRatio; foreach (var region in regions) { var maxChestCountRaw = region.Nodes.Count() * countChestRatioNormal; var maxChestCount = (int)Math.Max(maxChestCountRaw, 1); var rolledCount = _chestGeneratorRandomSource.RollChestCount(maxChestCount); var availableNodes = from node in region.Nodes where !map.Transitions.Keys.Contains(node) select node; var openNodes = new List <IMapNode>(availableNodes); for (var i = 0; i < rolledCount; i++) { // Выбрать из коллекции доступных узлов var rollIndex = _chestGeneratorRandomSource.RollNodeIndex(openNodes.Count); var containerNode = MapRegionHelper.FindNonBlockedNode(openNodes[rollIndex], map, openNodes); if (containerNode == null) { // в этом случае будет сгенерировано на один сундук меньше. // узел, с которого не удаётся найти подходящий узел, удаляем, // чтобы больше его не анализировать, т.к. всё равно будет такой же исход. openNodes.Remove(openNodes[rollIndex]); continue; } openNodes.Remove(containerNode); var container = new DropTablePropChest(containerNode, dropTables, _dropResolver); _propContainerManager.Add(container); chestCounter--; if (chestCounter <= 0) { // лимит сундуков в секторе исчерпан. break; } } } }
/// <summary> /// Создать сундуки в секторе. /// </summary> /// <param name="map">Карта сектора. Нужна для определения доступного места для сундука.</param> /// <param name="sectorSubScheme">Схема сектора. По сути - настройки для размещения сундуков.</param> /// <param name="regions">Регионы, в которых возможно размещение сундуков.</param> public void CreateChests(ISectorMap map, ISectorSubScheme sectorSubScheme, IEnumerable <MapRegion> regions) { var trashDropTables = GetTrashDropTables(sectorSubScheme); var treasuresDropTable = GetTreasuresDropTable(); var chestCounter = sectorSubScheme.TotalChestCount; //TODO В схемах хранить уже приведённое значение пропорции. var countChestRatioNormal = 1f / sectorSubScheme.RegionChestCountRatio; foreach (var region in regions) { var maxChestCountRaw = region.Nodes.Count() * countChestRatioNormal; var maxChestCount = (int)Math.Max(maxChestCountRaw, 1); if (region.Nodes.Count() <= 1) { // Для регионов, где только один узел, // не создаём сундуки, иначе проход может быть загорожен. // Актуально для фабрики карт на основе клеточного автомата, // потому что он может генерить регионы из одного узла. //TODO Попробовать проверять соседей узла. // Возможно, одноклеточный регион находится в конце тупика. // Тогда в нём можно разместить сундук. // Критерий доступности такого региона - у узла только одни сосед. continue; } var rolledCount = _chestGeneratorRandomSource.RollChestCount(maxChestCount); var availableNodes = from node in region.Nodes where !map.Transitions.Keys.Contains(node) where map.IsPositionAvailableForContainer(node) select node; var openNodes = new List <IMapNode>(availableNodes); for (var i = 0; i < rolledCount; i++) { var containerPurpose = _chestGeneratorRandomSource.RollPurpose(); // Выбрать из коллекции доступных узлов var rollIndex = _chestGeneratorRandomSource.RollNodeIndex(openNodes.Count); var containerNode = MapRegionHelper.FindNonBlockedNode(openNodes[rollIndex], map, openNodes); if (containerNode == null) { // в этом случае будет сгенерировано на один сундук меньше. // узел, с которого не удаётся найти подходящий узел, удаляем, // чтобы больше его не анализировать, т.к. всё равно будет такой же исход. openNodes.Remove(openNodes[rollIndex]); continue; } // Проверка, что сундук не перегораживает проход. var isValid = CheckMap(map, (HexNode)containerNode); if (!isValid) { // в этом случае будет сгенерировано на один сундук меньше. // узел, с которого не удаётся найти подходящий узел, удаляем, // чтобы больше его не анализировать, т.к. всё равно будет такой же исход. openNodes.Remove(openNodes[rollIndex]); continue; } openNodes.Remove(containerNode); IPropContainer container; switch (containerPurpose) { case PropContainerPurpose.Trash: container = new DropTablePropChest(containerNode, trashDropTables, _dropResolver) { Purpose = PropContainerPurpose.Trash }; break; case PropContainerPurpose.Treasures: container = new DropTablePropChest(containerNode, treasuresDropTable, _dropResolver) { Purpose = PropContainerPurpose.Treasures }; break; default: throw new InvalidOperationException($"Не корректное назначение {containerPurpose}."); } _propContainerManager.Add(container); chestCounter--; if (chestCounter <= 0) { // лимит сундуков в секторе исчерпан. break; } } } }