﻿# DDM 2.0 — Roman-style Proscriptions.
# A ruler may issue a writ from the start of the game. Dread, prestige, rank, income, treasury strength,
# relationships and personality determine whether the realm actually answers the call.

# Actor scope. A single hidden 14-day loop services all active writs; repeated issues do not create duplicate loops.
ddm_start_proscription_biweekly_loop_effect = {
    if = {
        limit = { NOT = { has_character_flag = ddm_proscription_biweekly_loop_active } }
        add_character_flag = ddm_proscription_biweekly_loop_active
        trigger_event = { id = ddm_manager.5210 days = 14 }
    }
}

# Target scope; scope:ddm_proscriber and scope:ddm_proscription_target required.
# Used at issue time and again only when a writ has no surviving hunters.
ddm_proscription_recruit_hunters_effect = {
    clear_variable_list = ddm_proscription_hunters
    set_variable = { name = ddm_proscription_hunter_count value = 0 }
    scope:ddm_proscriber = { set_variable = { name = ddm_proscription_eligible_count value = 0 } }

    scope:ddm_proscriber = {
        every_courtier_or_guest = {
            limit = { ddm_is_eligible_proscription_hunter_trigger = yes }
            scope:ddm_proscriber = { change_variable = { name = ddm_proscription_eligible_count add = 1 } }
            ddm_proscription_consider_hunter_effect = yes
        }
        every_vassal_or_below = {
            limit = { ddm_is_eligible_proscription_hunter_trigger = yes }
            scope:ddm_proscriber = { change_variable = { name = ddm_proscription_eligible_count add = 1 } }
            ddm_proscription_consider_hunter_effect = yes
        }
        every_vassal_or_below = {
            every_courtier_or_guest = {
                limit = { ddm_is_eligible_proscription_hunter_trigger = yes }
                scope:ddm_proscriber = { change_variable = { name = ddm_proscription_eligible_count add = 1 } }
                ddm_proscription_consider_hunter_effect = yes
            }
        }
    }

    scope:ddm_proscriber = {
        set_variable = { name = ddm_proscription_last_hunters value = scope:ddm_proscription_target.var:ddm_proscription_hunter_count }
        set_variable = { name = ddm_proscription_last_response_percent value = var:ddm_proscription_last_hunters }
        change_variable = { name = ddm_proscription_last_response_percent multiply = 100 }
        if = {
            limit = { var:ddm_proscription_eligible_count > 0 }
            change_variable = { name = ddm_proscription_last_response_percent divide = var:ddm_proscription_eligible_count }
        }
        else = { set_variable = { name = ddm_proscription_last_response_percent value = 0 } }
    }
}

# Target scope. A rebellion writ is attached to the war itself so a surviving rebellion can hand the writ to a new leader.
ddm_mark_rebellion_proscription_war_effect = {
    every_character_war = {
        limit = {
            primary_attacker = scope:ddm_proscription_target
            primary_defender = scope:ddm_proscriber
        }
        set_variable = { name = ddm_rebellion_proscription_owner value = scope:ddm_proscriber }
    }
}

# Target scope. Visible alertness rises by one full tier after every evasion/wounding, up to five tiers.
ddm_refresh_proscription_alertness_effect = {
    remove_character_modifier = ddm_proscription_alertness_1
    remove_character_modifier = ddm_proscription_alertness_2
    remove_character_modifier = ddm_proscription_alertness_3
    remove_character_modifier = ddm_proscription_alertness_4
    remove_character_modifier = ddm_proscription_alertness_5
    if = { limit = { has_variable = ddm_proscription_evasion_count var:ddm_proscription_evasion_count >= 5 } add_character_modifier = { modifier = ddm_proscription_alertness_5 } }
    else_if = { limit = { has_variable = ddm_proscription_evasion_count var:ddm_proscription_evasion_count >= 4 } add_character_modifier = { modifier = ddm_proscription_alertness_4 } }
    else_if = { limit = { has_variable = ddm_proscription_evasion_count var:ddm_proscription_evasion_count >= 3 } add_character_modifier = { modifier = ddm_proscription_alertness_3 } }
    else_if = { limit = { has_variable = ddm_proscription_evasion_count var:ddm_proscription_evasion_count >= 2 } add_character_modifier = { modifier = ddm_proscription_alertness_2 } }
    else_if = { limit = { has_variable = ddm_proscription_evasion_count var:ddm_proscription_evasion_count >= 1 } add_character_modifier = { modifier = ddm_proscription_alertness_1 } }
}

# Actor scope; scope:ddm_proscription_target required.
ddm_issue_proscription_effect = {
    save_scope_as = ddm_proscriber
    scope:ddm_proscription_target = {
        if = {
            limit = { has_variable = ddm_proscribed_by var:ddm_proscribed_by = { is_alive = no } }
            ddm_clear_target_proscription_effect = yes
        }
    }
    if = {
        limit = {
            scope:ddm_proscription_target = {
                NOT = { has_variable = ddm_proscribed_by }
                NOT = { has_character_flag = ddm_bounty_hunter_immunity }
                NOT = { has_character_flag = ddm_proscription_recently_revoked }
            }
            OR = {
                scope:ddm_proscription_target = { ddm_is_valid_proscription_target_trigger = yes }
                has_variable = ddm_proscription_transfer_mode
                has_variable = ddm_proscription_personal_issue_mode
            }
        }

        # Income-scaled promise: roughly three months of ordinary income, with sane floors/caps.
        set_variable = { name = ddm_proscription_promised_reward value = monthly_character_income }
        change_variable = { name = ddm_proscription_promised_reward multiply = 3 }
        if = { limit = { var:ddm_proscription_promised_reward < 15 } set_variable = { name = ddm_proscription_promised_reward value = 15 } }
        if = { limit = { var:ddm_proscription_promised_reward > 500 } set_variable = { name = ddm_proscription_promised_reward value = 500 } }

        scope:ddm_proscription_target = {
            set_variable = { name = ddm_proscribed_by value = scope:ddm_proscriber }
            set_variable = { name = ddm_proscription_reward value = scope:ddm_proscriber.var:ddm_proscription_promised_reward }
            set_variable = { name = ddm_proscription_evasion_count value = 0 }
            add_character_modifier = { modifier = ddm_proscribed_modifier }
            ddm_refresh_proscription_alertness_effect = yes
            ddm_proscription_recruit_hunters_effect = yes
            ddm_mark_rebellion_proscription_war_effect = yes
        }

        # Keep the ruler-owned active-writ registry unique. Reissuing a writ after revocation may encounter
        # a stale legacy entry from older saves; reactivate that entry instead of appending a duplicate.
        if = {
            limit = {
                OR = {
                    NOT = { has_variable_list = ddm_active_proscriptions }
                    NOT = { any_in_list = { variable = ddm_active_proscriptions this = scope:ddm_proscription_target } }
                }
            }
            add_to_variable_list = { name = ddm_active_proscriptions target = scope:ddm_proscription_target }
        }
        change_variable = { name = ddm_proscription_active_count add = 1 }
        if = {
            limit = { NOT = { has_variable = ddm_proscription_transfer_mode } }
            change_variable = { name = ddm_proscription_issued_total add = 1 }
            change_variable = { name = ddm_proscription_climate add = 5 }
            if = { limit = { var:ddm_proscription_climate > 100 } set_variable = { name = ddm_proscription_climate value = 100 } }
            if = {
                limit = { scope:ddm_proscription_target.var:ddm_proscription_hunter_count <= 0 }
                change_variable = { name = ddm_proscription_failure_total add = 1 }
                change_variable = { name = ddm_proscription_reputation subtract = 5 }
                if = { limit = { var:ddm_proscription_reputation < 0 } set_variable = { name = ddm_proscription_reputation value = 0 } }
            }
        }
        ddm_update_proscription_climate_modifier_effect = yes
        ddm_start_proscription_biweekly_loop_effect = yes
    }
}

