返回提交历史
Modified
src/controllers/api/nemesisController.ts
+62
-18
Modified
src/helpers/nemesisHelpers.ts
+37
-18
Modified
src/services/missionInventoryUpdateService.ts
+3
-5
XFEstudio/XFESpaceNinjaServer
feat: classic lich guess history (#2129)
Closes #2123 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2129 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
135b1e54
代码差异
3 个文件
+102
-41
@@ -1,12 +1,17 @@
1
1
import { version_compare } from "@/src/helpers/inventoryHelpers";
2
2
import {
3
3
consumeModCharge,
4
decodeNemesisGuess,
4
5
encodeNemesisGuess,
5
6
getInfNodes,
6
7
getKnifeUpgrade,
7
8
getNemesisManifest,
8
9
getNemesisPasscode,
9
10
getNemesisPasscodeModTypes,
11
GUESS_CORRECT,
12
GUESS_INCORRECT,
13
GUESS_NEUTRAL,
14
GUESS_NONE,
10
15
GUESS_WILDCARD,
11
16
IKnifeResponse
12
17
} from "@/src/helpers/nemesisHelpers";
@@ -98,18 +103,29 @@ export const nemesisController: RequestHandler = async (req, res) => {
98
103
if (inventory.Nemesis!.Faction == "FC_INFESTATION") {
99
104
const guess: number[] = [body.guess & 0xf, (body.guess >> 4) & 0xf, (body.guess >> 8) & 0xf];
100
105
const passcode = getNemesisPasscode(inventory.Nemesis!)[0];
101
102
// Add to GuessHistory
103
const result1 = passcode == guess[0] ? 0 : 1;
104
const result2 = passcode == guess[1] ? 0 : 1;
105
const result3 = passcode == guess[2] ? 0 : 1;
106
const result1 = passcode == guess[0] ? GUESS_CORRECT : GUESS_INCORRECT;
107
const result2 = passcode == guess[1] ? GUESS_CORRECT : GUESS_INCORRECT;
108
const result3 = passcode == guess[2] ? GUESS_CORRECT : GUESS_INCORRECT;
106
109
inventory.Nemesis!.GuessHistory.push(
107
encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
110
encodeNemesisGuess([
111
{
112
symbol: guess[0],
113
result: result1
114
},
115
{
116
symbol: guess[1],
117
result: result2
118
},
119
{
120
symbol: guess[2],
121
result: result3
122
}
123
])
108
124
);
109
125
110
126
// Increase antivirus if correct antivirus mod is installed
111
127
const response: IKnifeResponse = {};
112
if (result1 == 0 || result2 == 0 || result3 == 0) {
128
if (result1 == GUESS_CORRECT || result2 == GUESS_CORRECT || result3 == GUESS_CORRECT) {
113
129
let antivirusGain = 5;
114
130
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
115
131
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
@@ -150,19 +166,47 @@ export const nemesisController: RequestHandler = async (req, res) => {
150
166
await inventory.save();
151
167
res.json(response);
152
168
} else {
169
// For first guess, create a new entry.
170
if (body.position == 0) {
171
inventory.Nemesis!.GuessHistory.push(
172
encodeNemesisGuess([
173
{
174
symbol: GUESS_NONE,
175
result: GUESS_NEUTRAL
176
},
177
{
178
symbol: GUESS_NONE,
179
result: GUESS_NEUTRAL
180
},
181
{
182
symbol: GUESS_NONE,
183
result: GUESS_NEUTRAL
184
}
185
])
186
);
187
}
188
189
// Evaluate guess
190
const correct =
191
body.guess == GUESS_WILDCARD || getNemesisPasscode(inventory.Nemesis!)[body.position] == body.guess;
192
193
// Update entry
194
const guess = decodeNemesisGuess(
195
inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1]
196
);
197
guess[body.position].symbol = body.guess;
198
guess[body.position].result = correct ? GUESS_CORRECT : GUESS_INCORRECT;
199
inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1] = encodeNemesisGuess(guess);
200
201
// Increase rank if incorrect
153
202
let RankIncrease: number | undefined;
154
if (body.guess != GUESS_WILDCARD) {
155
const passcode = getNemesisPasscode(inventory.Nemesis!);
156
if (passcode[body.position] != body.guess) {
157
const manifest = getNemesisManifest(inventory.Nemesis!.manifest);
158
if (inventory.Nemesis!.Rank + 1 < manifest.systemIndexes.length) {
159
inventory.Nemesis!.Rank += 1;
160
RankIncrease = 1;
161
}
162
inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
163
await inventory.save();
164
}
203
if (!correct) {
204
RankIncrease = 1;
205
const manifest = getNemesisManifest(inventory.Nemesis!.manifest);
206
inventory.Nemesis!.Rank = Math.min(inventory.Nemesis!.Rank + 1, manifest.systemIndexes.length - 1);
207
inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
165
208
}
209
await inventory.save();
166
210
res.json({ RankIncrease });
167
211
}
168
212
} else if ((req.query.mode as string) == "rs") {
@@ -237,7 +237,7 @@ export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: TNemesisFacti
237
237
return passcode;
238
238
};
239
239
240
const reqiuemMods: readonly string[] = [
240
const requiemMods: readonly string[] = [
241
241
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
242
242
"/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
243
243
"/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
@@ -263,32 +263,51 @@ export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: TNeme
263
263
const passcode = getNemesisPasscode(nemesis);
264
264
return nemesis.Faction == "FC_INFESTATION"
265
265
? passcode.map(i => antivirusMods[i])
266
: passcode.map(i => reqiuemMods[i]);
266
: passcode.map(i => requiemMods[i]);
267
267
};
268
268
269
// Symbols; 0-7 are the normal requiem mods.
269
270
export const GUESS_NONE = 8;
270
271
export const GUESS_WILDCARD = 9;
271
272
272
export const encodeNemesisGuess = (
273
symbol1: number,
274
result1: number,
275
symbol2: number,
276
result2: number,
277
symbol3: number,
278
result3: number
279
): number => {
273
// Results; there are 3, 4, 5 as well which are more muted versions but unused afaik.
274
export const GUESS_NEUTRAL = 0;
275
export const GUESS_INCORRECT = 1;
276
export const GUESS_CORRECT = 2;
277
278
interface NemesisPositionGuess {
279
symbol: number;
280
result: number;
281
}
282
283
export type NemesisGuess = [NemesisPositionGuess, NemesisPositionGuess, NemesisPositionGuess];
284
285
export const encodeNemesisGuess = (guess: NemesisGuess): number => {
280
286
return (
281
(symbol1 & 0xf) |
282
((result1 & 3) << 12) |
283
((symbol2 << 4) & 0xff) |
284
((result2 << 14) & 0xffff) |
285
((symbol3 & 0xf) << 8) |
286
((result3 & 3) << 16)
287
(guess[0].symbol & 0xf) |
288
((guess[0].result & 3) << 12) |
289
((guess[1].symbol << 4) & 0xff) |
290
((guess[1].result << 14) & 0xffff) |
291
((guess[2].symbol & 0xf) << 8) |
292
((guess[2].result & 3) << 16)
287
293
);
288
294
};
289
295
290
export const decodeNemesisGuess = (val: number): number[] => {
291
return [val & 0xf, (val >> 12) & 3, (val & 0xff) >> 4, (val & 0xffff) >> 14, (val >> 8) & 0xf, (val >> 16) & 3];
296
export const decodeNemesisGuess = (val: number): NemesisGuess => {
297
return [
298
{
299
symbol: val & 0xf,
300
result: (val >> 12) & 3
301
},
302
{
303
symbol: (val & 0xff) >> 4,
304
result: (val & 0xffff) >> 14
305
},
306
{
307
symbol: (val >> 8) & 0xf,
308
result: (val >> 16) & 3
309
}
310
];
292
311
};
293
312
294
313
export interface IKnifeResponse {
@@ -1182,14 +1182,12 @@ export const addMissionRewards = async (
1182
1182
if (nodeIndex !== -1) inventory.Nemesis.InfNodes.splice(nodeIndex, 1);
1183
1183
1184
1184
if (inventory.Nemesis.InfNodes.length <= 0) {
1185
const manifest = getNemesisManifest(inventory.Nemesis.manifest);
1185
1186
if (inventory.Nemesis.Faction != "FC_INFESTATION") {
1186
inventory.Nemesis.Rank = Math.min(inventory.Nemesis.Rank + 1, 4);
1187
inventory.Nemesis.Rank = Math.min(inventory.Nemesis.Rank + 1, manifest.systemIndexes.length - 1);
1187
1188
inventoryChanges.Nemesis.Rank = inventory.Nemesis.Rank;
1188
1189
}
1189
inventory.Nemesis.InfNodes = getInfNodes(
1190
getNemesisManifest(inventory.Nemesis.manifest),
1191
inventory.Nemesis.Rank
1192
);
1190
inventory.Nemesis.InfNodes = getInfNodes(manifest, inventory.Nemesis.Rank);
1193
1191
}
1194
1192
1195
1193
if (inventory.Nemesis.Faction == "FC_INFESTATION") {