add local production bonuses

This commit is contained in:
2026-03-05 02:20:21 -05:00
parent f1deb33360
commit 4214eeb659
10 changed files with 103 additions and 59 deletions

55
src/data/cityBonuses.ts Normal file
View File

@@ -0,0 +1,55 @@
import type { AlbionCity } from '../types/api'
// Source: Albion Online Wiki — Production Bonuses
// Formula: RRR% = (1 - 1 / (1 + LPB/100)) × 100
//
// Royal cities base LPB: 18% → RRR ≈ 15.3%
// Specialization bonus: +15% → total 33% LPB → RRR ≈ 24.8%
// Black Market (not a crafting location): 0% LPB → RRR = 0%
const BASE_ROYAL_LPB = 18
const SPECIALIZATION_BONUS = 15
const ROYAL_CITIES = new Set<AlbionCity>([
'Fort Sterling', 'Lymhurst', 'Bridgewatch', 'Martlock', 'Thetford', 'Caerleon',
])
// Each regex matches all output item IDs that receive the +15% specialization bonus
// in that city, including artifact / avalon / crystal variants.
const SPECIALIZATION_PATTERNS: Partial<Record<AlbionCity, RegExp>> = {
'Fort Sterling': /_MAIN_HAMMER|_2H_HAMMER|_2H_POLEHAMMER|_2H_DUALHAMMER|_2H_RAM_|_MAIN_SPEAR|_2H_SPEAR|_2H_GLAIVE|_2H_HARPOON|_2H_TRIDENT|_HOLYSTAFF|_DIVINESTAFF|_HEAD_PLATE_|_ARMOR_CLOTH_/,
'Lymhurst': /_MAIN_SWORD|_2H_CLAYMORE|_2H_DUALSWORD|_SCIMITAR|_2H_CLEAVER|_2H_BOW|_LONGBOW|_WARBOW|_ARCANESTAFF|_ENIGMATICSTAFF|_ENIGMATICORB|_ARCANE_RINGPAIR|_HEAD_LEATHER_|_SHOES_LEATHER_/,
'Bridgewatch': /_CROSSBOW|_1HCROSSBOW|_DAGGER|_CLAWPAIR|_RAPIER|_DUALSICKLE|_CURSEDSTAFF|_DEMONICSTAFF|_SKULLORB|_ARMOR_PLATE_|_SHOES_CLOTH_/,
'Martlock': /_MAIN_AXE|_2H_AXE|_2H_HALBERD|_2H_SCYTHE|_2H_DUALAXE|_QUARTERSTAFF|_IRONCLADEDSTAFF|_DOUBLEBLADEDSTAFF|_COMBATSTAFF|_TWINSCYTHE|_ROCKSTAFF|_FROSTSTAFF|_GLACIALSTAFF|_ICEGAUNTLETS|_ICECRYSTAL|_SHOES_PLATE_|_OFF_/,
'Thetford': /_MAIN_MACE|_2H_MACE|_2H_FLAIL|_ROCKMACE|_2H_DUALMACE|_NATURESTAFF|_WILDSTAFF|_FIRESTAFF|_INFERNOSTAFF|_FIRE_RINGPAIR|_ARMOR_LEATHER_|_HEAD_CLOTH_/,
'Caerleon': /_2H_KNUCKLES|_SHAPESHIFTER|_2H_TOOL_/,
}
// Returns the Local Production Bonus (%) for crafting this item in the given city.
export function localProductionBonus(city: AlbionCity, outputItemId: string): number {
if (!ROYAL_CITIES.has(city)) return 0 // Black Market: no bonus
const pattern = SPECIALIZATION_PATTERNS[city]
const baseId = outputItemId.replace(/@\d$/, '') // strip enchantment suffix
const isSpecialized = pattern ? pattern.test(baseId) : false
return BASE_ROYAL_LPB + (isSpecialized ? SPECIALIZATION_BONUS : 0)
}
// Converts a Local Production Bonus (%) to the resulting Resource Return Rate (%).
// Formula: RRR = 1 - 1/(1 + LPB/100)
export function rrrFromBonus(lpb: number): number {
if (lpb === 0) return 0
return (1 - 1 / (1 + lpb / 100)) * 100
}
// Returns the effective RRR (%) for crafting this item in the given city.
export function cityRrr(city: AlbionCity, outputItemId: string): number {
return rrrFromBonus(localProductionBonus(city, outputItemId))
}
// Returns true for ingredients that are NOT subject to RRR (artefacts, ALCHEMY_RARE).
// Only basic resources (bars, planks, leather, cloth) are returned by the city bonus.
export function isRrrExempt(itemId: string): boolean {
return itemId.includes('_ARTEFACT_') || itemId.includes('_ALCHEMY_RARE_')
}