# Candidate/hunter scope; scope:ddm_proscriber + scope:ddm_proscription_target required.
ddm_proscription_consider_hunter_effect = {
    set_variable = { name = ddm_hunter_join_chance value = 5 }

    # The ruler's threat/standing is the backbone of the call.
    if = { limit = { scope:ddm_proscriber.dread >= 20 } change_variable = { name = ddm_hunter_join_chance add = 8 } }
    if = { limit = { scope:ddm_proscriber.dread >= 40 } change_variable = { name = ddm_hunter_join_chance add = 10 } }
    if = { limit = { scope:ddm_proscriber.dread >= 60 } change_variable = { name = ddm_hunter_join_chance add = 12 } }
    if = { limit = { scope:ddm_proscriber.dread >= 80 } change_variable = { name = ddm_hunter_join_chance add = 15 } }

    if = { limit = { scope:ddm_proscriber.prestige >= 500 } change_variable = { name = ddm_hunter_join_chance add = 4 } }
    if = { limit = { scope:ddm_proscriber.prestige >= 1000 } change_variable = { name = ddm_hunter_join_chance add = 5 } }
    if = { limit = { scope:ddm_proscriber.prestige >= 2000 } change_variable = { name = ddm_hunter_join_chance add = 6 } }
    if = { limit = { scope:ddm_proscriber.prestige >= 4000 } change_variable = { name = ddm_hunter_join_chance add = 7 } }

    if = { limit = { scope:ddm_proscriber.highest_held_title_tier = tier_county } change_variable = { name = ddm_hunter_join_chance add = 3 } }
    if = { limit = { scope:ddm_proscriber.highest_held_title_tier = tier_duchy } change_variable = { name = ddm_hunter_join_chance add = 6 } }
    if = { limit = { scope:ddm_proscriber.highest_held_title_tier = tier_kingdom } change_variable = { name = ddm_hunter_join_chance add = 10 } }
    if = { limit = { OR = { scope:ddm_proscriber.highest_held_title_tier = tier_empire scope:ddm_proscriber.highest_held_title_tier = tier_hegemony } } change_variable = { name = ddm_hunter_join_chance add = 14 } }

    if = { limit = { scope:ddm_proscriber.monthly_character_income > 0 } change_variable = { name = ddm_hunter_join_chance add = 3 } }
    if = { limit = { scope:ddm_proscriber.monthly_character_income >= 5 } change_variable = { name = ddm_hunter_join_chance add = 4 } }
    if = { limit = { scope:ddm_proscriber.monthly_character_income >= 10 } change_variable = { name = ddm_hunter_join_chance add = 5 } }
    if = { limit = { scope:ddm_proscriber.monthly_character_income >= 25 } change_variable = { name = ddm_hunter_join_chance add = 6 } }
    if = { limit = { scope:ddm_proscriber.monthly_character_income >= 50 } change_variable = { name = ddm_hunter_join_chance add = 7 } }
    if = { limit = { scope:ddm_proscriber.monthly_character_income >= 100 } change_variable = { name = ddm_hunter_join_chance add = 8 } }

    if = { limit = { scope:ddm_proscriber.gold >= scope:ddm_proscription_target.var:ddm_proscription_reward } change_variable = { name = ddm_hunter_join_chance add = 8 } }
    if = { limit = { scope:ddm_proscriber.gold < scope:ddm_proscription_target.var:ddm_proscription_reward } change_variable = { name = ddm_hunter_join_chance subtract = 15 } }
    if = { limit = { scope:ddm_proscriber.gold < 0 } change_variable = { name = ddm_hunter_join_chance subtract = 20 } }

    # Personal loyalties can overwhelm the bounty. Strong target loyalty is intentionally powerful.
    if = { limit = { opinion = { target = scope:ddm_proscriber value >= 50 } } change_variable = { name = ddm_hunter_join_chance add = 15 } }
    else_if = { limit = { opinion = { target = scope:ddm_proscriber value >= 25 } } change_variable = { name = ddm_hunter_join_chance add = 8 } }
    else_if = { limit = { opinion = { target = scope:ddm_proscriber value <= -50 } } change_variable = { name = ddm_hunter_join_chance subtract = 20 } }
    else_if = { limit = { opinion = { target = scope:ddm_proscriber value <= -25 } } change_variable = { name = ddm_hunter_join_chance subtract = 12 } }

    if = { limit = { opinion = { target = scope:ddm_proscription_target value >= 50 } } change_variable = { name = ddm_hunter_join_chance subtract = 35 } }
    else_if = { limit = { opinion = { target = scope:ddm_proscription_target value >= 25 } } change_variable = { name = ddm_hunter_join_chance subtract = 18 } }
    else_if = { limit = { opinion = { target = scope:ddm_proscription_target value <= -50 } } change_variable = { name = ddm_hunter_join_chance add = 15 } }
    else_if = { limit = { opinion = { target = scope:ddm_proscription_target value <= -25 } } change_variable = { name = ddm_hunter_join_chance add = 8 } }

    if = {
        limit = {
            exists = dynasty
            exists = scope:ddm_proscription_target.dynasty
            dynasty = scope:ddm_proscription_target.dynasty
        }
        change_variable = { name = ddm_hunter_join_chance subtract = 10 }
    }
    if = {
        limit = {
            exists = house
            exists = scope:ddm_proscription_target.house
            house = scope:ddm_proscription_target.house
        }
        change_variable = { name = ddm_hunter_join_chance subtract = 15 }
    }

    if = { limit = { has_trait = greedy } change_variable = { name = ddm_hunter_join_chance add = 12 } }
    if = { limit = { has_trait = ambitious } change_variable = { name = ddm_hunter_join_chance add = 8 } }
    if = { limit = { has_trait = brave } change_variable = { name = ddm_hunter_join_chance add = 5 } }
    if = { limit = { has_trait = vengeful } change_variable = { name = ddm_hunter_join_chance add = 7 } }
    if = { limit = { has_trait = just } change_variable = { name = ddm_hunter_join_chance subtract = 12 } }
    if = { limit = { has_trait = compassionate } change_variable = { name = ddm_hunter_join_chance subtract = 12 } }
    if = { limit = { has_trait = craven } change_variable = { name = ddm_hunter_join_chance subtract = 5 } }

    if = { limit = { has_variable = ddm_bountyhunter_completed var:ddm_bountyhunter_completed >= 1 } change_variable = { name = ddm_hunter_join_chance add = 5 } }
    if = { limit = { has_variable = ddm_bountyhunter_completed var:ddm_bountyhunter_completed >= 3 } change_variable = { name = ddm_hunter_join_chance add = 5 } }
    if = { limit = { has_variable = ddm_bountyhunter_completed var:ddm_bountyhunter_completed >= 7 } change_variable = { name = ddm_hunter_join_chance add = 5 } }

    if = { limit = { var:ddm_hunter_join_chance < 0 } set_variable = { name = ddm_hunter_join_chance value = 0 } }
    if = { limit = { var:ddm_hunter_join_chance > 85 } set_variable = { name = ddm_hunter_join_chance value = 85 } }

    random = {
        chance = var:ddm_hunter_join_chance
        save_temporary_scope_as = ddm_joining_hunter
        scope:ddm_proscription_target = {
            add_to_variable_list = { name = ddm_proscription_hunters target = scope:ddm_joining_hunter }
            change_variable = { name = ddm_proscription_hunter_count add = 1 }
        }
        # Volunteering only joins this writ's candidate pool. A character becomes a persistent
        # Bounty Office professional only when actually dispatched on a hunt.
    }
    remove_variable = ddm_hunter_join_chance
}

