﻿# v2.4.0 — Endowment Mastery
#
# Mastery is deliberately independent from physical Endowment. The canonical physical measurement pair
# remains immutable; these effects only alter domcom_endowment_mastery_xp and the learned Mastery trait.
#
# Thresholds (2.6.60 scale):
#   I  = 3
#   II = 8
#   III= 13
#   IV = 20
#   V  = 27
#   VI = 32
#
# First-time promotion across each rank raises Legitimacy by one stage when the character has a
# Legitimacy track. domcom_endowment_highest_mastery_rank is a permanent high-water mark, preventing
# repeated rank loss/re-gain from farming Legitimacy.

domcom_endowment_mastery_raise_legitimacy_stage_effect = {
    if = {
        limit = { has_legitimacy = yes legitimacy_level < 5 }
        set_variable = { name = domcom_endowment_mastery_start_legitimacy_level value = legitimacy_level }
        set_variable = { name = domcom_endowment_mastery_legitimacy_guard value = 0 }
        while = {
            limit = {
                var:domcom_endowment_mastery_legitimacy_guard < 100
                legitimacy_level <= var:domcom_endowment_mastery_start_legitimacy_level
            }
            add_legitimacy = 25
            change_variable = { name = domcom_endowment_mastery_legitimacy_guard add = 1 }
        }
        remove_variable = domcom_endowment_mastery_start_legitimacy_level
        remove_variable = domcom_endowment_mastery_legitimacy_guard
    }
}

domcom_clear_endowment_mastery_traits_effect = {
    if = { limit = { has_trait = domcom_endowment_mastery_1 } remove_trait = domcom_endowment_mastery_1 }
    if = { limit = { has_trait = domcom_endowment_mastery_2 } remove_trait = domcom_endowment_mastery_2 }
    if = { limit = { has_trait = domcom_endowment_mastery_3 } remove_trait = domcom_endowment_mastery_3 }
    if = { limit = { has_trait = domcom_endowment_mastery_4 } remove_trait = domcom_endowment_mastery_4 }
    if = { limit = { has_trait = domcom_endowment_mastery_5 } remove_trait = domcom_endowment_mastery_5 }
    if = { limit = { has_trait = domcom_endowment_mastery_6 } remove_trait = domcom_endowment_mastery_6 }
}

domcom_apply_native_endowment_mastery_xp_effect = {
    # Caller supplies domcom_endowment_mastery_native_delta in the mod's canonical 0..32 scale.
    # CK3 trait tracks are normalized to 0..100, so scale the delta before touching the native path.
    # Keeping the 0..32 mirror authoritative preserves existing saves/UI while the native path renders
    # the same milestone-node presentation used by CK3's other tracked traits.
    if = { limit = { has_trait = domcom_endowment_micro } add_trait_xp = { trait = domcom_endowment_micro track = mastery value = { add = var:domcom_endowment_mastery_native_delta multiply = 100 divide = 32 } } }
    else_if = { limit = { has_trait = domcom_endowment_small } add_trait_xp = { trait = domcom_endowment_small track = mastery value = { add = var:domcom_endowment_mastery_native_delta multiply = 100 divide = 32 } } }
    else_if = { limit = { has_trait = domcom_endowment_average } add_trait_xp = { trait = domcom_endowment_average track = mastery value = { add = var:domcom_endowment_mastery_native_delta multiply = 100 divide = 32 } } }
    else_if = { limit = { has_trait = domcom_endowment_big } add_trait_xp = { trait = domcom_endowment_big track = mastery value = { add = var:domcom_endowment_mastery_native_delta multiply = 100 divide = 32 } } }
    else_if = { limit = { has_trait = domcom_endowment_hung } add_trait_xp = { trait = domcom_endowment_hung track = mastery value = { add = var:domcom_endowment_mastery_native_delta multiply = 100 divide = 32 } } }
    else_if = { limit = { has_trait = domcom_endowment_massive } add_trait_xp = { trait = domcom_endowment_massive track = mastery value = { add = var:domcom_endowment_mastery_native_delta multiply = 100 divide = 32 } } }
}

