Absy Labs ABSY LABSKingshot Theorycraft

The build log · why you can trust it, and where you shouldn't

How this simulator was built

This is the full creation process, in order: how a mobile game's hidden combat engine becomes a calculator you can audit line by line. One question drives all of it: why should you believe the number it hands you?

Confirmed Probable Speculative every mechanic on this site, and in the engine, carries one of these.

The one rule that shaped everything

Every mechanic on this site is written down, with a mark for exactly how it was verified: read straight from code, reproduced by testing, or a reasoned guess that hasn't been proven yet. A guess never gets to masquerade as a fact. Everything below is that rule applied, step by step.

Scope, up front

The simulator models KingShot Expedition PvP: solo marches, rallies, garrisons and single matchups. It does not model Conquest or the Bear Hunt damage curve, and it is a development and matchup tool, not an official readout. Where a value is uncertain, the tool ships a toggle and says so, rather than picking a number for you.

The reliability grades

Every mechanical claim carries one of three grades. They're not decoration: they tell you precisely how much weight a number can bear, and they are the same three grades the engine itself uses internally.

Confirmed

Read or seen directly

Visible in the game UI, stated in patch notes, or readable in the open-source State-of-Survival engine code. The army factor, the per-troop math, the SkillMod formula.

Probable

Reproduced by testing

Not visible in the UI, but reproduced consistently across community testing and multiple matchups. Several op-code assignments and joiner edge cases.

Speculative

Inferred, not yet proven

A logical inference from comparable mechanics, not yet experimentally validated. The fatigue factor and Yang's exact pity rate. These ship as toggles, not assumptions.

A grade is a promise that can be upgraded. When a Speculative value earns a screenshot or a reproduced test, it moves up. When a Confirmed value turns out to disagree with the game, it gets fixed in public. That movement, in both directions, is the methodology working.

Step 1: reverse-engineer it, don't guess it

KingShot's combat is not documented by its developer. So the first job was not to invent a formula that "feels right," it was to find the real one. Two things made that possible.

First, lineage. KingShot's Expedition engine descends from State of Survival, an older KingsGroup title built on the same combat model, and SoS has an open-source engine implementation. That code is the single most reliable reference there is: it is the actual algorithm, not a guide's paraphrase of it. The army factor, the per-troop attack and defense computation, the round structure and the fatigue curve all come from reading it directly.

Second, cross-checking. Where the shared engine stops and KingShot-specific content begins (heroes, skills, op codes, gear curves, widget values), the rule was to triangulate: in-game screenshots, patch notes, community testing, and the catalog data sites, with disagreements recorded rather than averaged away. The whole approach is written up in a reference document, Escaping the Cargo Cult, which the codebase treats as authoritative and implements.

Probable  A handful of op-code assignments are reproduced by community testing but not visible anywhere in the UI. Those are tagged Probable in the engine, exposed as user-overridable, and never silently promoted to Confirmed.

Step 2: anchor it to a number that can't move

A reverse-engineered engine needs a fixed point: one fully worked example, computed by hand from the reference, that the code must reproduce exactly. SoS publishes one. Round zero, attacker Infantry against defender Infantry, with every input pinned:

-- army sizes (totals fixed at fight start)
army_factor   = sqrt(40,233 x 78,872) = 56,335
att_per_troop = 491 x (1+293.66%) x 10 x (1+251.82%) / 100 = 680
def_per_troop = 2557.9
SkillMod      = 1.26     type_bonus = 1.00     fatigue = 1.0000

-- result
damage = 56,335 x 680 / 2557.9 x 1.00 x 1.26 x 1.0 / 100 = 188.7
deaths = ceil(188.7) = 189
Confirmed  189 deaths. The engine carries this round-zero example as a permanent regression test. Any change to the damage formula, the per-troop computation, the SkillMod resolver or the bonus aggregation has to keep producing exactly 189, or the change is rejected before it ships. See the full worked example →

