@randsum/salvageunion
Version:
A flexible, type-safe dice roller for the Salvage Union system
80 lines (71 loc) • 2.63 kB
text/typescript
import type { SURefObjectTable } from 'salvageunion-reference'
import { SalvageUnionReference, resultForTable } from 'salvageunion-reference'
import type {
SalvageUnionRollRecord,
SalvageUnionTableListing,
SalvageUnionTableName
} from '../types'
import type { GameRollResult, RollRecord } from '@randsum/roller'
import { roll } from '@randsum/roller'
/**
* NOTE: This package does not use the createGameRoll factory pattern because:
*
* 1. External library dependency: The implementation requires integration with
* the `salvageunion-reference` library for table lookups, which doesn't fit
* the standard factory pattern focused on dice mechanics.
*
* 2. Table lookup pattern: The roll result is used as a lookup key for table
* resolution rather than being the primary game mechanic itself. The actual
* game logic is in the table lookup, not the dice roll.
*
* 3. Custom result structure: The result includes table-specific metadata
* (table data, table name, key, label, description) that extends beyond
* standard game roll interpretation.
*
* 4. Table processing logic: The implementation includes complex table result
* processing (label/value extraction, success checking) that is specific to
* the Salvage Union table system.
*
* This is more accurately a table lookup utility than a dice rolling mechanic,
* and would benefit from a specialized table-based factory if such a pattern
* emerges in other packages.
*/
function tableDataForTable(tableName: SalvageUnionTableName): SURefObjectTable {
const rollTable = SalvageUnionReference.RollTables.find(t => t.name === tableName)
if (!rollTable?.table) {
throw new Error(`Invalid Salvage Union table name: "${tableName}"`)
}
return rollTable.table
}
export function rollTable(
tableName: SalvageUnionTableName = 'Core Mechanic'
): GameRollResult<
SalvageUnionRollRecord,
undefined,
RollRecord<SalvageUnionTableListing | string>
> {
const { total, rolls } = roll({
sides: 20
})
const tableData = tableDataForTable(tableName)
const tableResult = resultForTable(tableData, total)
if (!tableResult.success) {
throw new Error(`Failed to get result from table: "${tableName}"`)
}
const { result, key } = tableResult
const resultTyped = result as { label?: string; value?: string }
const label = resultTyped.label ?? resultTyped.value ?? ''
const description = resultTyped.label ? (resultTyped.value ?? '') : ''
return {
rolls,
total,
result: {
key,
label,
description,
table: tableData,
tableName,
roll: total
}
}
}