delta-force-core 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md ADDED
@@ -0,0 +1,1020 @@
1
+ <div align="center">
2
+
3
+ <img src="./assets/logo.svg" alt="delta-force-core logo" width="200" />
4
+
5
+ # delta-force-core
6
+
7
+ **Core data & random-pick toolkit for Delta Force.**
8
+
9
+ [![npm version](https://img.shields.io/npm/v/delta-force-core?color=blue&logo=npm&logoColor=white)](https://www.npmjs.com/package/delta-force-core)
10
+ [![npm downloads](https://img.shields.io/npm/dm/delta-force-core?color=brightgreen)](https://www.npmjs.com/package/delta-force-core)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
12
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178c6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
13
+ [![Node.js](https://img.shields.io/badge/Node.js-%E2%89%A518-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
14
+ [![GitHub Stars](https://img.shields.io/github/stars/Zhoyi011/delta-force-core?style=social)](https://github.com/Zhoyi011/delta-force-core/stargazers)
15
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)
16
+
17
+ [简体中文](./README.md) · [English](./README.en.md)
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ <a id="status"></a>
24
+ > ## 📢 Project Status
25
+ >
26
+ > **v0.2.x** — Stable. Covers **operators / weapons / equipment / ammo**.
27
+ >
28
+ > **Roadmap**: attachment system, ammo variants (T1–T6), image assets, i18n.
29
+
30
+ ---
31
+
32
+ <a id="toc"></a>
33
+ ## 📖 Table of Contents
34
+
35
+ - [✨ Features](#features)
36
+ - [🎯 Use Cases](#use-cases)
37
+ - [🧠 Design Philosophy](#design)
38
+ - [📦 Installation](#install)
39
+ - [🚀 Quick Start](#quick-start)
40
+ - [🧩 Core Concepts](#concepts)
41
+ - [📘 API Reference](#api)
42
+ - [Engine](#api-engine)
43
+ - [Random Picker Functions](#api-random)
44
+ - [Query Functions](#api-query)
45
+ - [List Functions](#api-list)
46
+ - [User Overrides](#api-override)
47
+ - [📚 Data Modules](#data)
48
+ - [Operators](#data-operators)
49
+ - [Weapons](#data-weapons)
50
+ - [Equipment](#data-equipment)
51
+ - [Ammo](#data-ammo)
52
+ - [📄 index.json](#index-json)
53
+ - [🌐 Ecosystem & Integrations](#ecosystem)
54
+ - [🤝 Contributing](#contributing)
55
+ - [🛠 Development](#dev)
56
+ - [📅 Roadmap](#roadmap)
57
+ - [❓ FAQ](#faq)
58
+ - [📜 License](#license)
59
+ - [❤️ Credits](#thanks)
60
+
61
+ ---
62
+
63
+ <a id="features"></a>
64
+ ## ✨ Features
65
+
66
+ <table>
67
+ <tr>
68
+ <td align="center" width="25%">
69
+ <h3>📚 Complete Data</h3>
70
+ <p>Operators / Weapons / Equipment / Ammo<br/>All official fields covered</p>
71
+ </td>
72
+ <td align="center" width="25%">
73
+ <h3>🎲 Random Picker</h3>
74
+ <p>Random operator, weapon, gear<br/>One-click full loadout</p>
75
+ </td>
76
+ <td align="center" width="25%">
77
+ <h3>🔍 Query Tools</h3>
78
+ <p>By id / caliber / alias<br/>Type-safe with IDE hints</p>
79
+ </td>
80
+ <td align="center" width="25%">
81
+ <h3>🎨 User Overrides</h3>
82
+ <p>Quality / alias / tags<br/>Runtime-injected, non-invasive</p>
83
+ </td>
84
+ </tr>
85
+ </table>
86
+
87
+ - ✅ **Native TypeScript** — Full type definitions, IDE IntelliSense
88
+ - ✅ **ES Module** — Modern module system, tree-shaking friendly
89
+ - ✅ **Zero Dependencies** — Core library has no third-party deps
90
+ - ✅ **Forward Compatible** — All optional fields use `?:`, no breaking changes
91
+ - ✅ **Node + Browser** — Node.js ≥ 18 and modern browsers
92
+
93
+ ---
94
+
95
+ <a id="use-cases"></a>
96
+ ## 🎯 Use Cases
97
+
98
+ <table>
99
+ <tr>
100
+ <th width="20%">Scenario</th>
101
+ <th>Example</th>
102
+ </tr>
103
+ <tr>
104
+ <td>🎮 <b>Gacha Apps</b></td>
105
+ <td>One-click random loadout, inject your own quality ratings</td>
106
+ </tr>
107
+ <tr>
108
+ <td>📚 <b>Wiki / Data Sites</b></td>
109
+ <td>Consume structured data directly to render lists</td>
110
+ </tr>
111
+ <tr>
112
+ <td>🤖 <b>Discord / QQ Bots</b></td>
113
+ <td><code>getRandomLoadout()</code> works out of the box</td>
114
+ </tr>
115
+ <tr>
116
+ <td>🧪 <b>Game Data Research</b></td>
117
+ <td>Filter by caliber, tier, mode for statistical analysis</td>
118
+ </tr>
119
+ <tr>
120
+ <td>🌐 <b>Static Sites / CDN</b></td>
121
+ <td>Fetch <code>index.json</code> directly, no build needed</td>
122
+ </tr>
123
+ </table>
124
+
125
+ ---
126
+
127
+ <a id="design"></a>
128
+ ## 🧠 Design Philosophy
129
+
130
+ ### 1. Data and Logic are Separated
131
+
132
+ **Official data is read-only** and maintained by the library; **user preferences are injected at runtime** without polluting official data.
133
+
134
+ ```
135
+ ┌──────────────────────────────────────┐
136
+ │ Official Data (hardcoded, readonly) │
137
+ │ OPERATORS / WEAPONS / │
138
+ │ EQUIPMENT / AMMO │
139
+ └──────────────────┬───────────────────┘
140
+ │
141
+ ▼
142
+ ┌──────────────────────────────────────┐
143
+ │ User Overrides (optional, runtime) │
144
+ │ qualityOverride / aliasOverride / │
145
+ │ tagOverride │
146
+ └──────────────────┬───────────────────┘
147
+ │
148
+ ▼
149
+ ┌──────────────────────────────────────┐
150
+ │ Engine │
151
+ │ · Random picker · Query │
152
+ └──────────────────────────────────────┘
153
+ ```
154
+
155
+ ### 2. Why isn't `quality` part of official data?
156
+
157
+ Weapon quality in Delta Force (green / blue / purple / gold) is **not officially specified** — it's a **subjective rating** by the player community. Therefore:
158
+
159
+ - Official `Weapon` type **does NOT contain `quality`**
160
+ - Users inject their own ratings via `createEngine({ qualityOverride })`
161
+ - The default engine (no overrides) **returns empty when filtering by quality**
162
+
163
+ This is **by design** — we don't force one person's subjective ratings on everyone.
164
+
165
+ ### 3. Forward Compatible
166
+
167
+ All optional fields use `?:`. Adding new fields later (e.g., `caliber`, `image`, `slots`) won't break existing users.
168
+
169
+ ---
170
+
171
+ <a id="install"></a>
172
+ ## 📦 Installation
173
+
174
+ <details open>
175
+ <summary><b>npm / yarn / pnpm / bun</b></summary>
176
+
177
+ ```bash
178
+ # npm
179
+ npm install delta-force-core
180
+
181
+ # yarn
182
+ yarn add delta-force-core
183
+
184
+ # pnpm
185
+ pnpm add delta-force-core
186
+
187
+ # bun
188
+ bun add delta-force-core
189
+ ```
190
+
191
+ </details>
192
+
193
+ <details>
194
+ <summary><b>CDN (browser)</b></summary>
195
+
196
+ ```html
197
+ <!-- ES Module -->
198
+ <script type="module">
199
+ import { getRandomLoadout } from 'https://esm.sh/delta-force-core';
200
+ console.log(getRandomLoadout());
201
+ </script>
202
+
203
+ <!-- Or fetch raw JSON -->
204
+ <script type="module">
205
+ const res = await fetch('https://unpkg.com/delta-force-core/index.json');
206
+ const data = await res.json();
207
+ console.log(data.weapons);
208
+ </script>
209
+ ```
210
+
211
+ </details>
212
+
213
+ **Requirements**: Node.js ≥ 18 or any modern browser supporting ES Modules.
214
+
215
+ ---
216
+
217
+ <a id="quick-start"></a>
218
+ ## 🚀 Quick Start
219
+
220
+ ### Scenario 1 · Just reading data (Wiki users)
221
+
222
+ ```ts
223
+ import { WEAPONS, OPERATORS, EQUIPMENT, AMMO } from 'delta-force-core';
224
+
225
+ console.log(WEAPONS); // all weapons
226
+ console.log(OPERATORS); // all operators
227
+ console.log(EQUIPMENT.armors); // all armors
228
+ console.log(AMMO); // all ammo types
229
+ ```
230
+
231
+ ### Scenario 2 · Random picking (gacha apps)
232
+
233
+ ```ts
234
+ import { getRandomWeapon, getRandomLoadout } from 'delta-force-core';
235
+
236
+ console.log(getRandomWeapon()); // random weapon
237
+ console.log(getRandomLoadout()); // full random loadout
238
+ console.log(getRandomLoadout({ allowNormal: true })); // normal mode only
239
+ ```
240
+
241
+ ### Scenario 3 · Bring your own quality ratings
242
+
243
+ ```ts
244
+ import { createEngine } from 'delta-force-core';
245
+
246
+ const engine = createEngine({
247
+ qualityOverride: {
248
+ m4a1: '金色', // Gold
249
+ akm: '紫色', // Purple
250
+ k416: '金色', // Gold
251
+ },
252
+ });
253
+
254
+ console.log(engine.getRandomWeapon({ quality: '金色' }));
255
+ console.log(engine.getWeaponQuality('m4a1')); // '金色'
256
+ ```
257
+
258
+ ### Scenario 4 · Plain JS / JSON environments
259
+
260
+ ```js
261
+ import data from 'delta-force-core/index.json' with { type: 'json' };
262
+
263
+ console.log(data.weapons);
264
+ console.log(data.equipment.helmets);
265
+ ```
266
+
267
+ ---
268
+
269
+ <a id="concepts"></a>
270
+ ## 🧩 Core Concepts
271
+
272
+ ### Engine
273
+
274
+ `Engine` is the unified entry point for **all random picking and querying capabilities**. It consists of:
275
+
276
+ > **Official Data (fixed)** + **User Overrides (optional)** = **Engine**
277
+
278
+ - **Default Engine**: `defaultEngine` — official data + empty overrides, auto-registered on import
279
+ - **Custom Engine**: `createEngine(options)` — inject your own overrides
280
+
281
+ ### Overrides
282
+
283
+ | Override | Purpose | Impact |
284
+ |---|---|---|
285
+ | `qualityOverride` | Weapon quality rating | Affects `getRandomWeapon({ quality })` |
286
+ | `aliasOverride` | Aliases (e.g., `M4` → `m4a1`) | Affects `findWeaponByAlias()` |
287
+ | `tagOverride` | Personal tags | Metadata only, no effect on picking |
288
+
289
+ ### Normal Mode (`allowNormal`)
290
+
291
+ | Value | Behavior |
292
+ |---|---|
293
+ | `true` | Only items **allowed** in normal mode |
294
+ | `false` | Only items **blocked** in normal mode (e.g., AWM / M82) |
295
+ | `undefined` | No filter, everything in pool |
296
+
297
+ ---
298
+
299
+ <a id="api"></a>
300
+ ## 📘 API Reference
301
+
302
+ > 💡 **Tip**: All functions exported as `defaultEngine`-bound are equivalent to calling `createEngine()` first. Use `createEngine` for custom behavior.
303
+
304
+ <a id="api-engine"></a>
305
+ ### Engine
306
+
307
+ #### `createEngine(options?: EngineOptions): Engine`
308
+
309
+ Creates an engine instance.
310
+
311
+ ```ts
312
+ import { createEngine } from 'delta-force-core';
313
+
314
+ const engine = createEngine({
315
+ qualityOverride: { m4a1: '金色' },
316
+ aliasOverride: { m4a1: ['M4', 'M4卡宾枪'] },
317
+ tagOverride: { m4a1: ['经典', '入门'] },
318
+ });
319
+ ```
320
+
321
+ <details>
322
+ <summary><b>View EngineOptions type</b></summary>
323
+
324
+ ```ts
325
+ interface EngineOptions {
326
+ /** Weapon quality rating: weaponId → '绿色' | '蓝色' | '紫色' | '金色' */
327
+ qualityOverride?: Record<string, WeaponQuality>;
328
+ /** Aliases: entityId → string[] */
329
+ aliasOverride?: Record<string, string[]>;
330
+ /** Personal tags: entityId → string[] */
331
+ tagOverride?: Record<string, string[]>;
332
+ }
333
+ ```
334
+
335
+ </details>
336
+
337
+ ---
338
+
339
+ #### `defaultEngine`
340
+
341
+ Default engine with official data + empty overrides.
342
+
343
+ ```ts
344
+ import { defaultEngine } from 'delta-force-core';
345
+
346
+ defaultEngine.getRandomWeapon();
347
+ ```
348
+
349
+ All picker / query functions are also exported as default-engine-bound:
350
+
351
+ ```ts
352
+ import { getRandomWeapon } from 'delta-force-core';
353
+ // Equivalent to
354
+ import { defaultEngine } from 'delta-force-core';
355
+ defaultEngine.getRandomWeapon();
356
+ ```
357
+
358
+ ---
359
+
360
+ <a id="api-random"></a>
361
+ ### Random Picker Functions
362
+
363
+ All pickers use `Math.random()` with uniform distribution. **Empty pool throws.**
364
+
365
+ #### `getRandomOperator(category?: string): Operator`
366
+
367
+ Pick a random operator.
368
+
369
+ | Param | Type | Description |
370
+ |---|---|---|
371
+ | `category` | `string?` | Role category (`突击兵` / `支援兵` / `工程兵` / `侦察兵`), omit for all |
372
+
373
+ ```ts
374
+ getRandomOperator(); // any operator
375
+ getRandomOperator('突击兵'); // assault only
376
+ ```
377
+
378
+ ---
379
+
380
+ #### `getRandomWeapon(options?: WeaponOptions): Weapon`
381
+
382
+ Pick a random weapon.
383
+
384
+ | Option | Type | Description |
385
+ |---|---|---|
386
+ | `category` | `string?` | Weapon category |
387
+ | `quality` | `WeaponQuality?` | Quality (requires `qualityOverride`) |
388
+ | `allowNormal` | `boolean?` | Normal-mode filter |
389
+
390
+ ```ts
391
+ getRandomWeapon();
392
+ getRandomWeapon({ category: '突击步枪' });
393
+ getRandomWeapon({ allowNormal: true });
394
+ getRandomWeapon({ category: '狙击步枪', allowNormal: false });
395
+ engine.getRandomWeapon({ quality: '金色' });
396
+ ```
397
+
398
+ ---
399
+
400
+ #### `getRandomAmmo(options?: AmmoOptions): Ammo`
401
+
402
+ Pick a random ammo type.
403
+
404
+ | Option | Type | Description |
405
+ |---|---|---|
406
+ | `caliber` | `string?` | Caliber filter, e.g. `5.56x45mm` |
407
+
408
+ ```ts
409
+ getRandomAmmo();
410
+ getRandomAmmo({ caliber: '5.56x45mm' });
411
+ ```
412
+
413
+ ---
414
+
415
+ #### `getRandomArmor` / `getRandomHelmet` / `getRandomBackpack` / `getRandomChestRig`
416
+
417
+ ```ts
418
+ getRandomArmor(options?: TierOptions): EquipmentItem
419
+ getRandomHelmet(options?: TierOptions): EquipmentItem
420
+ getRandomBackpack(options?: TierOptions): EquipmentItem
421
+ getRandomChestRig(options?: TierOptions): EquipmentItem
422
+ ```
423
+
424
+ | Option | Type | Description |
425
+ |---|---|---|
426
+ | `tier` | `number?` | Specific tier (1–6), omit for all |
427
+ | `allowNormal` | `boolean?` | Normal-mode filter (armor/helmet) |
428
+
429
+ ```ts
430
+ getRandomArmor();
431
+ getRandomArmor({ tier: 5 });
432
+ getRandomHelmet({ allowNormal: true });
433
+ getRandomBackpack({ tier: 6 });
434
+ ```
435
+
436
+ ---
437
+
438
+ #### `getRandomLoadout(options?: LoadoutOptions): Loadout`
439
+
440
+ Generate a full random loadout.
441
+
442
+ ```ts
443
+ const loadout = getRandomLoadout({ allowNormal: true });
444
+
445
+ // Returns:
446
+ // {
447
+ // operator: {...},
448
+ // weapon: {...},
449
+ // armor: {...},
450
+ // helmet: {...},
451
+ // backpack: {...},
452
+ // chestRig: {...}
453
+ // }
454
+ ```
455
+
456
+ ---
457
+
458
+ <a id="api-query"></a>
459
+ ### Query Functions
460
+
461
+ | Function | Description |
462
+ |---|---|
463
+ | `findOperatorById(id)` | Find operator by id |
464
+ | `findWeaponById(id)` | Find weapon by id |
465
+ | `findAmmoById(id)` | Find ammo by id |
466
+ | `findArmorById(id)` | Find armor by id |
467
+ | `findHelmetById(id)` | Find helmet by id |
468
+ | `findBackpackById(id)` | Find backpack by id |
469
+ | `findChestRigById(id)` | Find chest rig by id |
470
+ | `findWeaponsByCaliber(caliber)` | Find weapons by caliber |
471
+ | `findAmmoByCaliber(caliber)` | Find ammo by caliber |
472
+ | `findWeaponByAlias(alias)` | Find weapon by alias (needs aliasOverride) |
473
+
474
+ ```ts
475
+ findWeaponById('m4a1');
476
+ // { id: 'm4a1', name: 'M4A1突击步枪', allowNormal: true }
477
+
478
+ findHelmetById('helmet_l4_gt1');
479
+ findWeaponsByCaliber('5.56x45mm');
480
+ ```
481
+
482
+ ---
483
+
484
+ <a id="api-list"></a>
485
+ ### List Functions
486
+
487
+ ```ts
488
+ listOperatorCategories();
489
+ // ['突击兵', '支援兵', '工程兵', '侦察兵']
490
+
491
+ listWeaponCategories();
492
+ // ['突击步枪', '冲锋枪', '精确射手步枪', '狙击步枪', '轻机枪', '霰弹枪', '手枪', '特殊武器']
493
+
494
+ listAllOperators(); // all operators flattened
495
+ listAllWeapons(); // all weapons flattened
496
+ ```
497
+
498
+ ---
499
+
500
+ <a id="api-override"></a>
501
+ ### User Overrides
502
+
503
+ ```ts
504
+ const engine = createEngine({
505
+ qualityOverride: { m4a1: '金色' },
506
+ aliasOverride: { m4a1: ['M4', 'M4卡宾枪'] },
507
+ tagOverride: { m4a1: ['经典', '入门'] },
508
+ });
509
+
510
+ engine.getWeaponQuality('m4a1'); // '金色'
511
+ engine.getAliases('m4a1'); // ['M4', 'M4卡宾枪']
512
+ engine.getTags('m4a1'); // ['经典', '入门']
513
+ ```
514
+
515
+ ---
516
+
517
+ <a id="data"></a>
518
+ ## 📚 Data Modules
519
+
520
+ <a id="data-operators"></a>
521
+ ### Operators
522
+
523
+ **Structure**
524
+
525
+ ```ts
526
+ interface Operator {
527
+ id: string;
528
+ name: string;
529
+ features?: string;
530
+ description?: string;
531
+ image?: string;
532
+ }
533
+
534
+ interface OperatorCategory {
535
+ category: string;
536
+ operators: Operator[];
537
+ }
538
+ ```
539
+
540
+ **Export**
541
+
542
+ ```ts
543
+ import { OPERATORS } from 'delta-force-core';
544
+ ```
545
+
546
+ **Categories**: 突击兵 / 支援兵 / 工程兵 / 侦察兵 (Assault / Support / Engineer / Recon)
547
+
548
+ ---
549
+
550
+ <a id="data-weapons"></a>
551
+ ### Weapons
552
+
553
+ **Structure**
554
+
555
+ ```ts
556
+ interface Weapon {
557
+ id: string;
558
+ name: string;
559
+ caliber?: string;
560
+ baseDamage?: number;
561
+ description?: string;
562
+ image?: string;
563
+ allowNormal?: boolean; // defaults to true
564
+ }
565
+ ```
566
+
567
+ > ⚠️ **Note**: Official `Weapon` has **no `quality`**. Quality comes from user overrides.
568
+
569
+ **Export**
570
+
571
+ ```ts
572
+ import { WEAPONS } from 'delta-force-core';
573
+ ```
574
+
575
+ **Categories & counts**:
576
+
577
+ | Category | Count |
578
+ |---|---|
579
+ | Assault Rifles | 24 |
580
+ | SMGs | 12 |
581
+ | DMRs | 10 |
582
+ | Sniper Rifles | 5 |
583
+ | LMGs | 4 |
584
+ | Shotguns | 5 |
585
+ | Pistols | 7 |
586
+ | Special | 1 |
587
+ | **Total** | **68** |
588
+
589
+ ---
590
+
591
+ <a id="data-equipment"></a>
592
+ ### Equipment
593
+
594
+ **Structure**
595
+
596
+ ```ts
597
+ interface EquipmentItem {
598
+ id: string;
599
+ name: string;
600
+ features?: string;
601
+ comment?: string;
602
+ description?: string;
603
+ image?: string;
604
+ }
605
+
606
+ interface EquipmentTier {
607
+ tier: number;
608
+ allowNormal?: boolean;
609
+ items: EquipmentItem[];
610
+ }
611
+
612
+ interface Equipment {
613
+ armors: EquipmentTier[];
614
+ helmets: EquipmentTier[];
615
+ backpacks: EquipmentTier[];
616
+ chest_rigs: EquipmentTier[];
617
+ }
618
+ ```
619
+
620
+ **Export**
621
+
622
+ ```ts
623
+ import { EQUIPMENT } from 'delta-force-core';
624
+
625
+ EQUIPMENT.armors; // Armor, tiers 1–6
626
+ EQUIPMENT.helmets; // Helmet, tiers 1–6
627
+ EQUIPMENT.backpacks; // Backpack, tiers 1–6
628
+ EQUIPMENT.chest_rigs; // Chest rig, tiers 1–5
629
+ ```
630
+
631
+ ---
632
+
633
+ <a id="data-ammo"></a>
634
+ ### Ammo
635
+
636
+ **Structure**
637
+
638
+ ```ts
639
+ interface Ammo {
640
+ id: string;
641
+ name: string;
642
+ caliber: string;
643
+ description?: string;
644
+ image?: string;
645
+ }
646
+ ```
647
+
648
+ > ⚠️ **Current granularity**: only caliber. Variants (e.g., M855 / M995) come later.
649
+
650
+ **Export**
651
+
652
+ ```ts
653
+ import { AMMO } from 'delta-force-core';
654
+ ```
655
+
656
+ **19 calibers currently**:
657
+
658
+ `.357 Magnum`, `.45 ACP`, `.58 AE`, `12 Gauge`, `12.7x55mm`, `5.45x39mm`, `5.56x45mm`, `5.7x28mm`, `5.8x42mm`, `6.8x51mm`, `7.62x39mm`, `7.62x51mm`, `7.62x54mm`, `9x19mm`, `9x39mm`, `4.6x30mm`, `.300 Blackout`, `箭矢`, `45-70 Govt`
659
+
660
+ ---
661
+
662
+ <a id="index-json"></a>
663
+ ## 📄 index.json
664
+
665
+ A full snapshot of the official data is generated at build time:
666
+
667
+ ```json
668
+ {
669
+ "$schema": "https://raw.githubusercontent.com/delta-force-core/schema/main/v1.json",
670
+ "version": "0.2.0",
671
+ "generatedAt": "2026-10-14T00:34:01.102Z",
672
+ "operators": [...],
673
+ "weapons": [...],
674
+ "equipment": {...},
675
+ "ammo": [...]
676
+ }
677
+ ```
678
+
679
+ **Use cases**:
680
+
681
+ - 🐍 Non-JS environments (e.g., Python scripts)
682
+ - 🌐 Direct CDN fetch (`https://unpkg.com/delta-force-core/index.json`)
683
+ - 📊 Data diffing
684
+
685
+ ```js
686
+ // ESM
687
+ import data from 'delta-force-core/index.json' with { type: 'json' };
688
+
689
+ // CommonJS
690
+ const data = require('delta-force-core/index.json');
691
+
692
+ // HTTP
693
+ const res = await fetch('https://unpkg.com/delta-force-core/index.json');
694
+ const data = await res.json();
695
+ ```
696
+
697
+ ---
698
+
699
+ <a id="ecosystem"></a>
700
+ ## 🌐 Ecosystem & Integrations
701
+
702
+ | Platform | Usage |
703
+ |---|---|
704
+ | **Node.js** | `npm install delta-force-core` |
705
+ | **Browser** | `https://esm.sh/delta-force-core` |
706
+ | **Deno** | `import ... from 'npm:delta-force-core'` |
707
+ | **Bun** | `bun add delta-force-core` |
708
+ | **Python** | Read `index.json` |
709
+ | **Discord.js** | See example below |
710
+
711
+ ### Discord.js Example
712
+
713
+ ```ts
714
+ import { Client, GatewayIntentBits, Events } from 'discord.js';
715
+ import { getRandomLoadout } from 'delta-force-core';
716
+
717
+ const client = new Client({ intents: [GatewayIntentBits.Guilds] });
718
+
719
+ client.on(Events.InteractionCreate, async (interaction) => {
720
+ if (!interaction.isChatInputCommand()) return;
721
+ if (interaction.commandName !== 'random-loadout') return;
722
+
723
+ const l = getRandomLoadout({ allowNormal: true });
724
+ await interaction.reply({
725
+ content: [
726
+ `🧑 **Operator**: ${l.operator.name}`,
727
+ `🔫 **Weapon**: ${l.weapon.name}`,
728
+ `🛡 **Armor**: ${l.armor.name}`,
729
+ `⛑ **Helmet**: ${l.helmet.name}`,
730
+ `🎒 **Backpack**: ${l.backpack.name}`,
731
+ `🎽 **Chest rig**: ${l.chestRig.name}`,
732
+ ].join('\n'),
733
+ });
734
+ });
735
+ ```
736
+
737
+ ---
738
+
739
+ <a id="contributing"></a>
740
+ ## 🤝 Contributing
741
+
742
+ ### Updating Data
743
+
744
+ **Just edit the corresponding file**:
745
+
746
+ ```
747
+ src/data/
748
+ ├─ operators.ts ← operators
749
+ ├─ weapons.ts ← weapons
750
+ ├─ equipment.ts ← equipment (armor / helmet / backpack / chest rig)
751
+ └─ ammo.ts ← ammo
752
+ ```
753
+
754
+ ### Example: add a weapon
755
+
756
+ ```ts
757
+ // src/data/weapons.ts
758
+ {
759
+ category: '突击步枪',
760
+ weapons: [
761
+ // ...existing
762
+ { id: 'new_rifle', name: 'New Rifle', allowNormal: true }, // ← add one line
763
+ ],
764
+ },
765
+ ```
766
+
767
+ ### Workflow
768
+
769
+ ```bash
770
+ # 1. edit data
771
+ vim src/data/weapons.ts
772
+
773
+ # 2. build + regenerate index.json
774
+ npm run build
775
+
776
+ # 3. commit
777
+ git add .
778
+ git commit -m "data: add XXX weapon"
779
+ git push origin main
780
+ ```
781
+
782
+ ### Rules
783
+
784
+ | Rule | Detail |
785
+ |---|---|
786
+ | `id` must be globally unique | Used for lookup; duplicates cause silent bugs |
787
+ | Do NOT add `quality` | Official data has no quality; users override it |
788
+ | `allowNormal` defaults to `true` | Only set `false` when needed |
789
+ | All optional fields use `?:` | Forward compatibility |
790
+ | New categories | Just append `{ category, weapons: [...] }` |
791
+
792
+ ### Commit Convention
793
+
794
+ Following [Conventional Commits](https://www.conventionalcommits.org/):
795
+
796
+ | Prefix | Purpose |
797
+ |---|---|
798
+ | `feat:` | New feature |
799
+ | `fix:` | Bug fix |
800
+ | `data:` | Data update |
801
+ | `refactor:` | Refactor |
802
+ | `docs:` | Docs |
803
+ | `chore:` | Chore |
804
+ | `test:` | Tests |
805
+
806
+ Examples:
807
+
808
+ ```
809
+ feat: add getRandomAmmo() with caliber filter
810
+ data: add 5 assault rifles
811
+ fix: correct AKM allowNormal flag
812
+ docs: update README installation
813
+ ```
814
+
815
+ ---
816
+
817
+ <a id="dev"></a>
818
+ ## 🛠 Development
819
+
820
+ ### Requirements
821
+
822
+ - Node.js ≥ 18
823
+ - TypeScript ≥ 5.4
824
+
825
+ ### Setup
826
+
827
+ ```bash
828
+ git clone https://github.com/Zhoyi011/delta-force-core.git
829
+ cd delta-force-core
830
+ npm install
831
+ ```
832
+
833
+ ### Project Structure
834
+
835
+ ```text
836
+ delta-force-core/
837
+ ├─ .gitignore
838
+ ├─ package.json
839
+ ├─ tsconfig.json
840
+ ├─ README.md
841
+ ├─ README.en.md
842
+ ├─ LICENSE
843
+ ├─ CONTRIBUTING.md
844
+ ├─ index.json ← build artifact
845
+ ├─ scripts/
846
+ │ └─ emit-json.mjs ← generate index.json
847
+ ├─ src/
848
+ │ ├─ types.ts ← all type definitions
849
+ │ ├─ engine.ts ← engine (createEngine + all methods)
850
+ │ ├─ index.ts ← main entry
851
+ │ └─ data/
852
+ │ ├─ index.ts ← data barrel export
853
+ │ ├─ operators.ts
854
+ │ ├─ weapons.ts
855
+ │ ├─ equipment.ts
856
+ │ └─ ammo.ts
857
+ └─ .github/
858
+ └─ workflows/ ← CI / auto-publish
859
+ ```
860
+
861
+ ### Commands
862
+
863
+ ```bash
864
+ npm run build # compile + generate index.json
865
+ npm run dev # watch mode
866
+ npm run emit-json # only generate index.json
867
+ ```
868
+
869
+ ### Publishing to npm
870
+
871
+ ```bash
872
+ npm version patch # or minor / major
873
+ npm publish # auto-runs prepublishOnly → npm run build
874
+ ```
875
+
876
+ ---
877
+
878
+ <a id="roadmap"></a>
879
+ ## 📅 Roadmap
880
+
881
+ <table>
882
+ <tr>
883
+ <th>Status</th>
884
+ <th>Feature</th>
885
+ <th>Version</th>
886
+ </tr>
887
+ <tr><td>✅ Done</td><td>Operators / Weapons / Equipment / Ammo</td><td>v0.1</td></tr>
888
+ <tr><td>✅ Done</td><td>Engine + user overrides (quality / alias / tag)</td><td>v0.2</td></tr>
889
+ <tr><td>🔄 In progress</td><td>Full README + docs</td><td>v0.2.x</td></tr>
890
+ <tr><td>📋 Planned</td><td>Attachment system (slots / compatibility)</td><td>v0.3</td></tr>
891
+ <tr><td>📋 Planned</td><td>Ammo variants (T1–T6, damage / pen)</td><td>v0.3</td></tr>
892
+ <tr><td>📋 Planned</td><td>Image assets</td><td>v0.4</td></tr>
893
+ <tr><td>💭 Considering</td><td>i18n (English / 日本語)</td><td>v1.0</td></tr>
894
+ </table>
895
+
896
+ ---
897
+
898
+ <a id="faq"></a>
899
+ ## ❓ FAQ
900
+
901
+ <details>
902
+ <summary><b>Q1: Why is there no <code>quality</code> on official weapons?</b></summary>
903
+
904
+ Quality is a **subjective rating**, not official data. We put it in the user override layer (`qualityOverride`) so everyone can use their own standards.
905
+
906
+ ```ts
907
+ const engine = createEngine({
908
+ qualityOverride: { m4a1: '金色' },
909
+ });
910
+ ```
911
+
912
+ </details>
913
+
914
+ <details>
915
+ <summary><b>Q2: Default engine vs custom engine?</b></summary>
916
+
917
+ **Default engine** `defaultEngine` = official data + empty overrides.
918
+
919
+ **Custom engine** = official data + your overrides. All methods behave identically, except custom engine applies your quality/alias/tag.
920
+
921
+ </details>
922
+
923
+ <details>
924
+ <summary><b>Q3: Can I use only the data without random picking?</b></summary>
925
+
926
+ Yes. Import data constants directly:
927
+
928
+ ```ts
929
+ import { WEAPONS, OPERATORS, EQUIPMENT, AMMO } from 'delta-force-core';
930
+ ```
931
+
932
+ Or use `index.json` (for non-JS environments).
933
+
934
+ </details>
935
+
936
+ <details>
937
+ <summary><b>Q4: How often is data updated?</b></summary>
938
+
939
+ Following game updates. We sync new equipment / weapons / operators as soon as possible.
940
+
941
+ You can also submit a PR to edit data files directly.
942
+
943
+ </details>
944
+
945
+ <details>
946
+ <summary><b>Q5: TypeScript support?</b></summary>
947
+
948
+ Written in native TypeScript, full type definitions. IDEs provide IntelliSense and type checking.
949
+
950
+ </details>
951
+
952
+ <details>
953
+ <summary><b>Q6: CommonJS support?</b></summary>
954
+
955
+ Main entry is **ES Module**. For CommonJS projects:
956
+
957
+ ```js
958
+ // Option 1: dynamic import
959
+ const { getRandomLoadout } = await import('delta-force-core');
960
+
961
+ // Option 2: use JSON directly
962
+ const data = require('delta-force-core/index.json');
963
+ ```
964
+
965
+ </details>
966
+
967
+ <details>
968
+ <summary><b>Q7: How to deploy my own <code>index.json</code>?</b></summary>
969
+
970
+ ```bash
971
+ # fork the repo → edit data → build
972
+ npm run build
973
+ # output in dist/, index.json at root
974
+ ```
975
+
976
+ Or use the one from the npm package:
977
+
978
+ ```
979
+ https://unpkg.com/delta-force-core/index.json
980
+ ```
981
+
982
+ </details>
983
+
984
+ <details>
985
+ <summary><b>Q8: How to contribute data fixes?</b></summary>
986
+
987
+ 1. Fork the repo
988
+ 2. Edit `src/data/*.ts`
989
+ 3. `npm run build` to verify compilation
990
+ 4. Submit a PR with source (screenshot / official announcement)
991
+
992
+ See the [Contributing](#contributing) section.
993
+
994
+ </details>
995
+
996
+ ---
997
+
998
+ <a id="license"></a>
999
+ ## 📜 License
1000
+
1001
+ Released under the [MIT License](./LICENSE).
1002
+
1003
+ ---
1004
+
1005
+ <a id="thanks"></a>
1006
+ ## ❤️ Credits
1007
+
1008
+ - Thanks to all community members who contributed Delta Force data
1009
+ - Thanks to [Shields.io](https://shields.io/) for badges
1010
+ - Thanks to [unpkg](https://unpkg.com/) / [esm.sh](https://esm.sh/) for CDN
1011
+
1012
+ ---
1013
+
1014
+ <div align="center">
1015
+
1016
+ **If this project helps you, please give it a ⭐ Star!**
1017
+
1018
+ [⬆ Back to Top](#delta-force-core)
1019
+
1020
+ </div>