# Actor/player scope. One-shot banner when at least one currently unproscribed political target exists.
# The latch clears once no eligible faction member or active rebel leader remains, so a later threat can alert again.
ddm_proscription_target_availability_effect = {
    # Character interactions have actor/recipient saved scopes but no ROOT scope. Save the current
    # ruler explicitly so this effect behaves identically from interactions and on-actions.
    save_scope_as = ddm_proscriber
    if = {
        limit = {
            OR = {
                ddm_has_eligible_faction_proscription_target_trigger = yes
                ddm_has_eligible_rebel_proscription_target_trigger = yes
            }
        }
        if = {
            limit = { NOT = { has_character_flag = ddm_proscription_target_available_notified } }
            add_character_flag = ddm_proscription_target_available_notified
            send_interface_toast = {
                type = event_toast_effect_neutral
                title = DDM_PROSCRIPTION_TARGET_AVAILABLE_TOAST
                left_icon = scope:ddm_proscriber
            }
        }
    }
    else = {
        remove_character_flag = ddm_proscription_target_available_notified
    }
}

# Actor scope. Rebuilds list/count from surviving linked targets; also clears stale target modifiers.
ddm_rebuild_active_proscriptions_effect = {
    save_scope_as = ddm_proscriber
    set_variable = { name = ddm_proscription_active_count value = 0 }

    # Snapshot the actor-owned registry without mutating it. Defied-the-Writ targets are repaired here:
    # old saves could retain a political writ even though the visible immunity modifier said they were untouchable.
    if = {
        limit = { has_variable_list = ddm_active_proscriptions }
        every_in_list = {
            variable = ddm_active_proscriptions
            if = {
                limit = {
                    is_alive = yes
                    has_variable = ddm_proscribed_by
                    var:ddm_proscribed_by = scope:ddm_proscriber
                    OR = { has_character_flag = ddm_bounty_hunter_immunity has_character_flag = ddm_proscription_recently_revoked }
                }
                ddm_clear_target_proscription_effect = yes
            }
            else_if = {
                limit = {
                    is_alive = yes
                    has_variable = ddm_proscribed_by
                    var:ddm_proscribed_by = scope:ddm_proscriber
                    NOT = { is_in_list = ddm_active_proscriptions_rebuild }
                }
                add_to_temporary_list = ddm_active_proscriptions_rebuild
            }
        }
    }

    # 2.6.30 performance: older saves can have writs that predate the persistent actor-owned list,
    # but importing them never needed to rescan every vassal and every vassal court every month.
    # Do the expensive compatibility sweep once, then trust the authoritative registry populated at issue time.
    if = {
        limit = { NOT = { has_character_flag = ddm_proscription_registry_import_v2630 } }
        every_vassal_or_below = {
            if = {
                limit = { is_alive = yes has_variable = ddm_proscribed_by var:ddm_proscribed_by = scope:ddm_proscriber }
                if = { limit = { OR = { has_character_flag = ddm_bounty_hunter_immunity has_character_flag = ddm_proscription_recently_revoked } } ddm_clear_target_proscription_effect = yes }
                else_if = { limit = { NOT = { is_in_list = ddm_active_proscriptions_rebuild } } add_to_temporary_list = ddm_active_proscriptions_rebuild }
            }
        }
        every_courtier_or_guest = {
            if = {
                limit = { is_alive = yes has_variable = ddm_proscribed_by var:ddm_proscribed_by = scope:ddm_proscriber }
                if = { limit = { OR = { has_character_flag = ddm_bounty_hunter_immunity has_character_flag = ddm_proscription_recently_revoked } } ddm_clear_target_proscription_effect = yes }
                else_if = { limit = { NOT = { is_in_list = ddm_active_proscriptions_rebuild } } add_to_temporary_list = ddm_active_proscriptions_rebuild }
            }
        }
        every_vassal_or_below = {
            every_courtier_or_guest = {
                if = {
                    limit = { is_alive = yes has_variable = ddm_proscribed_by var:ddm_proscribed_by = scope:ddm_proscriber }
                    if = { limit = { OR = { has_character_flag = ddm_bounty_hunter_immunity has_character_flag = ddm_proscription_recently_revoked } } ddm_clear_target_proscription_effect = yes }
                    else_if = { limit = { NOT = { is_in_list = ddm_active_proscriptions_rebuild } } add_to_temporary_list = ddm_active_proscriptions_rebuild }
                }
            }
        }
        add_character_flag = ddm_proscription_registry_import_v2630
    }
    every_primary_war_enemy = {
        if = {
            limit = { is_alive = yes has_variable = ddm_proscribed_by var:ddm_proscribed_by = scope:ddm_proscriber }
            if = { limit = { OR = { has_character_flag = ddm_bounty_hunter_immunity has_character_flag = ddm_proscription_recently_revoked } } ddm_clear_target_proscription_effect = yes }
            else_if = { limit = { NOT = { is_in_list = ddm_active_proscriptions_rebuild } } add_to_temporary_list = ddm_active_proscriptions_rebuild }
        }
    }

    # Replace the registry only after every traversal is finished. This also deduplicates legacy entries.
    clear_variable_list = ddm_active_proscriptions
    every_in_list = {
        list = ddm_active_proscriptions_rebuild
        save_temporary_scope_as = ddm_active_target
        scope:ddm_proscriber = {
            add_to_variable_list = { name = ddm_active_proscriptions target = scope:ddm_active_target }
            change_variable = { name = ddm_proscription_active_count add = 1 }
        }
    }
}

# Actor/player monthly maintenance and hunting.
ddm_proscription_monthly_effect = {
    save_scope_as = ddm_proscriber
    ddm_rebuild_active_proscriptions_effect = yes
    if = { limit = { var:ddm_proscription_active_count > 0 } ddm_start_proscription_biweekly_loop_effect = yes }

    if = {
        limit = { has_variable_list = ddm_active_proscriptions }
        every_in_list = {
            variable = ddm_active_proscriptions
            limit = { is_alive = yes has_variable = ddm_proscribed_by var:ddm_proscribed_by = scope:ddm_proscriber }

            # A proscribed faction member may simply abandon the conspiracy under pressure.
            if = {
                limit = {
                    is_a_faction_member = yes
                    joined_faction = { faction_target = scope:ddm_proscriber }
                }
                set_variable = { name = ddm_target_defection_chance value = 5 }
                if = { limit = { scope:ddm_proscriber.dread >= 40 } change_variable = { name = ddm_target_defection_chance add = 8 } }
                if = { limit = { scope:ddm_proscriber.dread >= 70 } change_variable = { name = ddm_target_defection_chance add = 12 } }
                if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 25 } change_variable = { name = ddm_target_defection_chance add = 8 } }
                if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 60 } change_variable = { name = ddm_target_defection_chance add = 12 } }
                if = { limit = { var:ddm_proscription_hunter_count >= 10 } change_variable = { name = ddm_target_defection_chance add = 10 } }
                if = { limit = { var:ddm_proscription_hunter_count >= 30 } change_variable = { name = ddm_target_defection_chance add = 10 } }
                if = { limit = { has_trait = brave } change_variable = { name = ddm_target_defection_chance subtract = 12 } }
                if = { limit = { has_trait = stubborn } change_variable = { name = ddm_target_defection_chance subtract = 8 } }
                if = { limit = { var:ddm_target_defection_chance > 65 } set_variable = { name = ddm_target_defection_chance value = 65 } }
                random = {
                    chance = var:ddm_target_defection_chance
                    leave_faction = joined_faction
                }
                remove_variable = ddm_target_defection_chance
            }
        }
    }

    if = {
        limit = { var:ddm_proscription_active_count <= 0 has_variable = ddm_proscription_climate var:ddm_proscription_climate > 0 }
        change_variable = { name = ddm_proscription_climate subtract = 1 }
        if = { limit = { var:ddm_proscription_climate < 0 } set_variable = { name = ddm_proscription_climate value = 0 } }
    }
    ddm_update_proscription_climate_modifier_effect = yes
}

