Value and price
How a crafted weapon's tier score (tierf), tier, value and trade price follow from its per-usage stats and pieces, at full precision for game v1.4.8. The stats themselves are in Weapon stats; the example recipes in Weapon templates.
Tier and value are TaleWorlds.Core.DefaultItemValueModel; trade price is DefaultTradeItemPriceFactorModel with DefaultPartyTradeModel.GetTradePenaltyFactor and TownMarketData.GetPrice (see Game code). No official module (SandBox, StoryMode, NavalDLC, BirthAndDeath) replaces any of these models. BirthAndDeath's only DLL, TaleWorlds.CampaignSystem.ViewModelCollection.BirthAndDeath.dll, holds its submodule and campaign options and no game model. The snippet tables and worked examples are computed by the Python model in src/bannerlord/crafting/.
Game version
The formulas were recovered from v1.4.6 IL of TaleWorlds.Core.dll and TaleWorlds.CampaignSystem.dll and compared method by method against v1.4.8 IL (cmp.txt), 172 methods: 92 match in full, 20 match in part, none differ. CraftingStats.CalculateWeaponTier is one of the partial matches: the v1.4.6 listing covers 11 of its 63 v1.4.8 instructions, and those 11 match.
38 methods were compared by header only: the v1.4.6 record holds no IL for them, so only their metadata tokens were compared, and those are unchanged. They include all of DefaultItemValueModel, among them the tier and value methods CalculateTierMeleeWeapon, CalculateTierCraftedWeapon, CalculateValue, GetFactor and CalculateWeaponTier, plus BladeData.Deserialize and CraftingCampaignBehavior.OpenNewPart. 22 methods are not in the v1.4.8 dumps: 21 DefaultItems getters, which only resolve material items, and DataExporter.GetPrice, which is in the exporter mod's DLL.
The evidence for the header-only tier and value methods is the export comparison in Validation: available usages, tierf ±0.001, tier and exact value match 5050/5050 unscaled and 5382/5382 scaled, price matches all 627,602 unscaled and 1,204,812 scaled export rows, and the largest value error is 0. The exports predate the current build (Weapon stats).
Tier
Per usage, from its integer stats:
t = 0.06 × v × (1 + weapon_length/100) − 3.5, clamped to [−1.5, 7.5]
v = max(thrust_damage × F(thrust type) × (thrust_speed/100)^1.5, 1.1 × swing_damage × F(swing type) × (speed_rating/100)^1.5) × class multiplier
thrust_damage,swing_damage,thrust_speed,speed_rating,weapon_length: the usage's stored stats.F: damage type factor. Cut 1, Pierce 1.15, Blunt 1.45, otherwise 1.1.1: swing counts this much more than thrust.- Class multiplier:
NotUsableWithOneHand0.8;ThrowingKnife,ThrowingAxe1.2;Javelin0.6; otherwise 1.
The item's melee tier combines the usages:
- Keep the best and second-best
tbefore clamping; both start at the lowest float, −3.4028234663852886 × 10³⁸. Atabove the second best becomes the best if it is at least the best (the old best moves to second), else the second best. - Clamp the best to [−1.5, 7.5]. With one usage, melee = best.
- With 2 or more usages, clamp the second best the same way, and melee = best × (1 + (second + 1.5) ÷ (best + 2.5))^0.2.
The pieces give the crafted tier:
crafted = 0.4 × (1.25 × average tier) + 0.6 × (1.3 × Σ(count × rank) ÷ (Σ count + 0.6) − 1.3)
average tier: the meantierof the design's pieces.count,rank: each iron material of each piece; rankIron1= 1 ..Iron6= 6.IronOre,Wood,Charcoalare skipped.- With no iron materials: crafted = average tier (0.1 for a design with no pieces).
tierf = 0.6 × melee + 0.4 × crafted
tier = clamp(round(tierf), 0, 6), rounded half to even.
Worked example, the one-handed sword recipe (wood_blade_1, vlandian_noble_guard_3, khuzait_grip_7, battania_pommel_6; see Weapon templates):
- Melee tier from its one usage: 0.8207.
- Piece tiers 1, 5, 2, 1: average 2.25, so
1.25 × 2.25 = 2.8125. - Iron: the guard needs
Iron5 ×1, the handleIron2 ×1; blade and pommel needWood.1.3 × (5 + 2) ÷ (2 + 0.6) − 1.3 = 2.2. crafted = 0.4 × 2.8125 + 0.6 × 2.2 = 2.445.tierf = 0.6 × 0.8207 + 0.4 × 2.445 = 1.4704; tier 1.
Value
value = trunc(100 × 2.75^clamp(tierf, −1, 7.5) × (1 + 0.2 × (appearance − 1)) + 100 × max(0, appearance − 1))
appearance: from the pommel, or the blade when there is no pommel.
Worked example, the one-handed sword: battania_pommel_6 has appearance 0.5, so 100 × 2.75^1.4704 × (1 + 0.2 × (0.5 − 1)) + 0 = 398.3, truncated to 398.
The 12 example recipes:
Tier score, value and price of the example weapons. Price is the sell price with Trade 86 and no market data.
| Weapon | Tier score from the stats | Tier score from the pieces | Tier score | Rounded tier | Appearance | Value | Price |
|---|---|---|---|---|---|---|---|
| One-handed sword | 0.8207 | 2.445 | 1.4704 | 1 | 0.5 | 398 | 130 |
| Two-handed sword | 5.0111 | 3.4752 | 4.3967 | 4 | 0.5 | 7,688 | 2,012 |
| Dagger | -1.4511 | 2.3352 | 0.0634 | 0 | 0.5 | 95 | 32 |
| Throwing knife | 1.7095 | 1.9057 | 1.7880 | 2 | 0.5 | 549 | 175 |
| One-handed axe | 3.0244 | 2.6594 | 2.8784 | 3 | 0.5 | 1,655 | 484 |
| Two-handed axe | 5.8434 | 2.9867 | 4.7007 | 5 | 0.5 | 10,457 | 2,680 |
| Throwing axe | 2.9743 | 3.7635 | 3.2900 | 3 | 0.5 | 2,509 | 711 |
| Two-handed polearm | 1.2508 | 2.8093 | 1.8742 | 2 | 0.5 | 599 | 190 |
| Pike | 2.5033 | 2.87 | 2.6500 | 3 | 0.5 | 1,313 | 391 |
| Javelin | 3.0154 | 2.045 | 2.6272 | 3 | 0.5 | 1,283 | 383 |
| Mace | 4.926 | 4.5079 | 4.7587 | 5 | 0.5 | 11,089 | 2,831 |
| Two-handed mace | 5.6847 | 3.5997 | 4.8507 | 5 | 0.5 | 12,170 | 3,088 |
| Rule | Number |
|---|---|
| Swing damage counts this much more than thrust damage | 1.1 |
| Pierce damage counts | 1.15 |
| Blunt damage counts | 1.45 |
| Two-handed-only usages count | 0.8 |
| Throwing knives and throwing axes count | 1.2 |
| Javelins count | 0.6 |
| Usage score to tier score: times | 0.06 |
| Usage score to tier score: minus | 3.5 |
| Share of the tier score from the stats | 0.6 |
| Share of the tier score from the pieces | 0.4 |
| Value at tier score 0 | 100 |
| Value multiplier per tier score point | 2.75 |
| Value multiplier per appearance point away from 1 | 0.2 |
| Value added per appearance point above 1 | 100 |
Scatter of the 12 example weapons, tier score on the x axis from 0 to 5, value on a log y axis from 100 to 30,000. Dagger 0.0634, 95; one-handed sword 1.4704, 398; throwing knife 1.7880, 549; two-handed polearm 1.8742, 599; javelin 2.6272, 1,283; pike 2.6500, 1,313; one-handed axe 2.8784, 1,655; throwing axe 3.2900, 2,509; two-handed sword 4.3967, 7,688; two-handed axe 4.7007, 10,457; mace 4.7587, 11,089; two-handed mace 4.8507, 12,170.
Trade price
TaleWorlds.CampaignSystem.GameComponents.DefaultTradeItemPriceFactorModel.GetPrice. The formulas below cover crafted weapons; other item types add category and horse branches to the same model.
item_value = value, or round(value × price_factor) with an item_modifiers.xml modifier.
sell price = max(1, floor(item_value × base ÷ (1 + penalty)))
buy price = max(1, ceil(item_value × base × (1 + penalty))); buying from a caravan with Silver Tongue: ceil(price × 0.85).
base = clamp((demand ÷ (0.1 × supply + 0.04 × in_store_value + 2))^0.6, 0.8, 1.3); when selling, in_store_value += value first.
price_factor: the item modifier's price factor.in_store_value,supply,demand: the town'sItemDatafor the item's category, so save state.
Town.GetItemPrice and Village.GetItemPrice read that market data and pass no merchant, so Merchant.Absent applies and the at-war, village, caravan and same-faction terms below stay off; a village uses its trade-bound town's market. Those terms apply only to TownMarketData.GetPrice callers that pass a merchant party. Trade goods clamp base to 0.1..10 instead, and animals use exponent 0.3.
penalty is built in this order:
p = 0.06.p += 0.5when at war with the merchant's faction (only with a client party).- When selling, unless the client is a caravan:
p += (1.5 + 0.25 × max(0, tierf − 1)) × A;A = 0.5with Artisan Smith on a player-crafted weapon, else 1. - Merchant in a village:
p += 1when selling,0.1when buying. - Merchant is a caravan:
p += 1when selling,0.1when buying. - With no client party:
penalty = p × 0.2, and the steps below are skipped. - Caravan client:
p ×= 0.5. p ×= 1 ÷ (1 + 0.002 × Trade),Tradebeing the Trade skill of the client's party leader.- penalty = p × (1 + Σ factors).
| Factor | Value | Condition |
|---|---|---|
| Appraiser | −0.15 |
selling |
| Arms Dealer | −0.2 |
selling |
| Aserai culture feat | −0.1 |
party has the feat |
| Village Network | −0.1 |
merchant's village is in the party's faction |
| Rumor Network | −0.05 |
merchant's town is in the party's faction |
| Distributed Goods | −0.15 |
buying from a village |
| Smuggler Connections | −0.5 |
main party, hero has the perk, crime rating with the merchant's faction above 0 |
Exporter quote
price in craftable_items*.csv is a sell quote with no market: the exporter passes isSelling=true, no merchant, and in_store_value = supply = demand = 0. Demand 0 makes base clamp to 0.8 for every weapon, so with no perks:
price = floor(value × 0.8 ÷ (1 + (1.56 + 0.25 × max(0, tierf − 1)) ÷ (1 + 0.002 × Trade)))
The exports fit only Trade = 86, so they reflect the export save's party leader. That skill is inferred from the prices.
Worked example, the one-handed sword (value 398, tierf 1.4704) at Trade 86: penalty = (0.06 + 1.5 + 0.25 × 0.4704) ÷ (1 + 0.002 × 86) = 1.4314, so price = floor(398 × 0.8 ÷ (1 + 1.4314)) = 130.
Sell price of the one-handed sword example (value 398, tier score 1.4704) with no market data, so the market factor is 0.8.
| Trade skill | Price penalty | Price |
|---|---|---|
| 0 | 1.6776 | 118 |
| 50 | 1.5251 | 126 |
| 86 | 1.4314 | 130 |
| 100 | 1.398 | 132 |
| 150 | 1.2905 | 139 |
| 200 | 1.1983 | 144 |
| 300 | 1.0485 | 155 |
| Price input | Number |
|---|---|
| Base penalty | 0.06 |
| Extra penalty when selling | 1.5 |
| Extra selling penalty per tier score point above 1 | 0.25 |
| Penalty is divided by 1 plus this per Trade skill point | 0.002 |
| Market factor, lowest | 0.8 |
| Market factor, highest | 1.3 |
Quirks
- Selling adds a penalty that grows with
tierf, on top of the0.8base floor, so sell price falls further belowvaluefor higher tiers.
Validation
Compared with the game-generated exports described in Weapon stats, on the same sample:
| Item check | Unscaled | Scaled |
|---|---|---|
| Available usages | 5050/5050 | 5382/5382 |
tierf ±0.001 |
5050/5050 | 5382/5382 |
tier |
5050/5050 | 5382/5382 |
value exact |
5050/5050 | 5382/5382 |
price, every export row, value and tierf from the export |
627,602/627,602 | 1,204,812/1,204,812 |
price, sampled items, computed from XML |
5,050/5,050 | 5,382/5,382 |
Largest value error: 0 unscaled, 0 scaled.
price rows matching each Trade skill, of 1,832,414: 84: 200,231, 85: 469,823, 86: 1,832,414, 87: 459,223, 88: 238,939.
Trade price with a market, merchant or perks is not validated: exports only exercise a no-market sell quote with no perks.
Game code
| Formula | Method |
|---|---|
| Tier, value | TaleWorlds.Core.DefaultItemValueModel |
| Trade price | GameComponents.DefaultTradeItemPriceFactorModel, DefaultPartyTradeModel.GetTradePenaltyFactor, TownMarketData.GetPrice |
| Perk values | CharacterDevelopment.DefaultPerks.InitializeAll |
IL decoded from game v1.4.8:
- DefaultItemValueModel.il:
CalculateTierMeleeWeapon,CalculateTierCraftedWeapon,GetFactor,CalculateValue,GetEquipmentValueFromTier,CalculateTier,CalculateWeaponTier. - CraftingStats.il:
CalculateWeaponTier. - DefaultTradeItemPriceFactorModel.il:
GetTradePenalty,GetPriceFactor,GetBasePriceFactor,GetPrice. - DefaultPartyTradeModel.il:
GetTradePenaltyFactor. - TownMarketData.il:
GetPrice. - DefaultPerks.il:
InitializeAll, the perk values.
Changelog
- v1.4.8 (2026-11-11): Rewritten as deep dive; facts unchanged.
- v1.4.8 (2026-11-10): Moved into the site; content unchanged.