All files / js map_access.js

97.05% Statements 66/68
88.88% Branches 32/36
100% Functions 5/5
97.05% Lines 66/68

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 6973x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 82409x 82409x 73x 73x 73x 73x 73x 73x 73x 2479558x 2479558x 32658901x 32657179x 32658870x 32658901x 32658901x 2479558x 2479558x 2479558x 2479558x 2479558x 15x 15x 2388527x 2479558x 73x 73x 73x 2891x 2891x 73x 73x 73x 73x 73x 22732x 22732x 22732x 387486x 387486x 387486x 21994x 22732x 73x 73x 73x 73x 1867879x     1867879x 1867879x 1867879x 1867879x  
// map_access.js — Map access helpers for C-to-JS translation.
// C ref: Various macros from decl.h, hack.h, rm.h.
//
// CONVENTIONS.md documents these as:
//   import { levl, m_at, obj_at, t_at } from './map_access.js';
//
// These provide the JS equivalents of C's levl[][], m_at(), OBJ_AT(), t_at().
 
import { game } from './gstate.js';
import { MON_FLOOR } from './const.js';
 
// C ref: levl[x][y] — access map location at (x, y).
// Returns the location struct or null if out of bounds.
export function levl(x, y) {
    return game.level?.at(x, y) || null;
}
 
// C ref: m_at(x, y) — find monster at position (x, y).
// C uses level.monsters[x][y] spatial table which excludes dead monsters
// and monsters removed from the map (like steeds via remove_monster).
// JS walks fmon but skips the steed (which is on fmon with valid mx/my
// but was removed from the map during mounting).
export function m_at(x, y) {
    const steed = game.u?.usteed;
    for (let m = game.fmon; m; m = m.nmon) {
        if (m === steed) continue;
        if (!m.dead
            && (m.mstate ?? MON_FLOOR) === MON_FLOOR
            && m.mx === x && m.my === y) return m;
    }
    const byMap = game.level?.monMap?.[x]?.[y] ?? null;
    if (byMap && !byMap.dead
        && (byMap.mstate ?? MON_FLOOR) === MON_FLOOR
        && byMap.wormno
        && (byMap.mx !== x || byMap.my !== y)) {
        return byMap;
    }
    return null;
}
 
// C ref: MON_AT(x, y) — is there a monster at (x, y)?
export function MON_AT(x, y) {
    return !!m_at(x, y);
}
 
 
// C ref: OBJ_AT(x, y) — find top object at position (x, y).
// Iterates the level objects array (newest first). Returns the object or null.
export function obj_at(x, y) {
    const objects = game.level?.objects;
    if (!objects) return null;
    for (let i = objects.length - 1; i >= 0; i--) {
        const obj = objects[i];
        if (obj.ox === x && obj.oy === y) return obj;
    }
    return null;
}
 
// C ref: t_at(x, y) — find trap at position (x, y).
// Returns the trap or null.
export function t_at(x, y) {
    for (let trap = game.ftrap; trap; trap = trap.ntrap) {
        if (trap.tx === x && trap.ty === y) return trap;
    }
    const traps = game.level?.traps;
    if (!traps) return null;
    return traps.find(t => t.tx === x && t.ty === y) || null;
}