This is the load-bearing validation of the entire simulator. Everything else is built so that this number never moves. When you read later that the engine "passes its tests," this is the test that matters most: hundreds of others pin the rest of the behavior, but this one pins the heart.

Step 3: build the engine in layers

The single hardest thing to get right is not the damage formula. It's knowing which bonus belongs in which layer. KingShot's battle report shows you one combined "Stat Bonuses" number, but that number is the end of a stack of separate systems that the engine has to keep apart, because they combine differently. Get the layering wrong and a calculator can match the visible number while computing the fight incorrectly.

Per-troop stats: the base

Every troop carries four small base stats (Attack, Lethality, Defense, Health), and every percentage bonus you own layers on top. They combine into two numbers per troop:

att_per_troop = base_atk x (1 + atk%/100) x base_let x (1 + let%/100) / 100
def_per_troop = base_def x (1 + def%/100) x base_hp  x (1 + hp%/100) / 100

Attack pairs with Lethality, Defense pairs with Health, and the two factors multiply. That is why a pure-attack build and a pure-lethality build are not interchangeable even at the same total percentage: the product is what counts. Confirmed against the SoS per-troop calculation; base Lethality and base Defense are both 10 across every tier.

The split: what's visible, what's hidden

The bonuses that feed those two numbers are not one bucket. The engine separates them into three systems that the in-game report quietly merges:

  1. The visible bonus vector. Research, governor gear, charms, pets, masters, alliance tech, VIP, widget stat bonuses (sixteen fields, four stats by four troop categories), plus fixed-value minister appointments (Field Commander / Marshal / King). These are plain additive percentages.
  2. SkillMod. Hero, joiner and widget skill effects. These do not add into the vector; they form a separate multiplier (next section).
  3. Section D. City, pet and turret buffs. A third layer again, with its own combination rule (below).

Two hero passives (Helga's Power of the Deer and Amadeus's Born Leader) are unusual in one way only: they are account-wide, applied to all your troops whenever you own the hero, even when that hero is not deployed. But they combine additively, inside the visible vector, like research and gear. An earlier version of the docs called them a multiplicative, leader-only passive; the in-game skill text ("active even when absent") plus a source-by-source breakdown of a real account corrected that, and this time both the docs and the engine were fixed. The old test that seemed to confirm the multiplicative reading could not tell the difference, because the hero was owned in both arms, so an account-wide bonus looked invisible. That is the grade discipline applied to the project's own write-ups.

SkillMod: four families, eleven ops

Every skill effect outside the visible stats resolves into one multiplier:

SkillMod = (DamageUp x OppDefenseDown) / (OppDamageDown x DefenseUp)

Effects are sorted into four families across eleven op codes. The combination rule is easy to get backward:

  • Same op code: additive. Sum the percentages, then apply once.
  • Different ops, same family: multiplicative. Each composes on the last.

This is why four Chenkos lose to two Chenkos plus two Amanes: stacking one op code just adds, while diversifying across the family multiplies cleanly. Treating all stacking as additive, or all as multiplicative, ranks rally compositions wrong, even with an otherwise correct damage formula. In a rally, up to four joiners feed their skills into exactly this multiplier. The full op table and family rules →

Probable  A few skills' op assignments are community-reproduced, not UI-visible. Each is overridable in the tool, so if you disagree with a routing you can change it and re-run, instead of trusting ours.

Section D: buffs that cancel before they multiply

City, pet and turret buffs are their own layer, and they have a subtle rule: within one layer, your buff and the enemy's matching debuff are additive and net out first; only then do layers multiply across each other. (Minister appointments were once modeled in this layer too; a controlled battle-report capture showed they add additively, like research and gear, so they were moved to the visible vector above. Same grade discipline as the Helga case.)

section_d_factor(stat) =
  product over layers of [ 1 + (your_buff% - enemy_debuff%) / 100 ]