# v2.5.0 path normalization repair. 2.4.x wrote the 0..64 mirror directly into a CK3 0..100 trait
# track, which is why the path could appear as one fully-filled bar with no useful milestone spacing.
# Reapply the same immutable physical band to reset only the attached trait-track data, then seed 0..100.
domcom_normalize_endowment_mastery_track_v250_effect = {
    if = {
        limit = {
            domcom_should_express_endowment_trigger = yes age >= 18
            has_variable = domcom_endowment_mastery_xp
            NOT = { has_character_flag = domcom_mastery_track_normalized_v250 }
        }
        # Preserve the canonical body profile; removing/re-adding only repairs the track container.
        if = { limit = { has_trait = domcom_endowment_micro } remove_trait = domcom_endowment_micro add_trait = domcom_endowment_micro }
        else_if = { limit = { has_trait = domcom_endowment_small } remove_trait = domcom_endowment_small add_trait = domcom_endowment_small }
        else_if = { limit = { has_trait = domcom_endowment_average } remove_trait = domcom_endowment_average add_trait = domcom_endowment_average }
        else_if = { limit = { has_trait = domcom_endowment_big } remove_trait = domcom_endowment_big add_trait = domcom_endowment_big }
        else_if = { limit = { has_trait = domcom_endowment_hung } remove_trait = domcom_endowment_hung add_trait = domcom_endowment_hung }
        else_if = { limit = { has_trait = domcom_endowment_massive } remove_trait = domcom_endowment_massive add_trait = domcom_endowment_massive }
        set_variable = { name = domcom_endowment_mastery_native_delta value = var:domcom_endowment_mastery_xp }
        domcom_apply_native_endowment_mastery_xp_effect = yes
        remove_variable = domcom_endowment_mastery_native_delta
        add_character_flag = domcom_native_endowment_mastery_seeded
        add_character_flag = domcom_mastery_track_normalized_v250
    }
}

# v2.5.1 — proportional Mastery migration. Existing 0..255 progress becomes the equivalent
# position on the new 0..64 scale rather than being clamped or reset. The native CK3 0..100
# trait track already represents the same percentage, so it does not need to be rebuilt.
domcom_migrate_endowment_mastery_v251_effect = {
    if = {
        limit = {
            domcom_should_express_endowment_trigger = yes age >= 18
            has_variable = domcom_endowment_mastery_xp
            NOT = { has_character_flag = domcom_mastery_scale_migrated_v251 }
        }
        set_variable = { name = domcom_mastery_migration_old_xp value = var:domcom_endowment_mastery_xp }
        set_variable = { name = domcom_endowment_mastery_xp value = { value = var:domcom_mastery_migration_old_xp multiply = 64 divide = 255 round = yes } }
        if = { limit = { var:domcom_endowment_mastery_xp < 0 } set_variable = { name = domcom_endowment_mastery_xp value = 0 } }
        if = { limit = { var:domcom_endowment_mastery_xp > 64 } set_variable = { name = domcom_endowment_mastery_xp value = 64 } }
        remove_variable = domcom_mastery_migration_old_xp
        add_character_flag = domcom_mastery_scale_migrated_v251
    }
}

# v2.6.60 — Endowment Mastery returns to a 0..32 scale. Existing 0..64 progress is
# migrated proportionally and lazily per character, so AI records do not require a world scan.
domcom_migrate_endowment_mastery_v2660_effect = {
    if = {
        limit = {
            has_variable = domcom_endowment_mastery_xp
            NOT = { has_character_flag = domcom_mastery_scale_migrated_v2660 }
        }
        set_variable = { name = domcom_mastery_migration_old_xp_2660 value = var:domcom_endowment_mastery_xp }
        set_variable = { name = domcom_endowment_mastery_xp value = { value = var:domcom_mastery_migration_old_xp_2660 multiply = 32 divide = 64 round = yes } }
        if = { limit = { var:domcom_endowment_mastery_xp < 0 } set_variable = { name = domcom_endowment_mastery_xp value = 0 } }
        if = { limit = { var:domcom_endowment_mastery_xp > 32 } set_variable = { name = domcom_endowment_mastery_xp value = 32 } }
        remove_variable = domcom_mastery_migration_old_xp_2660
        add_character_flag = domcom_mastery_scale_migrated_v2660
    }
}

