clear_log = {
    effect = {
        debug_log = "CRUSADERWARS3"
    }

}

CW_Sieges_MainParticipants = {
    effect = {
        # CWTRACE markers are pure literals — they cannot abort, so the LAST
        # CWTRACE line in debug.log marks the last effect the chain reached.
        # grep "CWTRACE" debug.log to see exactly how far the siege chain got.
        debug_log = "CWTRACE:MainParticipants_enter"
        root = {
            debug_log = "PLAYER_CHARACTER:[GetPlayer.GetID]"
        }

        scope:leftMainParticipant = {
            debug_log = "LEFT_MAIN_PARTICIPANT:[THIS.Char.GetID]"
        }

        scope:rightMainParticipant = {
            debug_log = "RIGHT_MAIN_PARTICIPANT:[THIS.Char.GetID]"
        }

        scope:leftCommander = {
            debug_log = "LEFT_COMMANDER:[THIS.Char.GetID]"
        }

        scope:rightCommander = {
            debug_log = "RIGHT_COMMANDER:[THIS.Char.GetID]"
        }

        if = {
            limit = { scope:playerSide = yes }
              debug_log = "PLAYER_SIDE:Attacker"
        }
        else = {
              debug_log = "PLAYER_SIDE:Defender"
        }
    }
}

CW_Sieges_Defender = {
    # Root = province controller (character scope).
    # GARRISON and FORT_LEVEL removed — MakeScopeValue scopes cannot be
    # created in the GUI layer for the effect system (the Execute call
    # silently fails). These values are now read from the CK3 save file.
    effect = {
        debug_log = "CWTRACE:Defender_enter"
        root = {
            debug_log = "GARRISON_CULTURE:[THIS.Char.GetCulture.GetID]"
            debug_log = "HOLDER_MARTIAL:[THIS.Char.GetSkill( 'martial' )]"
        }
    }
}

CW_Sieges_Defender_Characters = {
    effect = {
        scope:defenderLeader = {
            debug_log = "ID:[THIS.Char.GetID]|||NAME:[THIS.Char.GetNameNoTooltip]|||CULTURE_ID:[THIS.Char.GetCulture.GetID]|||PROWESS:[THIS.Char.GetProwess]|||MARTIAL:[THIS.Char.GetSkill( 'martial' )]|||OWNER_ID:[THIS.Char.GetLiege.GetID]|||TYPE:Commander|||FEUDAL_RANK:[THIS.Char.GetPrimaryTitle.GetTierFrame]|||PRIMARY_TITLE:[THIS.Char.GetPrimaryTitle.GetKey]|||PRIMARY_TITLE_NAME:[THIS.Char.GetPrimaryTitle.GetNameNoTooltip]"
            every_knight = {
                debug_log = "ID:[THIS.Char.GetID]|||NAME:[THIS.Char.GetNameNoTooltip]|||CULTURE_ID:[THIS.Char.GetCulture.GetID]|||PROWESS:[THIS.Char.GetProwess]|||MARTIAL:[THIS.Char.GetSkill( 'martial' )]|||OWNER_ID:[THIS.Char.GetLiege.GetID]|||TYPE:Knight|||FEUDAL_RANK:[THIS.Char.GetPrimaryTitle.GetTierFrame]|||PRIMARY_TITLE:[THIS.Char.GetPrimaryTitle.GetKey]|||PRIMARY_TITLE_NAME:[THIS.Char.GetPrimaryTitle.GetNameNoTooltip]"
            }
        }
    }
}