# Target scope. Remove dead/imprisoned hunters and recalculate the live response before each biweekly pulse.
ddm_proscription_prune_hunters_effect = {
    save_scope_as = ddm_proscription_prune_target
    # Do not remove hunters from the same persistent list CK3 is currently iterating. Snapshot survivors,
    # then replace the list after traversal; this mirrors the hardened active-writ registry.
    if = {
        limit = { has_variable_list = ddm_proscription_hunters }
        every_in_list = {
            variable = ddm_proscription_hunters
            limit = {
                is_alive = yes
                is_imprisoned = no
                NOT = { is_in_list = ddm_proscription_hunters_rebuild }
            }
            add_to_temporary_list = ddm_proscription_hunters_rebuild
        }
    }
    clear_variable_list = ddm_proscription_hunters
    set_variable = { name = ddm_proscription_hunter_count value = 0 }
    every_in_list = {
        list = ddm_proscription_hunters_rebuild
        save_temporary_scope_as = ddm_live_proscription_hunter
        scope:ddm_proscription_prune_target = {
            add_to_variable_list = { name = ddm_proscription_hunters target = scope:ddm_live_proscription_hunter }
            change_variable = { name = ddm_proscription_hunter_count add = 1 }
        }
    }
}

# Actor/player scope. Every 14 days: transfer marked rebellion writs if leadership changed, re-recruit empty writs, then stage one meaningful attempt (occasionally two for very broad responses).
ddm_proscription_biweekly_effect = {
    save_scope_as = ddm_proscriber
    ddm_rebuild_active_proscriptions_effect = yes

    # A rebellion writ follows the marked war if CK3 replaced the original leader after death/capture.
    every_character_war = {
        limit = {
            has_variable = ddm_rebellion_proscription_owner
            var:ddm_rebellion_proscription_owner = scope:ddm_proscriber
            primary_defender = scope:ddm_proscriber
        }
        primary_attacker = {
            if = {
                limit = {
                    is_alive = yes
                    is_imprisoned = no
                    NOT = { has_variable = ddm_proscribed_by }
                    NOT = { has_character_flag = ddm_bounty_hunter_immunity }
                    NOT = { has_character_flag = ddm_proscription_recently_revoked }
                }
                save_temporary_scope_as = ddm_proscription_target
                scope:ddm_proscriber = {
                    set_variable = { name = ddm_proscription_transfer_mode value = 1 }
                    ddm_issue_proscription_effect = yes
                    remove_variable = ddm_proscription_transfer_mode
                }
            }
        }
    }

    ddm_rebuild_active_proscriptions_effect = yes
    if = {
        limit = { has_variable_list = ddm_active_proscriptions }
        every_in_list = {
            variable = ddm_active_proscriptions
            limit = { is_alive = yes has_variable = ddm_proscribed_by var:ddm_proscribed_by = scope:ddm_proscriber }
            save_temporary_scope_as = ddm_proscription_target
            ddm_proscription_prune_hunters_effect = yes

            # If nobody answered, the proclamation remains live and the realm is asked again every two weeks.
            if = {
                limit = { NOT = { has_variable = ddm_proscription_hunter_count } OR = { var:ddm_proscription_hunter_count <= 0 NOT = { has_variable_list = ddm_proscription_hunters } } }
                ddm_proscription_recruit_hunters_effect = yes
            }

            if = {
                limit = { has_variable_list = ddm_proscription_hunters var:ddm_proscription_hunter_count > 0 }
                # Select first, execute second. Never clear/remove from ddm_proscription_hunters while CK3
                # still owns a random_in_list iterator over that same persistent list.
                random_in_list = {
                    variable = ddm_proscription_hunters
                    limit = { is_alive = yes is_imprisoned = no NOT = { has_character_flag = ddm_proscription_recent_attempt } }
                    save_temporary_scope_as = ddm_selected_proscription_hunter
                    scope:ddm_proscription_target = {
                        set_variable = { name = ddm_pending_proscription_hunter value = scope:ddm_selected_proscription_hunter }
                    }
                }
                scope:ddm_proscription_target = {
                    if = {
                        limit = {
                            has_variable = ddm_pending_proscription_hunter
                            var:ddm_pending_proscription_hunter = { is_alive = yes is_imprisoned = no }
                        }
                        var:ddm_pending_proscription_hunter = { save_scope_as = ddm_proscription_hunter }
                        remove_variable = ddm_pending_proscription_hunter
                        scope:ddm_proscription_hunter = { add_character_flag = { flag = ddm_proscription_recent_attempt days = 28 } }
                        ddm_proscription_hunt_attempt_effect = yes
                    }
                }
            }

            # Very broad participation can create a second independent attempt on the same pulse, but never dozens of rolls at once.
            if = {
                limit = { is_alive = yes has_variable = ddm_proscribed_by var:ddm_proscription_hunter_count >= 30 }
                random = {
                    chance = 35
                    random_in_list = {
                        variable = ddm_proscription_hunters
                        limit = { is_alive = yes is_imprisoned = no NOT = { has_character_flag = ddm_proscription_recent_attempt } }
                        save_temporary_scope_as = ddm_selected_proscription_hunter
                        scope:ddm_proscription_target = {
                            set_variable = { name = ddm_pending_proscription_hunter value = scope:ddm_selected_proscription_hunter }
                        }
                    }
                    scope:ddm_proscription_target = {
                        if = {
                            limit = {
                                has_variable = ddm_pending_proscription_hunter
                                var:ddm_pending_proscription_hunter = { is_alive = yes is_imprisoned = no }
                            }
                            var:ddm_pending_proscription_hunter = { save_scope_as = ddm_proscription_hunter }
                            remove_variable = ddm_pending_proscription_hunter
                            scope:ddm_proscription_hunter = { add_character_flag = { flag = ddm_proscription_recent_attempt days = 28 } }
                            ddm_proscription_hunt_attempt_effect = yes
                        }
                    }
                }
            }
        }
    }
}