domcom_clear_external_endowment_mastery_bonus_effect = {
    if = { limit = { has_character_modifier = domcom_external_endowment_mastery_1_modifier } remove_character_modifier = domcom_external_endowment_mastery_1_modifier }
    if = { limit = { has_character_modifier = domcom_external_endowment_mastery_2_modifier } remove_character_modifier = domcom_external_endowment_mastery_2_modifier }
    if = { limit = { has_character_modifier = domcom_external_endowment_mastery_3_modifier } remove_character_modifier = domcom_external_endowment_mastery_3_modifier }
    if = { limit = { has_character_modifier = domcom_external_endowment_mastery_4_modifier } remove_character_modifier = domcom_external_endowment_mastery_4_modifier }
    if = { limit = { has_character_modifier = domcom_external_endowment_mastery_5_modifier } remove_character_modifier = domcom_external_endowment_mastery_5_modifier }
    if = { limit = { has_character_modifier = domcom_external_endowment_mastery_6_modifier } remove_character_modifier = domcom_external_endowment_mastery_6_modifier }
}

domcom_sync_external_endowment_mastery_bonus_effect = {
    domcom_clear_external_endowment_mastery_bonus_effect = yes
    if = {
        limit = {
            domcom_external_replaces_endowment_trait_trigger = yes
            has_variable = domcom_endowment_mastery_xp
        }
        if = { limit = { var:domcom_endowment_mastery_xp >= 32 } add_character_modifier = { modifier = domcom_external_endowment_mastery_6_modifier } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 27 } add_character_modifier = { modifier = domcom_external_endowment_mastery_5_modifier } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 20 } add_character_modifier = { modifier = domcom_external_endowment_mastery_4_modifier } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 13 } add_character_modifier = { modifier = domcom_external_endowment_mastery_3_modifier } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 8 } add_character_modifier = { modifier = domcom_external_endowment_mastery_2_modifier } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 3 } add_character_modifier = { modifier = domcom_external_endowment_mastery_1_modifier } }
    }
}

domcom_sync_endowment_mastery_trait_effect = {
    # The six former Mastery traits are never displayed or used for bonuses anymore.
    domcom_clear_endowment_mastery_traits_effect = yes
    if = {
        limit = {
            domcom_should_express_endowment_trigger = yes age >= 18
            has_variable = domcom_canonical_length_tenths
            has_variable = domcom_canonical_girth_tenths
        }
        if = { limit = { NOT = { has_variable = domcom_endowment_mastery_xp } } set_variable = { name = domcom_endowment_mastery_xp value = 0 } }
        domcom_migrate_endowment_mastery_v251_effect = yes
        domcom_migrate_endowment_mastery_v2660_effect = yes
        if = { limit = { var:domcom_endowment_mastery_xp < 0 } set_variable = { name = domcom_endowment_mastery_xp value = 0 } }
        if = { limit = { var:domcom_endowment_mastery_xp > 32 } set_variable = { name = domcom_endowment_mastery_xp value = 32 } }
        if = { limit = { NOT = { has_variable = domcom_endowment_highest_mastery_rank } } set_variable = { name = domcom_endowment_highest_mastery_rank value = 0 } }

        # Native Mastery track bonuses live on Dominion's physical Endowment trait. If a compatibility
        # layer has replaced that anatomy trait, keep the 0..32 variable authoritative and use the
        # external-rank modifier below instead. Clearing the seed flag also makes removing the compatch safe:
        # Dominion can rebuild its native track the next time this character is refreshed.
        if = {
            limit = { domcom_external_replaces_endowment_trait_trigger = yes }
            if = { limit = { has_character_flag = domcom_native_endowment_mastery_seeded } remove_character_flag = domcom_native_endowment_mastery_seeded }
        }
        else = {
            domcom_normalize_endowment_mastery_track_v250_effect = yes
            if = {
                limit = { NOT = { has_character_flag = domcom_native_endowment_mastery_seeded } }
                set_variable = { name = domcom_endowment_mastery_native_delta value = var:domcom_endowment_mastery_xp }
                domcom_apply_native_endowment_mastery_xp_effect = yes
                remove_variable = domcom_endowment_mastery_native_delta
                add_character_flag = domcom_native_endowment_mastery_seeded
            }
        }

        set_variable = { name = domcom_endowment_mastery_current_rank value = 0 }
        if = { limit = { var:domcom_endowment_mastery_xp >= 32 } set_variable = { name = domcom_endowment_mastery_current_rank value = 6 } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 27 } set_variable = { name = domcom_endowment_mastery_current_rank value = 5 } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 20 } set_variable = { name = domcom_endowment_mastery_current_rank value = 4 } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 13 } set_variable = { name = domcom_endowment_mastery_current_rank value = 3 } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 8 } set_variable = { name = domcom_endowment_mastery_current_rank value = 2 } }
        else_if = { limit = { var:domcom_endowment_mastery_xp >= 3 } set_variable = { name = domcom_endowment_mastery_current_rank value = 1 } }

        if = {
            limit = { var:domcom_endowment_mastery_current_rank > var:domcom_endowment_highest_mastery_rank }
            if = { limit = { var:domcom_endowment_highest_mastery_rank < 1 var:domcom_endowment_mastery_current_rank >= 1 } domcom_endowment_mastery_raise_legitimacy_stage_effect = yes }
            if = { limit = { var:domcom_endowment_highest_mastery_rank < 2 var:domcom_endowment_mastery_current_rank >= 2 } domcom_endowment_mastery_raise_legitimacy_stage_effect = yes }
            if = { limit = { var:domcom_endowment_highest_mastery_rank < 3 var:domcom_endowment_mastery_current_rank >= 3 } domcom_endowment_mastery_raise_legitimacy_stage_effect = yes }
            if = { limit = { var:domcom_endowment_highest_mastery_rank < 4 var:domcom_endowment_mastery_current_rank >= 4 } domcom_endowment_mastery_raise_legitimacy_stage_effect = yes }
            if = { limit = { var:domcom_endowment_highest_mastery_rank < 5 var:domcom_endowment_mastery_current_rank >= 5 } domcom_endowment_mastery_raise_legitimacy_stage_effect = yes }
            if = { limit = { var:domcom_endowment_highest_mastery_rank < 6 var:domcom_endowment_mastery_current_rank >= 6 } domcom_endowment_mastery_raise_legitimacy_stage_effect = yes }
            set_variable = { name = domcom_endowment_highest_mastery_rank value = var:domcom_endowment_mastery_current_rank }
            if = { limit = { is_ai = no } send_interface_toast = { type = event_toast_effect_good title = domcom_endowment_mastery_rank_up_toast left_icon = root } }
        }
        domcom_sync_external_endowment_mastery_bonus_effect = yes
        remove_variable = domcom_endowment_mastery_current_rank
    }
    else = { domcom_clear_external_endowment_mastery_bonus_effect = yes }
}

