ultimatedarktower 2.5.0 → 4.0.0
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/CHANGELOG.md +61 -1
- package/README.md +84 -71
- package/dist/esm/index.mjs +1270 -268
- package/dist/src/UltimateDarkTower.d.ts +48 -6
- package/dist/src/UltimateDarkTower.js +115 -53
- package/dist/src/UltimateDarkTower.js.map +1 -1
- package/dist/src/adapters/NodeBluetoothAdapter.js +9 -5
- package/dist/src/adapters/NodeBluetoothAdapter.js.map +1 -1
- package/dist/src/adapters/WebBluetoothAdapter.js +11 -8
- package/dist/src/adapters/WebBluetoothAdapter.js.map +1 -1
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.js +34 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/sinks/IndexedDBSink.d.ts +26 -0
- package/dist/src/sinks/IndexedDBSink.js +165 -0
- package/dist/src/sinks/IndexedDBSink.js.map +1 -0
- package/dist/src/udtBleConnection.d.ts +28 -5
- package/dist/src/udtBleConnection.js +80 -13
- package/dist/src/udtBleConnection.js.map +1 -1
- package/dist/src/udtBluetoothAdapter.d.ts +6 -6
- package/dist/src/udtBluetoothAdapter.js.map +1 -1
- package/dist/src/udtCommandFactory.d.ts +6 -0
- package/dist/src/udtCommandFactory.js +26 -22
- package/dist/src/udtCommandFactory.js.map +1 -1
- package/dist/src/udtCommandQueue.d.ts +6 -3
- package/dist/src/udtCommandQueue.js +28 -5
- package/dist/src/udtCommandQueue.js.map +1 -1
- package/dist/src/udtConstants.d.ts +3 -8
- package/dist/src/udtConstants.js +2 -0
- package/dist/src/udtConstants.js.map +1 -1
- package/dist/src/udtDiagnostics.d.ts +122 -0
- package/dist/src/udtDiagnostics.js +228 -0
- package/dist/src/udtDiagnostics.js.map +1 -0
- package/dist/src/udtGameBoard.d.ts +38 -0
- package/dist/src/udtGameBoard.js +86 -0
- package/dist/src/udtGameBoard.js.map +1 -0
- package/dist/src/udtLogger.d.ts +16 -0
- package/dist/src/udtLogger.js +41 -2
- package/dist/src/udtLogger.js.map +1 -1
- package/dist/src/udtSeedParser.d.ts +124 -0
- package/dist/src/udtSeedParser.js +369 -0
- package/dist/src/udtSeedParser.js.map +1 -0
- package/dist/src/udtSystemRandom.d.ts +58 -0
- package/dist/src/udtSystemRandom.js +154 -0
- package/dist/src/udtSystemRandom.js.map +1 -0
- package/dist/src/udtTowerCommands.d.ts +4 -2
- package/dist/src/udtTowerCommands.js +24 -43
- package/dist/src/udtTowerCommands.js.map +1 -1
- package/dist/src/udtTowerResponse.d.ts +9 -5
- package/dist/src/udtTowerResponse.js +5 -6
- package/dist/src/udtTowerResponse.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* udtSeedParser.ts — Encode and decode Return to Dark Tower game seeds.
|
|
3
|
+
*
|
|
4
|
+
* Seeds are 12-character base-34 strings formatted as XXXX-XXXX-XXXX.
|
|
5
|
+
* The alphabet uses 34 characters (excludes '0' and 'o' — visually identical in the game font).
|
|
6
|
+
*
|
|
7
|
+
* Structure:
|
|
8
|
+
* chars 0–5: Setup section — bitwise-encoded game configuration
|
|
9
|
+
* chars 6–11: RNG seed section — base-34 little-endian polynomial
|
|
10
|
+
*
|
|
11
|
+
* Ported from the official C# SeedParser implementation.
|
|
12
|
+
*/
|
|
13
|
+
export type Tier1Foe = 'Brigands' | 'Oreks' | 'Shadow Wolves' | 'Spine Fiends';
|
|
14
|
+
export type Tier2Foe = 'Frost Trolls' | 'Clan of Neuri' | 'Lemures' | 'Widowmade Spiders';
|
|
15
|
+
export type Tier3Foe = 'Dragons' | 'Mormos' | 'Striga' | 'Titans';
|
|
16
|
+
export type Adversary = 'Ashstrider' | 'Bane of Omens' | 'Empress of Shades' | 'Gaze Eternal' | 'Gravemaw' | 'Isa the Exile' | 'Lingering Rot' | "Utuk'Ku";
|
|
17
|
+
export type Ally = 'Gleb' | 'Grigor' | 'Hakan' | 'Letha' | 'Miras' | 'Nimet' | 'Tomas' | 'Vasa' | 'Yana' | 'Zaida';
|
|
18
|
+
export type Difficulty = 'Heroic' | 'Gritty';
|
|
19
|
+
export type GameSource = 'Core' | 'Competitive';
|
|
20
|
+
export type ExpansionType = 'Alliances' | 'Monuments';
|
|
21
|
+
export type Confidence = 'confirmed' | 'suspected' | 'unknown';
|
|
22
|
+
export declare const TIER1_FOES: readonly Tier1Foe[];
|
|
23
|
+
export declare const TIER2_FOES: readonly Tier2Foe[];
|
|
24
|
+
export declare const TIER3_FOES: readonly Tier3Foe[];
|
|
25
|
+
export declare const ADVERSARIES: readonly Adversary[];
|
|
26
|
+
export declare const ALLIES: readonly Ally[];
|
|
27
|
+
export declare const DIFFICULTIES: readonly Difficulty[];
|
|
28
|
+
export declare const GAME_SOURCES: readonly GameSource[];
|
|
29
|
+
export interface SeedBank {
|
|
30
|
+
initializationSeed: number;
|
|
31
|
+
questSeed: number;
|
|
32
|
+
seedString: string;
|
|
33
|
+
}
|
|
34
|
+
export interface DecodedSeed {
|
|
35
|
+
/** Normalized seed string (XXXX-XXXX-XXXX, uppercase). */
|
|
36
|
+
seed: string;
|
|
37
|
+
tier1Foe: Tier1Foe;
|
|
38
|
+
tier2Foe: Tier2Foe;
|
|
39
|
+
tier3Foe: Tier3Foe;
|
|
40
|
+
adversary: Adversary;
|
|
41
|
+
ally: Ally;
|
|
42
|
+
difficulty: Difficulty;
|
|
43
|
+
source: GameSource;
|
|
44
|
+
expansions: ExpansionType[];
|
|
45
|
+
/** Player count (1–4). */
|
|
46
|
+
playerCount: number;
|
|
47
|
+
/** RNG seed integer (base-34 polynomial from chars 6–11). */
|
|
48
|
+
rngSeed: number;
|
|
49
|
+
seedBank: SeedBank;
|
|
50
|
+
/** Raw setup character values [0–5] for inspection. */
|
|
51
|
+
setup: number[];
|
|
52
|
+
}
|
|
53
|
+
export interface SeedConfig {
|
|
54
|
+
source: GameSource;
|
|
55
|
+
playerCount: number;
|
|
56
|
+
adversary: Adversary;
|
|
57
|
+
ally: Ally;
|
|
58
|
+
difficulty: Difficulty;
|
|
59
|
+
foes: [Tier1Foe, Tier2Foe, Tier3Foe];
|
|
60
|
+
expansions: ExpansionType[];
|
|
61
|
+
}
|
|
62
|
+
export interface CharDiff {
|
|
63
|
+
charIndex: number;
|
|
64
|
+
value1: number;
|
|
65
|
+
value2: number;
|
|
66
|
+
char1: string;
|
|
67
|
+
char2: string;
|
|
68
|
+
}
|
|
69
|
+
export interface SeedComparison {
|
|
70
|
+
seed1: string;
|
|
71
|
+
seed2: string;
|
|
72
|
+
diffs: CharDiff[];
|
|
73
|
+
setupDiffs: CharDiff[];
|
|
74
|
+
rngDiffs: CharDiff[];
|
|
75
|
+
}
|
|
76
|
+
export interface CharInfo {
|
|
77
|
+
index: number;
|
|
78
|
+
char: string;
|
|
79
|
+
value: number;
|
|
80
|
+
section: 'setup' | 'rng';
|
|
81
|
+
field?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface CharDump {
|
|
84
|
+
seed: string;
|
|
85
|
+
chars: CharInfo[];
|
|
86
|
+
}
|
|
87
|
+
export declare function charToValue(c: string): number;
|
|
88
|
+
export declare function valueToChar(v: number): string;
|
|
89
|
+
/**
|
|
90
|
+
* Normalize and validate a seed string.
|
|
91
|
+
* Accepts with or without dashes, case-insensitive.
|
|
92
|
+
* Returns the normalized XXXX-XXXX-XXXX form (uppercase).
|
|
93
|
+
*/
|
|
94
|
+
export declare function validateSeed(seed: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Decode a seed string into its component fields.
|
|
97
|
+
* Matches the C# ConvertSeedToGame implementation exactly.
|
|
98
|
+
*/
|
|
99
|
+
export declare function decodeSeed(seed: string): DecodedSeed;
|
|
100
|
+
/**
|
|
101
|
+
* Extract just the RNG seed integer from a seed string.
|
|
102
|
+
*/
|
|
103
|
+
export declare function decodeRngSeed(seed: string): number;
|
|
104
|
+
/**
|
|
105
|
+
* Encode a game configuration into a seed string.
|
|
106
|
+
* Matches the C# CreateSeed implementation.
|
|
107
|
+
* The RNG portion (chars 6–11) is randomly generated.
|
|
108
|
+
*/
|
|
109
|
+
export declare function createSeed(config: SeedConfig): {
|
|
110
|
+
seed: string;
|
|
111
|
+
rngValue: number;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Encode a game configuration with a specific RNG value (deterministic).
|
|
115
|
+
*/
|
|
116
|
+
export declare function encodeSeed(config: SeedConfig, rngValue: number): string;
|
|
117
|
+
/**
|
|
118
|
+
* Compare two seeds at the character level.
|
|
119
|
+
*/
|
|
120
|
+
export declare function compareSeedsRaw(seed1: string, seed2: string): SeedComparison;
|
|
121
|
+
/**
|
|
122
|
+
* Dump all characters of a seed with section and field labels.
|
|
123
|
+
*/
|
|
124
|
+
export declare function dumpSeedChars(seed: string): CharDump;
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* udtSeedParser.ts — Encode and decode Return to Dark Tower game seeds.
|
|
4
|
+
*
|
|
5
|
+
* Seeds are 12-character base-34 strings formatted as XXXX-XXXX-XXXX.
|
|
6
|
+
* The alphabet uses 34 characters (excludes '0' and 'o' — visually identical in the game font).
|
|
7
|
+
*
|
|
8
|
+
* Structure:
|
|
9
|
+
* chars 0–5: Setup section — bitwise-encoded game configuration
|
|
10
|
+
* chars 6–11: RNG seed section — base-34 little-endian polynomial
|
|
11
|
+
*
|
|
12
|
+
* Ported from the official C# SeedParser implementation.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.GAME_SOURCES = exports.DIFFICULTIES = exports.ALLIES = exports.ADVERSARIES = exports.TIER3_FOES = exports.TIER2_FOES = exports.TIER1_FOES = void 0;
|
|
16
|
+
exports.charToValue = charToValue;
|
|
17
|
+
exports.valueToChar = valueToChar;
|
|
18
|
+
exports.validateSeed = validateSeed;
|
|
19
|
+
exports.decodeSeed = decodeSeed;
|
|
20
|
+
exports.decodeRngSeed = decodeRngSeed;
|
|
21
|
+
exports.createSeed = createSeed;
|
|
22
|
+
exports.encodeSeed = encodeSeed;
|
|
23
|
+
exports.compareSeedsRaw = compareSeedsRaw;
|
|
24
|
+
exports.dumpSeedChars = dumpSeedChars;
|
|
25
|
+
// ── Base-34 Alphabet ───────────────────────────────────────────────────────
|
|
26
|
+
const ALPHABET = 'a123456789bcdefghijklmnpqrstuvwxyz';
|
|
27
|
+
const BASE = 34;
|
|
28
|
+
const SETUP_LENGTH = 6;
|
|
29
|
+
const RNG_SEED_LENGTH = 6;
|
|
30
|
+
const SEED_LENGTH = SETUP_LENGTH + RNG_SEED_LENGTH; // 12
|
|
31
|
+
// Build lookup maps
|
|
32
|
+
const CHAR_TO_VALUE = new Map();
|
|
33
|
+
const VALUE_TO_CHAR = new Map();
|
|
34
|
+
for (let i = 0; i < ALPHABET.length; i++) {
|
|
35
|
+
CHAR_TO_VALUE.set(ALPHABET[i], i);
|
|
36
|
+
VALUE_TO_CHAR.set(i, ALPHABET[i]);
|
|
37
|
+
}
|
|
38
|
+
// ── Lookup Arrays (index = encoded value) ──────────────────────────────────
|
|
39
|
+
exports.TIER1_FOES = ['Brigands', 'Oreks', 'Shadow Wolves', 'Spine Fiends'];
|
|
40
|
+
exports.TIER2_FOES = ['Frost Trolls', 'Clan of Neuri', 'Lemures', 'Widowmade Spiders'];
|
|
41
|
+
exports.TIER3_FOES = ['Dragons', 'Mormos', 'Striga', 'Titans'];
|
|
42
|
+
exports.ADVERSARIES = [
|
|
43
|
+
'Ashstrider',
|
|
44
|
+
'Bane of Omens',
|
|
45
|
+
'Empress of Shades',
|
|
46
|
+
'Gaze Eternal',
|
|
47
|
+
'Gravemaw',
|
|
48
|
+
'Isa the Exile',
|
|
49
|
+
'Lingering Rot',
|
|
50
|
+
"Utuk'Ku",
|
|
51
|
+
];
|
|
52
|
+
exports.ALLIES = [
|
|
53
|
+
'Gleb', 'Grigor', 'Hakan', 'Letha', 'Miras',
|
|
54
|
+
'Nimet', 'Tomas', 'Vasa', 'Yana', 'Zaida',
|
|
55
|
+
];
|
|
56
|
+
exports.DIFFICULTIES = ['Heroic', 'Gritty'];
|
|
57
|
+
exports.GAME_SOURCES = ['Core', 'Competitive'];
|
|
58
|
+
// ── Character Conversion ───────────────────────────────────────────────────
|
|
59
|
+
function charToValue(c) {
|
|
60
|
+
const v = CHAR_TO_VALUE.get(c.toLowerCase());
|
|
61
|
+
if (v === undefined) {
|
|
62
|
+
throw new Error(`Invalid seed character: '${c}'`);
|
|
63
|
+
}
|
|
64
|
+
return v;
|
|
65
|
+
}
|
|
66
|
+
function valueToChar(v) {
|
|
67
|
+
const c = VALUE_TO_CHAR.get(v);
|
|
68
|
+
if (c === undefined) {
|
|
69
|
+
throw new Error(`Invalid seed value: ${v} (must be 0–${BASE - 1})`);
|
|
70
|
+
}
|
|
71
|
+
return c;
|
|
72
|
+
}
|
|
73
|
+
// ── Seed Validation ────────────────────────────────────────────────────────
|
|
74
|
+
/**
|
|
75
|
+
* Normalize and validate a seed string.
|
|
76
|
+
* Accepts with or without dashes, case-insensitive.
|
|
77
|
+
* Returns the normalized XXXX-XXXX-XXXX form (uppercase).
|
|
78
|
+
*/
|
|
79
|
+
function validateSeed(seed) {
|
|
80
|
+
const stripped = seed.replace(/[-\s]/g, '').toLowerCase();
|
|
81
|
+
if (stripped.length !== SEED_LENGTH) {
|
|
82
|
+
throw new Error(`Invalid seed length: expected ${SEED_LENGTH} characters, got ${stripped.length}`);
|
|
83
|
+
}
|
|
84
|
+
for (const c of stripped) {
|
|
85
|
+
if (!CHAR_TO_VALUE.has(c)) {
|
|
86
|
+
throw new Error(`Invalid seed character: '${c}'`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const upper = stripped.toUpperCase();
|
|
90
|
+
return `${upper.slice(0, 4)}-${upper.slice(4, 8)}-${upper.slice(8, 12)}`;
|
|
91
|
+
}
|
|
92
|
+
// ── Seed Decoding ──────────────────────────────────────────────────────────
|
|
93
|
+
/**
|
|
94
|
+
* Decode a seed string into its component fields.
|
|
95
|
+
* Matches the C# ConvertSeedToGame implementation exactly.
|
|
96
|
+
*/
|
|
97
|
+
function decodeSeed(seed) {
|
|
98
|
+
const normalized = validateSeed(seed);
|
|
99
|
+
const stripped = normalized.replace(/-/g, '').toLowerCase();
|
|
100
|
+
// Decode setup section (chars 0–5)
|
|
101
|
+
const setup = [];
|
|
102
|
+
for (let i = 0; i < SETUP_LENGTH; i++) {
|
|
103
|
+
setup.push(charToValue(stripped[i]));
|
|
104
|
+
}
|
|
105
|
+
// Decode RNG section (chars 6–11) — base-34 little-endian polynomial
|
|
106
|
+
let rngSeed = 0;
|
|
107
|
+
for (let i = 0; i < RNG_SEED_LENGTH; i++) {
|
|
108
|
+
const value = charToValue(stripped[SETUP_LENGTH + i]);
|
|
109
|
+
rngSeed += value * Math.round(Math.pow(BASE, i));
|
|
110
|
+
}
|
|
111
|
+
// setup[0] = foeByteA: bits 0–1 = Tier 1, bits 2–3 = Tier 2, bit 4 = Tier 3 low bit
|
|
112
|
+
const foeByteA = setup[0];
|
|
113
|
+
const tier1 = foeByteA & 0b00011;
|
|
114
|
+
const tier2 = (foeByteA & 0b01100) >> 2;
|
|
115
|
+
// setup[1] = foeByteB: bits 0–3 = Adversary, bit 4 = Tier 3 high bit
|
|
116
|
+
const foeByteB = setup[1];
|
|
117
|
+
const tier3 = ((foeByteA & 0b10000) >> 4) | ((foeByteB & 0b10000) >> 3);
|
|
118
|
+
const adversaryIndex = foeByteB & 0b01111;
|
|
119
|
+
// setup[2] = allyByte
|
|
120
|
+
const allyIndex = setup[2];
|
|
121
|
+
// setup[3] = extraByte: bit 0 = Difficulty, bits 1–2 = Expansions, bit 3 = Source
|
|
122
|
+
const extra = setup[3];
|
|
123
|
+
const difficultyIndex = extra & 0b00001;
|
|
124
|
+
const expansionBits = (extra & 0b00110) >> 1;
|
|
125
|
+
const sourceBits = (extra & 0b01000) >> 2; // intentionally >> 2, not >> 3 (matches C#)
|
|
126
|
+
// setup[4] = versionByte (always 0, reserved)
|
|
127
|
+
// setup[5] = ancillaryByte: bits 0–1 = Player count
|
|
128
|
+
const playerCount = (setup[5] & 0b00011) + 1;
|
|
129
|
+
// Decode expansions
|
|
130
|
+
const expansions = [];
|
|
131
|
+
if (expansionBits & 0b01)
|
|
132
|
+
expansions.push('Monuments');
|
|
133
|
+
if (expansionBits & 0b10)
|
|
134
|
+
expansions.push('Alliances');
|
|
135
|
+
// Decode source — C# switch: 0b00 = Core, 0b10 = Competitive
|
|
136
|
+
let source;
|
|
137
|
+
switch (sourceBits) {
|
|
138
|
+
case 0b10:
|
|
139
|
+
source = 'Competitive';
|
|
140
|
+
break;
|
|
141
|
+
default:
|
|
142
|
+
source = 'Core';
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
const seedBank = {
|
|
146
|
+
initializationSeed: rngSeed,
|
|
147
|
+
questSeed: rngSeed - 1,
|
|
148
|
+
seedString: normalized,
|
|
149
|
+
};
|
|
150
|
+
return {
|
|
151
|
+
seed: normalized,
|
|
152
|
+
tier1Foe: exports.TIER1_FOES[tier1],
|
|
153
|
+
tier2Foe: exports.TIER2_FOES[tier2],
|
|
154
|
+
tier3Foe: exports.TIER3_FOES[tier3],
|
|
155
|
+
adversary: exports.ADVERSARIES[adversaryIndex],
|
|
156
|
+
ally: exports.ALLIES[allyIndex],
|
|
157
|
+
difficulty: exports.DIFFICULTIES[difficultyIndex],
|
|
158
|
+
source,
|
|
159
|
+
expansions,
|
|
160
|
+
playerCount,
|
|
161
|
+
rngSeed,
|
|
162
|
+
seedBank,
|
|
163
|
+
setup,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Extract just the RNG seed integer from a seed string.
|
|
168
|
+
*/
|
|
169
|
+
function decodeRngSeed(seed) {
|
|
170
|
+
const normalized = validateSeed(seed);
|
|
171
|
+
const stripped = normalized.replace(/-/g, '').toLowerCase();
|
|
172
|
+
let rngSeed = 0;
|
|
173
|
+
for (let i = 0; i < RNG_SEED_LENGTH; i++) {
|
|
174
|
+
const value = charToValue(stripped[SETUP_LENGTH + i]);
|
|
175
|
+
rngSeed += value * Math.round(Math.pow(BASE, i));
|
|
176
|
+
}
|
|
177
|
+
return rngSeed;
|
|
178
|
+
}
|
|
179
|
+
// ── Seed Encoding ──────────────────────────────────────────────────────────
|
|
180
|
+
/**
|
|
181
|
+
* Encode a game configuration into a seed string.
|
|
182
|
+
* Matches the C# CreateSeed implementation.
|
|
183
|
+
* The RNG portion (chars 6–11) is randomly generated.
|
|
184
|
+
*/
|
|
185
|
+
function createSeed(config) {
|
|
186
|
+
// Encode foes into foeByteA and foeByteB
|
|
187
|
+
let foeByteA = 0;
|
|
188
|
+
let foeByteB = 0;
|
|
189
|
+
const tier1Index = exports.TIER1_FOES.indexOf(config.foes[0]);
|
|
190
|
+
const tier2Index = exports.TIER2_FOES.indexOf(config.foes[1]);
|
|
191
|
+
const tier3Index = exports.TIER3_FOES.indexOf(config.foes[2]);
|
|
192
|
+
if (tier1Index < 0)
|
|
193
|
+
throw new Error(`Invalid Tier 1 foe: ${config.foes[0]}`);
|
|
194
|
+
if (tier2Index < 0)
|
|
195
|
+
throw new Error(`Invalid Tier 2 foe: ${config.foes[1]}`);
|
|
196
|
+
if (tier3Index < 0)
|
|
197
|
+
throw new Error(`Invalid Tier 3 foe: ${config.foes[2]}`);
|
|
198
|
+
foeByteA = tier1Index & 0b00011;
|
|
199
|
+
foeByteA |= (tier2Index & 0b00011) << 2;
|
|
200
|
+
// Tier 3 split: low bit → foeByteA bit 4, high bit → foeByteB bit 4
|
|
201
|
+
foeByteA |= (tier3Index & 0b01) << 4;
|
|
202
|
+
foeByteB |= ((tier3Index >> 1) & 0b01) << 4;
|
|
203
|
+
// Encode adversary into foeByteB bits 0–3
|
|
204
|
+
const adversaryIndex = exports.ADVERSARIES.indexOf(config.adversary);
|
|
205
|
+
if (adversaryIndex < 0)
|
|
206
|
+
throw new Error(`Invalid adversary: ${config.adversary}`);
|
|
207
|
+
foeByteB |= adversaryIndex & 0b01111;
|
|
208
|
+
// Encode ally
|
|
209
|
+
const allyIndex = exports.ALLIES.indexOf(config.ally);
|
|
210
|
+
if (allyIndex < 0)
|
|
211
|
+
throw new Error(`Invalid ally: ${config.ally}`);
|
|
212
|
+
// Encode extra byte: bit 0 = difficulty, bits 1–2 = expansions, bit 3 = source
|
|
213
|
+
let extraByte = 0;
|
|
214
|
+
if (config.difficulty === 'Gritty')
|
|
215
|
+
extraByte |= 0b00001;
|
|
216
|
+
for (const expansion of config.expansions) {
|
|
217
|
+
switch (expansion) {
|
|
218
|
+
case 'Monuments':
|
|
219
|
+
extraByte |= 0b00010;
|
|
220
|
+
break;
|
|
221
|
+
case 'Alliances':
|
|
222
|
+
extraByte |= 0b00100;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (config.source === 'Competitive')
|
|
227
|
+
extraByte |= 0b01000;
|
|
228
|
+
// Version byte (always 0)
|
|
229
|
+
const versionByte = 0;
|
|
230
|
+
// Player count
|
|
231
|
+
const playerCountByte = Math.max(0, Math.min(3, config.playerCount - 1));
|
|
232
|
+
// Build setup string
|
|
233
|
+
let seedStr = valueToChar(foeByteA) +
|
|
234
|
+
valueToChar(foeByteB) +
|
|
235
|
+
valueToChar(allyIndex) +
|
|
236
|
+
valueToChar(extraByte) +
|
|
237
|
+
valueToChar(versionByte) +
|
|
238
|
+
valueToChar(playerCountByte);
|
|
239
|
+
// Generate random RNG portion
|
|
240
|
+
let rngValue = 0;
|
|
241
|
+
for (let i = 0; i < RNG_SEED_LENGTH; i++) {
|
|
242
|
+
const value = Math.floor(Math.random() * BASE);
|
|
243
|
+
seedStr += valueToChar(value);
|
|
244
|
+
rngValue += value * Math.round(Math.pow(BASE, i));
|
|
245
|
+
}
|
|
246
|
+
const upper = seedStr.toUpperCase();
|
|
247
|
+
const formatted = `${upper.slice(0, 4)}-${upper.slice(4, 8)}-${upper.slice(8, 12)}`;
|
|
248
|
+
return { seed: formatted, rngValue };
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Encode a game configuration with a specific RNG value (deterministic).
|
|
252
|
+
*/
|
|
253
|
+
function encodeSeed(config, rngValue) {
|
|
254
|
+
// Encode setup portion (same as createSeed)
|
|
255
|
+
let foeByteA = 0;
|
|
256
|
+
let foeByteB = 0;
|
|
257
|
+
const tier1Index = exports.TIER1_FOES.indexOf(config.foes[0]);
|
|
258
|
+
const tier2Index = exports.TIER2_FOES.indexOf(config.foes[1]);
|
|
259
|
+
const tier3Index = exports.TIER3_FOES.indexOf(config.foes[2]);
|
|
260
|
+
if (tier1Index < 0)
|
|
261
|
+
throw new Error(`Invalid Tier 1 foe: ${config.foes[0]}`);
|
|
262
|
+
if (tier2Index < 0)
|
|
263
|
+
throw new Error(`Invalid Tier 2 foe: ${config.foes[1]}`);
|
|
264
|
+
if (tier3Index < 0)
|
|
265
|
+
throw new Error(`Invalid Tier 3 foe: ${config.foes[2]}`);
|
|
266
|
+
foeByteA = tier1Index & 0b00011;
|
|
267
|
+
foeByteA |= (tier2Index & 0b00011) << 2;
|
|
268
|
+
foeByteA |= (tier3Index & 0b01) << 4;
|
|
269
|
+
foeByteB |= ((tier3Index >> 1) & 0b01) << 4;
|
|
270
|
+
const adversaryIndex = exports.ADVERSARIES.indexOf(config.adversary);
|
|
271
|
+
if (adversaryIndex < 0)
|
|
272
|
+
throw new Error(`Invalid adversary: ${config.adversary}`);
|
|
273
|
+
foeByteB |= adversaryIndex & 0b01111;
|
|
274
|
+
const allyIndex = exports.ALLIES.indexOf(config.ally);
|
|
275
|
+
if (allyIndex < 0)
|
|
276
|
+
throw new Error(`Invalid ally: ${config.ally}`);
|
|
277
|
+
let extraByte = 0;
|
|
278
|
+
if (config.difficulty === 'Gritty')
|
|
279
|
+
extraByte |= 0b00001;
|
|
280
|
+
for (const expansion of config.expansions) {
|
|
281
|
+
switch (expansion) {
|
|
282
|
+
case 'Monuments':
|
|
283
|
+
extraByte |= 0b00010;
|
|
284
|
+
break;
|
|
285
|
+
case 'Alliances':
|
|
286
|
+
extraByte |= 0b00100;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (config.source === 'Competitive')
|
|
291
|
+
extraByte |= 0b01000;
|
|
292
|
+
const versionByte = 0;
|
|
293
|
+
const playerCountByte = Math.max(0, Math.min(3, config.playerCount - 1));
|
|
294
|
+
let seedStr = valueToChar(foeByteA) +
|
|
295
|
+
valueToChar(foeByteB) +
|
|
296
|
+
valueToChar(allyIndex) +
|
|
297
|
+
valueToChar(extraByte) +
|
|
298
|
+
valueToChar(versionByte) +
|
|
299
|
+
valueToChar(playerCountByte);
|
|
300
|
+
// Encode RNG value as base-34 little-endian
|
|
301
|
+
let remaining = rngValue;
|
|
302
|
+
for (let i = 0; i < RNG_SEED_LENGTH; i++) {
|
|
303
|
+
const digit = remaining % BASE;
|
|
304
|
+
seedStr += valueToChar(digit);
|
|
305
|
+
remaining = Math.floor(remaining / BASE);
|
|
306
|
+
}
|
|
307
|
+
const upper = seedStr.toUpperCase();
|
|
308
|
+
return `${upper.slice(0, 4)}-${upper.slice(4, 8)}-${upper.slice(8, 12)}`;
|
|
309
|
+
}
|
|
310
|
+
// ── Seed Comparison ────────────────────────────────────────────────────────
|
|
311
|
+
/**
|
|
312
|
+
* Compare two seeds at the character level.
|
|
313
|
+
*/
|
|
314
|
+
function compareSeedsRaw(seed1, seed2) {
|
|
315
|
+
const n1 = validateSeed(seed1);
|
|
316
|
+
const n2 = validateSeed(seed2);
|
|
317
|
+
const s1 = n1.replace(/-/g, '').toLowerCase();
|
|
318
|
+
const s2 = n2.replace(/-/g, '').toLowerCase();
|
|
319
|
+
const diffs = [];
|
|
320
|
+
for (let i = 0; i < SEED_LENGTH; i++) {
|
|
321
|
+
const v1 = charToValue(s1[i]);
|
|
322
|
+
const v2 = charToValue(s2[i]);
|
|
323
|
+
if (v1 !== v2) {
|
|
324
|
+
diffs.push({
|
|
325
|
+
charIndex: i,
|
|
326
|
+
value1: v1,
|
|
327
|
+
value2: v2,
|
|
328
|
+
char1: s1[i],
|
|
329
|
+
char2: s2[i],
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
seed1: n1,
|
|
335
|
+
seed2: n2,
|
|
336
|
+
diffs,
|
|
337
|
+
setupDiffs: diffs.filter((d) => d.charIndex < SETUP_LENGTH),
|
|
338
|
+
rngDiffs: diffs.filter((d) => d.charIndex >= SETUP_LENGTH),
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
// ── Seed Dump ──────────────────────────────────────────────────────────────
|
|
342
|
+
const SETUP_FIELD_LABELS = {
|
|
343
|
+
0: 'Tier1/Tier2/Tier3lo',
|
|
344
|
+
1: 'Adversary/Tier3hi',
|
|
345
|
+
2: 'Ally',
|
|
346
|
+
3: 'Difficulty/Expansions/Source',
|
|
347
|
+
4: 'Version',
|
|
348
|
+
5: 'PlayerCount',
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* Dump all characters of a seed with section and field labels.
|
|
352
|
+
*/
|
|
353
|
+
function dumpSeedChars(seed) {
|
|
354
|
+
const normalized = validateSeed(seed);
|
|
355
|
+
const stripped = normalized.replace(/-/g, '').toLowerCase();
|
|
356
|
+
const chars = [];
|
|
357
|
+
for (let i = 0; i < SEED_LENGTH; i++) {
|
|
358
|
+
const isSetup = i < SETUP_LENGTH;
|
|
359
|
+
chars.push({
|
|
360
|
+
index: i,
|
|
361
|
+
char: stripped[i],
|
|
362
|
+
value: charToValue(stripped[i]),
|
|
363
|
+
section: isSetup ? 'setup' : 'rng',
|
|
364
|
+
field: isSetup ? SETUP_FIELD_LABELS[i] : undefined,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return { seed: normalized, chars };
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=udtSeedParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"udtSeedParser.js","sourceRoot":"","sources":["../../src/udtSeedParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* udtSystemRandom.ts — TypeScript replica of C# System.Random.
|
|
3
|
+
*
|
|
4
|
+
* Implements the .NET Framework System.Random PRNG algorithm exactly,
|
|
5
|
+
* producing identical sequences for identical seeds. This is necessary
|
|
6
|
+
* because Return to Dark Tower (Unity/.NET) uses System.Random for all
|
|
7
|
+
* procedural generation.
|
|
8
|
+
*
|
|
9
|
+
* Algorithm: Modified Knuth subtractive generator.
|
|
10
|
+
* Reference: .NET Framework 4.x source (unchanged since .NET 1.0).
|
|
11
|
+
*
|
|
12
|
+
* All arithmetic uses 32-bit signed integer semantics via (value | 0)
|
|
13
|
+
* to match C#'s int overflow behavior.
|
|
14
|
+
*/
|
|
15
|
+
export declare class SystemRandom {
|
|
16
|
+
private seedArray;
|
|
17
|
+
private inext;
|
|
18
|
+
private inextp;
|
|
19
|
+
/**
|
|
20
|
+
* Create a new PRNG instance with the given seed.
|
|
21
|
+
* Matches C# `new System.Random(seed)` exactly.
|
|
22
|
+
*/
|
|
23
|
+
constructor(seed: number);
|
|
24
|
+
/**
|
|
25
|
+
* Replicate .NET's System.Random constructor seeding algorithm.
|
|
26
|
+
*/
|
|
27
|
+
private initialize;
|
|
28
|
+
/**
|
|
29
|
+
* Internal sample — returns value in range [0, Int32.MaxValue).
|
|
30
|
+
* Matches C#'s InternalSample().
|
|
31
|
+
*/
|
|
32
|
+
private internalSample;
|
|
33
|
+
/**
|
|
34
|
+
* Sample — returns a double in range [0.0, 1.0).
|
|
35
|
+
* Matches C#'s Sample().
|
|
36
|
+
*/
|
|
37
|
+
private sample;
|
|
38
|
+
/**
|
|
39
|
+
* Returns a non-negative random integer less than Int32.MaxValue.
|
|
40
|
+
* Matches C# `Random.Next()`.
|
|
41
|
+
*/
|
|
42
|
+
next(): number;
|
|
43
|
+
/**
|
|
44
|
+
* Returns a non-negative random integer less than maxValue.
|
|
45
|
+
* Matches C# `Random.Next(maxValue)`.
|
|
46
|
+
*/
|
|
47
|
+
nextMax(maxValue: number): number;
|
|
48
|
+
/**
|
|
49
|
+
* Returns a random integer in range [minValue, maxValue).
|
|
50
|
+
* Matches C# `Random.Next(minValue, maxValue)`.
|
|
51
|
+
*/
|
|
52
|
+
nextRange(minValue: number, maxValue: number): number;
|
|
53
|
+
/**
|
|
54
|
+
* Returns a random double in range [0.0, 1.0).
|
|
55
|
+
* Matches C# `Random.NextDouble()`.
|
|
56
|
+
*/
|
|
57
|
+
nextDouble(): number;
|
|
58
|
+
}
|