Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

comprehensive solution for fort-destroying brawls #5064

Open
myk002 opened this issue Dec 1, 2024 · 3 comments
Open

comprehensive solution for fort-destroying brawls #5064

myk002 opened this issue Dec 1, 2024 · 3 comments

Comments

@myk002
Copy link
Member

myk002 commented Dec 1, 2024

Institute brawl monitoring and defusal in a dead consistent and fire & forget way, probably enabled by default. The goal is to fix bugs so that tavern brawls are constrained in a way that matches player expectations, not to remove them entirely (although "pacifism" could be a setting that force stops all infighting always). Possibly merge with or roll in existing or newfound anti loyalty cascade features, as discovery of the root causes would necessitate.

@myk002 myk002 added this to 50.15-r2 Dec 1, 2024
@github-project-automation github-project-automation bot moved this to Todo in 50.15-r2 Dec 1, 2024
@chdoc
Copy link
Member

chdoc commented Dec 1, 2024

This one may be tough, mainly due to a lack of data. I have only encountered large scale-brawls in two of my forts. Both forts were fairly mature (about 8 years) and had about 190 citizens. I only let one of those two brawls run to completion: about 12 dead and 36 injured. Still not sure what made it stop when it did.

Nevertheless, let me document my findings. Brawls are activities and can be found in df.global.world.activities.all as entries of type Conflict where both engage the other side at conflict_level Brawl. However, this is also true for single animals, brawling with your citizens. There may be other false positives, but I don't know about them.

I wrote a little script that detects brawls and stops the game if it finds one:

local message =
"A brawl has started! Unless you intervene RIGHT NOW, there is a good chance that a significant \z
portion of your population will die.[B]\z
Run fix-brawl to downgrade the brawl to a nonviolent encounter, or disable check-brawl in the \z
control panel to keep this message from reappearing."

for _,activity in ipairs(df.global.world.activities.all) do
    if activity.type == df.activity_entry_type.Conflict then
        for _,conflict in ipairs(activity.events) do
            for i,side in ipairs(conflict.sides) do
                for j, opponents in ipairs(side.enemies) do
                    if opponents.conflict_level == df.conflict_level.Brawl then
                        -- Ignore conflicts where the first side consists of a single animal
                        if #side.unit_ids == 1 then
                            local unit = df.unit.find(side.unit_ids[0])
                            if unit and dfhack.units.isAnimal(unit) then
                                goto next_conflict
                            end
                        end
                        dfhack.world.SetPauseState(true)
                        dfhack.gui.showPopupAnnouncement(message)
                        return
                    end
                end
            end
            ::next_conflict::
        end
    end
end

I use the control panel to run this script every 50 ticks. The main point of this script is to stop the game, so that I can investigate what leads to brawls.

As it comes to mitigating brawls, I have found that downgrading the engagement level from Brawl to Encounter tends to resolve the issue. However, I have seen it go back up to Brawl. So, if this is the fix, this will need to be monitored.

for _,activity in ipairs(df.global.world.activities.all) do
    if activity.type == df.activity_entry_type.Conflict then
        for _,conflict in ipairs(activity.events) do
            for i,side in ipairs(conflict.sides) do
                for j,opponents in ipairs(side.enemies) do
                    if opponents.conflict_level == df.conflict_level.Brawl then
                        opponents.conflict_level = df.conflict_level.Encounter
                        print(('Activity %d side %d oppenent %d downgraded from Brawl to %s'):format(
                            conflict.activity_id, i, j, df.conflict_level[opponents.conflict_level]))
                    end
                end
            end
        end
    end
end

@Bumber64 wrote a script that lists all conflicts.

@myk002
Copy link
Member Author

myk002 commented Dec 24, 2024

Ozzatron: Spitballing for fun:
Dwarves at greater than zero stress are never stopped from joining a brawl
Dwarves at less than zero stress have asymptotically high chances to be stopped from joining a brawl, with -10K stress at 99% chance

Angry, unhappy, depressed forts have a good chance to "finish themselves off" in epic bloody brawls, but well treated dwarves won't randomly beat each other to a pulp.

I feel that matches DF player expectations?
Adjust for the anger propensity and/or other similar personality facets as you see fit

@Bumber64
Copy link
Contributor

Spitballing for fun: Dwarves at greater than zero stress are never stopped from joining a brawl Dwarves at less than zero stress have asymptotically high chances to be stopped from joining a brawl, with -10K stress at 99% chance

I think it might be all or nothing. If you allow some dwarves to remain in the fight, they're going to pull the others right back in (else they wouldn't have joined in the first place). The probable outcome is a loop of dwarves re-entering conflict, flooding their thoughts with "joining existing conflict" entries, and possibly freezing them in place with job cancel spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Todo
Development

No branches or pull requests

3 participants