feat(packer): 提取可交互 NPC 的地图定位并独立存储
将场景数据生成时对 objectType 的判定粒度细化。保留对普通怪物的忽略过滤,对于包含 baseIsMonsters 标识的命名 NPC 记录,将类型标识拆分为 'npc' 并单独放入 scene.json 的 npcs 数组中打包。
This commit is contained in:
parent
e3ca14c357
commit
11e0688930
|
|
@ -344,14 +344,19 @@ for (const row of objectsTable.rows) {
|
|||
|
||||
/** Object members grouped by token and mode, built once. */
|
||||
const objectMembers = new Map<string, Map<string, string[]>>()
|
||||
const monsterMembers = new Map<string, Map<string, string[]>>()
|
||||
for (const name of allNames) {
|
||||
if (!name.toLowerCase().startsWith(OBJECT_PREFIX.toLowerCase())) continue
|
||||
const rest = name.slice(OBJECT_PREFIX.length).split('\\')
|
||||
const isObj = name.toLowerCase().startsWith(OBJECT_PREFIX.toLowerCase())
|
||||
const isMon = name.toLowerCase().startsWith('data\\global\\monsters\\')
|
||||
if (!isObj && !isMon) continue
|
||||
const prefixLen = isObj ? OBJECT_PREFIX.length : 22 // 'data\\global\\monsters\\'.length
|
||||
const rest = name.slice(prefixLen).split('\\')
|
||||
if (rest.length < 3) continue
|
||||
const token = (rest[0] ?? '').toUpperCase()
|
||||
const mode = (rest[1] ?? '').toLowerCase()
|
||||
if (!objectMembers.has(token)) objectMembers.set(token, new Map())
|
||||
const modes = objectMembers.get(token)!
|
||||
const map = isObj ? objectMembers : monsterMembers
|
||||
if (!map.has(token)) map.set(token, new Map())
|
||||
const modes = map.get(token)!
|
||||
if (!modes.has(mode)) modes.set(mode, [])
|
||||
modes.get(mode)!.push(name)
|
||||
}
|
||||
|
|
@ -378,8 +383,9 @@ function compRank(path: string): number {
|
|||
* @param modeToken - animation mode token the engine places the object in (`NU`/`OP`/…).
|
||||
* @returns the member name and how many candidates there were.
|
||||
*/
|
||||
function pickObjectMember(token: string, modeToken: string): { member: string; candidates: number } | null {
|
||||
const dirs = objectMembers.get(token)
|
||||
function pickObjectMember(token: string, modeToken: string, baseIsMonsters = false): { member: string; candidates: number } | null {
|
||||
const map = baseIsMonsters ? monsterMembers : objectMembers
|
||||
const dirs = map.get(token)
|
||||
if (dirs === undefined) return null
|
||||
const all = [...dirs.values()].flat().filter(name => {
|
||||
const lower = name.toLowerCase()
|
||||
|
|
@ -641,6 +647,7 @@ async function bakeDs1Variant(
|
|||
|
||||
const objectPages = new PageBuilder(palette)
|
||||
const objects: unknown[] = []
|
||||
const npcs: unknown[] = []
|
||||
const missingObjects: string[] = []
|
||||
let objectsWithArt = 0
|
||||
const placementByMember = new Map<string, { placement: Placement; offsetX: number; offsetY: number }>()
|
||||
|
|
@ -655,7 +662,7 @@ async function bakeDs1Variant(
|
|||
}
|
||||
if (resolved.kind === 'monster') continue
|
||||
const row = resolved.row
|
||||
const pick = resolved.token === '' ? null : pickObjectMember(resolved.token, resolved.mode)
|
||||
const pick = resolved.token === '' ? null : pickObjectMember(resolved.token, resolved.mode, resolved.kind === 'npc')
|
||||
const orthoX = (object.x - object.y) * ORTHO_SUB_TILE_WIDTH + scene.originX
|
||||
const orthoY = (object.x + object.y) * ORTHO_SUB_TILE_HEIGHT + scene.originY
|
||||
|
||||
|
|
@ -723,7 +730,8 @@ async function bakeDs1Variant(
|
|||
}
|
||||
}
|
||||
|
||||
objects.push({
|
||||
const list = resolved.kind === 'npc' ? npcs : objects
|
||||
list.push({
|
||||
id: object.id,
|
||||
type: object.type,
|
||||
name: row?.name ?? resolved.token,
|
||||
|
|
@ -793,6 +801,7 @@ async function bakeDs1Variant(
|
|||
walls: scene.walls.map(draw => [draw.frameIndex, draw.x, draw.y, draw.cellX, draw.cellY]),
|
||||
roofs: scene.roofs.map(draw => [draw.frameIndex, draw.x, draw.y, draw.cellX, draw.cellY]),
|
||||
objects,
|
||||
npcs,
|
||||
collision: { width: scene.gridWidth, height: scene.gridHeight, runs },
|
||||
spawn: spawn === null ? null : [Math.round(spawn.x), Math.round(spawn.y)],
|
||||
stats: {
|
||||
|
|
@ -804,6 +813,7 @@ async function bakeDs1Variant(
|
|||
missingRefs: scene.missingRefs,
|
||||
walkable: 1 - [...scene.blocked].reduce((sum, value) => sum + value, 0) / scene.blocked.length,
|
||||
objects: objects.length,
|
||||
npcs: npcs.length,
|
||||
objectsWithArt,
|
||||
objectsUnresolved: missingObjects,
|
||||
objectsArtPending: (objects as any[]).filter(o => o.member !== null && o.frame === null).length,
|
||||
|
|
@ -840,6 +850,7 @@ async function bakeDs1Variant(
|
|||
cells: `${String(scene.cellsX)}x${String(scene.cellsY)}`,
|
||||
frames: scene.frames.length,
|
||||
objects: objects.length,
|
||||
npcs: npcs.length,
|
||||
pages: pageFiles.length,
|
||||
objectPages: objectFiles.length,
|
||||
missingTiles: scene.missingTiles,
|
||||
|
|
|
|||
Loading…
Reference in New Issue