[Гайд] Все механики разведения в Cobblemon (мод Cobbreeding)
Автор: sanlover · Обновлён:
📘 Гайд по всем механикам разведения в Cobblemon (мод Cobbreeding)
Этот гайд — результат анализа кода мода Cobbreeding.
В нём нет воды и устаревших догадок — только реальная логика, на которую действительно опирается игра при формировании яйца.
⚠️ На момент публикации: официальной вики или документации по Cobbreeding не существует.
📌 Этот гайд — единственный источник с цифрами, основанный на исходном коде самого мода.
ЦитатаГайд подробно объясняет:
- Как формируется яйцо
- Какие параметры могут быть унаследованы.
- Как влияют различные удерживаемые предметы.
- Как работает шанс получения шайни.
- Как передаются способности, приёмы, шары и аспекты
Предполагается, что читатель уже имеет общее представление о моде Cobblemon и возможности размножения.
🗂️ Оглавление:
- 🥚 Формирование яйца
- 🧬 Механика передачи IV при размножении покемонов
- 🧠 Наследование характера
- 🧪 Наследование способностей
-
Наследование Покебола
- ✨ Наследование шайни-статуса
- 💿Наследование приёмов
-
Наследование яйцевых приёмов через Зеркальный Лист
- 🧾 Наследование аспектов
- 👪 Правила подбора родителей и определение возможных яиц
- 🌍Полезные ссылки
1. 🥚 Формирование яйца
Когда выбрана пара совместимых родителей, начинается процесс формирования яйца.
На этом этапе система последовательно рассчитывает все параметры будущего покемона — от вида до приёмов.
📋 Что рассчитывается?
- Вид и форма
- Индивидуальные значения IV
- Характер
- Способность
- Покебол
- Шайн-статус
- Egg Moves
- Аспекты
⚙️ Общий алгоритм
1. Выбирается родительская пара.
2. Определяется вид и форма будущего покемона.
3. Рассчитываются все свойства потомка.
4. Эти данные объединяются в новое яйцо с готовыми параметрами.
🔧 Реализация в коде
Скрытый текст
fun chooseEgg(form: FormData, parents: Pair<Pokemon, Pokemon>): PokemonProperties { return PokemonProperties.Builder(form) .setParent1(parents.first.uuid) // UUID первого родителя .setParent2(parents.second.uuid) // UUID второго родителя .setIVs(calcStats(parents)) // Расчёт IV (уникальных параметров) .setNature(calcNature(parents)) // Характер .setAbility(calcAbility(form, parents)) // Способность .setCaughtBall(calcBall(parents)) // Покебол .setShiny(calcShiny(parents)) // Шайн-статус .setEggMoves(calcEggMoves(parents, form)) // Наследуемые приёмы .setAspects(calcAspects(parents)) // Аспекты (визуальные/сезонные) .build() // Построение объекта потомка }
2. 🧬 Механика предачи IV при размножении покемонов
При размножении каждый покемон получает индивидуальные значения характеристик (IV), часть из которых может быть унаследована от родителей.
Всего у покемона 6 характеристик:
- HP — Очки здоровья
- Attack — Атака
- Defence — Защита
- Special Attack — Спец. атака
- Special Defence — Спец. защита
- Speed — Скорость
⚙️ Общая логика наследования
1. В начале для потомка создаются случайные IV для всех 6 характеристик.
2. Затем система определяет, какие параметры будут унаследованы от родителей, в зависимости от:
- наличия удерживаемых предметов (Power Items);
- использования узла судьбы (Destiny Knot).
3. Всего может быть унаследовано до 5 параметров, остальные останутся случайными.
📋 Удерживаемые предметы (Power Items) и их влияние
Груз силы (power_weight) - Очки здоровья (HP)
Наруч силы (power_bracer) - Атака (Attack)
Пояс силы (power_belt) - Защита (Defence)
Линзы силы (power_lens) - Спец. атака (Special Attack)
Повязка силы (power_band) - Спец. защита (Special Defence)
Браслет силы (power_anklet) - Скорость (Speed)
⚙️ Как работают Power Items:
- Если один родитель держит Power Item — он обязательно передаёт соответствующий параметр.
- Если оба родителя держат Power Items, выбирается один случайный родитель, и передаётся только один параметр.
- Если ни один родитель не использует Power Item, система случайным образом выбирает:
- одну характеристику;
- одного родителя, от которого она будет унаследована.
Цитата💡 Этот переданный параметр всегда становится первым унаследованным значением в итоговых IV.
⚙️Влияние узла судьбы
После передачи первого параметра определяется, сколько дополнительных характеристик будет унаследовано от родителей:
- Если у хотя бы одного родителя есть
узел судьбы (Destiny Knot), будет передано ещё 4 параметра.
- Если
узел судьбы не используется, передаются ещё 2 параметра.
Каждый параметр выбирается по следующему принципу:
1. Из оставшихся характеристик выбирается случайная.
2. Выбирается случайный родитель.
3. Если у него есть значение IV по этому параметру — оно передаётся.
4. Характеристика исключается из дальнейшего выбора.
Цитата💡В результате потомок получает 3 или 5 унаследованных параметров, в зависимости от наличия узла судьбы.
⚙️Остальные IV
Все параметры, которые не были выбраны для наследования, остаются полностью случайными. Они не зависят от родителей или предметов и определяются заново при создании потомка.
Цитата💡Даже при идеальных условиях (Power Item + Destiny Knot) нельзя передать все 6 параметров — один из них всегда будет случайным.
🔧 Реализация в коде
Скрытый текст
private fun calcStats(parents: Pair<Pokemon, Pokemon>): IVs { // Создаём случайные IV для потомка val finalStats = IVs.createRandomIVs() // Извлекаем родителей из пары val (father, mother) = parents // Набор всех возможных характеристик (IV) val ivs = mutableSetOf( Stats.HP, Stats.ATTACK, Stats.DEFENCE, Stats.SPECIAL[/i]ATTACK, Stats.SPECIAL[/i]DEFENCE, Stats.SPEED ) // Определяем, какие IV будут переданы с помощью удерживаемых предметов (Power Items) val ivsToChooseFrom = mapOf( Pair(father, powerItemToIV(father.heldItem().item)), Pair(mother, powerItemToIV(mother.heldItem().item)) ).filterNot { it.value == null } // Временные переменные для текущего IV и родителя var iv: Stats var parent: Pokemon // Если ни у одного из родителей нет Power Item — выбираем случайную характеристику и случайного родителя if (ivsToChooseFrom.isEmpty()) { iv = ivs.random() parent = parents.random() } else { // Если Power Items есть у обоих — выбираем одного случайным образом и сохраняем соответствующий параметр val (pokemon, stat) = ivsToChooseFrom.toList().random() iv = stat!! parent = pokemon } // Устанавливаем выбранное значение IV у потомка parent.ivs[iv]?.let { finalStats[iv] = it } // Исключаем переданный параметр из списка оставшихся ivs.remove(iv) // Определяем, сколько параметров будет дополнительно унаследовано: // если есть узел судьбы (Destiny Knot) — 4 параметра, иначе — 2 var ivCount = if (father.heldItem().item == CobblemonItems.DESTINY[/i]KNOT | | mother.heldItem().item == CobblemonItems.DESTINY[/i]KNOT) 4 else 2 // Передаём оставшиеся характеристики, пока не будет достигнуто нужное количество while (ivCount != 0) { // Выбираем случайную характеристику из оставшихся iv = ivs.random() // Выбираем случайного родителя parent = parents.random() // Если у родителя есть значение IV — передаём его потомку parent.ivs[iv]?.let { finalStats[iv] = it } // Удаляем характеристику из оставшихся ivs.remove(iv) // Уменьшаем счётчик ivCount-- } // Возвращаем сформированные IV потомка return finalStats }
3. 🧠 Наследование характера
Каждый покемон имеет характер (Nature), который влияет на развитие его параметров. Один параметр усиливается на 10%, другой — уменьшается на 10%. Некоторые характеры — нейтральные и не изменяют ничего.
⚙️Как определяется характер у потомка:
- Если ни один родитель не держит
Камень вечности (Everstone) — характер потомка будет случайным.
- Если один родитель держит
Камень вечности — потомок наследует характер именно этого родителя.
- Если
Камень вечности есть у обоих родителей, один из них выбирается случайно, и его характер передаётся потомку.
Цитата💡
Камень вечности — это единственный способ гарантировать нужный характер у потомка.
📋 Таблица характеров и их влияние
Цитата💡Характеры без влияния (—) называются нейтральными и не влияют на параметры.
💡Переводы характеров соответствуют официальной русской локализации мода Cobblemon.
🧾 Авторские предпочтения
Некоторые характеры чаще используются для определённых ролей. Не силён в этом, но вот небольшая подборка:
⚔️ Физический атакующий:
- Adamant — усиливает Атаку, снижает Спец. атаку.
- Jolly — увеличивает Скорость, снижает Спец. атаку.
🔥 Специальный атакующий:
- Modest — повышает Спец. атаку, снижает обычную атаку.
- Timid — увеличивает Скорость, снижает обычную атаку.
🛡️ Танки и защитники:
- Bold — усиливает Защиту, снижает Атаку.
- Calm — усиливает Спец. защиту, снижает Атаку.
- Relaxed — усиливает Защиту, снижает Скорость (часто не критично).
🔧 Реализация в коде
Скрытый текст
private fun calcNature(parents: Pair < Pokemon, Pokemon > ): Nature { // Извлекаем родителей val(father, mother) = parents // Проверяем, держит ли кто-то из родителей Камень вечности (Everstone) val parentsItems = mapOf( Pair(father, father.heldItem().item), Pair(mother, mother.heldItem().item) ).filterNot { it.value != CobblemonItems.EVERSTONE } // Если ни у кого нет Everstone — возвращаем случайный характер if (parentsItems.isEmpty()) return Natures.getRandomNature() // Иначе выбираем одного из родителей с Everstone и передаём его характер return parentsItems.toList().random().first.nature }
4. 🧪 Наследование способностей
При размножении покемон может получить одну из доступных способностей (Ability) своей формы.
Форма покемона может иметь до трёх способностей: две обычные и одну скрытую.
📋 Виды способностей
⚙️ Как выбирается способность
1. Определяется родитель, от которого будет передаваться способность:
- если в паре есть Дитто — используется не-Дитто родитель;
- если Дитто нет — используется мать.
2. Система пытается сохранить способность этого родителя у потомка.
3. Если родительская способность не сохраняется (по шансам), выбирается другая доступная способность формы.
4. Если альтернатив нет — способность родителя сохраняется в любом случае.
Цитата💡Потомок всегда получит одну из доступных способностей своей формы. Но с высокой вероятностью это будет та же, что у выбранного родителя.
🎲 Шансы сохранить способность
Цитата💡Если альтернативная способность недоступна — родительская способность сохраняется автоматически.
💡Если у формы покемона только одна способность — шанс не применяется, потомок получает её гарантированно.
🔧 Реализация в коде
Скрытый текст
private fun calcAbility(form: FormData, parents: Pair<Pokemon, Pokemon>): String { val (father, mother) = parents // Определяем родителя, от которого будет передаваться способность: // если в паре участвует Дитто — используем второго родителя, // если нет — используем мать. val ancestor = if (mother.species == getByName("ditto")) father else mother val oldAbility = ancestor.ability // Если способность "заставлена" (forced) и соответствующая настройка включена, // то возвращаем её напрямую, без шанса. // Однако по умолчанию (если настройка отключена), это поведение игнорируется. return if (oldAbility.forced && Cobbreeding.config.forcedAbilitiesEnabled) oldAbility.name else { // Получаем приоритет и индекс способности родителя. // Если индекс определён (≥ 0), используем его напрямую. val (priority, index) = if (oldAbility.index >= 0) Pair(oldAbility.priority, oldAbility.index) else { // Если индекс не задан, пытаемся определить его вручную: // ищем в мапе способностей ту, что соответствует шаблону родителя. // Если не находим — по умолчанию берём 0 и наименьший приоритет. val entry = ancestor.form.abilities.mapping.entries.firstOrNull { ([/i], abilities) -> abilities.map { it.template }.contains(oldAbility.template) } entry?.run { Pair(key, value.map { it.template }.indexOf(oldAbility.template)) } ?: Pair(Priority.LOWEST, 0) } // Определяем унаследованную способность: // 1) сперва пытаемся взять способность на той же позиции и с тем же приоритетом; // 2) если не находим — берём первую из этого приоритета; // 3) если и тут не находим — первую из самого низкого приоритета; // 4) если вообще ничего нет — подставляем "заглушку" (DUMMY). val inheritedAbility = form.abilities.mapping[priority]?.getOrNull(index)?.template ?: form.abilities.mapping[priority]?.firstOrNull()?.template ?: form.abilities.mapping[Priority.LOWEST]?.firstOrNull()?.template ?: Abilities.DUMMY // Формируем список возможных альтернативных способностей (не совпадающих с inheritedAbility). // Если скрытые способности разрешены — используем все приоритеты. // Если запрещены — исключаем способности с приоритетом LOW (скрытые). val remainingAbilities = if (Cobbreeding.config.hiddenAbilitiesEnabled) form.abilities.mapping.values .flatten() .map { it.template } .filterNot { it == inheritedAbility } else form.abilities.mapping.values .flatten() .filterNot { it.priority == Priority.LOW } .map { it.template } .filterNot { it == inheritedAbility } // Определяем шанс сохранить способность родителя: // 60% для скрытых, 80% для остальных. val chance = when (priority) { Priority.LOW -> 6u // 60% для приоритета LOW (Hidden) else -> 8u // 80% для остальных } // Если список альтернатив пуст или шанс прошёл — оставляем способность родителя. // Иначе выбираем случайную из альтернативных. val template = if (remainingAbilities.isEmpty() | | Random.nextUInt(10u) < chance) inheritedAbility else remainingAbilities.random() // Возвращаем имя итоговой способности return template.name } }
Цитата💡Настройка hiddenAbilitiesEnabled в конфиге включена — скрытые способности передаются.
💡Настройка forcedAbilitiesEnabled по умолчанию выключена — «заставленные» способности игнорируются.
5.
Наследование Покебола
Покебол, в котором был пойман родитель, также может передаться потомку. Это влияет только на внешний вид и не даёт игрового преимущества, но может быть важен для коллекционеров.
📋 Как выбирается покебол:
1. По умолчанию потомок получает Покебол от матери.
2. Если родители — одного вида, потомок получает Покебол одного из них случайным образом.
3. Если мать — Дитто, Покебол передаётся от отца.
4. Некоторые Покеболы не могут быть унаследованы и заменяются на стандартный: Черишбол (Cherish Ball) и Мастербол (Master Ball).
Цитата💡Дитто никогда не передаёт Покебол, даже если он — второй родитель.
🔧 Реализация в коде
Скрытый текст
private fun calcBall(parents: Pair < Pokemon, Pokemon > ): String { var ball = parents.second.caughtBall // По умолчанию — Покебол матери // Если оба родителя одного вида — Покебол выбирается случайно от одного из них if (parents.first.species.name == parents.second.species.name) ball = parents.random().caughtBall // Если мать — Дитто, Покебол наследуется от отца if (parents.second.species.name == "Ditto") ball = parents.first.caughtBall // Некоторые Покеболы нельзя передать напрямую: заменяются на обычный if (ball == PokeBalls.CHERISH[/i]BALL | | ball == PokeBalls.MASTER[/i]BALL) ball = PokeBalls.POKE[/i]BALL return ball.name.toString() }
6. ✨ Наследование шайни-статуса
Покемон может родиться шайни — с редкой и уникальной расцветкой.
Это чисто визуальный эффект, не влияющий на силу или характеристики, но высоко ценится среди коллекционеров.
📋 Базовая вероятность
- По умолчанию шанс рождения шайни — 1 к 8192
- Этот шанс может увеличиться, если активированы специальные параметры в конфигурации сервера и соблюдены некоторые условия
📋 Методы увеличения шанса
Цитата💡По умолчанию включён только masuda. Метод crystal доступен, но неизвестно, активен ли он на сервере mcskill.
⚙️ Как рассчитывается шанс
1. Начальный шанс рождения шайни: 1 / 8192
2. За каждого родителя-шайни (если активен crystal) — шанс умножается на 4
3. Если родители пойманы разными тренерами (masuda) — шанс также умножается на 4
4. Итоговый шанс — это результат деления 8192 на 4 за каждое выполненное условие
🧪 Примеры итоговых шансов
Цитата💡 Если crystal отключён, максимальный шанс, который можно получить — 1 / 2048 (только за счёт masuda). Значение 1 / 128 возможно только если crystal включён и оба родителя — шайни.
🔧 Реализация в коде
Скрытый текст
private fun calcShiny(parents: Pair<Pokemon, Pokemon>): Boolean? { // Получаем список включённых методов повышения шанса (из конфигурации) val shinyMethod = Cobbreeding.config.shinyMethod // Если shiny-статус отключён полностью — не рассчитываем, возвращаем null if ("disabled" in shinyMethod) return null // Множитель, на который делится шанс при срабатывании условий (по умолчанию: 4) val shinyMultiplier = Cobbreeding.config.shinyMultiplier // Базовый шанс получения шайни (по умолчанию: 1 / 8192) var shinyOdds = Cobblemon.config.shinyRate // Метод crystal: увеличивает шанс, если один или оба родителя — шайни if ("crystal" in shinyMethod) { // Если первый родитель — шайни if (parents.first.shiny) shinyOdds /= shinyMultiplier // Если второй родитель — шайни if (parents.second.shiny) shinyOdds /= shinyMultiplier } // Метод masuda: увеличивает шанс, если родители от разных оригинальных тренеров if ("masuda" in shinyMethod) { // Получаем UUID оригинальных тренеров обоих родителей val owner1 = parents.first.originalTrainer ?: parents.first.getOwnerPlayer()?.stringUUID val owner2 = parents.second.originalTrainer ?: parents.second.getOwnerPlayer()?.stringUUID // Если тренеры отличаются — делим шанс ещё раз if (owner1 != null && owner2 != null && owner1 != owner2) shinyOdds /= shinyMultiplier } // Если шанс меньше 1 (например, при методе "always") — потомок точно будет шайни if (shinyOdds < 1) return true // Генерируем случайное число от 0 до shinyOdds // Если выпадает 0 — потомок будет шайни return Random.nextInt(0, shinyOdds.toInt()) == 0 }
7. 💿 Наследование приёмов
Яйцевые приёмы — это особые атаки, которые нельзя получить через уровень, ТМ или тренера.
Они передаются только при размножении, если родитель владеет или имеет доступ к такому приёму.
Цитата💡На сервере механика упрощена: можно использовать ТМ/TR для изучения приёмов яйцевых групп.
⚙️Общая логика наследования
1. У формы покемона есть список доступных яйцевых приёмов.
2. У каждого из родителей проверяются:
- все изученные приёмы;
- все потенциальные приёмы, к которым у него есть доступ.
3. Если хотя бы один из этих приёмов совпадает с доступным яйцевым — он добавляется к потомку.
4. Исключение: если рождается Пичу (Pichu), и у одного из родителей есть Световой шар (Light Ball), то приём Volt Tackle добавляется всегда.
Цитата💡 Достаточно, чтобы один из родителей мог выучить нужный приём — не обязательно, чтобы он уже его знал.
🧪 Пример
- У Пикачу есть доступ к приёму Fake Out, а у Риолу — это яйцевый приём.
- Если Пикачу участвует в размножении — Риолу может унаследовать Fake Out.
🔧 Реализация в коде
Скрытый текст
private fun calcEggMoves(parents: Pair < Pokemon, Pokemon > , child: FormData): List < String > { // Получаем список возможных яйцевых приёмов у данной формы потомка val possibleEggMoves = child.moves.eggMoves val eggMoves = LinkedList < String > () // Перебираем каждого родителя for (parent in parents.toList()) { // Получаем все потенциально доступные приёмы (включая наследуемые, ТМ и по уровню) val allAccessibleMoves = parent.allAccessibleMoves.toMutableSet() // Добавляем текущие выученные приёмы for (move in parent.moveSet.getMoves()) allAccessibleMoves += move.template // Сравниваем с яйцевыми приёмами потомка — добавляем совпадения for (accessibleMove in allAccessibleMoves) { if (possibleEggMoves.contains(accessibleMove)) eggMoves.add(accessibleMove.name) } } // Специальный случай: если вылупляется Пичу и один из родителей держит Light Ball if ( child.species.name == "Pichu" && parents.toList().any { p - > p.heldItem().item == CobblemonItems.LIGHT[/i]BALL } ) eggMoves.add("volttackle") return eggMoves }
8.
Наследование яйцевых приёмов через Зеркальный Лист
Некоторые приёмы покемоны могут перенять напрямую, без размножения. Это становится возможным, если покемон держит специальный предмет —
Зеркальный Лист (Mirror Herb).
⚙️Как работает механика
1. В пастбище проверяются все покемоны.
2. Если покемон держит Зеркальный Лист.
- Определяется список приёмов, которые он теоретически может получить при рождении.
3. Все остальные покемоны в загоне перебираются:
- Сравниваются их доступные и выученные приёмы.
4. Если какой-либо приём совпадает с потенциальными у покемона с Зеркальным Листом — он добавляется к нему.
📋 Что это даёт?
- Позволяет выучить уникальные или редкие приёмы, не прибегая к размножению.
- Работает даже если покемон-источник приёма не изучал его напрямую, а просто имеет к нему доступ.
- Применимо к одиночному покемону — не требует пары .
🔧 Реализация в коде
Скрытый текст
fun applyMirrorHerb(pokemon: List<Pokemon?>) { // Ищем покемонов, держащих Mirror Herb for (holder in pokemon) { if (holder != null && holder.heldItem().item == CobblemonItems.MIRROR_HERB) { // Получаем список приёмов, которые этот покемон может получить при рождении val possibleEggMoves = getBaby(holder.form).moves.eggMoves // Перебираем всех других покемонов в загоне for (other in pokemon) { if (other != null) { // Собираем все приёмы, к которым у них есть доступ val allAccessibleMoves = other.allAccessibleMoves.toMutableSet() for (move in other.moveSet.getMoves()) allAccessibleMoves.add(move.template) // Если у другого покемона есть приём, совпадающий с возможностями holder'а — передаём for (accessibleMove in allAccessibleMoves) { if (possibleEggMoves.contains(accessibleMove)) holder.benchedMoves.add(BenchedMove(accessibleMove, 0)) } } } } } }
9. 🧬 Наследование аспектов
Аспекты — это скрытые метки, прикреплённые к покемону. Они используются для хранения нестандартных характеристик:
например, визуальных эффектов, пола (male, female), шайни-статуса (shiny), а также уникальных особенностей, добавленных через датапаки или моды (например, сезонные или ивентовые аспекты).
⚙️Как работает наследование аспектов
1. Аспекты наследуются от матери, если в паре нет Дитто.
2. Если мать — Дитто, аспекты передаются от отца.
3. Перед передачей из набора аспектов удаляются следующие системные теги:
- shiny
- male
- female
Цитата💡Это делается для того, чтобы не нарушить механику шайни-статуса и пола, которые определяются отдельно.
📋 Что можно передать через аспекты?
- Особые формы покемонов, не влияющие на параметры, но изменяющие внешний вид (например, цвет глаз, узоры, зимние окраски).
- Модифицированные метки, добавленные другими модами — если они реализованы как aspect.
🧪 Пример
Если у матери установлен аспект snowfest2023, то этот аспект будет передан потомку.
А вот аспект shiny — не будет передан, так как он определяется отдельной системой.
🔧 Реализация в коде
Скрытый текст
private fun calcAspects(parents: Pair<Pokemon, Pokemon>): List<String> { // Определяем родителя, от которого будут унаследованы аспекты: // если второй родитель — Дитто, используем первого (отца), // иначе — второго (матери). Т.е. при наличии Дитто аспекты не берутся от него. val mother = if (parents.second.species == getByName("ditto")) parents.first else parents.second // Копируем все аспекты выбранного родителя (например, сезонные, пользовательские и т.п.) val aspects = mother.aspects.toMutableList() // Удаляем аспекты, которые не должны передаваться: // shiny — рассчитывается отдельно; // male/female — определяется системой пола. aspects.remove("shiny") aspects.remove("male") aspects.remove("female") // Возвращаем оставшиеся аспекты — они будут применены к потомку return aspects }
10. 👪 Правила подбора родителей и определение возможных яиц
Не любая пара покемонов может оставить яйцо. Перед созданием яйца система проверяет совместимость родителей — их пол, группы яиц, исключения и участие Дитто.
📋 Условия совместимости
1. Оба родителя должны принадлежать к одной и той же группе яиц,
если только один из них не является Дитто.
2. Минимум один из родителей должен быть мужского пола, другой — женского.
3. Покемоны из группы Undiscovered не способны к размножению.
4. Дитто может спариваться почти с любым другим покемоном.
⚙️ Кто определяет вид потомка?
- Если в паре участвует Дитто — потомок всегда получается второго родителя (не-Дитто).
- В обычной паре (без Дитто) вид потомка определяется по женскому покемону.
⚠️ Особые случаи
⚙️Как определяется возможный потомок
1. Если у покемона есть цепочка эволюций — отслеживается базовая форма.
Потомок всегда будет этой первой эволюцией.
2. Некоторые формы (например, региональные) имеют исключения: их базовая форма может быть нестандартной.
3. Для таких форм вручную заданы специальные варианты потомков:
🔧 Реализация в коде
Скрытый текст
Определение возможных яиц
fun getPossibleEggs(pokemon: List<Pokemon>): Collection<Map.Entry<FormData, List<Pair<Pokemon, Pokemon>>>> { // Словарь, где ключ — форма потенциального потомка, значение — список родительских пар val eggs = HashMap<FormData, MutableList<Pair<Pokemon, Pokemon>>>() // Перебираем все возможные уникальные пары покемонов for (i in pokemon.indices) { for (j in i + 1 until pokemon.size) { val pokemon1 = pokemon[i] val species1 = pokemon1.species val eggGroups1 = species1.eggGroups val pokemon2 = pokemon[j] val species2 = pokemon2.species val eggGroups2 = species2.eggGroups // Проверяем, что оба покемона не находятся в группе Undiscovered // (такие покемоны не могут размножаться вообще) if (!eggGroups1.contains(EggGroup.UNDISCOVERED) && !eggGroups2.contains(EggGroup.UNDISCOVERED)) { // Если один из покемонов — Дитто if (eggGroups1.contains(EggGroup.DITTO)) { // Потомок формируется от второго покемона dittoBreed(pokemon2)?.let { // Добавляем пару (отец, мать) в список потомков соответствующей формы if (eggs.containsKey(it)) eggs[it]?.add(Pair(pokemon2, pokemon1)) else eggs[it] = mutableListOf(Pair(pokemon2, pokemon1)) } } else if (eggGroups2.contains(EggGroup.DITTO)) { dittoBreed(pokemon1)?.let { if (eggs.containsKey(it)) eggs[it]?.add(Pair(pokemon1, pokemon2)) else eggs[it] = mutableListOf(Pair(pokemon1, pokemon2)) } } // Если оба покемона НЕ Дитто и их группы яиц пересекаются else if (eggGroups1.any(eggGroups2::contains)) { // Женщина-самка слева if (pokemon1.gender == Gender.FEMALE && pokemon2.gender == Gender.MALE) { // Вид потомка определяется по самке getBaby(pokemon1).let { if (eggs.containsKey(it)) eggs[it]?.add(Pair(pokemon2, pokemon1)) else eggs[it] = mutableListOf(Pair(pokemon2, pokemon1)) } } // Женщина-самка справа else if (pokemon2.gender == Gender.FEMALE && pokemon1.gender == Gender.MALE) { getBaby(pokemon2).let { if (eggs.containsKey(it)) eggs[it]?.add(Pair(pokemon1, pokemon2)) else eggs[it] = mutableListOf(Pair(pokemon1, pokemon2)) } } } } } } // Специальный случай: Нидоран♀ и Нидоран♂ — всегда выводятся вместе if (eggs.containsKey(getByName("nidoranf")!!.standardForm)) { eggs[getByName("nidoranm")!!.standardForm] = eggs[getByName("nidoranf")!!.standardForm]!! } else if (eggs.containsKey(getByName("nidoranm")!!.standardForm)) { eggs[getByName("nidoranf")!!.standardForm] = eggs[getByName("nidoranm")!!.standardForm]!! } // То же самое для Volbeat и Illumise — возможны оба результата if (eggs.containsKey(getByName("illumise")!!.standardForm)) { eggs[getByName("volbeat")!!.standardForm] = eggs[getByName("illumise")!!.standardForm]!! } else if (eggs.containsKey(getByName("volbeat")!!.standardForm)) { eggs[getByName("illumise")!!.standardForm] = eggs[getByName("volbeat")!!.standardForm]!! } // Возвращаем мапу: форма → список допустимых родительских пар return eggs.mapValues { (_, v) -> v.toList() }.entries }
Определение формы потомка
fun getBaby(pokemon: FormData): FormData { // Переход к базовому виду — пока у текущего вида есть предэволюция var species = pokemon.species while (species.preEvolution != null) { species = species.preEvolution!!.species } // Обработка исключений для региональных форм: // У этих форм потомок — не стандартная базовая форма, а конкретный слот формы if (pokemon.species.name == "Sirfetch’d" || pokemon.species.name == "Cursola" || pokemon.species.name == "Obstagoon" || pokemon.species.name == "Runerigus" || pokemon.species.name == "Clodsire" || pokemon.species.name == "Overqwil" || pokemon.species.name == "Sneasler") return species.forms[1] // Исключения, у которых потомок — третья форма (слот 2) if (pokemon.species.name == "Perrserker" || pokemon.species.name == "Basculegion") return species.forms[2] // В остальных случаях: ищем подходящую форму по showdownId return species.forms.find { it.formOnlyShowdownId().contains(pokemon.formOnlyShowdownId()) } ?: species.standardForm }
11. 🌍Полезные ссылки
- Репозиторий мода Cobbreeding
- Репозиторий мода Cobblemon
- Информация о шансах и местах спавна покемонов
- Расшифровка тегов биомов
- Краткая и частично устаревшая wiki от разработчика Cobbreeding (Информация в гайде считается более приоритетной)
Послесловие
На этом я заканчиваю и благодарю вас за внимание. Буду рад комментариям, вопросам и обсуждению. Играю на втором сервере, бываю часто — не стесняйтесь писать в игре.
На всякий случай добавлю, что шанс вылупления любого яйца - 50% каждые 10 минут. Знаю, что у некоторых игроков всё ещё возникают сомнения в работе механик, особенно касательно узла судьбы и power-айтемов. Специально для вас, друзья, я вывел 54 потомка от фиксированной пары родителей, отследил все IV и провёл краткий анализ.
📊 Результаты и визуализация — в отдельном исследовании: https://www.kaggle.com/code/sanlovty/breeding-theory-check-by-sanlover
P.s.: Если ручки дойдут оформить гайд, ждите гайд на cobblenav со сломанным pokefinder'om.Цитата💬 Если вы замечаете неточности или хотите дополнить гайд — пишите.
Я постараюсь продолжить отслеживать обновления мода и по возможности буду дополнять материал.
🌸Благодарности:🌸
- wt04d - информация о возможности изучения яйцевых атак через ТМ\TR.