# Target scope. Executes a hunt attempt using saved actor/hunter scopes.
ddm_proscription_hunt_attempt_effect = {
    if = {
        limit = {
            is_alive = yes
            has_variable = ddm_proscribed_by
            var:ddm_proscribed_by = scope:ddm_proscriber
            NOT = { has_character_flag = ddm_bounty_hunter_immunity }
            NOT = { has_character_flag = ddm_proscription_recently_revoked }
            exists = scope:ddm_proscription_hunter
            scope:ddm_proscription_hunter = { is_alive = yes }
        }
        # Any hunter who actually takes the field is a real Bounty Office professional.
        # Register at dispatch-time so the office cannot lose hunters who came from political writs.
        scope:ddm_proscription_hunter = { ddm_register_bounty_office_hunter_effect = yes }

        set_variable = { name = ddm_hunt_success_chance value = 14 }

        # Hunter: intrigue finds the opening, martial reads the wartime/security environment, prowess executes it.
        if = { limit = { scope:ddm_proscription_hunter.intrigue >= 10 } change_variable = { name = ddm_hunt_success_chance add = 4 } }
        if = { limit = { scope:ddm_proscription_hunter.intrigue >= 15 } change_variable = { name = ddm_hunt_success_chance add = 5 } }
        if = { limit = { scope:ddm_proscription_hunter.intrigue >= 20 } change_variable = { name = ddm_hunt_success_chance add = 6 } }
        if = { limit = { scope:ddm_proscription_hunter.martial >= 10 } change_variable = { name = ddm_hunt_success_chance add = 3 } }
        if = { limit = { scope:ddm_proscription_hunter.martial >= 15 } change_variable = { name = ddm_hunt_success_chance add = 4 } }
        if = { limit = { scope:ddm_proscription_hunter.martial >= 20 } change_variable = { name = ddm_hunt_success_chance add = 5 } }
        if = { limit = { scope:ddm_proscription_hunter.prowess >= 10 } change_variable = { name = ddm_hunt_success_chance add = 3 } }
        if = { limit = { scope:ddm_proscription_hunter.prowess >= 15 } change_variable = { name = ddm_hunt_success_chance add = 4 } }
        if = { limit = { scope:ddm_proscription_hunter.prowess >= 20 } change_variable = { name = ddm_hunt_success_chance add = 5 } }
        if = { limit = { scope:ddm_proscription_hunter.var:ddm_bountyhunter_completed >= 3 } change_variable = { name = ddm_hunt_success_chance add = 6 } }
        if = { limit = { scope:ddm_proscription_hunter.var:ddm_bountyhunter_completed >= 7 } change_variable = { name = ddm_hunt_success_chance add = 8 } }
        if = { limit = { scope:ddm_proscription_hunter.var:ddm_bountyhunter_completed >= 15 } change_variable = { name = ddm_hunt_success_chance add = 10 } }

        # Target opposed check.
        if = { limit = { intrigue >= 10 } change_variable = { name = ddm_hunt_success_chance subtract = 3 } }
        if = { limit = { intrigue >= 15 } change_variable = { name = ddm_hunt_success_chance subtract = 5 } }
        if = { limit = { intrigue >= 20 } change_variable = { name = ddm_hunt_success_chance subtract = 6 } }
        if = { limit = { martial >= 10 } change_variable = { name = ddm_hunt_success_chance subtract = 3 } }
        if = { limit = { martial >= 15 } change_variable = { name = ddm_hunt_success_chance subtract = 4 } }
        if = { limit = { martial >= 20 } change_variable = { name = ddm_hunt_success_chance subtract = 5 } }
        if = { limit = { prowess >= 10 } change_variable = { name = ddm_hunt_success_chance subtract = 3 } }
        if = { limit = { prowess >= 15 } change_variable = { name = ddm_hunt_success_chance subtract = 4 } }
        if = { limit = { prowess >= 20 } change_variable = { name = ddm_hunt_success_chance subtract = 5 } }

        # The proscribing ruler lends fear and institutional reach, but does not replace the hunter's own skill.
        if = { limit = { scope:ddm_proscriber.dread >= 40 } change_variable = { name = ddm_hunt_success_chance add = 4 } }
        if = { limit = { scope:ddm_proscriber.dread >= 70 } change_variable = { name = ddm_hunt_success_chance add = 6 } }
        if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 25 } change_variable = { name = ddm_hunt_success_chance add = 4 } }
        if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 60 } change_variable = { name = ddm_hunt_success_chance add = 6 } }

        # Every successful evasion permanently hardens the quarry for this writ: +12 defense per tier, up to five.
        if = {
            limit = { has_variable = ddm_proscription_evasion_count var:ddm_proscription_evasion_count > 0 }
            set_variable = { name = ddm_proscription_alert_penalty value = var:ddm_proscription_evasion_count }
            change_variable = { name = ddm_proscription_alert_penalty multiply = 12 }
            change_variable = { name = ddm_hunt_success_chance subtract = var:ddm_proscription_alert_penalty }
            remove_variable = ddm_proscription_alert_penalty
        }
        if = { limit = { has_trait = wounded_1 } change_variable = { name = ddm_hunt_success_chance add = 4 } }
        if = { limit = { has_trait = wounded_2 } change_variable = { name = ddm_hunt_success_chance add = 7 } }
        if = { limit = { has_trait = wounded_3 } change_variable = { name = ddm_hunt_success_chance add = 10 } }

        if = { limit = { var:ddm_hunt_success_chance < 5 } set_variable = { name = ddm_hunt_success_chance value = 5 } }
        if = { limit = { var:ddm_hunt_success_chance > 75 } set_variable = { name = ddm_hunt_success_chance value = 75 } }

        remove_variable = ddm_hunt_succeeded
        random = {
            chance = var:ddm_hunt_success_chance
            set_variable = { name = ddm_hunt_succeeded value = 1 }
        }

        if = {
            limit = { has_variable = ddm_hunt_succeeded }
            # 2.5.5: the Office policy is authoritative. A successful hunt does exactly what the ruler
            # ordered instead of randomly converting an "alive" writ into a killing or vice versa.
            if = {
                limit = { scope:ddm_proscriber = { has_variable = ddm_proscription_outcome_policy var:ddm_proscription_outcome_policy = 2 } }
                ddm_proscription_kill_target_effect = yes
            }
            else = {
                ddm_proscription_capture_target_effect = yes
            }
        }
        else = {
            # A failed political hunt is still a career attempt/loss for the assigned hunter.
            if = {
                limit = { scope:ddm_proscription_hunter = { is_alive = yes } }
                scope:ddm_proscription_hunter = { ddm_record_hunter_loss_effect = yes }
            }
            if = { limit = { NOT = { has_variable = ddm_proscription_evasion_count } } set_variable = { name = ddm_proscription_evasion_count value = 0 } }
            if = { limit = { var:ddm_proscription_evasion_count < 5 } change_variable = { name = ddm_proscription_evasion_count add = 1 } }
            ddm_refresh_proscription_alertness_effect = yes

            # Most misses are quiet. A minority expose the hunter or get the hunter killed.
            random_list = {
                80 = { }
                12 = {
                    add_opinion = { target = scope:ddm_proscription_hunter modifier = ddm_proscription_target_warned_opinion }
                    remove_list_variable = { name = ddm_proscription_hunters target = scope:ddm_proscription_hunter }
                    change_variable = { name = ddm_proscription_hunter_count subtract = 1 }
                    if = { limit = { var:ddm_proscription_hunter_count < 0 } set_variable = { name = ddm_proscription_hunter_count value = 0 } }
                    scope:ddm_proscriber = {
                        change_variable = { name = ddm_proscription_reputation subtract = 1 }
                        if = { limit = { var:ddm_proscription_reputation < 0 } set_variable = { name = ddm_proscription_reputation value = 0 } }
                    }
                }
                8 = {
                    if = {
                        limit = { scope:ddm_proscription_hunter = { is_alive = yes } }
                        save_scope_as = ddm_proscription_target_event
                        scope:ddm_proscription_hunter = { save_scope_as = ddm_proscription_hunter_event }
                        remove_list_variable = { name = ddm_proscription_hunters target = scope:ddm_proscription_hunter }
                        change_variable = { name = ddm_proscription_hunter_count subtract = 1 }
                        if = { limit = { var:ddm_proscription_hunter_count < 0 } set_variable = { name = ddm_proscription_hunter_count value = 0 } }
                        scope:ddm_proscription_hunter = { death = { death_reason = death_murder killer = scope:ddm_proscription_target } }
                        if = { limit = { scope:ddm_proscriber = { is_ai = no } } scope:ddm_proscriber = { set_variable = { name = ddm_event_target value = scope:ddm_proscription_target } set_variable = { name = ddm_event_hunter value = scope:ddm_proscription_hunter } trigger_event = ddm_manager.5203 } }
                    }
                }
            }
            # Political hunt evasions feed the same one-year Survivor I-VIII track as relationship-writ
            # defenses. At eight defenses, Defied the Writ can close every active writ for three years.
            if = { limit = { is_alive = yes } ddm_record_bounty_survival_effect = yes }
        }
        remove_variable = ddm_hunt_succeeded
        remove_variable = ddm_hunt_success_chance
    }
}