So your +20% city attack against an enemy's -20% city-attack-down nets to zero in the city layer (factor 1.00), not 1.20 x 0.80 = 0.96. The naive multiply quietly loses you 4%. Getting this exactly right meant carrying both fighters' raw buffs all the way into the damage step so the engine can see both sides and cancel them per layer. How the layers combine →

The skills that break the rules

A handful of mechanics genuinely don't fit the additive op-code system. Forcing them in would produce a confident, wrong number, so they get bespoke handling instead:

MechanicHeroHow it's modeled
Per-attack target debuffPetra, AlcarOne roll per attacking squad; the debuff lasts the round, then resets.
Accumulating "pity" procYangChance climbs with each miss. Base 40% reaches a steady state near 58%.
DodgeMargotScales incoming damage by (1 - dodge), not folded into a defense op.
Conditional TerrorSophiaOne skill applies Terror, another only fires against a Terror'd target.
Timed RNG buffsJaeger, Zoe, MarlinSteady-state occupancy of a duration window, not just chance times duration.

Each of these is pinned by its own tests, because each is exactly the kind of detail a simpler tool flattens into a wrong average.

Step 4: two ways to run a fight

The same fight can be run two ways, and the simulator does both on purpose.

Expected mode is deterministic: every chance-based skill collapses to its average contribution, so the same inputs always give the same answer. The classification of which skills scale their chance versus their value (and the steady-state occupancy of timed buffs) is what keeps these averages honest rather than naive. Expected mode is what makes screening millions of compositions fast.

Monte Carlo mode then re-rolls the survivors with real randomness (default 200 trials, reported with a 95% confidence interval) so the final ranking reflects variance, not just the mean. A high-average but swingy rally and a slightly lower-average but steady one are told apart here, not in the average. The two modes are built to agree in expectation; the gap between them is the variance, and that gap is information, so the tool keeps both rather than collapsing to one.

Step 5: from one fight to a million

"Who wins this fight" is one simulation. "Which of my compositions wins" is potentially millions. The Best Counter and Best Defense tools answer the second, which needs a different machine.

  1. Screen. A NumPy-vectorized version of the exact same engine runs every candidate in Expected mode at once. It is verified, on a thousand random configs, to match the sequential engine within floating-point precision, so speed never costs correctness.
  2. Refine. The top survivors get re-run under Monte Carlo, so the final order reflects variance, and a high-mean but unreliable composition can't win on the average alone.

The candidate space is capped (around 1.5 million compositions) and runs behind a one-at-a-time queue with a graceful cancel that returns the best results found so far. The vectorized path is never the place a new mechanic is added first: the sequential engine is made correct, then the batch path is brought up to parity, then the parity test guards it.

Step 6: read an account from a screenshot

Entering an entire roster by hand is the fastest way to abandon a tool, so the simulator reads it from screenshots. Two problems had to be solved honestly.

Reading the pixels. Troop counts, hero stars, gear quality, levels and the special-bonus popup are each parsed with anchored, count-based optical recognition rather than one hopeful full-image pass. Small white text drawn over busy art (the troop level, the hero level overlay) is invisible to a naive scan, so the pipeline anchors on the reliable element first and takes a targeted crop for the fragile one. When a screenshot has been recompressed below the point where the glyphs survive, the tool says "re-upload the original" instead of inventing a plausible value. That last part is the methodology again: a confident wrong number is worse than an honest blank.

Peeling. The harder half is math, not vision. The battle report shows the combined "Stat Bonuses" total after leader percentages, Helga and Amadeus passives, widget stats and Section D buffs are all mixed in. To feed the engine, that total has to be run backward, peeling each layer off in reverse order to recover the plain additive vector underneath. Peeling and the engine are held to a round-trip test: build a fighter the manual way, peel it, and the peeled version must produce bit-identical battle output. If they ever drift, that test fails loudly.

