Лучшие модовые сервера Minecraft

Технологии, Магия, Эволюция, Покемоны
и многие другие режимы уже ждут вас!

Начать играть
Гайды

[Гайд] Все механики разведения в Cobblemon (мод Cobbreeding)

Автор: sanlover · Обновлён:

📘 Гайд по всем механикам разведения в Cobblemon (мод Cobbreeding)

Этот гайд — результат анализа кода мода Cobbreeding.  
В нём нет воды и устаревших догадок — только реальная логика, на которую действительно опирается игра при формировании яйца.

⚠️ На момент публикации: официальной вики или документации по Cobbreeding не существует.  
📌 Этот гайд — единственный источник с цифрами, основанный на исходном коде самого мода.

Цитата

Гайд подробно объясняет:

  • Как формируется яйцо  
  • Какие параметры могут быть унаследованы.
  • Как влияют различные удерживаемые предметы.
  • Как работает шанс получения шайни.
  • Как передаются способности, приёмы, шары и аспекты  

Предполагается, что читатель уже имеет общее представление о моде Cobblemon и возможности размножения.


 

🗂️ Оглавление:

  1. 🥚 Формирование яйца
  2. 🧬 Механика передачи IV при размножении покемонов
  3. 🧠 Наследование характера
  4. 🧪 Наследование способностей
  5. image.png.d8ac5dbd4caf17ae0636116e6b4736d2.png Наследование Покебола
  6. Наследование шайни-статуса
  7. 💿Наследование приёмов
  8. mirror_herb.png.173bcb80ba7fdcefe19b8a0a02c5a886.png Наследование яйцевых приёмов через Зеркальный Лист
  9. 🧾 Наследование аспектов
  10. 👪 Правила подбора родителей и определение возможных яиц
  11. 🌍Полезные ссылки

 


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.png.f92d5957c3f074a383fec483cdb68d4a.png Груз силы (power_weight) - Очки здоровья (HP)
power_bracer.png.88d4c54fc69487d6fb799aaa386e2d15.png Наруч силы (power_bracer) - Атака (Attack)
power_belt.png.090dad4aeb622bbb8afa3be96107456e.png Пояс силы (power_belt) - Защита (Defence)
power_lens.png.d6c87fae5b80807e56e48cff140e2c33.png Линзы силы (power_lens) - Спец. атака (Special Attack)
power_band.png.dee4d2a65bd39c9665b7cb4646d3bc06.png Повязка силы (power_band) - Спец. защита (Special Defence)
power_anklet.png.bf349ea49e39df6a189fca72e044329a.png Браслет силы (power_anklet) - Скорость (Speed)
 

⚙️ Как работают Power Items:

- Если один родитель держит Power Item — он обязательно передаёт соответствующий параметр.
- Если оба родителя держат Power Items, выбирается один случайный родитель, и передаётся только один параметр.
- Если ни один родитель не использует Power Item, система случайным образом выбирает:
    - одну характеристику;
    - одного родителя, от которого она будет унаследована.

Цитата

💡 Этот переданный параметр всегда становится первым унаследованным значением в итоговых IV.

⚙️Влияние узла судьбы

После передачи первого параметра определяется, сколько дополнительных характеристик будет унаследовано от родителей:

- Если у хотя бы одного родителя есть destiny_knot.png.92410df67ca316f48cd8d04ae6fffb2a.png узел судьбы (Destiny Knot), будет передано ещё 4 параметра.
- Если
destiny_knot.png.92410df67ca316f48cd8d04ae6fffb2a.png узел судьбы не используется, передаются ещё 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.png.c89b46f62d7e13e5991312db9c52c3da.png Камень вечности (Everstone) — характер потомка будет случайным.
- Если один родитель держит everstone.png.c89b46f62d7e13e5991312db9c52c3da.png Камень вечности — потомок наследует характер именно этого родителя.
- Если everstone.png.c89b46f62d7e13e5991312db9c52c3da.png Камень вечности  есть у обоих родителей, один из них выбирается случайно, и его характер передаётся потомку.

Цитата

💡 everstone.png.c89b46f62d7e13e5991312db9c52c3da.png Камень вечности — это единственный способ гарантировать нужный характер у потомка.


📋 Таблица характеров и их влияние

image.png.d990eeeb5225b4019eae74e3a891fa52.png

Цитата

💡Характеры без влияния (—) называются нейтральными и не влияют на параметры.

💡Переводы характеров соответствуют официальной русской локализации мода 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) своей формы.  
Форма покемона может иметь до трёх способностей: две обычные и одну скрытую.


📋 Виды способностей