# Target scope. End relevant rebellion wars before capture/death can swap leaders.
ddm_proscription_end_rebel_wars_effect = {
    if = {
        limit = { has_trait = peasant_leader }
        every_character_war = {
            limit = {
                primary_attacker = scope:ddm_proscription_target
                primary_defender = scope:ddm_proscriber
                has_variable = ddm_rebellion_proscription_owner
                var:ddm_rebellion_proscription_owner = scope:ddm_proscriber
            }
            end_war = defender
        }
    }
    else = {
        set_variable = { name = ddm_rebellion_collapse_chance value = 35 }
        if = { limit = { scope:ddm_proscriber.dread >= 40 } change_variable = { name = ddm_rebellion_collapse_chance add = 10 } }
        if = { limit = { scope:ddm_proscriber.dread >= 70 } change_variable = { name = ddm_rebellion_collapse_chance add = 15 } }
        if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 25 } change_variable = { name = ddm_rebellion_collapse_chance add = 10 } }
        if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 60 } change_variable = { name = ddm_rebellion_collapse_chance add = 10 } }
        if = { limit = { var:ddm_rebellion_collapse_chance > 85 } set_variable = { name = ddm_rebellion_collapse_chance value = 85 } }
        remove_variable = ddm_rebellion_collapses_now
        random = { chance = var:ddm_rebellion_collapse_chance set_variable = { name = ddm_rebellion_collapses_now value = 1 } }
        if = {
            limit = { has_variable = ddm_rebellion_collapses_now }
            every_character_war = {
                limit = {
                    primary_attacker = scope:ddm_proscription_target
                    primary_defender = scope:ddm_proscriber
                    has_variable = ddm_rebellion_proscription_owner
                    var:ddm_rebellion_proscription_owner = scope:ddm_proscriber
                }
                end_war = defender
            }
        }
        # Otherwise CK3 may choose a replacement leader. The war-level marker lets the biweekly loop transfer the writ.
        remove_variable = ddm_rebellion_collapses_now
        remove_variable = ddm_rebellion_collapse_chance
    }
}

ddm_proscription_capture_target_effect = {
    save_scope_as = ddm_proscription_target
    scope:ddm_proscription_hunter = { ddm_register_bounty_office_hunter_effect = yes }
    save_scope_as = ddm_hunter_capture_target
    ddm_proscription_end_rebel_wars_effect = yes
    save_scope_as = ddm_proscription_target_event
    scope:ddm_proscription_hunter = { save_scope_as = ddm_proscription_hunter_event }
    scope:ddm_proscriber = { save_scope_as = ddm_writ_captor }
    ddm_prepare_writ_hostage_effect = yes
    scope:ddm_proscriber = {
        imprison = { target = scope:ddm_proscription_target type = dungeon }
    }
    scope:ddm_proscription_hunter = { ddm_record_hunter_live_capture_effect = yes ddm_reward_bounty_hunter_effect = yes }
    scope:ddm_proscriber = {
        change_variable = { name = ddm_proscription_success_total add = 1 }
        change_variable = { name = ddm_proscription_reputation add = 4 }
        if = { limit = { var:ddm_proscription_reputation > 100 } set_variable = { name = ddm_proscription_reputation value = 100 } }
    }
    ddm_clear_target_proscription_effect = yes
    if = { limit = { scope:ddm_proscriber = { is_ai = no } } scope:ddm_proscriber = { set_variable = { name = ddm_event_target value = scope:ddm_proscription_target } set_variable = { name = ddm_event_hunter value = scope:ddm_proscription_hunter } trigger_event = ddm_manager.5200 } }
}

ddm_proscription_kill_target_effect = {
    save_scope_as = ddm_proscription_target
    scope:ddm_proscription_hunter = { ddm_register_bounty_office_hunter_effect = yes }
    ddm_proscription_end_rebel_wars_effect = yes
    save_scope_as = ddm_proscription_target_event
    scope:ddm_proscription_hunter = { save_scope_as = ddm_proscription_hunter_event }
    scope:ddm_proscription_hunter = { ddm_record_hunter_kill_effect = yes ddm_reward_bounty_hunter_effect = yes }
    scope:ddm_proscriber = {
        change_variable = { name = ddm_proscription_success_total add = 1 }
        change_variable = { name = ddm_proscription_reputation add = 5 }
        if = { limit = { var:ddm_proscription_reputation > 100 } set_variable = { name = ddm_proscription_reputation value = 100 } }
    }
    ddm_clear_target_proscription_effect = yes
    death = { death_reason = death_murder killer = scope:ddm_proscription_hunter }
    if = { limit = { scope:ddm_proscriber = { is_ai = no } } scope:ddm_proscriber = { set_variable = { name = ddm_event_target value = scope:ddm_proscription_target } set_variable = { name = ddm_event_hunter value = scope:ddm_proscription_hunter } trigger_event = ddm_manager.5201 } }
}

ddm_proscription_wound_target_effect = {
    save_scope_as = ddm_proscription_target
    save_scope_as = ddm_proscription_target_event
    scope:ddm_proscription_hunter = { save_scope_as = ddm_proscription_hunter_event }
    if = {
        limit = { OR = { has_trait = wounded_1 has_trait = wounded_2 } }
        change_trait_rank = { trait = wounded rank = 1 max = 3 }
    }
    else_if = { limit = { has_trait = wounded_3 } }
    else = { add_trait = wounded_1 }
    if = { limit = { NOT = { has_variable = ddm_proscription_evasion_count } } set_variable = { name = ddm_proscription_evasion_count value = 0 } }
    if = { limit = { var:ddm_proscription_evasion_count < 5 } change_variable = { name = ddm_proscription_evasion_count add = 1 } }
    ddm_refresh_proscription_alertness_effect = yes
    scope:ddm_proscription_hunter = { add_prestige = 25 }
    if = { limit = { scope:ddm_proscriber = { is_ai = no } } scope:ddm_proscriber = { set_variable = { name = ddm_event_target value = scope:ddm_proscription_target } set_variable = { name = ddm_event_hunter value = scope:ddm_proscription_hunter } trigger_event = ddm_manager.5202 } }
}

# Hunter scope; actor/target scopes required.
ddm_reward_bounty_hunter_effect = {
    if = { limit = { NOT = { has_variable = ddm_bountyhunter_completed } } set_variable = { name = ddm_bountyhunter_completed value = 0 } }
    change_variable = { name = ddm_bountyhunter_completed add = 1 }
    ddm_update_hunter_level_effect = yes
    add_prestige = 75
    if = { limit = { exists = dynasty } dynasty = { add_dynasty_prestige = 25 } }

    # Pay as much of the promised income-scaled bounty as the ruler can currently honor.
    scope:ddm_proscriber = {
        set_variable = { name = ddm_proscription_actual_reward value = scope:ddm_proscription_target.var:ddm_proscription_reward }
        if = { limit = { gold < var:ddm_proscription_actual_reward } set_variable = { name = ddm_proscription_actual_reward value = gold } }
        if = { limit = { var:ddm_proscription_actual_reward < 0 } set_variable = { name = ddm_proscription_actual_reward value = 0 } }
    }
    add_gold = scope:ddm_proscriber.var:ddm_proscription_actual_reward
    scope:ddm_proscriber = {
        change_variable = { name = ddm_proscription_actual_reward multiply = -1 }
        add_gold = var:ddm_proscription_actual_reward
        remove_variable = ddm_proscription_actual_reward
        add_opinion = { target = scope:ddm_proscription_hunter modifier = ddm_proscription_hunter_grateful_opinion }
    }
    add_opinion = { target = scope:ddm_proscriber modifier = ddm_proscription_ruler_rewarded_opinion }
    ddm_refresh_bounty_hunter_modifier_effect = yes
}