Step 7: turn a roster into a plan

The combat tools answer "who wins?" Benchmark answers the earlier question every F2P player actually has: "what do I build next?" It ranks each leader slot you own against a tier-matched training dummy across solo attack, rally, defense and garrison, on generation-specific meta formations (the dummy plays the real counter-split, not a flat 33/33/33), then turns that ranking into a shard-budget roadmap: develop, hold, or set aside, ordered by the power you actually gain per shard.

Rule of thumb  Benchmark deliberately ignores the specific opponent, your joiners, your gear and your buffs. It is a development-priority tool, not a matchup oracle. For "will this rally beat that garrison," use Best Counter. How Benchmark works →

How a change actually ships

None of the above stays correct by accident. The development process is built so that a well-meaning refactor cannot quietly break the math.

  • Tests are the spec. Around 970 of them. New behavior gets a test first; changed behavior updates a test explicitly, with a reference to the decision that justified it. Tests are never deleted to make something compile.
  • Decisions are logged, not remembered. Every non-trivial choice is written down with its rationale, its math impact and its test surface, so a future session inherits the reasoning instead of re-deriving it or contradicting it.
  • The anchor gates everything. The round-zero 189, plus the per-piece gear, buff-layering, sign-convention and stacking tests, all have to stay green, in the same environment, before a change is allowed to land.

A concrete example of the discipline catching itself: forge mastery on gear was modeled for a long time as flat percentage points added to the base bonus. The in-game "Gear Details" panel disagreed. A mythic level-50 helm with a +32.5% base shows +35.75% at mastery 1, which is 32.5 multiplied by 1.10, not the +42.5% the additive model predicted. The two formulas happen to agree only when the base is exactly 100% (a fully red, level-200 piece), which is why the full-red lock-in tests had never noticed. The fix was one line, a new test that fails the old model, and a logged decision. That is the whole method in miniature: the game is the authority, the disagreement gets reproduced, the correction ships with a test that would have caught it.

What it deliberately doesn't do

An honest tool is as clear about its edges as its center. The simulator does not model Conquest (real-time hero duels) or the Bear Hunt damage curve: those are different engines, and faking them would be the exact dishonesty this project exists to avoid. It does not simulate garrison leader replacement; you enter the active leader. The joiner model assumes the realistic maxed-skill case rather than enumerating every partial level, which is a stated simplification, not a hidden one. And it will never hand you a confident number for something nobody has confirmed. It gives you a toggle, and it tells you it's a toggle.

The sources, in full

Nothing here is invented. The mechanics trace to a small set of references, and where they disagree, the disagreement is recorded rather than hidden:

  • The open-source State-of-Survival engine: the exact algorithm of the original KingsGroup engine, and the source of the Confirmed combat math.
  • Escaping the Cargo Cult: the project's own reference write-up, which the codebase implements directly.
  • Daryl's KingShot guides and working simulator: joiner mechanics, the op-code taxonomy, cross-validation against in-game reports.
  • kingshotdata.com: hero stat database, skill descriptions, per-star tables.
  • The full SoS combat formula write-up (army factor and fatigue).
  • Frakinator's KingShot calculator and community testing from MTwyDev and others.

A few honest questions

Is this an official KingShot tool?

No. Absy Labs is community-built and not affiliated with or endorsed by KingsGroup. It's free, open and ad-free, and it stays that way.

If the engine is reverse-engineered, how do you know it's right?

You don't take it on faith. The Confirmed math is read from open-source code, the round-zero example pins the arithmetic to a known answer, and roughly 970 tests pin the rest. Where certainty runs out, the grade says so.

I found a value that looks wrong. Now what?

That's the most useful thing you can bring. The grades exist to be upgraded and the corrections happen in public. Come argue it with a screenshot.

Found a value that's wrong?

Bring evidence. The reliability grades exist to be upgraded, and that's how the model gets better.