forked from OpenWF/SpaceNinjaServer
		
	feat: classic lich guess history (#2129)
Closes #2123 Reviewed-on: OpenWF/SpaceNinjaServer#2129 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									b7c47b91ff
								
							
						
					
					
						commit
						135b1e54fe
					
				@ -1,12 +1,17 @@
 | 
				
			|||||||
import { version_compare } from "@/src/helpers/inventoryHelpers";
 | 
					import { version_compare } from "@/src/helpers/inventoryHelpers";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    consumeModCharge,
 | 
					    consumeModCharge,
 | 
				
			||||||
 | 
					    decodeNemesisGuess,
 | 
				
			||||||
    encodeNemesisGuess,
 | 
					    encodeNemesisGuess,
 | 
				
			||||||
    getInfNodes,
 | 
					    getInfNodes,
 | 
				
			||||||
    getKnifeUpgrade,
 | 
					    getKnifeUpgrade,
 | 
				
			||||||
    getNemesisManifest,
 | 
					    getNemesisManifest,
 | 
				
			||||||
    getNemesisPasscode,
 | 
					    getNemesisPasscode,
 | 
				
			||||||
    getNemesisPasscodeModTypes,
 | 
					    getNemesisPasscodeModTypes,
 | 
				
			||||||
 | 
					    GUESS_CORRECT,
 | 
				
			||||||
 | 
					    GUESS_INCORRECT,
 | 
				
			||||||
 | 
					    GUESS_NEUTRAL,
 | 
				
			||||||
 | 
					    GUESS_NONE,
 | 
				
			||||||
    GUESS_WILDCARD,
 | 
					    GUESS_WILDCARD,
 | 
				
			||||||
    IKnifeResponse
 | 
					    IKnifeResponse
 | 
				
			||||||
} from "@/src/helpers/nemesisHelpers";
 | 
					} from "@/src/helpers/nemesisHelpers";
 | 
				
			||||||