ddm_refresh_bounty_hunter_modifier_effect = {
    remove_character_modifier = ddm_bounty_hunter_1
    remove_character_modifier = ddm_bounty_hunter_2
    remove_character_modifier = ddm_bounty_hunter_3
    remove_character_modifier = ddm_bounty_hunter_4
    if = { limit = { var:ddm_bountyhunter_completed >= 15 } add_character_modifier = { modifier = ddm_bounty_hunter_4 } }
    else_if = { limit = { var:ddm_bountyhunter_completed >= 7 } add_character_modifier = { modifier = ddm_bounty_hunter_3 } }
    else_if = { limit = { var:ddm_bountyhunter_completed >= 3 } add_character_modifier = { modifier = ddm_bounty_hunter_2 } }
    else_if = { limit = { var:ddm_bountyhunter_completed >= 1 } add_character_modifier = { modifier = ddm_bounty_hunter_1 } }
}

# Target scope.
ddm_clear_target_proscription_effect = {
    remove_character_modifier = ddm_proscribed_modifier
    remove_character_modifier = ddm_proscription_alertness_1
    remove_character_modifier = ddm_proscription_alertness_2
    remove_character_modifier = ddm_proscription_alertness_3
    remove_character_modifier = ddm_proscription_alertness_4
    remove_character_modifier = ddm_proscription_alertness_5
    remove_variable = ddm_proscribed_by
    remove_variable = ddm_personal_proscription
    remove_variable = ddm_proscription_reward
    remove_variable = ddm_proscription_hunter_count
    remove_variable = ddm_proscription_evasion_count
    clear_variable_list = ddm_proscription_hunters
}

# Actor scope with scope:ddm_proscription_target.
ddm_revoke_proscription_effect = {
    # Never rely on ROOT here. Character-interaction on_accept blocks do not provide one.
    # Manual revocation closes the current writ session first, then places the quarry behind a seven-day
    # reissue lock. The owner registry is intentionally NOT rebuilt here: scheduled monthly/biweekly
    # maintenance prunes the now-stale entry safely after this interaction has completely returned.
    save_scope_as = ddm_proscriber
    if = {
        limit = {
            exists = scope:ddm_proscription_target
            scope:ddm_proscription_target = {
                has_variable = ddm_proscribed_by
                var:ddm_proscribed_by = scope:ddm_proscriber
            }
        }
        scope:ddm_proscription_target = {
            every_character_war = {
                limit = {
                    primary_attacker = scope:ddm_proscription_target
                    primary_defender = scope:ddm_proscriber
                    has_variable = ddm_rebellion_proscription_owner
                    var:ddm_rebellion_proscription_owner = scope:ddm_proscriber
                }
                remove_variable = ddm_rebellion_proscription_owner
            }
            add_character_flag = { flag = ddm_proscription_recently_revoked days = 7 }
            add_character_modifier = { modifier = ddm_proscription_recently_revoked days = 7 }
            ddm_clear_target_proscription_effect = yes
        }
        if = {
            limit = { has_variable = ddm_proscription_active_count var:ddm_proscription_active_count > 0 }
            change_variable = { name = ddm_proscription_active_count subtract = 1 }
        }
    }
}

# Actor scope. Used by the Realm Office mass buttons.
ddm_proscribe_all_faction_members_effect = {
    save_scope_as = ddm_proscriber
    # Faction-scope traversal is authoritative for brewing factions. A temporary seen-list prevents a
    # character who sits in multiple factions from receiving duplicate writs during the same click.
    every_targeting_faction = {
        every_faction_member = {
            limit = {
                is_alive = yes
                NOT = { has_variable = ddm_proscribed_by }
                NOT = { has_character_flag = ddm_bounty_hunter_immunity }
                NOT = { has_character_flag = ddm_proscription_recently_revoked }
                NOT = { is_in_list = ddm_proscription_mass_seen }
            }
            add_to_temporary_list = ddm_proscription_mass_seen
            save_temporary_scope_as = ddm_proscription_target
            scope:ddm_proscriber = { ddm_issue_proscription_effect = yes }
        }
    }
    ddm_rebuild_active_proscriptions_effect = yes
    ddm_proscription_target_availability_effect = yes
}

ddm_proscribe_active_rebel_leaders_effect = {
    save_scope_as = ddm_proscriber
    # every_primary_war_enemy traverses every active war. A seen-list makes the bulk action robust even if
    # the same ruler is somehow primary enemy in more than one simultaneous war.
    every_primary_war_enemy = {
        limit = {
            is_alive = yes
            NOT = { has_variable = ddm_proscribed_by }
            NOT = { has_character_flag = ddm_bounty_hunter_immunity }
            NOT = { has_character_flag = ddm_proscription_recently_revoked }
            NOT = { is_in_list = ddm_proscription_rebel_mass_seen }
            ddm_is_proscription_rebel_leader_trigger = yes
        }
        add_to_temporary_list = ddm_proscription_rebel_mass_seen
        save_temporary_scope_as = ddm_proscription_target
        scope:ddm_proscriber = { ddm_issue_proscription_effect = yes }
    }
    ddm_rebuild_active_proscriptions_effect = yes
    ddm_proscription_target_availability_effect = yes
}

ddm_revoke_all_proscriptions_effect = {
    save_scope_as = ddm_proscriber
    if = {
        limit = { has_variable_list = ddm_active_proscriptions }
        every_in_list = {
            variable = ddm_active_proscriptions
            limit = { has_variable = ddm_proscribed_by var:ddm_proscribed_by = scope:ddm_proscriber }
            add_character_flag = { flag = ddm_proscription_recently_revoked days = 7 }
            add_character_modifier = { modifier = ddm_proscription_recently_revoked days = 7 }
            ddm_clear_target_proscription_effect = yes
        }
    }
    every_character_war = {
        limit = { has_variable = ddm_rebellion_proscription_owner var:ddm_rebellion_proscription_owner = scope:ddm_proscriber }
        remove_variable = ddm_rebellion_proscription_owner
    }
    clear_variable_list = ddm_active_proscriptions
    set_variable = { name = ddm_proscription_active_count value = 0 }
}

# Quarterly realm-wide deterrence. This does not forbid faction creation; it makes continued membership risky.
ddm_proscription_quarterly_intimidation_effect = {
    save_scope_as = ddm_proscriber
    if = {
        limit = {
            OR = {
                var:ddm_proscription_reputation > 0
                var:ddm_proscription_climate > 0
            }
        }
        every_targeting_faction = {
          every_faction_member = {
            limit = {
                is_alive = yes
                NOT = { has_variable = ddm_proscribed_by }
                NOT = { is_in_list = ddm_proscription_fear_seen }
            }
            add_to_temporary_list = ddm_proscription_fear_seen
            set_variable = { name = ddm_faction_fear_chance value = 0 }
            if = { limit = { scope:ddm_proscriber.dread >= 40 } change_variable = { name = ddm_faction_fear_chance add = 5 } }
            if = { limit = { scope:ddm_proscriber.dread >= 70 } change_variable = { name = ddm_faction_fear_chance add = 8 } }
            if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 25 } change_variable = { name = ddm_faction_fear_chance add = 7 } }
            if = { limit = { scope:ddm_proscriber.var:ddm_proscription_reputation >= 60 } change_variable = { name = ddm_faction_fear_chance add = 10 } }
            if = { limit = { scope:ddm_proscriber.var:ddm_proscription_climate >= 25 } change_variable = { name = ddm_faction_fear_chance add = 5 } }
            if = { limit = { scope:ddm_proscriber.var:ddm_proscription_climate >= 60 } change_variable = { name = ddm_faction_fear_chance add = 7 } }
            if = { limit = { opinion = { target = scope:ddm_proscriber value >= 25 } } change_variable = { name = ddm_faction_fear_chance add = 5 } }
            if = { limit = { has_trait = brave } change_variable = { name = ddm_faction_fear_chance subtract = 10 } }
            if = { limit = { has_trait = stubborn } change_variable = { name = ddm_faction_fear_chance subtract = 6 } }
            if = { limit = { var:ddm_faction_fear_chance < 0 } set_variable = { name = ddm_faction_fear_chance value = 0 } }
            if = { limit = { var:ddm_faction_fear_chance > 45 } set_variable = { name = ddm_faction_fear_chance value = 45 } }
            random = {
                chance = var:ddm_faction_fear_chance
                leave_faction = prev
            }
            remove_variable = ddm_faction_fear_chance
          }
        }
    }
}

