Skip to content

Commit f25893c

Browse files
committed
feat(kcd2alchemy): Added base value to each potion and updated types.
1 parent 4b9bf8b commit f25893c

File tree

6 files changed

+185
-2
lines changed

6 files changed

+185
-2
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
22

33
# other
4-
tmp_local/*
4+
tmp_local/
55

66
# dependencies
77
/node_modules

public/tools/kcd2_alchemy/potions.json

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
"id": "01",
44
"name": "Aesop",
5+
"baseValue": 55,
56
"ingredients": {
67
"liquid": "Spirits",
78
"items": [
@@ -76,6 +77,7 @@
7677
{
7778
"id": "02",
7879
"name": "Aqua Vitalis",
80+
"baseValue": 55,
7981
"ingredients": {
8082
"liquid": "Water",
8183
"items": [
@@ -141,6 +143,7 @@
141143
{
142144
"id": "03",
143145
"name": "Artemisia",
146+
"baseValue": 55,
144147
"ingredients": {
145148
"liquid": "Spirits",
146149
"items": [
@@ -205,6 +208,7 @@
205208
{
206209
"id": "04",
207210
"name": "Bane Poison",
211+
"baseValue": 50,
208212
"ingredients": {
209213
"liquid": "Wine",
210214
"items": [
@@ -278,6 +282,7 @@
278282
{
279283
"id": "05",
280284
"name": "Bowman’s Brew",
285+
"baseValue": 55,
281286
"ingredients": {
282287
"liquid": "Spirits",
283288
"items": [
@@ -350,6 +355,7 @@
350355
{
351356
"id": "06",
352357
"name": "Buck’s Blood Potion",
358+
"baseValue": 55,
353359
"ingredients": {
354360
"liquid": "Oil",
355361
"items": [
@@ -424,6 +430,7 @@
424430
{
425431
"id": "07",
426432
"name": "Chamomile Decoction",
433+
"baseValue": 35,
427434
"ingredients": {
428435
"liquid": "Wine",
429436
"items": [
@@ -492,6 +499,7 @@
492499
{
493500
"id": "08",
494501
"name": "Cockerel",
502+
"baseValue": 55,
495503
"ingredients": {
496504
"liquid": "Spirits",
497505
"items": [
@@ -558,6 +566,7 @@
558566
{
559567
"id": "09",
560568
"name": "Digestive Potion",
569+
"baseValue": 35,
561570
"ingredients": {
562571
"liquid": "Water",
563572
"items": [
@@ -634,6 +643,7 @@
634643
{
635644
"id": "10",
636645
"name": "Dollmaker Potion",
646+
"baseValue": 45,
637647
"ingredients": {
638648
"liquid": "Spirits",
639649
"items": [
@@ -700,6 +710,7 @@
700710
{
701711
"id": "11",
702712
"name": "Embrocation",
713+
"baseValue": 55,
703714
"ingredients": {
704715
"liquid": "Oil",
705716
"items": [
@@ -778,6 +789,7 @@
778789
{
779790
"id": "12",
780791
"name": "Fever Tonic",
792+
"baseValue": 40,
781793
"ingredients": {
782794
"liquid": "Wine",
783795
"items": [
@@ -828,6 +840,7 @@
828840
{
829841
"id": "13",
830842
"name": "Fox",
843+
"baseValue": 55,
831844
"ingredients": {
832845
"liquid": "Oil",
833846
"items": [
@@ -908,6 +921,7 @@
908921
{
909922
"id": "14",
910923
"name": "Hair o’ the Dog",
924+
"baseValue": 55,
911925
"ingredients": {
912926
"liquid": "Water",
913927
"items": [
@@ -980,6 +994,7 @@
980994
{
981995
"id": "15",
982996
"name": "Lead Shot Gunpowder",
997+
"baseValue": 50,
983998
"ingredients": {
984999
"liquid": "Water",
9851000
"items": [
@@ -1045,6 +1060,7 @@
10451060
{
10461061
"id": "16",
10471062
"name": "Lethean Water",
1063+
"baseValue": 100,
10481064
"ingredients": {
10491065
"liquid": "Spirits",
10501066
"items": [
@@ -1106,6 +1122,7 @@
11061122
{
11071123
"id": "17",
11081124
"name": "Lion Perfume",
1125+
"baseValue": 70,
11091126
"ingredients": {
11101127
"liquid": "Spirits",
11111128
"items": [
@@ -1172,6 +1189,7 @@
11721189
{
11731190
"id": "18",
11741191
"name": "Lullaby",
1192+
"baseValue": 45,
11751193
"ingredients": {
11761194
"liquid": "Oil",
11771195
"items": [
@@ -1246,6 +1264,7 @@
12461264
{
12471265
"id": "19",
12481266
"name": "Marigold Decoction",
1267+
"baseValue": 50,
12491268
"ingredients": {
12501269
"liquid": "Water",
12511270
"items": [
@@ -1312,6 +1331,7 @@
13121331
{
13131332
"id": "20",
13141333
"name": "Mintha Perfume",
1334+
"baseValue": 70,
13151335
"ingredients": {
13161336
"liquid": "Wine",
13171337
"items": [
@@ -1384,6 +1404,7 @@
13841404
{
13851405
"id": "21",
13861406
"name": "Moonshine",
1407+
"baseValue": 1.9,
13871408
"ingredients": {
13881409
"liquid": "Spirits",
13891410
"items": [
@@ -1425,6 +1446,7 @@
14251446
{
14261447
"id": "22",
14271448
"name": "Nighthawk",
1449+
"baseValue": 55,
14281450
"ingredients": {
14291451
"liquid": "Water",
14301452
"items": [
@@ -1501,6 +1523,7 @@
15011523
{
15021524
"id": "23",
15031525
"name": "Painkiller Brew",
1526+
"baseValue": 55,
15041527
"ingredients": {
15051528
"liquid": "Spirits",
15061529
"items": [
@@ -1573,6 +1596,7 @@
15731596
{
15741597
"id": "24",
15751598
"name": "Quickfinger",
1599+
"baseValue": 55,
15761600
"ingredients": {
15771601
"liquid": "Water",
15781602
"items": [
@@ -1644,6 +1668,7 @@
16441668
{
16451669
"id": "25",
16461670
"name": "Saviour Schnapps",
1671+
"baseValue": 35,
16471672
"ingredients": {
16481673
"liquid": "Wine",
16491674
"items": [
@@ -1709,6 +1734,7 @@
17091734
{
17101735
"id": "26",
17111736
"name": "Scattershot Powder",
1737+
"baseValue": 30,
17121738
"ingredients": {
17131739
"liquid": "Water",
17141740
"items": [
@@ -1774,6 +1800,7 @@
17741800
{
17751801
"id": "27",
17761802
"name": "Soap",
1803+
"baseValue": 8.5,
17771804
"ingredients": {
17781805
"liquid": "Oil",
17791806
"items": [
@@ -1835,4 +1862,4 @@
18351862
],
18361863
"notes": null
18371864
}
1838-
]
1865+
]

scripts/convert-ingredients-to-ids.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type PotionItemById = { id: string; quantity: number };
2323
type Potion = {
2424
id: string;
2525
name: string;
26+
baseValue?: number; // optional for backward-compat; preserved via spread
2627
ingredients: {
2728
liquid: string; // unchanged in this conversion
2829
items: PotionItemByName[] | PotionItemById[];
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env node
2+
// ESM TypeScript script to enrich potions.json with baseValue from CSV
3+
4+
import { readFile, writeFile } from 'node:fs/promises'
5+
import path from 'node:path'
6+
7+
type Potion = Record<string, unknown> & {
8+
id?: string
9+
name?: string
10+
}
11+
12+
const JSON_PATH = path.resolve('public/tools/kcd2_alchemy/potions.json')
13+
const CSV_PATH = path.resolve('tmp_local/kcd2-potion-value.csv')
14+
15+
function detectNewline(text: string): '\n' | '\r\n' {
16+
return text.includes('\r\n') ? '\r\n' : '\n'
17+
}
18+
19+
// Minimal CSV parser supporting quoted fields and comma separation.
20+
function parseCSV(text: string): string[][] {
21+
const rows: string[][] = []
22+
let row: string[] = []
23+
let field = ''
24+
let inQuotes = false
25+
26+
for (let i = 0; i < text.length; i++) {
27+
const ch = text[i]
28+
const next = text[i + 1]
29+
30+
if (inQuotes) {
31+
if (ch === '"') {
32+
if (next === '"') {
33+
field += '"' // Escaped quote
34+
i++
35+
} else {
36+
inQuotes = false
37+
}
38+
} else {
39+
field += ch
40+
}
41+
} else {
42+
if (ch === '"') {
43+
inQuotes = true
44+
} else if (ch === ',') {
45+
row.push(field)
46+
field = ''
47+
} else if (ch === '\n') {
48+
// End of record (support CRLF and LF)
49+
row.push(field)
50+
rows.push(row)
51+
row = []
52+
field = ''
53+
} else if (ch === '\r') {
54+
// ignore; will be handled by \n
55+
} else {
56+
field += ch
57+
}
58+
}
59+
}
60+
// flush last field/row if any
61+
if (field.length > 0 || row.length > 0) {
62+
row.push(field)
63+
rows.push(row)
64+
}
65+
// Trim whitespace around fields
66+
return rows.map(r => r.map(v => v.trim()))
67+
}
68+
69+
async function main() {
70+
const [jsonRaw, csvRaw] = await Promise.all([
71+
readFile(JSON_PATH, 'utf8'),
72+
readFile(CSV_PATH, 'utf8'),
73+
])
74+
75+
const newline = detectNewline(jsonRaw)
76+
const potions: Potion[] = JSON.parse(jsonRaw)
77+
78+
const rows = parseCSV(csvRaw)
79+
if (rows.length === 0) {
80+
throw new Error('CSV appears empty')
81+
}
82+
83+
const header = rows[0].map(h => h.toLowerCase())
84+
const nameIdx = header.findIndex(h => h === 'potion name' || h === 'name' || h === 'potion')
85+
const valueIdx = header.findIndex(h => h === 'base value' || h === 'base price' || h === 'value' || h === 'price')
86+
if (nameIdx === -1 || valueIdx === -1) {
87+
throw new Error('CSV missing required columns: "Potion Name" and "Base Value"')
88+
}
89+
90+
const valueMap = new Map<string, number>()
91+
for (let i = 1; i < rows.length; i++) {
92+
const r = rows[i]
93+
if (!r || r.length === 0) continue
94+
const name = (r[nameIdx] ?? '').trim()
95+
if (!name) continue
96+
const rawVal = (r[valueIdx] ?? '').replace(/[^0-9.\-]/g, '')
97+
const num = Number.parseFloat(rawVal)
98+
if (!Number.isNaN(num)) {
99+
valueMap.set(name, num)
100+
}
101+
}
102+
103+
let matched = 0
104+
let defaulted = 0
105+
106+
const enriched = potions.map(p => {
107+
const name = (p.name ?? '').trim()
108+
const val = valueMap.get(name)
109+
const baseValue = typeof val === 'number' && Number.isFinite(val) ? val : 0
110+
if (val !== undefined) matched++
111+
else defaulted++
112+
113+
const { id, ingredients, instructions, quantity, effects, notes, ...rest } = p
114+
const out = {
115+
id,
116+
name,
117+
baseValue,
118+
ingredients,
119+
instructions,
120+
quantity,
121+
effects,
122+
notes,
123+
...rest,
124+
}
125+
return out
126+
})
127+
128+
const json = JSON.stringify(enriched, null, 2)
129+
const normalized = newline === '\r\n' ? json.replace(/\n/g, '\r\n') : json
130+
await writeFile(JSON_PATH, normalized, 'utf8')
131+
132+
console.log(`Updated ${enriched.length} potions. Matched: ${matched}, Defaulted: ${defaulted}`)
133+
}
134+
135+
main().catch(err => {
136+
console.error(err)
137+
process.exitCode = 1
138+
})

0 commit comments

Comments
 (0)