domcom_initialize_endowment_mastery_effect = {
    if = { limit = { domcom_should_express_endowment_trigger = yes age >= 18 } domcom_restore_canonical_endowment_effect = yes }
    if = {
        limit = {
            domcom_should_express_endowment_trigger = yes
            age >= 18
            has_variable = domcom_canonical_length_tenths
            has_variable = domcom_canonical_girth_tenths
        }
        if = { limit = { NOT = { has_variable = domcom_endowment_mastery_xp } } set_variable = { name = domcom_endowment_mastery_xp value = 0 } }
        if = { limit = { NOT = { has_variable = domcom_endowment_highest_mastery_rank } } set_variable = { name = domcom_endowment_highest_mastery_rank value = 0 } }
        domcom_sync_endowment_mastery_trait_effect = yes
    }
}

# Generic internal delta application. Callers set domcom_endowment_mastery_pending_delta, then use this.
domcom_endowment_mastery_apply_pending_delta_effect = {
    domcom_initialize_endowment_mastery_effect = yes
    if = {
        limit = { domcom_should_express_endowment_trigger = yes age >= 18 has_variable = domcom_endowment_mastery_xp has_variable = domcom_endowment_mastery_pending_delta }
        set_variable = { name = domcom_endowment_mastery_old_xp value = var:domcom_endowment_mastery_xp }
        change_variable = { name = domcom_endowment_mastery_xp add = var:domcom_endowment_mastery_pending_delta }
        if = { limit = { var:domcom_endowment_mastery_xp < 0 } set_variable = { name = domcom_endowment_mastery_xp value = 0 } }
        if = { limit = { var:domcom_endowment_mastery_xp > 32 } set_variable = { name = domcom_endowment_mastery_xp value = 32 } }
        set_variable = { name = domcom_endowment_mastery_native_delta value = var:domcom_endowment_mastery_xp }
        change_variable = { name = domcom_endowment_mastery_native_delta subtract = var:domcom_endowment_mastery_old_xp }
        domcom_apply_native_endowment_mastery_xp_effect = yes
        remove_variable = domcom_endowment_mastery_old_xp
        remove_variable = domcom_endowment_mastery_native_delta
        domcom_sync_endowment_mastery_trait_effect = yes
    }
    remove_variable = domcom_endowment_mastery_pending_delta
}