CW_Sieges_Attacker_Characters = {
    # GENERAL(s) + KNIGHTS: per besieging army, emit its ACTUAL field commander
    # and the knights of that army's owner.
    #
    # The previous version emitted only scope:attackerLeader (the besieging realm
    # leader) — its commander line and its knights. But the bridge resolves an
    # army's general from the save's `commander=` field (usually a DIFFERENT
    # character — a retinue/courtier commander — not the realm leader), so the
    # lookup missed and the attacker fell back to a synthetic "Captain"; and
    # allied/vassal armies' knights were never emitted at all.
    #
    # Fix: iterate the province's armies (scope:siegeProvince, same root proven by
    # CW_Sieges_Armies). For each army emit THIS.Army.GetCommander as the commander
    # record, then army_owner = { every_knight } for that army's knights. army_owner
    # is a SCRIPT scope-link (valid to open { } on); the THIS.Army.Get* data
    # functions are read only inside the debug_log "[...]" string, never as a { }
    # block (which is invalid in an effect and previously aborted the animation chain).
    #
    # every_army_in_location is unfiltered (matches CW_Sieges_Armies): the bridge
    # keeps only the besieger side downstream (SaveFile.Sieges, via the SIDE tag),
    # and assigns each emitted knight to its army by the save's per-army regiment
    # list — so non-besieger and duplicate knight records are inert lookup-pool
    # entries, never double-counted. Covers the war leader + allies + vassals.
    # (scope:attackerLeader is now unused here but still passed by window_siege.gui.)
    effect = {
        scope:siegeProvince = {
            every_army_in_location = {
                debug_log = "ID:[THIS.Army.GetCommander.GetID]|||NAME:[THIS.Army.GetCommander.GetNameNoTooltip]|||CULTURE_ID:[THIS.Army.GetCommander.GetCulture.GetID]|||PROWESS:[THIS.Army.GetCommander.GetProwess]|||MARTIAL:[THIS.Army.GetCommander.GetSkill( 'martial' )]|||OWNER_ID:[THIS.Army.GetCommander.GetLiege.GetID]|||TYPE:Commander|||FEUDAL_RANK:[THIS.Army.GetCommander.GetPrimaryTitle.GetTierFrame]|||PRIMARY_TITLE:[THIS.Army.GetCommander.GetPrimaryTitle.GetKey]|||PRIMARY_TITLE_NAME:[THIS.Army.GetCommander.GetPrimaryTitle.GetNameNoTooltip]"
                army_owner = {
                    every_knight = {
                        debug_log = "ID:[THIS.Char.GetID]|||NAME:[THIS.Char.GetNameNoTooltip]|||CULTURE_ID:[THIS.Char.GetCulture.GetID]|||PROWESS:[THIS.Char.GetProwess]|||MARTIAL:[THIS.Char.GetSkill( 'martial' )]|||OWNER_ID:[THIS.Char.GetLiege.GetID]|||TYPE:Knight|||FEUDAL_RANK:[THIS.Char.GetPrimaryTitle.GetTierFrame]|||PRIMARY_TITLE:[THIS.Char.GetPrimaryTitle.GetKey]|||PRIMARY_TITLE_NAME:[THIS.Char.GetPrimaryTitle.GetNameNoTooltip]"
                    }
                }
            }
        }
    }
}