@ -98,18 +103,29 @@ export const nemesisController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        if (inventory.Nemesis!.Faction == "FC_INFESTATION") {
 | 
					        if (inventory.Nemesis!.Faction == "FC_INFESTATION") {
 | 
				
			||||||
            const guess: number[] = [body.guess & 0xf, (body.guess >> 4) & 0xf, (body.guess >> 8) & 0xf];
 | 
					            const guess: number[] = [body.guess & 0xf, (body.guess >> 4) & 0xf, (body.guess >> 8) & 0xf];
 | 
				
			||||||
            const passcode = getNemesisPasscode(inventory.Nemesis!)[0];
 | 
					            const passcode = getNemesisPasscode(inventory.Nemesis!)[0];
 | 
				
			||||||
 | 
					            const result1 = passcode == guess[0] ? GUESS_CORRECT : GUESS_INCORRECT;
 | 
				
			||||||
            // Add to GuessHistory
 | 
					            const result2 = passcode == guess[1] ? GUESS_CORRECT : GUESS_INCORRECT;
 | 
				
			||||||
            const result1 = passcode == guess[0] ? 0 : 1;
 | 
					            const result3 = passcode == guess[2] ? GUESS_CORRECT : GUESS_INCORRECT;
 | 
				
			||||||
            const result2 = passcode == guess[1] ? 0 : 1;
 | 
					 | 
				
			||||||
            const result3 = passcode == guess[2] ? 0 : 1;
 | 
					 | 
				
			||||||
            inventory.Nemesis!.GuessHistory.push(
 | 
					            inventory.Nemesis!.GuessHistory.push(
 | 
				
			||||||
                encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
 | 
					                encodeNemesisGuess([
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        symbol: guess[0],
 | 
				
			||||||
 | 
					                        result: result1
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        symbol: guess[1],
 | 
				
			||||||
 | 
					                        result: result2
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        symbol: guess[2],
 | 
				
			||||||
 | 
					                        result: result3
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ])
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Increase antivirus if correct antivirus mod is installed
 | 
					            // Increase antivirus if correct antivirus mod is installed
 | 
				
			||||||
            const response: IKnifeResponse = {};
 | 
					            const response: IKnifeResponse = {};
 | 
				
			||||||
            if (result1 == 0 || result2 == 0 || result3 == 0) {
 | 
					            if (result1 == GUESS_CORRECT || result2 == GUESS_CORRECT || result3 == GUESS_CORRECT) {
 | 
				
			||||||
                let antivirusGain = 5;
 | 
					                let antivirusGain = 5;
 | 
				
			||||||
                const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
 | 
					                const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
 | 
				
			||||||
                const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
 | 
					                const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
 | 
				
			||||||
@ -150,19 +166,47 @@ export const nemesisController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            res.json(response);
 | 
					            res.json(response);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            let RankIncrease: number | undefined;
 | 
					            // For first guess, create a new entry.
 | 
				
			||||||
            if (body.guess != GUESS_WILDCARD) {
 | 
					            if (body.position == 0) {
 | 
				
			||||||
                const passcode = getNemesisPasscode(inventory.Nemesis!);
 | 
					                inventory.Nemesis!.GuessHistory.push(
 | 
				
			||||||
                if (passcode[body.position] != body.guess) {
 | 
					                    encodeNemesisGuess([
 | 
				
			||||||
                    const manifest = getNemesisManifest(inventory.Nemesis!.manifest);
 | 
					                        {
 | 
				
			||||||
                    if (inventory.Nemesis!.Rank + 1 < manifest.systemIndexes.length) {
 | 
					                            symbol: GUESS_NONE,
 | 
				
			||||||
                        inventory.Nemesis!.Rank += 1;
 | 
					                            result: GUESS_NEUTRAL
 | 
				
			||||||
                        RankIncrease = 1;
 | 
					                        },
 | 
				
			||||||
                    }
 | 
					                        {
 | 
				
			||||||
                    inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
 | 
					                            symbol: GUESS_NONE,
 | 
				
			||||||
                    await inventory.save();
 | 
					                            result: GUESS_NEUTRAL
 | 
				
			||||||
                }
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            symbol: GUESS_NONE,
 | 
				
			||||||
 | 
					                            result: GUESS_NEUTRAL
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    ])
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Evaluate guess
 | 
				
			||||||
 | 
					            const correct =
 | 
				
			||||||
 | 
					                body.guess == GUESS_WILDCARD || getNemesisPasscode(inventory.Nemesis!)[body.position] == body.guess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Update entry
 | 
				
			||||||
 | 
					            const guess = decodeNemesisGuess(
 | 
				
			||||||
 | 
					                inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1]
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            guess[body.position].symbol = body.guess;
 | 
				
			||||||
 | 
					            guess[body.position].result = correct ? GUESS_CORRECT : GUESS_INCORRECT;
 | 
				
			||||||
 | 
					            inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1] = encodeNemesisGuess(guess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Increase rank if incorrect
 | 
				
			||||||
 | 
					            let RankIncrease: number | undefined;
 | 
				
			||||||
 | 
					            if (!correct) {
 | 
				
			||||||
 | 
					                RankIncrease = 1;
 | 
				
			||||||
 | 
					                const manifest = getNemesisManifest(inventory.Nemesis!.manifest);
 | 
				
			||||||
 | 
					                inventory.Nemesis!.Rank = Math.min(inventory.Nemesis!.Rank + 1, manifest.systemIndexes.length - 1);
 | 
				
			||||||
 | 
					                inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            await inventory.save();
 | 
				
			||||||
            res.json({ RankIncrease });
 | 
					            res.json({ RankIncrease });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else if ((req.query.mode as string) == "rs") {
 | 
					    } else if ((req.query.mode as string) == "rs") {
 | 
				
			||||||
 | 
				
			|||||||
@ -237,7 +237,7 @@ export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: TNemesisFacti
 | 
				
			|||||||
    return passcode;
 | 
					    return passcode;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const reqiuemMods: readonly string[] = [
 | 
					const requiemMods: readonly string[] = [
 | 
				
			||||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
 | 
					    "/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
 | 
				
			||||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
 | 
					    "/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
 | 
				
			||||||
    "/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
 | 
					    "/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
 | 
				
			||||||
@ -263,32 +263,51 @@ export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: TNeme
 | 
				
			|||||||
    const passcode = getNemesisPasscode(nemesis);
 | 
					    const passcode = getNemesisPasscode(nemesis);
 | 
				
			||||||
    return nemesis.Faction == "FC_INFESTATION"
 | 
					    return nemesis.Faction == "FC_INFESTATION"
 | 
				
			||||||
        ? passcode.map(i => antivirusMods[i])
 | 
					        ? passcode.map(i => antivirusMods[i])
 | 
				
			||||||
        : passcode.map(i => reqiuemMods[i]);
 | 
					        : passcode.map(i => requiemMods[i]);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Symbols; 0-7 are the normal requiem mods.
 | 
				
			||||||
export const GUESS_NONE = 8;
 | 
					export const GUESS_NONE = 8;
 | 
				
			||||||
export const GUESS_WILDCARD = 9;
 | 
					export const GUESS_WILDCARD = 9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const encodeNemesisGuess = (
 | 
					// Results; there are 3, 4, 5 as well which are more muted versions but unused afaik.
 | 
				
			||||||
    symbol1: number,
 | 
					export const GUESS_NEUTRAL = 0;
 | 
				
			||||||
    result1: number,
 | 
					export const GUESS_INCORRECT = 1;
 | 
				
			||||||
    symbol2: number,
 | 
					export const GUESS_CORRECT = 2;
 | 
				
			||||||
    result2: number,
 | 
					
 | 
				
			||||||
    symbol3: number,
 | 
					interface NemesisPositionGuess {
 | 
				
			||||||
    result3: number
 | 
					    symbol: number;
 | 
				
			||||||
): number => {
 | 
					    result: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NemesisGuess = [NemesisPositionGuess, NemesisPositionGuess, NemesisPositionGuess];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const encodeNemesisGuess = (guess: NemesisGuess): number => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        (symbol1 & 0xf) |
 | 
					        (guess[0].symbol & 0xf) |
 | 
				
			||||||
        ((result1 & 3) << 12) |
 | 
					        ((guess[0].result & 3) << 12) |
 | 
				
			||||||
        ((symbol2 << 4) & 0xff) |
 | 
					        ((guess[1].symbol << 4) & 0xff) |
 | 
				
			||||||
        ((result2 << 14) & 0xffff) |
 | 
					        ((guess[1].result << 14) & 0xffff) |
 | 
				
			||||||
        ((symbol3 & 0xf) << 8) |
 | 
					        ((guess[2].symbol & 0xf) << 8) |
 | 
				
			||||||
        ((result3 & 3) << 16)
 | 
					        ((guess[2].result & 3) << 16)
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const decodeNemesisGuess = (val: number): number[] => {
 | 
					export const decodeNemesisGuess = (val: number): NemesisGuess => {
 | 
				
			||||||
    return [val & 0xf, (val >> 12) & 3, (val & 0xff) >> 4, (val & 0xffff) >> 14, (val >> 8) & 0xf, (val >> 16) & 3];
 | 
					    return [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            symbol: val & 0xf,
 | 
				
			||||||
 | 
					            result: (val >> 12) & 3
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            symbol: (val & 0xff) >> 4,
 | 
				
			||||||
 | 
					            result: (val & 0xffff) >> 14
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            symbol: (val >> 8) & 0xf,
 | 
				
			||||||
 | 
					            result: (val >> 16) & 3
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IKnifeResponse {
 | 
					export interface IKnifeResponse {
 | 
				
			||||||
 | 
				
			|||||||
@ -1182,14 +1182,12 @@ export const addMissionRewards = async (
 | 
				
			|||||||
            if (nodeIndex !== -1) inventory.Nemesis.InfNodes.splice(nodeIndex, 1);
 | 
					            if (nodeIndex !== -1) inventory.Nemesis.InfNodes.splice(nodeIndex, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (inventory.Nemesis.InfNodes.length <= 0) {
 | 
					            if (inventory.Nemesis.InfNodes.length <= 0) {
 | 
				
			||||||
 | 
					                const manifest = getNemesisManifest(inventory.Nemesis.manifest);
 | 
				
			||||||
                if (inventory.Nemesis.Faction != "FC_INFESTATION") {
 | 
					                if (inventory.Nemesis.Faction != "FC_INFESTATION") {
 | 
				
			||||||
                    inventory.Nemesis.Rank = Math.min(inventory.Nemesis.Rank + 1, 4);
 | 
					                    inventory.Nemesis.Rank = Math.min(inventory.Nemesis.Rank + 1, manifest.systemIndexes.length - 1);
 | 
				
			||||||
                    inventoryChanges.Nemesis.Rank = inventory.Nemesis.Rank;
 | 
					                    inventoryChanges.Nemesis.Rank = inventory.Nemesis.Rank;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                inventory.Nemesis.InfNodes = getInfNodes(
 | 
					                inventory.Nemesis.InfNodes = getInfNodes(manifest, inventory.Nemesis.Rank);
 | 
				
			||||||
                    getNemesisManifest(inventory.Nemesis.manifest),
 | 
					 | 
				
			||||||
                    inventory.Nemesis.Rank
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (inventory.Nemesis.Faction == "FC_INFESTATION") {
 | 
					            if (inventory.Nemesis.Faction == "FC_INFESTATION") {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user