domcom_endowment_mastery_tantalize_success_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = 5 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_tantalize_failure_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = -1 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_direct_positive_sex_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = 5 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_strong_positive_sex_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = 5 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_positive_sex_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = 3 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_warm_sex_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = 4 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_neutral_sex_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = 1 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_negative_sex_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = -2 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}
domcom_endowment_mastery_severe_negative_sex_effect = {
    set_variable = { name = domcom_endowment_mastery_pending_delta value = -5 }
    domcom_endowment_mastery_apply_pending_delta_effect = yes
}

# Run from an adult qualifying Endowment participant. scope:domcom_mastery_partner is the other participant.
# This intentionally uses only vanilla relationship/opinion/attraction primitives so base Dominion remains
# soft-compatible with Carnalitas and Carnalitas Love Reimagined rather than hard-depending on their
# internal scene implementation.
domcom_endowment_mastery_rate_carnalitas_partner_effect = {
    save_scope_as = domcom_mastery_student
    if = {
        limit = {
            domcom_should_express_endowment_trigger = yes age >= 18
            exists = scope:domcom_mastery_partner
            scope:domcom_mastery_partner = { is_alive = yes age >= 18 }
        }

        if = {
            limit = {
                scope:domcom_mastery_partner = {
                    OR = {
                        is_imprisoned_by = scope:domcom_mastery_student
                        opinion = { target = scope:domcom_mastery_student value <= -50 }
                    }
                }
            }
            domcom_endowment_mastery_severe_negative_sex_effect = yes
        }
        else_if = {
            limit = {
                OR = {
                    has_relation_lover = scope:domcom_mastery_partner
                    has_relation_soulmate = scope:domcom_mastery_partner
                }
                is_attracted_to_gender_of = scope:domcom_mastery_partner
                scope:domcom_mastery_partner = { is_attracted_to_gender_of = scope:domcom_mastery_student }
            }
            domcom_endowment_mastery_strong_positive_sex_effect = yes
        }
        else_if = {
            limit = {
                is_consort_of = scope:domcom_mastery_partner
                is_attracted_to_gender_of = scope:domcom_mastery_partner
                scope:domcom_mastery_partner = {
                    is_attracted_to_gender_of = scope:domcom_mastery_student
                    opinion = { target = scope:domcom_mastery_student value >= 20 }
                }
            }
            domcom_endowment_mastery_warm_sex_effect = yes
        }
        else_if = {
            limit = {
                is_attracted_to_gender_of = scope:domcom_mastery_partner
                scope:domcom_mastery_partner = {
                    is_attracted_to_gender_of = scope:domcom_mastery_student
                    opinion = { target = scope:domcom_mastery_student value >= 20 }
                }
            }
            domcom_endowment_mastery_positive_sex_effect = yes
        }
        else_if = {
            limit = { scope:domcom_mastery_partner = { opinion = { target = scope:domcom_mastery_student value >= 0 } } }
            domcom_endowment_mastery_neutral_sex_effect = yes
        }
        else = { domcom_endowment_mastery_negative_sex_effect = yes }
    }
}