CW_Sieges_Armies = {
    # Root = siege province (province scope). No limit — matches land
    # battle CW_Armies which also captures all armies in the location.
    #
    # NO CWTRACE marker here (nor in the *_Characters effects): the C# parser
    # (ReadArmiesLines / ReadCharactersLines) iterates EVERY line in this
    # effect's bucket and assumes each is a "|||"-delimited record, so a literal
    # trace line would NRE the bridge. A death inside this effect is instead
    # detectable from the emitted records plus the absence of the following
    # effect's CWTRACE marker (the next one is CWTRACE:Terrain_enter).
    effect = {
        root = {
            every_army_in_location = {
                # SIDE classification: an army at the besieged province is a BESIEGER when its
                # owner is (a) the sieging realm leader himself, (b) an ally who joined that
                # leader's war, or (c) — the original check — at war with the holding's
                # controller. The controller check ALONE is unreliable: the controller is often
                # a non-principal enemy vassal the besiegers are not directly "at war with", and
                # is_at_war_with "does not consider your lieges' wars" (CK3 triggers.log) — so in
                # an ally's war every besieger (a co-besieging player and allied stacks included)
                # was tagged SIDE:Other and dropped by SaveFile.Sieges. The two
                # scope:siegingRealmCharacter checks are ADDITIVE (a union with the old check),
                # so they can only ADD real co-besiegers, never drop one that used to be kept.
                #
                # army_owner is a SCRIPT scope-link (valid to open { } on in a limit). Verified
                # triggers (CK3 triggers.log): is_at_war_with, is_allied_in_war. The new
                # scope:siegingRealmCharacter is passed by window_siege.gui via
                # GetSiegingRealmCharacter (already proven at that file's rightMainParticipant).
                # Both records keep the |||-delimited shape the C# armies parser requires.
                #
                # NEEDS IN-GAME (-debug_mode) VERIFICATION: in an ally's-war siege, confirm the
                # allied co-besiegers now emit SIDE:Attacker (grep debug.log) before relying on it.
                if = {
                    limit = {
                        OR = {
                            army_owner = { this = scope:siegingRealmCharacter }
                            army_owner = { is_allied_in_war = scope:siegingRealmCharacter }
                            army_owner = { is_at_war_with = scope:siegeDefender }
                        }
                    }
                    debug_log = "ID:[THIS.Army.GetArmyId]|||NAME:[THIS.Army.GetNameNoTooltip]|||OWNER_ID:[THIS.Army.GetOwner.GetID]|||OWNER_CULTURE_ID:[THIS.Army.GetOwner.GetCulture.GetID]|||OWNER_PRIMARY_TITLE_NAME:[THIS.Army.GetOwner.GetPrimaryTitle.GetNameNoTooltip]|||COMMANDER_NAME:[THIS.Army.GetCommander.GetNameNoTooltip]|||OWNER_KNIGHT_EFFECTIVENESS:[THIS.Army.GetOwner.GetKnightEffectiveness]|||SIDE:Attacker"
                }
                else = {
                    debug_log = "ID:[THIS.Army.GetArmyId]|||NAME:[THIS.Army.GetNameNoTooltip]|||OWNER_ID:[THIS.Army.GetOwner.GetID]|||OWNER_CULTURE_ID:[THIS.Army.GetOwner.GetCulture.GetID]|||OWNER_PRIMARY_TITLE_NAME:[THIS.Army.GetOwner.GetPrimaryTitle.GetNameNoTooltip]|||COMMANDER_NAME:[THIS.Army.GetCommander.GetNameNoTooltip]|||OWNER_KNIGHT_EFFECTIVENESS:[THIS.Army.GetOwner.GetKnightEffectiveness]|||SIDE:Other"
                }
            }
        }
    }
}

