All files / js nhlua.js

86.71% Statements 124/143
72.54% Branches 37/51
80% Functions 4/5
86.71% Lines 124/143

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 14473x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x   23x 73x                                 73x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 1x 73x 73x 73x 73x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x     1x 9x 9x 9x 9x 9x 9x 9x 9x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 2x 2x 23x 23x 23x 23x 23x 23x 23x 23x 2x 2x 2x 2x 2x 2x 2x 86x 2x 2x 2x 3x 73x 73x 3x 3x  
// nhlua.js — tutorial/game-state helpers (port slice from nhlua.c)
 
import { game } from './gstate.js';
import { setworn, setnotworn } from './worn.js';
import {
    NO_SPELL, W_ARM, W_ARMC, W_ARMH, W_ARMS, W_ARMG, W_ARMF, W_ARMU,
    W_WEP, W_SWAPWEP, W_QUIVER, W_RINGL, W_RINGR, W_AMUL,
} from './const.js';
import { pline } from './pline.js';
import { addinv_nomerge, useupall } from './invent.js';
 
function extract_inventory_obj(obj) {
    const g = game;
    let prev = null;
    for (let cur = g.invent; cur; prev = cur, cur = cur.nobj) {
        if (cur !== obj) continue;
        if (prev) prev.nobj = cur.nobj || null;
        else g.invent = cur.nobj || null;
        cur.nobj = null;
        return cur;
    }
    return null;
}
 
function clear_worn_slot(mask) {
    const g = game;
    switch (mask) {
    case 0x00000001: g.u.uarm = null; break;
    case 0x00000002: g.u.uarmc = null; break;
    case 0x00000004: g.u.uarmh = null; break;
    case 0x00000008: g.u.uarms = null; break;
    case 0x00000010: g.u.uarmg = null; break;
    case 0x00000020: g.u.uarmf = null; break;
    case 0x00000040: g.u.uarmu = null; break;
    case 0x00000100: g.u.uwep = null; break;
    case 0x00000200: g.u.uquiver = null; break;
    case 0x00000400: g.u.uswapwep = null; break;
    default: break;
    }
}
 
function rewireWornSlotsFromInventory() {
    const g = game;
    g.u.uarm = null;
    g.u.uarmc = null;
    g.u.uarmh = null;
    g.u.uarms = null;
    g.u.uarmg = null;
    g.u.uarmf = null;
    g.u.uarmu = null;
    g.u.uwep = null;
    g.u.uswapwep = null;
    g.u.uquiver = null;
    g.u.uleft = null;
    g.u.uright = null;
    g.u.uamul = null;
 
    for (let obj = g.invent; obj; obj = obj.nobj) {
        const wornmask = obj.owornmask || 0;
        if (!wornmask) continue;
        if (wornmask & W_ARM) g.u.uarm = obj;
        if (wornmask & W_ARMC) g.u.uarmc = obj;
        if (wornmask & W_ARMH) g.u.uarmh = obj;
        if (wornmask & W_ARMS) g.u.uarms = obj;
        if (wornmask & W_ARMG) g.u.uarmg = obj;
        if (wornmask & W_ARMF) g.u.uarmf = obj;
        if (wornmask & W_ARMU) g.u.uarmu = obj;
        if (wornmask & W_WEP) g.u.uwep = obj;
        if (wornmask & W_SWAPWEP) g.u.uswapwep = obj;
        if (wornmask & W_QUIVER) g.u.uquiver = obj;
        if (wornmask & W_RINGL) g.u.uleft = obj;
        if (wornmask & W_RINGR) g.u.uright = obj;
        if (wornmask & W_AMUL) g.u.uamul = obj;
    }
}
 
// setnotworn imported from worn.js
 
export async function nhl_gamestate(reststate = false) {
    const g = game;
    if (reststate && g.gmst_stored) {
        const cur_uz = { ...g.u.uz };
        const cur_uz0 = { ...g.u.uz0 };
 
        g.moves = g.gmst_moves;
        await pline(`Resetting time to move #${g.moves}.`);
        g.gmst_moves = 0;
        // C ref: nhlua.c nhl_gamestate(reststate): reset invlet allocator
        // before reinserting saved inventory.
        g.lastinvnr = 51;
 
        while (g.invent) {
            useupall(g.invent);
        }
        while (g.gmst_invent) {
            const otmp = g.gmst_invent;
            const wornmask = otmp.owornmask || 0;
            g.gmst_invent = otmp.nobj || null;
            otmp.nobj = null;
            otmp.owornmask = 0;
            addinv_nomerge(otmp);
            if (wornmask) setworn(otmp, wornmask);
        }
 
        if (g.gmst_ubak) Object.assign(g.u, g.gmst_ubak);
        if (g.gmst_mvitals) g.mvitals = structuredClone(g.gmst_mvitals);
        if (g.gmst_spl_book) g.spl_book = structuredClone(g.gmst_spl_book);
 
        g.u.uz = cur_uz;
        g.u.uz0 = cur_uz0;
        rewireWornSlotsFromInventory();
 
        g.gmst_ubak = null;
        g.gmst_mvitals = null;
        g.gmst_spl_book = null;
        g.gmst_stored = false;
    } else if (!reststate && !g.gmst_stored) {
        g.gmst_moves = g.moves;
        while (g.invent) {
            const otmp = g.invent;
            const wornmask = otmp.owornmask || 0;
            setnotworn(otmp);
            extract_inventory_obj(otmp);
            otmp.owornmask = wornmask;
            otmp.nobj = g.gmst_invent;
            g.gmst_invent = otmp;
        }
        // C ref: nhlua.c nhl_gamestate(!reststate): tutorial inventory starts
        // invlet assignment from 'a'.
        g.lastinvnr = 51;
        g.gmst_ubak = { ...g.u };
        g.gmst_mvitals = structuredClone(g.mvitals);
        g.gmst_spl_book = structuredClone(g.spl_book);
        g.spl_book = new Array(g.spl_book.length).fill(null).map(() => ({
            sp_id: NO_SPELL, sp_lev: 0, sp_know: 0,
        }));
        g.gmst_stored = true;
    }
}
 
export async function tutorial(entering) {
    await nhl_gamestate(!entering ? true : false);
}