# carn_on_sex_v2 can fire once for each participant. A short partner-specific guard means a single sexual
# encounter is graded once per qualifying Endowment participant, while sex with a different partner on the same day can
# still count. Direct Dominion intimacy sets domcom_mastery_direct_sex_guard during had_sex_with_effect,
# preventing the optional Carnalitas hook from double-awarding the same encounter.
domcom_process_carnalitas_mastery_effect = {
    if = {
        limit = {
            scope:carn_sex_partner = { age >= 18 is_alive = yes }
            OR = {
                AND = {
                    exists = scope:carn_sex_player
                    scope:carn_sex_player = { age >= 18 is_alive = yes }
                }
                AND = {
                    NOT = { exists = scope:carn_sex_player }
                    age >= 18
                    is_alive = yes
                }
            }
        }
        # carn_on_sex_v2 exposes the actual participant as scope:carn_sex_player. Root is usually
        # the scene character, but other mods can fire the hook from a different root; using the
        # explicit participant scope keeps AI men from silently missing Mastery progression.
        if = {
            limit = { exists = scope:carn_sex_player }
            scope:carn_sex_player = { save_scope_as = domcom_mastery_carn_a }
        }
        else = { save_scope_as = domcom_mastery_carn_a }
        scope:carn_sex_partner = { save_scope_as = domcom_mastery_carn_b }

        if = {
            limit = {
                scope:domcom_mastery_carn_a = {
                    domcom_should_express_endowment_trigger = yes
                    NOT = { has_character_flag = domcom_mastery_direct_sex_guard }
                    NOT = {
                        AND = {
                            has_character_flag = domcom_endowment_mastery_carn_guard
                            has_variable = domcom_endowment_mastery_carn_guard_partner
                            var:domcom_endowment_mastery_carn_guard_partner = scope:domcom_mastery_carn_b
                        }
                    }
                }
            }
            scope:domcom_mastery_carn_b = { save_scope_as = domcom_mastery_partner }
            scope:domcom_mastery_carn_a = {
                set_variable = { name = domcom_endowment_mastery_carn_guard_partner value = scope:domcom_mastery_carn_b }
                add_character_flag = { flag = domcom_endowment_mastery_carn_guard days = 1 }
                domcom_endowment_mastery_rate_carnalitas_partner_effect = yes
            }
        }

        if = {
            limit = {
                scope:domcom_mastery_carn_b = {
                    domcom_should_express_endowment_trigger = yes
                    NOT = { has_character_flag = domcom_mastery_direct_sex_guard }
                    NOT = {
                        AND = {
                            has_character_flag = domcom_endowment_mastery_carn_guard
                            has_variable = domcom_endowment_mastery_carn_guard_partner
                            var:domcom_endowment_mastery_carn_guard_partner = scope:domcom_mastery_carn_a
                        }
                    }
                }
            }
            scope:domcom_mastery_carn_a = { save_scope_as = domcom_mastery_partner }
            scope:domcom_mastery_carn_b = {
                set_variable = { name = domcom_endowment_mastery_carn_guard_partner value = scope:domcom_mastery_carn_a }
                add_character_flag = { flag = domcom_endowment_mastery_carn_guard days = 1 }
                domcom_endowment_mastery_rate_carnalitas_partner_effect = yes
            }
        }
    }
}

# Save migration is intentionally player-only and O(Players), not a world scan. Unranked NPCs need no
# stored state; the first relevant profile/sex/Tantalize initializes them lazily at 0 XP.
domcom_migrate_endowment_mastery_v240_once_effect = {
    if = {
        limit = { NOT = { has_global_variable = domcom_endowment_mastery_migration_v240 } }
        every_player = {
            if = { limit = { domcom_should_express_endowment_trigger = yes age >= 18 } domcom_initialize_endowment_mastery_effect = yes }
        }
        set_global_variable = domcom_endowment_mastery_migration_v240
    }
}


# v2.4.1 save bridge: native path seeding + impossible self/lawful-partner cuck provenance repair.
domcom_migrate_native_mastery_and_cuck_repair_v241_once_effect = {
    if = {
        limit = { NOT = { has_global_variable = domcom_native_mastery_cuck_repair_v241 } }
        every_player = {
            if = { limit = { domcom_should_express_endowment_trigger = yes age >= 18 } domcom_initialize_endowment_mastery_effect = yes }
            domcom_repair_lawful_partner_cuck_provenance_effect = yes
        }
        set_global_variable = domcom_native_mastery_cuck_repair_v241
    }
}


# v2.5.0 save bridge: normalize any already-seeded 2.4.x Endowment Mastery path to CK3's native
# 0..100 trait-track scale. NPCs repair lazily the first time their Endowment is processed.
domcom_migrate_mastery_track_scale_v250_once_effect = {
    if = {
        limit = { NOT = { has_global_variable = domcom_mastery_track_scale_v250 } }
        every_player = {
            if = { limit = { domcom_should_express_endowment_trigger = yes age >= 18 } domcom_initialize_endowment_mastery_effect = yes }
        }
        set_global_variable = domcom_mastery_track_scale_v250
    }
}