CW_Sieges_Terrain = {
    # Root = siege PROVINCE scope (the window passes
    # SiegeWindow.GetSiege.GetProvince.MakeScope). Read the province directly
    # via THIS.Province.* — the analog of the working land CW_Terrain, which
    # casts its Combat root with THIS.Combat.GetProvince.*
    #
    # The previous version rooted on the siege and used THIS.Siege.GetProvince.*.
    # CK3 has no 'Siege' scope-cast keyword (unlike 'Combat'), so THIS.Siege
    # resolved to nothing and the effect aborted the whole animation chain
    # (pdx_gui_animation_runtime_state error): CW_Sieges_Battle and CW_Keyword
    # never ran, so the bridge never saw its CW_Keyword sentinel and polled
    # forever. The province root is already proven by CW_Sieges_Armies above.
    #
    # THIS.Province is the best-grounded bet but UNVERIFIED in-game (the chain
    # never reached terrain before, so neither THIS.Province nor THIS.Siege has
    # actually run here). The per-line CWTRACE markers below make the next run
    # definitive: the last "CWTRACE:Terrain_*_ok" present in debug.log is the
    # last accessor that succeeded, so the first missing one is the culprit.
    # If only "Terrain_enter" appears (no "_region_ok"), the THIS.Province cast
    # itself failed — pivot to the GUI-layer accessor
    # (SiegeWindow.GetSiege.GetProvince.GetTerrain.*, proven at window_siege.gui
    # line 154) with a matching C# parser change.
    effect = {
        debug_log = "CWTRACE:Terrain_enter"
        debug_log = "REGION:[THIS.Province.Custom('GetProvinceRegion')]"
        debug_log = "CWTRACE:Terrain_region_ok"
        debug_log = "TERRAIN:[THIS.Province.GetTerrain.GetName]"
        debug_log = "CWTRACE:Terrain_terrain_ok"
        debug_log = "WINTER:[THIS.Province.GetWinterSeverityName]"
        debug_log = "CWTRACE:Terrain_winter_ok"
        debug_log = "PROVINCE_ID:[THIS.Province.GetID]"
        debug_log = "CWTRACE:Terrain_provinceid_ok"
        debug_log = "SPECIAL_BUILDING:[THIS.Province.GetHolding.GetSpecialBuildingType.GetKey]"
        debug_log = "CWTRACE:Terrain_special_ok"
        # Holding fort level. Province.GetFortLevel is a documented data function
        # (the siege window shows it at window_siege.gui:790). Emitted here from the
        # province root — the old MakeScopeValue attempt in CW_Sieges_Defender failed,
        # so FORT_LEVEL had been dropped and the bridge always saw 0 (clamped to 1).
        debug_log = "FORT_LEVEL:[THIS.Province.GetFortLevel]"
        debug_log = "CWTRACE:Terrain_fortlevel_ok"
        # is_coastal is a SCRIPT TRIGGER ("Is the province a coastal province",
        # CK3 triggers.log), NOT a data function — there is no Province.IsCoastal
        # in the data-types dump, so the old THIS.Province.IsCoastal silently
        # failed and always emitted NO. The effect root IS the province scope, so
        # the bare trigger evaluates against it directly.
        if = {
            limit = { is_coastal = yes }
            debug_log = "IS_COASTAL:YES"
        }
        else = {
            debug_log = "IS_COASTAL:NO"
        }
        debug_log = "CWTRACE:Terrain_exit"
    }
}

CW_Sieges_Battle = {
    # Root = siege PROVINCE scope (same as CW_Sieges_Terrain). YEAR/MONTH come
    # from the global GetCurrentDate, exactly like land CW_Battle.
    #
    # Battle name = "Siege of <holding>". Province.GetTitle is the besieged
    # barony's LandedTitle (data-types dump: Province.GetTitle -> Title), and
    # GetNameNoTierNoTooltip strips BOTH the tier ("Barony of") AND tooltip markup,
    # yielding a clean "<holding>" (e.g. "Dublin"). We prepend "Siege of " to match
    # the CK3 siege window title.
    #
    # We deliberately do NOT use Province.GetSiege.GetName (the literal UI title):
    # Siege has no GetNameNoTooltip variant, so its GetName can carry CK3 tooltip
    # markup that would corrupt the BATTLE_NAME line. GetNameNoTierNoTooltip is a
    # proven-clean Title accessor (the NoTooltip family is used 10x elsewhere here)
    # and produces the same visible "Siege of Dublin" with no markup risk.
    effect = {
        debug_log = "CWTRACE:Battle_enter"
        debug_log = "BATTLE_NAME:Siege of [THIS.Province.GetTitle.GetNameNoTierNoTooltip]"
        debug_log = "CWTRACE:Battle_name_ok"
        debug_log = "YEAR:[GetCurrentDate.GetYear]"
        debug_log = "MONTH:[GetCurrentDate.GetMonthOfYear]"
        debug_log = "CWTRACE:Battle_exit"
    }
}

CW_Keyword = {
    effect = {
        # If this fires, the whole siege chain completed and the bridge will
        # detect the "CW_Keyword" substring and start processing.
        debug_log = "CWTRACE:Keyword_enter"
        debug_log = "CRUSADERWARS3"
    }
}
