Street Brawl Advisor - Gidntsquia/deadlock-street-brawl-helper GitHub Wiki

Street Brawl Advisor

Code: src/brawl/engine.ts, CLI: scripts/brawl-cli.ts.

Street Brawl is the 4v4 mode with no shop, first to 3 round wins. Before each round the game offers three sets of three cards and you keep one card per set, with one re-roll of a set per round. docs/street-brawl-plan.md has the full plan. The draft shows one set at a time ("choice 1 of 3" … "3 of 3"), so live advice is per set and the re-roll decision is made with the current set only. There are no per-slot caps in Brawl; the 4-active-item cap still applies. Rare cards are one tier higher than the set's normal tier; enhanced cards are the same item with better numbers.

Souls per round are 5600 / 7400 / 9400 / 11600 / 14000 with a 50 second buy phase, and the tier of each set is fixed by round (item_draft_rounds_per_game_round, normal tier to rare tier):

round set 1 set 2 set 3
1 1 to 2 2 to 3 3 to 4
2 2 to 3 3 to 4 3 to 4
3 2 to 3 3 to 4 4 to 5
4 3 to 4 3 to 4 4 to 5
5 4 to 5 4 to 5 4 to 5

Of the 251 items in the catalog, 173 are draftable: not disabled, tier 1 or higher, and not a component placeholder. 17 of those are tier-5 legendaries that only show up in this mode; they carry a placeholder cost of 9999 and the engine keeps them.

Scoring

adviseDraft({ round, owned, enemies, sets }) scores every card and returns the jointly best one-per-set choice and a re-roll suggestion. Everything in the draft is free and the order is fixed by round, so the normal-mode cost-efficiency and buy-time terms are gone. The weights are BRAWL_WEIGHTS in engine.ts:

score(card) = 1.0  * sqrt(pop)     pop     = matches / matches of the most-picked item OF THE SAME TIER
            + 1.0  * winLift       (shrunkWR - heroMeanWR) x 10 x pop, K = max(200, 5 % of the tier's top item)
            + 0.3  * kit           soul-equivalent stat value under the hero's kit multipliers, relative to
                                   the tier median, clipped at 2x (unpriced items = tier median, i.e. neutral)
            + 1.0  * (tier - 1)    a rare (tier-bumped) card is a whole tier above the rest of its set
            + 0.5  * counter       mean over known enemies of (lift vs that enemy - lift vs the field) x 10 x pop
            + 0.5  * synergy       mean pair win-lift (x10) with items already held (pairs with >= 20 matches)
            + 0.1  * [active]      - 0.5 if 4 actives are already held (Brawl keeps the 4-active cap)
            + 0.15 * [upgrades an item you hold]
            + 0.6  * [enhanced]    and kit x 1.25 (the enhanced multiplier is UNVERIFIED; the API has no numbers)
            + 0.15 * carry         [enhanced] only: tiers gained x sqrt(pop) of the best item it builds into
                                   (an 800-soul tier-1 card uses 0.9 and 0.6 instead of 0.6 and 0.15)
            - 1.0  * [you already hold this item]

Enemy-filtered rows below 50 matches are ignored, so the counter term only moves on populated pairings.

  • Popularity and win-lift are normalised within tier because a tier-4 item is picked less often than a tier-1 item mostly because it is offered less often. Cross-tier usage says little about quality. That means the within-tier terms only rank a card among its own tier (spread about 0.2 worst .. 1.4 best, for every tier and hero), so the tier bonus is what compares a rare card with the normal cards next to it. One tier is worth the whole within-tier spread: a median tier-3 card beats the best tier-2 card, and only a tier-3 card that is useless for the hero loses to a top tier-2 pick (everything in the draft is free, so a 3200-soul item is nearly always the better take than a 1600-soul one).
  • Per-hero enhanced factor. The enhanced part (flat bonus, carry and the kit x 1.25 term) is multiplied by a factor between 0 and 1 for that hero and item (enhancedFactor in kit.ts). An item whose enhancement boosts weapon damage (Ricochet, from the user's judgement; the API has no numbers, so UNVERIFIED) keeps only the hero's weapon-damage use: Infernus deals little weapon damage, his bullets carry on-hit effects, so he keeps 0.2 and enhanced Ricochet adds about 0.13 instead of 0.6. Items with no priced stat lines get a floor of 0.5. The tooltip row reads Enhanced +0.12 (weapon stats, little use for Infernus).
  • Legendary weight. When a re-roll refills a rare (legendary) slot, items graded S for the hero within their tier are legendaryS (4) times as likely as the rest. Legendary items come late and some are game-breaking, so rerolling a weak legendary for a chance at a top one is worth more than the average legendary says.
  • No veto: the engine's gain math alone decides a re-roll, even with an S or A card in the set.
  • An enhanced item stays enhanced when it is upgraded (enhanced Grit becomes an enhanced Divine Barrier), so an enhanced card also earns carry: how many tiers its best upgrade sits above it times the square root of that upgrade's within-tier popularity. It counts for little in general (0.15) and a lot in the 800-soul set (0.6), the only set of its kind: round 1 is fought mostly on that item and a tier-1 item has the longest upgrade path ahead. There enhanced Extra Spirit (into Boundless Spirit) gains about 1.7 from carry and the flat bonus is 0.9, so a good enhanced 800 card beats a strong rare tier-2 card; enhanced Mystic Burst (into Tankbuster) gains about 0.3.
  • With several sets given at once (CLI, offline) the pick is the best of the one-per-set combinations, adding pair synergy between the picks themselves; two copies of the same item in one round are penalised. The app passes the single visible set.

Ability order editor

The ability order editor stays collapsed under Ability order for <hero>. Open it and it looks like the game's ability upgrade panel (the same picture the overlay shows after a draft): your four abilities in bar order, labelled 1, 2, 3 and 4 (their place on the bar, not your keybinds), and above each one the 1, 2 and 5 point upgrades, bottom to top.

  • Pick a round with the Round 1 to Round 5 buttons. The title shows Round N: X points, Y left (Street Brawl hands out 6/6/5/5/10 points; unspent points carry over).
  • Click an upgrade you have not bought to buy it in that round; it shows R<n>. Click a bought one to sell it (the upgrades above it on that ability go too).
  • Upgrades are bought bottom up: the 2 point one needs the 1 point one in the same or an earlier round. Spending more than a round has is refused, with a line saying why.
  • Upgrades from earlier rounds are greyed with a check, as on the overlay; this round's are lilac.
  • Once every upgrade has a round, the order replaces the standard one in the panel after each draft and the panel says Your order. Reset to default order drops your order; Start from empty clears every upgrade.

The default (shown until you change it) is the recorded order with the best blended score (shrunk win rate times log of matches), with its matches and win rate. Orders saved by older versions load unchanged.

Re-roll

For each set, the expected best score of three fresh cards is computed exactly from the round's tier pool (every draftable item of the tier, P(max ≤ v) = Π_j F_j(v) over the per-slot score distributions, mixing the normal and rare tier by the rare chance per card). Both the RARE and the ENHANCED flag belong to the slot and survive a re-roll, so an enhanced slot is drawn enhanced and a rare slot is drawn at the rare tier; unseen slots draw each flag at its chance. Items are drawn evenly within a tier, except tier 1: the config's item_drafts[1].bucket splits those draws 40/60 between a normal and a good bucket without listing the good items, so the normal share is spread evenly and the good share by popularity. That is what makes re-rolling a weak rare or enhanced card worthwhile: the slot keeps its bonus and only the item is drawn again.

The rare and enhanced chances are the rates seen on screen, 4 rare and 3 enhanced of the 27 fixture cards (15 % and 11 %; RARE_PER_CARD / ENHANCED_PER_CARD in engine.ts). They are not the config's weight tables, which read as 39 % and 26 % per card and made a fresh set look better than the best card of its tier. Set either constant to null to fall back to the config.

Example: Infernus, round 1, set 1 offers Healbane (rare), enhanced Mystic Burst and Mystic Regeneration. A re-roll keeps a rare tier-2 slot and an enhanced tier-1 slot, and the chance of an enhanced Extra Spirit, Extended Magazine or Rapid Rounds in that slot makes the fresh set worth 2.61 against Healbane's 2.17, more than the 0.31 that holding the re-roll is worth: re-roll.

The set whose best card is expected to be beaten by a fresh draw is the re-roll candidate, taken whenever the gain is positive (REROLL_GAIN_THRESHOLD = 0). The value of saving the round's one re-roll for a later set is shown alongside and vetoes the call when it is at least the gain; it is backward induction over the later sets' best-of-3 distributions. The state-dependent terms (synergy, counter, upgrade) are stripped from the current best first, so it is on the same scale as the pool.

CLI

npm run brawl -- --hero 1 --pool                                   # top items per tier, sanity check
npm run brawl -- --hero 1 --round 2 --owned "Extra Charge,Duration Extender" --enemies "Lash,Seven" \
    --set "Improved Spirit,Enchanter's Emblem,Swift Striker" --set "Superior Duration,Toxic Bullets,Warp Stone+"

Items are given by name (case-insensitive) or id, up to three --set arguments. A trailing + marks an enhanced card. --json prints the picks and scores as JSON instead of the readable breakdown.

⚠️ **GitHub.com Fallback** ⚠️