image.png.46f567771609166a6ef850cf8b859614.png

 

⚙️ Как выбирается способность

1. Определяется родитель, от которого будет передаваться способность:
    - если в паре есть Дитто — используется не-Дитто родитель;
    - если Дитто нет — используется мать.
2. Система пытается сохранить способность этого родителя у потомка.
3. Если родительская способность не сохраняется (по шансам), выбирается другая доступная способность формы.
4. Если альтернатив нет — способность родителя сохраняется в любом случае.

Цитата

💡Потомок всегда получит одну из доступных способностей своей формы. Но с высокой вероятностью это будет та же, что у выбранного родителя.

🎲 Шансы сохранить способность

NVIDIA_Overlay_rj5IT2RSvF.png.34c356bea7dbd46190d414cddae9ebe5.png

Цитата

💡Если альтернативная способность недоступна — родительская способность сохраняется автоматически. 

💡Если у формы покемона только одна способность — шанс не применяется, потомок получает её гарантированно.

🔧 Реализация в коде 

Скрытый текст
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. image.png.d8ac5dbd4caf17ae0636116e6b4736d2.png Наследование Покебола

Покебол, в котором был пойман родитель, также может передаться потомку. Это влияет только на внешний вид и не даёт игрового преимущества, но может быть важен для коллекционеров.

📋 Как выбирается покебол:

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
  • Этот шанс может увеличиться, если активированы специальные параметры в конфигурации сервера и соблюдены некоторые условия

📋 Методы увеличения шанса

image.png.8bfdc21845464e02f46713d3dd32628d.png

Цитата

💡По умолчанию включён только masuda. Метод crystal доступен, но неизвестно, активен ли он на сервере mcskill.

⚙️ Как рассчитывается шанс

1. Начальный шанс рождения шайни: 1 / 8192
2. За каждого родителя-шайни (если активен crystal) — шанс умножается на 4
3. Если родители пойманы разными тренерами (masuda) — шанс также умножается на 4
4. Итоговый шанс — это результат деления 8192 на 4 за каждое выполненное условие

🧪 Примеры итоговых шансов

image.png.dc0db0f2576653b206220858b88ed534.png

 

Цитата

💡 Если 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.png.173bcb80ba7fdcefe19b8a0a02c5a886.png Наследование яйцевых приёмов через Зеркальный Лист

Некоторые приёмы покемоны могут перенять напрямую, без размножения. Это становится возможным, если покемон держит специальный предмет —  mirror_herb.png.173bcb80ba7fdcefe19b8a0a02c5a886.png Зеркальный Лист (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. Дитто может спариваться почти с любым другим покемоном.

⚙️ Кто определяет вид потомка?

- Если в паре участвует Дитто — потомок всегда получается второго родителя (не-Дитто).
- В обычной паре (без Дитто) вид потомка определяется по женскому покемону.

⚠️ Особые случаи

image.png.fa2dca57d9f12fe37b2369743e166173.png

⚙️Как определяется возможный потомок
1. Если у покемона есть цепочка эволюций — отслеживается базовая форма.  
    Потомок всегда будет этой первой эволюцией.
2. Некоторые формы (например, региональные) имеют исключения: их базовая форма может быть нестандартной.
3. Для таких форм вручную заданы специальные варианты потомков:
NVIDIA_Overlay_LP9mST9YYs.png.80e33ce430d5c7c6150b580cd086959e.png

🔧 Реализация в коде 

Скрытый текст

Определение возможных яиц

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. 🌍Полезные ссылки


Послесловие
На этом я заканчиваю и благодарю вас за внимание. Буду рад комментариям, вопросам и обсуждению. Играю на втором сервере, бываю часто — не стесняйтесь писать в игре.

На всякий случай добавлю, что шанс вылупления любого яйца - 50% каждые 10 минут. Знаю, что у некоторых игроков всё ещё возникают сомнения в работе механик, особенно касательно узла судьбы и power-айтемов. Специально для вас, друзья, я вывел 54 потомка от фиксированной пары родителей, отследил все IV и провёл краткий анализ.
📊 Результаты и визуализация — в отдельном исследовании: https://www.kaggle.com/code/sanlovty/breeding-theory-check-by-sanlover

Цитата

💬 Если вы замечаете неточности или хотите дополнить гайд — пишите.
Я постараюсь продолжить отслеживать обновления мода и по возможности буду дополнять материал.

P.s.: Если ручки дойдут оформить гайд, ждите гайд на cobblenav со сломанным pokefinder'om.


🌸Благодарности:🌸

  • wt04d - информация о возможности изучения яйцевых атак через ТМ\TR.

Похожие гайды