ddm_update_proscription_climate_modifier_effect = {
    remove_character_modifier = ddm_proscription_climate_low
    remove_character_modifier = ddm_proscription_climate_medium
    remove_character_modifier = ddm_proscription_climate_high
    if = { limit = { var:ddm_proscription_climate >= 70 } add_character_modifier = { modifier = ddm_proscription_climate_high } }
    else_if = { limit = { var:ddm_proscription_climate >= 35 } add_character_modifier = { modifier = ddm_proscription_climate_medium } }
    else_if = { limit = { var:ddm_proscription_climate >= 10 } add_character_modifier = { modifier = ddm_proscription_climate_low } }
}

# Lightweight UI preparation: counts and reward preview only.
ddm_prepare_proscription_ui_effect = {
    ddm_prepare_personal_proscription_settings_effect = yes
    ddm_rebuild_active_proscriptions_effect = yes
    ddm_rebuild_hunter_roster_ui_effect = yes
    if = { limit = { var:ddm_proscription_active_count > 0 } ddm_start_proscription_biweekly_loop_effect = yes }
    set_variable = { name = ddm_proscription_preview_reward value = monthly_character_income }
    change_variable = { name = ddm_proscription_preview_reward multiply = 3 }
    if = { limit = { var:ddm_proscription_preview_reward < 15 } set_variable = { name = ddm_proscription_preview_reward value = 15 } }
    if = { limit = { var:ddm_proscription_preview_reward > 500 } set_variable = { name = ddm_proscription_preview_reward value = 500 } }
}


# ---------------------------------------------------------------------------
# 2.5.5 — PERSONAL PROSCRIPTIONS, OUTCOME POLICY, AND AUTOMATION
# ---------------------------------------------------------------------------
# Actor scope. Keeps compact UI counters ready and defaults old saves to "Take Alive".
ddm_prepare_personal_proscription_settings_effect = {
    if = { limit = { NOT = { has_variable = ddm_personal_proscriptions_year } } set_variable = { name = ddm_personal_proscriptions_year value = 0 } }
    if = { limit = { NOT = { has_variable = ddm_proscription_outcome_policy } } set_variable = { name = ddm_proscription_outcome_policy value = 1 } }
    if = { limit = { NOT = { has_variable = ddm_personal_proscription_auto } } set_variable = { name = ddm_personal_proscription_auto value = 0 } }
    set_variable = { name = ddm_personal_proscription_cap value = 0 }
    if = { limit = { highest_held_title_tier = tier_kingdom } set_variable = { name = ddm_personal_proscription_cap value = 6 } }
    else_if = { limit = { highest_held_title_tier = tier_empire } set_variable = { name = ddm_personal_proscription_cap value = 8 } }
    else_if = { limit = { highest_held_title_tier = tier_hegemony } set_variable = { name = ddm_personal_proscription_cap value = 12 } }
    set_variable = { name = ddm_personal_proscription_remaining value = var:ddm_personal_proscription_cap }
    change_variable = { name = ddm_personal_proscription_remaining subtract = var:ddm_personal_proscriptions_year }
    if = { limit = { var:ddm_personal_proscription_remaining < 0 } set_variable = { name = ddm_personal_proscription_remaining value = 0 } }
}

# Actor scope with scope:ddm_proscription_target. Political writs intentionally bypass this allowance.
ddm_issue_personal_proscription_effect = {
    save_scope_as = ddm_proscriber
    ddm_prepare_personal_proscription_settings_effect = yes
    if = {
        limit = {
            ddm_personal_proscription_quota_available_trigger = yes
            scope:ddm_proscription_target = { ddm_is_valid_personal_proscription_target_trigger = yes }
        }
        change_variable = { name = ddm_personal_proscriptions_year add = 1 }
        scope:ddm_proscription_target = { set_variable = { name = ddm_personal_proscription value = 1 } }
        set_variable = { name = ddm_proscription_personal_issue_mode value = 1 }
        ddm_issue_proscription_effect = yes
        remove_variable = ddm_proscription_personal_issue_mode
        ddm_prepare_personal_proscription_settings_effect = yes
    }
}

# Candidate scope. Add only strongly disliked/rival targets to the actor's temporary automation pool.
ddm_try_add_personal_proscription_auto_candidate_effect = {
    save_temporary_scope_as = ddm_personal_auto_candidate
    if = {
        limit = {
            ddm_is_automatic_personal_proscription_candidate_trigger = yes
            NOT = { is_in_list = ddm_personal_auto_candidates }
            OR = {
                has_relation_rival = scope:ddm_proscriber
                has_relation_nemesis = scope:ddm_proscriber
                scope:ddm_proscriber = { opinion = { target = scope:ddm_personal_auto_candidate value <= -75 } }
            }
        }
        add_to_temporary_list = ddm_personal_auto_candidates
    }
}

# Actor scope. One discretionary writ per monthly pulse, until the rank-based annual allowance is spent.
# Candidate discovery is local/relation-based rather than a whole-world scan for performance.
ddm_personal_proscription_automation_effect = {
    save_scope_as = ddm_proscriber
    ddm_prepare_personal_proscription_settings_effect = yes
    if = {
        limit = {
            var:ddm_personal_proscription_auto = 1
            ddm_personal_proscription_quota_available_trigger = yes
        }

        # Spouses are explicit so an independently landed spouse remains eligible.
        every_spouse = { ddm_try_add_personal_proscription_auto_candidate_effect = yes }
        every_relation = { type = rival ddm_try_add_personal_proscription_auto_candidate_effect = yes }
        every_courtier_or_guest = { ddm_try_add_personal_proscription_auto_candidate_effect = yes }
        every_vassal_or_below = { ddm_try_add_personal_proscription_auto_candidate_effect = yes }

        if = {
            limit = { any_in_list = { list = ddm_personal_auto_candidates count >= 1 } }
            random_in_list = {
                list = ddm_personal_auto_candidates
                save_temporary_scope_as = ddm_proscription_target
            }
            if = {
                limit = { exists = scope:ddm_proscription_target }
                ddm_issue_personal_proscription_effect = yes
                send_interface_toast = {
                    type = event_toast_effect_neutral
                    title = DDM_PERSONAL_PROSCRIPTION_AUTO_TOAST
                    left_icon = scope:ddm_proscriber
                    right_icon = scope:ddm_proscription_target
                }
            }
        }
    }
}

# Actor scope, yearly pulse.
ddm_personal_proscription_yearly_reset_effect = {
    set_variable = { name = ddm_personal_proscriptions_year value = 0 }
    ddm_prepare_personal_proscription_settings_effect = yes
}
