From 7295dc8b3e054114c93f9247331634c6fc7c0fb9 Mon Sep 17 00:00:00 2001 From: troytt <47798984@qq.com> Date: Sat, 26 Sep 2026 14:59:12 +0000 Subject: [PATCH] feat(portal): implement v1.13c Town Portal tome/scroll, DS1 town positions & two-way travel (#394) - Resolve exact Diablo II v1.13c DS1 Type-2 Object #33 (Objects.txt ID 59) Town Portal sub-tiles across all 9 town presets (Acts 1-5) in src/game/portal.ts - Implement TownPortalSlot.mouthInLevel(levelId) and enterFrom(levelId) per ObjMode.cpp:3245 (wilderness -> town keeps portal open; town -> wilderness closes portal) - Add 20-charge quantity tracking for Tome of Town Portal (tbk) and Tome of Identify (ibk), right-click casting for tbk/tsc in inventory, and scroll-to-tome refill - Bake authentic TP DCC sprite atlases (tptrlitophth, tphdlitophth, tptrlitonhth, tphdlitonhth) into public/overlays/town_portal_* - Render Town Portal entity with OP/ON DCC animation, dynamic blue light (Light=19, RGB 64/110/255), overhead destination label, and proximity walk-to-interact in src/scene/act-scene.ts - Add unit and parity tests in tests/town-portal.test.ts Closes #394 --- public/overlays/town_portal_on_hd.json | 148 ++++++ public/overlays/town_portal_on_hd.png | Bin 0 -> 77094 bytes public/overlays/town_portal_on_tr.json | 148 ++++++ public/overlays/town_portal_on_tr.png | Bin 0 -> 6895 bytes public/overlays/town_portal_op_hd.json | 148 ++++++ public/overlays/town_portal_op_hd.png | Bin 0 -> 53672 bytes public/overlays/town_portal_op_tr.json | 148 ++++++ public/overlays/town_portal_op_tr.png | Bin 0 -> 2831 bytes scripts/pack-overlays.ts | 46 +- src/game/portal.ts | 132 +++++- src/render/overlays-meta.ts | 608 +++++++++++++++++++++++++ src/scene/act-scene.ts | 391 ++++++++++++++-- src/ui/hud-manager.ts | 8 +- src/ui/inventory.ts | 34 +- src/ui/world-panels.ts | 6 +- tests/town-portal.test.ts | 279 ++++++++++++ 16 files changed, 2034 insertions(+), 62 deletions(-) create mode 100644 public/overlays/town_portal_on_hd.json create mode 100644 public/overlays/town_portal_on_hd.png create mode 100644 public/overlays/town_portal_on_tr.json create mode 100644 public/overlays/town_portal_on_tr.png create mode 100644 public/overlays/town_portal_op_hd.json create mode 100644 public/overlays/town_portal_op_hd.png create mode 100644 public/overlays/town_portal_op_tr.json create mode 100644 public/overlays/town_portal_op_tr.png create mode 100644 tests/town-portal.test.ts diff --git a/public/overlays/town_portal_on_hd.json b/public/overlays/town_portal_on_hd.json new file mode 100644 index 0000000..58d4ee1 --- /dev/null +++ b/public/overlays/town_portal_on_hd.json @@ -0,0 +1,148 @@ +{ + "name": "town_portal_on_hd", + "celFile": "tphdlitonhth", + "width": 1024, + "height": 319, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 3, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -54, + "top": -120, + "width": 109, + "height": 159 + }, + "groups": [ + [ + [ + 0, + 0, + 109, + 159, + -54, + -120 + ], + [ + 110, + 0, + 109, + 159, + -54, + -120 + ], + [ + 220, + 0, + 109, + 159, + -54, + -120 + ], + [ + 330, + 0, + 109, + 159, + -54, + -120 + ], + [ + 440, + 0, + 109, + 159, + -54, + -120 + ], + [ + 550, + 0, + 109, + 159, + -54, + -120 + ], + [ + 660, + 0, + 109, + 159, + -54, + -120 + ], + [ + 770, + 0, + 109, + 159, + -54, + -120 + ], + [ + 880, + 0, + 109, + 159, + -54, + -120 + ], + [ + 0, + 160, + 109, + 159, + -54, + -120 + ], + [ + 110, + 160, + 109, + 159, + -54, + -120 + ], + [ + 220, + 160, + 109, + 159, + -54, + -120 + ], + [ + 330, + 160, + 109, + 159, + -54, + -120 + ], + [ + 440, + 160, + 109, + 159, + -54, + -120 + ], + [ + 550, + 160, + 109, + 159, + -54, + -120 + ] + ] + ] +} \ No newline at end of file diff --git a/public/overlays/town_portal_on_hd.png b/public/overlays/town_portal_on_hd.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4a78c155546a18942eb56d8625261ee8de1b99 GIT binary patch literal 77094 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

`icbWJ4vEkn!!*^LGn7W|v`^yb7DkNcDJ2|I}a- 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 MMNNg0XBI*K2m3-9oB#j- literal 0 HcmV?d00001 diff --git a/public/overlays/town_portal_on_tr.json b/public/overlays/town_portal_on_tr.json new file mode 100644 index 0000000..c262263 --- /dev/null +++ b/public/overlays/town_portal_on_tr.json @@ -0,0 +1,148 @@ +{ + "name": "town_portal_on_tr", + "celFile": "tptrlitonhth", + "width": 512, + "height": 181, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 0, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -23, + "top": -85, + "width": 46, + "height": 90 + }, + "groups": [ + [ + [ + 0, + 0, + 46, + 90, + -23, + -85 + ], + [ + 47, + 0, + 46, + 90, + -23, + -85 + ], + [ + 94, + 0, + 46, + 90, + -23, + -85 + ], + [ + 141, + 0, + 46, + 90, + -23, + -85 + ], + [ + 188, + 0, + 46, + 90, + -23, + -85 + ], + [ + 235, + 0, + 46, + 90, + -23, + -85 + ], + [ + 282, + 0, + 46, + 90, + -23, + -85 + ], + [ + 329, + 0, + 46, + 90, + -23, + -85 + ], + [ + 376, + 0, + 46, + 90, + -23, + -85 + ], + [ + 423, + 0, + 46, + 90, + -23, + -85 + ], + [ + 0, + 91, + 46, + 90, + -23, + -85 + ], + [ + 47, + 91, + 46, + 90, + -23, + -85 + ], + [ + 94, + 91, + 46, + 90, + -23, + -85 + ], + [ + 141, + 91, + 46, + 90, + -23, + -85 + ], + [ + 188, + 91, + 46, + 90, + -23, + -85 + ] + ] + ] +} \ No newline at end of file diff --git a/public/overlays/town_portal_on_tr.png b/public/overlays/town_portal_on_tr.png new file mode 100644 index 0000000000000000000000000000000000000000..8b4ca97ba287b78685b1c93bb19f52701c4d4ad1 GIT binary patch literal 6895 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 ab3v+?Keg$oeIxB(Uq{1Gy++kO{C@y_dE+4f literal 0 HcmV?d00001 diff --git a/public/overlays/town_portal_op_hd.json b/public/overlays/town_portal_op_hd.json new file mode 100644 index 0000000..3103ff6 --- /dev/null +++ b/public/overlays/town_portal_op_hd.json @@ -0,0 +1,148 @@ +{ + "name": "town_portal_op_hd", + "celFile": "tphdlitophth", + "width": 1024, + "height": 608, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 3, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -93, + "top": -141, + "width": 188, + "height": 202 + }, + "groups": [ + [ + [ + 0, + 0, + 188, + 202, + -93, + -141 + ], + [ + 189, + 0, + 188, + 202, + -93, + -141 + ], + [ + 378, + 0, + 188, + 202, + -93, + -141 + ], + [ + 567, + 0, + 188, + 202, + -93, + -141 + ], + [ + 756, + 0, + 188, + 202, + -93, + -141 + ], + [ + 0, + 203, + 188, + 202, + -93, + -141 + ], + [ + 189, + 203, + 188, + 202, + -93, + -141 + ], + [ + 378, + 203, + 188, + 202, + -93, + -141 + ], + [ + 567, + 203, + 188, + 202, + -93, + -141 + ], + [ + 756, + 203, + 188, + 202, + -93, + -141 + ], + [ + 0, + 406, + 188, + 202, + -93, + -141 + ], + [ + 189, + 406, + 188, + 202, + -93, + -141 + ], + [ + 378, + 406, + 188, + 202, + -93, + -141 + ], + [ + 567, + 406, + 188, + 202, + -93, + -141 + ], + [ + 756, + 406, + 188, + 202, + -93, + -141 + ] + ] + ] +} \ No newline at end of file diff --git a/public/overlays/town_portal_op_hd.png b/public/overlays/town_portal_op_hd.png new file mode 100644 index 0000000000000000000000000000000000000000..f5934a87b5479b24b0910275f1695173d9574dcf GIT binary patch literal 53672 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 literal 0 HcmV?d00001 diff --git a/public/overlays/town_portal_op_tr.json b/public/overlays/town_portal_op_tr.json new file mode 100644 index 0000000..b7a8ff2 --- /dev/null +++ b/public/overlays/town_portal_op_tr.json @@ -0,0 +1,148 @@ +{ + "name": "town_portal_op_tr", + "celFile": "tptrlitophth", + "width": 512, + "height": 181, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 0, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -23, + "top": -85, + "width": 45, + "height": 90 + }, + "groups": [ + [ + [ + 0, + 0, + 45, + 90, + -23, + -85 + ], + [ + 46, + 0, + 45, + 90, + -23, + -85 + ], + [ + 92, + 0, + 45, + 90, + -23, + -85 + ], + [ + 138, + 0, + 45, + 90, + -23, + -85 + ], + [ + 184, + 0, + 45, + 90, + -23, + -85 + ], + [ + 230, + 0, + 45, + 90, + -23, + -85 + ], + [ + 276, + 0, + 45, + 90, + -23, + -85 + ], + [ + 322, + 0, + 45, + 90, + -23, + -85 + ], + [ + 368, + 0, + 45, + 90, + -23, + -85 + ], + [ + 414, + 0, + 45, + 90, + -23, + -85 + ], + [ + 460, + 0, + 45, + 90, + -23, + -85 + ], + [ + 0, + 91, + 45, + 90, + -23, + -85 + ], + [ + 46, + 91, + 45, + 90, + -23, + -85 + ], + [ + 92, + 91, + 45, + 90, + -23, + -85 + ], + [ + 138, + 91, + 45, + 90, + -23, + -85 + ] + ] + ] +} \ No newline at end of file diff --git a/public/overlays/town_portal_op_tr.png b/public/overlays/town_portal_op_tr.png new file mode 100644 index 0000000000000000000000000000000000000000..f29c54025692872e2dce1979ae3b38a7dee6fc9f GIT binary patch literal 2831 zcmZ`*dpMMN8-8ZY$f1ZrQOR*6hfXvRrqVhygtbm7icAb5R<&N+Mr51BW+RPAR3?X- z9EzFEVG`Rg4&!qyip4NF)a3lVd$_J|w`;$D-s|~Y@B2L0{kxz0xt}+Q>}a({N?8g3 z*4S8Ex&UC&5SS9;=yTf}D+K_lP8-Vut}(YJ`l=&_h>GImb5}58;!=ytPQQ`jvEmP= z$6hgfspWmSI%_TJ_PH52IdMHo1nTD43?)NDv+++qZAQ>K(b z?T3w?#|4#=04kOCxvEqu)xp74#4TU zcU%`aTm*lI1e!J_d9NAqL5M_Voi;nE+guqR6y~h)uSLcjjLb-KSU8+*Ckr`8vhc{MO!Gni(}LEFQ_5MJ_QL+-k0I

sbZcjmyELTM=jHZvMHqR{XqH~M$Ii>9a75S>

1_v1ar zjxS)6oQ(t*F|%kV5Sf4Df}}89$xv)?^af7?kiG4f84mZuhq0t4ln~SGVPb90?2auw zo=s}H5^F%85!Sj2gXmTevG26L;1hy8+t)JPt-Zzmh9Kr3g&SSo5h~er9o0qaFKa90 z(4GxVdBjS{w*7VTm}m7mXOZKzf0yLtuo%gt{KVGm7%qP1#9!^&91$pm%IA&*=$q9@ z+$8|~8pIG{+wIXy$uD;$XN?@`M7E=NFdUZhnfDVN+kh09tKvr?6s))QA>+ob%02gIJ)+o}$@`E@E|9|^OL#=hf}p) zyxC1FuS@==r^hSGLJaBDl7%<}8&280(?Yw^Ar+os|MGw#chO8HQ1_8 z!x#rl1Y0IGp1Hzbj|HBMGBhL$XIZqJf^|kQius6J*XBQeJGK|zy|c>v2Ytd0&qu-VZTYdUY~(A z#n%B=809w=^K%>=u{LcP`d@dv8#XoC?0Y0F_;nC$RXL34DIT~pYy}t(NAQbQznkuT3L6v;YPeFGO#qN3!7*h-l0O5J#*X4#9{iCG7LJN>Hj6*j7heArouCv znS}~siY~~77o+XVzM0;bPii)B+4MM%TrESAvB4tZr4!v=K6U*yst6;}4fk@Ovwhdk z0hn$AxE6jg0r(@hbkI}{pA+JPM?5ASol7b*8mYJW)k-6_T)hu5+UyAQ#rosZ15KK{ zxeF4zjv3xry;TW=xDAHacWe95$XHZ6uD1D0{=w23z-&^6;0kO0js)ep<(0=?8;v?J zw;T!4Dk`j>i{Fty-XwG25Y8nNu^E8!tZ6^Bjxu?Nx0_e%D0)-26GviUba}jgqoSA7Brz$lqKMv8nE{@Qpnmf0c zK4a$Fji132z(~Q|quD2k?j*5}Qvd3$x`0I57Pb|3D35)#S z=gvB5xLNJIGI_yA}3j8@f( ze)vYA)%lu~r5;xC)CHPopLv|fH!f=8gVNjjI@yw&Ay|^VZEfJX9`_qm|AR{=Hye0S z(gn?Z-?Qn#TNa%BYwmw5fODmdmy8dxC+J>3FH$`>??p$d_v6ug%Ak$5enuU70-M8* KmX8kleg9ujD%aBh literal 0 HcmV?d00001 diff --git a/scripts/pack-overlays.ts b/scripts/pack-overlays.ts index 6117777..5bce56b 100644 --- a/scripts/pack-overlays.ts +++ b/scripts/pack-overlays.ts @@ -1503,6 +1503,47 @@ export const OVERLAY_TARGETS: readonly OverlayTarget[] = [ lightRadius: 0, lightColor: [255, 255, 255] as const, }, + // Authentic Diablo II v1.13c Town Portal Object Art (Objects.txt ID 59, Token TP: tpophth.cof & tponhth.cof) + { + name: 'town_portal_op_tr', + celFile: 'tptrlitophth', + aliases: ['tptrlitophth'], + animRate: 16, + trans: 0, + preDraw: false, + lightRadius: 19, + lightColor: [64, 64, 255] as const, + }, + { + name: 'town_portal_op_hd', + celFile: 'tphdlitophth', + aliases: ['tphdlitophth'], + animRate: 16, + trans: 3, + preDraw: false, + lightRadius: 19, + lightColor: [64, 64, 255] as const, + }, + { + name: 'town_portal_on_tr', + celFile: 'tptrlitonhth', + aliases: ['tptrlitonhth'], + animRate: 16, + trans: 0, + preDraw: false, + lightRadius: 19, + lightColor: [64, 64, 255] as const, + }, + { + name: 'town_portal_on_hd', + celFile: 'tphdlitonhth', + aliases: ['tphdlitonhth'], + animRate: 16, + trans: 3, + preDraw: false, + lightRadius: 19, + lightColor: [64, 64, 255] as const, + }, ] as const export async function bakeOverlays( @@ -1549,7 +1590,10 @@ export async function bakeOverlays( const metaRecord: Record = {} for (const target of OVERLAY_TARGETS) { - const raw = await readMpqFile(`data/global/overlays/${target.celFile}.dcc`) + const raw = + (await readMpqFile(`data/global/overlays/${target.celFile}.dcc`)) ?? + (await readMpqFile(`data/global/objects/tp/tr/${target.celFile}.dcc`)) ?? + (await readMpqFile(`data/global/objects/tp/hd/${target.celFile}.dcc`)) if (!raw) throw new Error(`Overlay DCC not found: data/global/overlays/${target.celFile}.dcc`) const dcc = decodeDcc(raw) diff --git a/src/game/portal.ts b/src/game/portal.ts index f59db5c..d55688d 100644 --- a/src/game/portal.ts +++ b/src/game/portal.ts @@ -156,6 +156,81 @@ export interface OpenPortal { /** The mouth in town, in sub-tiles. */ readonly townX: number readonly townY: number + /** Optional creation timestamp (ms) for the 15-frame opening animation (OP -> ON). */ + readonly createdAtMs?: number +} + +/** + * Authentic Diablo II v1.13c Town Portal DS1 special tile coordinates (`subTile = tile * 5 + 3`). + * + * Extracted from `D2GAME_CreateLinkPortal_6FD13B20` (`Skills.cpp:3006`) -> + * `DUNGEON_FindActSpawnLocationEx(pAct, nDestLevel, 11, &nX, &nY, 3)` (`D2Dungeon.cpp:391`) -> + * `DrlgPreset.cpp:1406–1438` (`style = 33, seq = 0` -> `nTileIndex = 11`) and + * `sub_6FD788D0` (`DrlgDrlgWarp.cpp:153–174` fallback to `pTileInfo[0]` for Harrogath `townWest.ds1`). + */ +export const TOWN_PORTAL_SUBTILES_BY_VARIANT: Readonly> = { + '1-act-1-town-townn1': { x: 153, y: 73 }, // TownN1.ds1 tile (30, 14) + '1-act-1-town-towne1': { x: 173, y: 103 }, // TownE1.ds1 tile (34, 20) + '1-act-1-town-towns1': { x: 153, y: 158 }, // TownS1.ds1 tile (30, 31) + '1-act-1-town-townw1': { x: 83, y: 128 }, // TownW1.ds1 tile (16, 25) + '40-act-2-town-lutw': { x: 178, y: 53 }, // LutW.ds1 tile (35, 10) + '40-act-2-town-lutn': { x: 178, y: 53 }, // LutN.ds1 tile (35, 10) + '75-act-3-town-docktown3': { x: 158, y: 68 }, // DockTown3.ds1 tile (31, 13) + '103-act-4-town-fortress': { x: 48, y: 43 }, // Fortress.ds1 tile (9, 8) + '109-act-5-town-townwest': { x: 98, y: 23 }, // townWest.ds1 tile (19, 4) via pTileInfo[0] +} + +export const DEFAULT_TOWN_PORTAL_SUBTILES_BY_LEVEL: Readonly> = { + 1: { x: 153, y: 158 }, // Default Act 1 town variant is TownS1 (south gate to Blood Moor) + 40: { x: 178, y: 53 }, + 75: { x: 158, y: 68 }, + 103: { x: 48, y: 43 }, + 109: { x: 98, y: 23 }, +} + +/** + * Resolve the authentic 1.13c Town Portal sub-tile position in a town level. + * + * @param townLevelId - Town `Levels.txt` ID (`1, 40, 75, 103, 109`). + * @param townVariantLabel - Optional town preset variant label or DS1 name. + * @returns Sub-tile `{ x, y }` for the town portal mouth in town. + */ +export function resolveTownPortalSubTile( + townLevelId: number, + townVariantLabel?: string, +): { x: number; y: number } { + if (townVariantLabel) { + const key = townVariantLabel.trim().toLowerCase() + const direct = TOWN_PORTAL_SUBTILES_BY_VARIANT[key] + if (direct !== undefined) { + return { x: direct.x, y: direct.y } + } + if (townLevelId === 1) { + if (key.includes('townn')) return { x: 153, y: 73 } + if (key.includes('towne')) return { x: 173, y: 103 } + if (key.includes('towns')) return { x: 153, y: 158 } + if (key.includes('townw')) return { x: 83, y: 128 } + } + } + const byLevel = DEFAULT_TOWN_PORTAL_SUBTILES_BY_LEVEL[townLevelId] + if (byLevel !== undefined) { + return { x: byLevel.x, y: byLevel.y } + } + throw new Error(`resolveTownPortalSubTile: invalid town levelId ${String(townLevelId)}`) +} + +/** Description of the portal mouth visible in a given level. */ +export interface PortalMouthInLevel { + /** Sub-tile X of the portal mouth in this level. */ + readonly x: number + /** Sub-tile Y of the portal mouth in this level. */ + readonly y: number + /** Destination `Levels.txt` ID when stepping into this mouth. */ + readonly toLevelId: number + /** True when this mouth is the one inside town (clicking it closes the portal). */ + readonly isTownMouth: boolean + /** Optional creation timestamp (ms) for opening animation playback. */ + readonly createdAtMs?: number } /** @@ -195,7 +270,37 @@ export class TownPortalSlot { } /** - * Where stepping into a mouth in the given level leads. + * Describe the portal mouth present in `levelId`, if any. + * + * @param levelId - the level currently loaded. + * @returns the mouth present in `levelId`, or null. + */ + mouthInLevel(levelId: number): PortalMouthInLevel | null { + const portal = this.open + if (portal === null) return null + if (levelId === portal.fromLevelId) { + return { + x: portal.fromX, + y: portal.fromY, + toLevelId: portal.townLevelId, + isTownMouth: false, + ...(portal.createdAtMs !== undefined ? { createdAtMs: portal.createdAtMs } : {}), + } + } + if (levelId === portal.townLevelId) { + return { + x: portal.townX, + y: portal.townY, + toLevelId: portal.fromLevelId, + isTownMouth: true, + ...(portal.createdAtMs !== undefined ? { createdAtMs: portal.createdAtMs } : {}), + } + } + return null + } + + /** + * Where stepping into a mouth in the given level leads (pure query). * * @param levelId - the level the player is standing in. * @returns the other mouth, or null when this level has no mouth. @@ -211,6 +316,31 @@ export class TownPortalSlot { } return null } + + /** + * Step into the portal mouth in `levelId` (`OBJECTS_OperateFunction15_Portal`, `ObjMode.cpp:3125`): + * - Entering from the wilderness (`levelId === fromLevelId`) transports the player to town + * and keeps the portal open so the return mouth remains in town. + * - Entering from town (`levelId === townLevelId`) transports the player back to the wilderness + * and **closes the portal** (`ObjMode.cpp:3245`). + * + * @param levelId - the level the player is entering the portal from. + * @returns the travel destination, or null if no portal mouth is in `levelId`. + */ + enterFrom(levelId: number): TravelTarget | null { + const portal = this.open + if (portal === null) return null + if (levelId === portal.fromLevelId) { + return { levelId: portal.townLevelId, x: portal.townX, y: portal.townY } + } + if (levelId === portal.townLevelId) { + const target: TravelTarget = { levelId: portal.fromLevelId, x: portal.fromX, y: portal.fromY } + this.open = null + return target + } + return null + } } export { ACT_TOWNS, townLevelForAct } from './acts.ts' + diff --git a/src/render/overlays-meta.ts b/src/render/overlays-meta.ts index 122b343..290aa46 100644 --- a/src/render/overlays-meta.ts +++ b/src/render/overlays-meta.ts @@ -22372,6 +22372,602 @@ export const DEATHSENTRY_EXPLODE_META: OverlayMeta = { ] } +export const TOWN_PORTAL_OP_TR_META: OverlayMeta = { + "name": "town_portal_op_tr", + "celFile": "tptrlitophth", + "width": 512, + "height": 181, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 0, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -23, + "top": -85, + "width": 45, + "height": 90 + }, + "groups": [ + [ + [ + 0, + 0, + 45, + 90, + -23, + -85 + ], + [ + 46, + 0, + 45, + 90, + -23, + -85 + ], + [ + 92, + 0, + 45, + 90, + -23, + -85 + ], + [ + 138, + 0, + 45, + 90, + -23, + -85 + ], + [ + 184, + 0, + 45, + 90, + -23, + -85 + ], + [ + 230, + 0, + 45, + 90, + -23, + -85 + ], + [ + 276, + 0, + 45, + 90, + -23, + -85 + ], + [ + 322, + 0, + 45, + 90, + -23, + -85 + ], + [ + 368, + 0, + 45, + 90, + -23, + -85 + ], + [ + 414, + 0, + 45, + 90, + -23, + -85 + ], + [ + 460, + 0, + 45, + 90, + -23, + -85 + ], + [ + 0, + 91, + 45, + 90, + -23, + -85 + ], + [ + 46, + 91, + 45, + 90, + -23, + -85 + ], + [ + 92, + 91, + 45, + 90, + -23, + -85 + ], + [ + 138, + 91, + 45, + 90, + -23, + -85 + ] + ] + ] +} + +export const TOWN_PORTAL_OP_HD_META: OverlayMeta = { + "name": "town_portal_op_hd", + "celFile": "tphdlitophth", + "width": 1024, + "height": 608, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 3, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -93, + "top": -141, + "width": 188, + "height": 202 + }, + "groups": [ + [ + [ + 0, + 0, + 188, + 202, + -93, + -141 + ], + [ + 189, + 0, + 188, + 202, + -93, + -141 + ], + [ + 378, + 0, + 188, + 202, + -93, + -141 + ], + [ + 567, + 0, + 188, + 202, + -93, + -141 + ], + [ + 756, + 0, + 188, + 202, + -93, + -141 + ], + [ + 0, + 203, + 188, + 202, + -93, + -141 + ], + [ + 189, + 203, + 188, + 202, + -93, + -141 + ], + [ + 378, + 203, + 188, + 202, + -93, + -141 + ], + [ + 567, + 203, + 188, + 202, + -93, + -141 + ], + [ + 756, + 203, + 188, + 202, + -93, + -141 + ], + [ + 0, + 406, + 188, + 202, + -93, + -141 + ], + [ + 189, + 406, + 188, + 202, + -93, + -141 + ], + [ + 378, + 406, + 188, + 202, + -93, + -141 + ], + [ + 567, + 406, + 188, + 202, + -93, + -141 + ], + [ + 756, + 406, + 188, + 202, + -93, + -141 + ] + ] + ] +} + +export const TOWN_PORTAL_ON_TR_META: OverlayMeta = { + "name": "town_portal_on_tr", + "celFile": "tptrlitonhth", + "width": 512, + "height": 181, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 0, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -23, + "top": -85, + "width": 46, + "height": 90 + }, + "groups": [ + [ + [ + 0, + 0, + 46, + 90, + -23, + -85 + ], + [ + 47, + 0, + 46, + 90, + -23, + -85 + ], + [ + 94, + 0, + 46, + 90, + -23, + -85 + ], + [ + 141, + 0, + 46, + 90, + -23, + -85 + ], + [ + 188, + 0, + 46, + 90, + -23, + -85 + ], + [ + 235, + 0, + 46, + 90, + -23, + -85 + ], + [ + 282, + 0, + 46, + 90, + -23, + -85 + ], + [ + 329, + 0, + 46, + 90, + -23, + -85 + ], + [ + 376, + 0, + 46, + 90, + -23, + -85 + ], + [ + 423, + 0, + 46, + 90, + -23, + -85 + ], + [ + 0, + 91, + 46, + 90, + -23, + -85 + ], + [ + 47, + 91, + 46, + 90, + -23, + -85 + ], + [ + 94, + 91, + 46, + 90, + -23, + -85 + ], + [ + 141, + 91, + 46, + 90, + -23, + -85 + ], + [ + 188, + 91, + 46, + 90, + -23, + -85 + ] + ] + ] +} + +export const TOWN_PORTAL_ON_HD_META: OverlayMeta = { + "name": "town_portal_on_hd", + "celFile": "tphdlitonhth", + "width": 1024, + "height": 319, + "directions": 1, + "frames": 15, + "framesPerDirection": 15, + "animRate": 16, + "trans": 3, + "preDraw": false, + "lightRadius": 19, + "lightColor": [ + 64, + 64, + 255 + ], + "box": { + "left": -54, + "top": -120, + "width": 109, + "height": 159 + }, + "groups": [ + [ + [ + 0, + 0, + 109, + 159, + -54, + -120 + ], + [ + 110, + 0, + 109, + 159, + -54, + -120 + ], + [ + 220, + 0, + 109, + 159, + -54, + -120 + ], + [ + 330, + 0, + 109, + 159, + -54, + -120 + ], + [ + 440, + 0, + 109, + 159, + -54, + -120 + ], + [ + 550, + 0, + 109, + 159, + -54, + -120 + ], + [ + 660, + 0, + 109, + 159, + -54, + -120 + ], + [ + 770, + 0, + 109, + 159, + -54, + -120 + ], + [ + 880, + 0, + 109, + 159, + -54, + -120 + ], + [ + 0, + 160, + 109, + 159, + -54, + -120 + ], + [ + 110, + 160, + 109, + 159, + -54, + -120 + ], + [ + 220, + 160, + 109, + 159, + -54, + -120 + ], + [ + 330, + 160, + 109, + 159, + -54, + -120 + ], + [ + 440, + 160, + 109, + 159, + -54, + -120 + ], + [ + 550, + 160, + 109, + 159, + -54, + -120 + ] + ] + ] +} + // Backward compatibility aliases for primary aura constants export const MIGHT_AURA_META: OverlayMeta = MIGHT_FRONT_AURA_META @@ -22613,6 +23209,10 @@ export const ALL_OVERLAY_NAMES: readonly string[] = [ "direwolfcharged", "blade_shield", "deathsentry_explode", + "town_portal_op_tr", + "town_portal_op_hd", + "town_portal_on_tr", + "town_portal_on_hd", ] export const OVERLAY_METAS: Readonly> = { @@ -23223,4 +23823,12 @@ export const OVERLAY_METAS: Readonly> = { "expansion/dethsentry01": DEATHSENTRY_EXPLODE_META, "deathsentry": DEATHSENTRY_EXPLODE_META, "dethsentry01": DEATHSENTRY_EXPLODE_META, + "town_portal_op_tr": TOWN_PORTAL_OP_TR_META, + "tptrlitophth": TOWN_PORTAL_OP_TR_META, + "town_portal_op_hd": TOWN_PORTAL_OP_HD_META, + "tphdlitophth": TOWN_PORTAL_OP_HD_META, + "town_portal_on_tr": TOWN_PORTAL_ON_TR_META, + "tptrlitonhth": TOWN_PORTAL_ON_TR_META, + "town_portal_on_hd": TOWN_PORTAL_ON_HD_META, + "tphdlitonhth": TOWN_PORTAL_ON_HD_META, } diff --git a/src/scene/act-scene.ts b/src/scene/act-scene.ts index 594cce7..12fcafc 100644 --- a/src/scene/act-scene.ts +++ b/src/scene/act-scene.ts @@ -92,7 +92,7 @@ import { KeyboardInput } from '../sim/input.ts' import type { SceneEntrance, SceneWarp, SceneWaypoint } from '../game/level-links.ts' import { SEAM_TRIGGER_SUBTILES, WARP_TRIGGER_SUBTILES } from '../game/level-links.ts' import { FadeOverlay, SEAM_FADE_MS, WARP_FADE_MS, subTileToScene } from './transition.ts' -import { TownPortalSlot, WaypointNetwork, townLevelForAct } from '../game/portal.ts' +import { TownPortalSlot, WaypointNetwork, resolveTownPortalSubTile, townLevelForAct, type OpenPortal } from '../game/portal.ts' import { findMatchingVariant, getDefaultTownVariant, oppositeSide, type Side } from '../game/variants.ts' import { Minimap } from '../ui/minimap.ts' import type { MinimapLevel, MinimapMarker } from '../ui/minimap.ts' @@ -360,6 +360,8 @@ export interface ActSceneState { eliteMultiplier?: EliteMultiplier | undefined /** Dynamic monster re-budget and re-stream method without page reload. */ reloadMonsters?: (options?: { density?: number | string; elite?: number | string }) => Promise | void + /** Active player Town Portal (if open). */ + portal?: OpenPortal | null | undefined } declare global { @@ -374,6 +376,9 @@ declare global { reloadMonsters?: (options?: { density?: number | string; elite?: number | string }) => Promise | void setPlayers?: (count: number, partyCount?: number) => void executeCommand?: (cmd: string) => boolean + castTownPortal?: () => boolean + enterTownPortal?: () => void + getPortal?: () => OpenPortal | null } } } @@ -1521,6 +1526,8 @@ export function getSkillRange( case 62: return 450 case 63: return 0 case 64: return 480 + case 219: + case 220: return 0 default: return 450 } } @@ -1564,6 +1571,8 @@ export function getSkillMana(skillId: number, hudManager?: HudManager | null): n case 57: return 19 case 58: return 5 case 63: return 0 + case 219: + case 220: return 0 default: return 10 } } @@ -1586,6 +1595,9 @@ export function castSkill( hasAmmo?: boolean | undefined waypointNetwork?: any | undefined openStash?: ((stash: any) => void) | undefined + portalSlot?: TownPortalSlot | undefined + onEnterPortal?: (() => void) | undefined + onCastTownPortal?: (() => boolean) | undefined }, ): boolean { const { engine, runtime, hudManager, status, playerAnimator, character } = context @@ -2002,6 +2014,23 @@ export function castSkill( } } + if (context.portalSlot && context.onEnterPortal && runtime.grid) { + const mouth = context.portalSlot.mouthInLevel(runtime.levelId) + if (mouth) { + const portalPos = subTileToScene(mouth.x, mouth.y, runtime.grid) + if ( + Math.hypot(portalPos.x - targetX, portalPos.y - targetY) <= 64 || + Math.hypot(portalPos.x - targetX, (portalPos.y - 40) - targetY) <= 64 + ) { + player.cooldown = 0 + engine.metrics.casts += 1 + status.textContent = '心灵传动进入传送门' + context.onEnterPortal() + return true + } + } + } + // 4. Generic ground cast / feedback player.cooldown = 0 engine.metrics.casts += 1 @@ -2009,6 +2038,18 @@ export function castSkill( return true } + if (skillId === 219 || skillId === 220) { + // Scroll of Town Portal (219) / Book of Town Portal (220) + if (context.onCastTownPortal) { + const ok = context.onCastTownPortal() + if (!ok) return false + player.cooldown = 10 + engine.metrics.casts += 1 + return true + } + return false + } + if (skillId === 59) { // Blizzard (Skill 59): spawn invisible blizzardcenter emitter missile at target coordinates // 1.13c Skills.txt: Param1: 7 (radius subtiles), Param3: 4 (interval ticks), delay: 45 (1.8s cooldown) @@ -3277,6 +3318,7 @@ export type PendingInteraction = | { readonly kind: 'npc'; readonly npc: NpcEntity } | { readonly kind: 'waypoint'; readonly waypoint: SceneWaypoint; readonly worldPos: { readonly x: number; readonly y: number } } | { readonly kind: 'stash'; readonly stash: TownStashEntity } + | { readonly kind: 'portal'; readonly worldPos: { readonly x: number; readonly y: number } } | { readonly kind: 'monster'; readonly monster: Monster; readonly skillId?: number } | { readonly kind: 'ground-item'; readonly item: GroundItemEntity } @@ -3298,6 +3340,9 @@ export interface SceneMouseControllerOptions { readonly status: HTMLElement readonly playerAnimator?: ActorAnimator | undefined readonly getCharacter?: (() => LoadedCharacter | null) | undefined + readonly portalSlot?: TownPortalSlot | undefined + readonly onEnterPortal?: (() => void) | undefined + readonly onCastTownPortal?: (() => boolean) | undefined } /** @@ -3396,10 +3441,13 @@ export class SceneMouseController { readonly status: HTMLElement readonly playerAnimator?: ActorAnimator | undefined readonly getCharacter?: (() => LoadedCharacter | null) | undefined + readonly portalSlot?: TownPortalSlot | undefined + readonly onEnterPortal?: (() => void) | undefined + readonly onCastTownPortal?: (() => boolean) | undefined navTarget: { x: number; y: number } | null = null pendingInteraction: PendingInteraction | null = null - activeClickType: 'none' | 'ground' | 'npc' | 'waypoint' | 'stash' | 'monster' = 'none' + activeClickType: 'none' | 'ground' | 'npc' | 'waypoint' | 'stash' | 'portal' | 'monster' = 'none' isLeftMouseDown = false isRightMouseDown = false lastClientPos: { x: number; y: number } | null = null @@ -3419,6 +3467,9 @@ export class SceneMouseController { this.status = options.status this.playerAnimator = options.playerAnimator this.getCharacter = options.getCharacter + this.portalSlot = options.portalSlot + this.onEnterPortal = options.onEnterPortal + this.onCastTownPortal = options.onCastTownPortal ;(this.engine as any).dialog = null } @@ -3847,6 +3898,30 @@ export class SceneMouseController { return } + // 3b. Check Town Portal: within ~48 px of portal vertical oval [portalPos.y - 80, portalPos.y] + const activePortalMouth = this.portalSlot?.mouthInLevel(runtime.levelId) ?? null + if (activePortalMouth !== null) { + const portalPos = subTileToScene(activePortalMouth.x, activePortalMouth.y, runtime.grid) + const clampedPortalY = Math.max(portalPos.y - 80, Math.min(portalPos.y, worldY)) + const minPortalDist = Math.hypot(portalPos.x - worldX, clampedPortalY - worldY) + if (minPortalDist <= 48) { + this.activeClickType = 'portal' + const distToPlayer = Math.hypot(portalPos.x - player.x, portalPos.y - player.y) + if (distToPlayer <= 80) { // OperateRange = 2 tiles (~80 px) + this.navTarget = null + this.pendingInteraction = null + player.facing = facingOf(portalPos.x - player.x, portalPos.y - player.y) + this.onEnterPortal?.() + } else { + this.pendingInteraction = { kind: 'portal', worldPos: portalPos } + this.navTarget = { x: portalPos.x, y: portalPos.y } + this.lastDist = distToPlayer + this.stuckTicks = 0 + } + return + } + } + // 4. Check Monster: living monster within ~32 px let clickedMonster: Monster | null = null let bestMonDist = 36 @@ -3931,6 +4006,9 @@ export class SceneMouseController { hasAmmo: options?.hasAmmo, waypointNetwork: this.waypointNetwork, openStash: (s: any) => this.openStash(s), + portalSlot: this.portalSlot, + onEnterPortal: this.onEnterPortal, + onCastTownPortal: this.onCastTownPortal, }) } @@ -4053,6 +4131,17 @@ export class SceneMouseController { } else { this.navTarget = { x: stash.x, y: stash.y } } + } else if (this.pendingInteraction.kind === 'portal') { + const { worldPos } = this.pendingInteraction + const dist = Math.hypot(worldPos.x - player.x, worldPos.y - player.y) + if (dist <= 80) { + this.navTarget = null + this.pendingInteraction = null + player.facing = facingOf(worldPos.x - player.x, worldPos.y - player.y) + this.onEnterPortal?.() + } else { + this.navTarget = { x: worldPos.x, y: worldPos.y } + } } else if (this.pendingInteraction.kind === 'monster') { const monster = this.pendingInteraction.monster if (monster.state === 'dead' || monster.hp <= 0) { @@ -4371,13 +4460,25 @@ async function loadRuntimeForLevel( viewport: { width: number; height: number }, charBases: readonly string[], fromSide?: Side, + preferredVariantLabel?: string, ): Promise { const index = await getPackIndex(packBase) if (index === null) return null const candidates = index.levels.filter(entry => entry.levelId === levelId) if (candidates.length === 0) return null const requiredSide = fromSide ? oppositeSide(fromSide) : undefined - const entry = findMatchingVariant(candidates, requiredSide, variantSeed) + let entry: PackIndexEntry | undefined + if (requiredSide === undefined && preferredVariantLabel !== undefined) { + entry = candidates.find( + c => c.label === preferredVariantLabel || c.slug === preferredVariantLabel, + ) + } + if (entry === undefined && requiredSide === undefined && isTownLevel(levelId)) { + entry = getDefaultTownVariant(candidates, candidates[0]!.act) + } + if (entry === undefined) { + entry = findMatchingVariant(candidates, requiredSide, variantSeed) + } if (entry === undefined) return null return await buildPackRuntime(packBase, index, entry, viewport, charBases) } @@ -5884,6 +5985,64 @@ export function drawCastOverlay( renderer.setBlendMode('normal') } +/** + * Render an active Diablo II 1.13c Town Portal (`Objects.txt` ID 59, Token `TP`): + * - Plays 15-frame opening sequence (`OP`: `tptrlitophth` + `tphdlitophth`) at 200/256 * 25 fps (51.2 ms/frame, 768 ms total), + * then loops 15-frame operating sequence (`ON`: `tptrlitonhth` + `tphdlitonhth`). + * - Draws `TR` ground shadow layer with normal blending and `HD` blue vortex layer with additive blending. + * - Falls back to a procedural blue portal vortex oval in unit test / offline environments. + */ +export function drawTownPortal( + renderer: SpriteRenderer, + x: number, + y: number, + elapsedMs: number, + overlayArtMap: ReadonlyMap, +): void { + const frameDurationMs = 51.2 // 1000 / (25 * 200 / 256) + const openDurationMs = 15 * frameDurationMs // 768 ms + const isOpening = elapsedMs < openDurationMs + const trArt = overlayArtMap.get(isOpening ? 'town_portal_op_tr' : 'town_portal_on_tr') + const hdArt = overlayArtMap.get(isOpening ? 'town_portal_op_hd' : 'town_portal_on_hd') + const rawFrameIdx = isOpening + ? Math.min(14, Math.max(0, Math.floor(elapsedMs / frameDurationMs))) + : Math.max(0, Math.floor((elapsedMs - openDurationMs) / frameDurationMs)) % 15 + + let drewSprite = false + if (trArt !== undefined) { + const group = trArt.frames[0] + const frame = group?.[rawFrameIdx] ?? group?.[0] + if (frame !== undefined) { + const drawX = frame.anchorX !== undefined ? x + frame.anchorX : x - frame.width / 2 + const drawY = frame.anchorY !== undefined ? y + frame.anchorY : y - frame.height / 2 + renderer.draw(frame, drawX, drawY, { + atlas: trArt.handle, + blendMode: 'normal', + }) + drewSprite = true + } + } + if (hdArt !== undefined) { + const group = hdArt.frames[0] + const frame = group?.[rawFrameIdx] ?? group?.[0] + if (frame !== undefined) { + const drawX = frame.anchorX !== undefined ? x + frame.anchorX : x - frame.width / 2 + const drawY = frame.anchorY !== undefined ? y + frame.anchorY : y - frame.height / 2 + renderer.draw(frame, drawX, drawY, { + atlas: hdArt.handle, + blendMode: 'additive', + elevationY: Math.max(0, frame.height - 16), + }) + renderer.setBlendMode('normal') + drewSprite = true + } + } + if (!drewSprite) { + renderer.drawSolid(x - 18, y - 82, 36, 82, [0.22, 0.48, 1.0, 0.75], { blendMode: 'additive' }) + renderer.setBlendMode('normal') + } +} + /** Quality colors for ground item highlights and glints. */ export const GROUND_ITEM_QUALITY_COLORS: Record = { normal: [0.88, 0.88, 0.88, 1.0], @@ -6635,6 +6794,83 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st const minimap = new Minimap() const waypointNetwork = new WaypointNetwork() const portalSlot = new TownPortalSlot() + const townVariantByAct = new Map() + if (isTownLevel(runtime.levelId) && runtime.variant) { + townVariantByAct.set(runtime.act, runtime.variant) + } + + /** + * Where the player is, in sub-tiles. + * + * The inverse of the isometric projection: scene pixels back to the grid the + * links are expressed in. + * + * @returns the player's sub-tile. + */ + const playerSubTile = (): { x: number; y: number } => { + const dx = (engine.world.player.x - runtime.grid.originX) / ORTHO_SUB_TILE_WIDTH + const dy = (engine.world.player.y - runtime.grid.originY) / ORTHO_SUB_TILE_HEIGHT + return { x: Math.round((dy + dx) / 2), y: Math.round((dy - dx) / 2) } + } + + /** + * Cast a Town Portal from the current non-town level, placing the wilderness + * mouth on a walkable sub-tile next to the player and the town mouth at the + * authentic 1.13c DS1 Object #33 (`Objects.txt` ID 59) Town Portal Spot. + */ + const castTownPortal = (): boolean => { + if (isTownLevel(runtime.levelId)) { + playInventoryFullFeedback() + showNotification('无法在城镇中开启回城传送门', 2000, status) + return false + } + + const here = playerSubTile() + const candidateOffsets = [ + { dx: 2, dy: -1 }, + { dx: 2, dy: 0 }, + { dx: 0, dy: -2 }, + { dx: -2, dy: 1 }, + { dx: 1, dy: -1 }, + { dx: 0, dy: 0 }, + ] + let fromX = here.x + let fromY = here.y + for (const off of candidateOffsets) { + const cx = here.x + off.dx + const cy = here.y + off.dy + const scenePos = subTileToScene(cx, cy, runtime.grid) + if (!isBlockedAt(runtime.grid, scenePos.x, scenePos.y)) { + fromX = cx + fromY = cy + break + } + } + + const townLevelId = townLevelForAct(runtime.act) + const townSub = resolveTownPortalSubTile( + townLevelId, + townVariantByAct.get(runtime.act), + ) + portalSlot.cast({ + fromLevelId: runtime.levelId, + fromX, + fromY, + townLevelId, + townX: townSub.x, + townY: townSub.y, + createdAtMs: performance.now(), + }) + state.portal = portalSlot.current() + + if (character?.clips?.['sc']) { + playerAnimator.play('sc', character.clips['sc'], { restart: true }) + } + const townNames = getLevelNames(townLevelId) + status.textContent = `已开启返回 ${townNames.nameZh} 的传送门` + return true + } + const hudCanvas = document.querySelector('#d2-hud-canvas') hudManager = hudCanvas !== null ? new HudManager(hudCanvas, { @@ -6644,9 +6880,7 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st onWaypointTeleport: (targetAct, slug, levelId) => { void teleportViaWaypoint(targetAct, slug, levelId) }, - onCastTownPortal: () => { - status.textContent = `已通过回城之书开启返回 ${ACT_NAMES_ZH[runtime.act] ?? '营地'} 的传送门` - }, + onCastTownPortal: () => castTownPortal(), onDropItemToGround: (item) => { const player = engine.world.player const groundItem = engine.dropItem(item, player.x, player.y) @@ -6677,6 +6911,34 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st } } + /** True while a transition is in flight, so nothing triggers a second one. */ + let travelling = false + let lastContactWaypointId: number | null = null + let minimapCache: { key: string; level: MinimapLevel } | null = null + + /** + * Enter the open Town Portal from the current level: + * - Entering from wilderness transitions to town beside the Town Portal and keeps the portal open. + * - Entering from town transitions back to the wilderness mouth and closes the portal. + */ + const enterTownPortal = (): void => { + if (travelling || runtime.source !== 'pack') return + const dest = portalSlot.enterFrom(runtime.levelId) + state.portal = portalSlot.current() + if (dest !== null) { + void travel(dest.levelId, WARP_FADE_MS, { x: dest.x, y: dest.y }) + } + } + + if (typeof window !== 'undefined') { + ;(window as any).__d2webPortalSlot = portalSlot + if (window.__d2webActScene) { + window.__d2webActScene.castTownPortal = castTownPortal + window.__d2webActScene.enterTownPortal = enterTownPortal + window.__d2webActScene.getPortal = () => portalSlot.current() + } + } + const mouseController = new SceneMouseController({ canvas, engine, @@ -6688,6 +6950,9 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st status, playerAnimator, getCharacter: () => character, + portalSlot, + onEnterPortal: enterTownPortal, + onCastTownPortal: castTownPortal, }) mouseController.attach() if (groundLabelOverlay !== null) { @@ -6702,11 +6967,6 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st (window as any).__d2webMouseController = mouseController } - /** True while a transition is in flight, so nothing triggers a second one. */ - let travelling = false - let lastContactWaypointId: number | null = null - let minimapCache: { key: string; level: MinimapLevel } | null = null - /** * Tell the waypoint network about whatever level is loaded. * @@ -6726,20 +6986,6 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st } registerWaypoints(runtime) - /** - * Where the player is, in sub-tiles. - * - * The inverse of the isometric projection: scene pixels back to the grid the - * links are expressed in. - * - * @returns the player's sub-tile. - */ - const playerSubTile = (): { x: number; y: number } => { - const dx = (engine.world.player.x - runtime.grid.originX) / ORTHO_SUB_TILE_WIDTH - const dy = (engine.world.player.y - runtime.grid.originY) / ORTHO_SUB_TILE_HEIGHT - return { x: Math.round((dy + dx) / 2), y: Math.round((dy - dx) / 2) } - } - /** * Replace the level under the running loop. * @@ -6760,6 +7006,9 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st monsterArtMap = new Map() runtime = next + if (isTownLevel(next.levelId) && next.variant) { + townVariantByAct.set(next.act, next.variant) + } floorBounds = buildBounds(next.floors) shadowBounds = buildBounds(next.shadows ?? []) wallBounds = buildBounds(next.walls) @@ -6934,6 +7183,7 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st { width: canvas.width, height: canvas.height }, runtime.charBases, fromSide, + isTownLevel(toLevelId) ? townVariantByAct.get(runtime.act) : undefined, ) if (next === null) { status.textContent = `资源包里没有关卡 ${String(toLevelId)}。` @@ -6947,13 +7197,25 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st // that no edge describes. const back = next.entrances.find(entrance => entrance.toLevelId === fromLevelId) ?? next.warps.find(warp => warp.toLevelId === fromLevelId) - const landing = override + const rawLanding = override ?? (back === undefined ? { x: Math.floor(next.grid.cellsX * SUB_TILES_PER_TILE / 2), y: Math.floor(next.grid.cellsY * SUB_TILES_PER_TILE / 2), } : { x: back.arriveX, y: back.arriveY }) + let landing = rawLanding + const activeMouthInNext = portalSlot.mouthInLevel(next.levelId) + if ( + activeMouthInNext !== null && + activeMouthInNext.x === rawLanding.x && + activeMouthInNext.y === rawLanding.y + ) { + const besidePos = subTileToScene(rawLanding.x + 1, rawLanding.y + 1, next.grid) + if (!isBlockedAt(next.grid, besidePos.x, besidePos.y)) { + landing = { x: rawLanding.x + 1, y: rawLanding.y + 1 } + } + } await swapLevel(next, landing) preloadRemaining(next, renderer) } catch (err) { @@ -7058,14 +7320,14 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st const wantsUse = input.takeUse() if (wantsUse) { - const portalTarget = portalSlot.otherEnd(runtime.levelId) for (const warp of runtime.warps) { if (!near(warp.x, warp.y, WARP_TRIGGER_SUBTILES)) continue void travel(warp.toLevelId, WARP_FADE_MS) return } - if (portalTarget !== null) { - void travel(portalTarget.levelId, WARP_FADE_MS, { x: portalTarget.x, y: portalTarget.y }) + const activeMouth = portalSlot.mouthInLevel(runtime.levelId) + if (activeMouth !== null && near(activeMouth.x, activeMouth.y, WARP_TRIGGER_SUBTILES)) { + enterTownPortal() return } } @@ -7103,19 +7365,7 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st } if (input.takePortal()) { - const townLevelId = townLevelForAct(runtime.act) - if (runtime.levelId !== townLevelId) { - const townSite = waypointNetwork.destinations().find(site => site.levelId === townLevelId) - portalSlot.cast({ - fromLevelId: runtime.levelId, - fromX: here.x, - fromY: here.y, - townLevelId, - townX: townSite?.x ?? here.x, - townY: townSite?.y ?? here.y, - }) - status.textContent = `已打开回城门(${runtime.level})。走到原地按 G 返回。` - } + castTownPortal() } } @@ -7437,6 +7687,20 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st } } + const activePortalMouthForLight = portalSlot.mouthInLevel(runtime.levelId) + if (activePortalMouthForLight !== null) { + const portalFlicker = (Math.sin(engine.world.tick * 0.35) * 1.5) | 0 + lightGrid.addLight({ + subTileX: activePortalMouthForLight.x, + subTileY: activePortalMouthForLight.y, + radius: 19 + portalFlicker, + intensity: 235, + red: 64, + green: 110, + blue: 255, + }) + } + const effectiveAmbIntensity = rawIntensity > 0 ? rawIntensity : 5 const effR = overrideAmb !== undefined ? overrideAmb.red : (rawIntensity > 0 ? environment.currentRed : 185) const effG = overrideAmb !== undefined ? overrideAmb.green : (rawIntensity > 0 ? environment.currentGreen : 175) @@ -7769,6 +8033,18 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st ) } + const activePortalMouth = portalSlot.mouthInLevel(runtime.levelId) + const activePortalPos = + activePortalMouth !== null + ? subTileToScene(activePortalMouth.x, activePortalMouth.y, runtime.grid) + : null + if (activePortalMouth !== null && activePortalPos !== null) { + const portalElapsedMs = Math.max(0, renderStarted - (activePortalMouth.createdAtMs ?? 0)) + pushEntity(activePortalPos.x, activePortalPos.y, () => { + drawTownPortal(renderer, activePortalPos.x, activePortalPos.y, portalElapsedMs, overlayArtMap) + }) + } + const groundSimTime = (engine.world.tick + ((engine.world as any).alpha ?? 0)) * 40 for (const gItem of engine.groundItems.all) { pushEntity(gItem.x, gItem.y, () => { @@ -7857,12 +8133,42 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st labelsContainer.appendChild(label) } if (label.textContent !== npc.def.name) label.textContent = npc.def.name + label.style.color = '#c8a15a' label.style.left = `${domX}px` label.style.top = `${domY - 2}px` label.style.fontSize = fontSizePx label.hidden = false labelCount += 1 } + + if (activePortalMouth !== null && activePortalPos !== null) { + const topX = activePortalPos.x + const topY = activePortalPos.y - 94 + const domX = rect.left + rect.width * 0.5 + (topX - camX) * camera.zoom * scaleX + const domY = rect.top + rect.height * 0.5 + (topY - camY) * camera.zoom * scaleY + if (domX > -100 && domX < rect.width + 100 && domY > -100 && domY < rect.height + 100) { + let label = labelPool[labelCount] + if (label === undefined) { + label = document.createElement('div') + label.style.position = 'absolute' + label.style.transform = 'translate(-50%, -100%)' + label.style.textShadow = '1px 1px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000' + label.style.whiteSpace = 'nowrap' + label.style.pointerEvents = 'none' + labelPool.push(label) + labelsContainer.appendChild(label) + } + const portalLabelText = `传送门 -> ${getLevelNames(activePortalMouth.toLevelId).nameZh}` + if (label.textContent !== portalLabelText) label.textContent = portalLabelText + label.style.color = '#6cb4ff' + label.style.left = `${domX}px` + label.style.top = `${domY - 2}px` + label.style.fontSize = fontSizePx + label.hidden = false + labelCount += 1 + } + } + for (let index = labelCount; index < labelPool.length; index += 1) labelPool[index]!.hidden = true } @@ -7899,6 +8205,7 @@ async function runScene(initialRuntime: MapRuntime, renderer: SpriteRenderer, st } } + state.portal = portalSlot.current() state.drawCalls = renderer.drawCalls state.quadsDrawn = renderer.quadsSubmitted state.culledDraws = culledDraws diff --git a/src/ui/hud-manager.ts b/src/ui/hud-manager.ts index 93004bb..27d9bfd 100644 --- a/src/ui/hud-manager.ts +++ b/src/ui/hud-manager.ts @@ -302,7 +302,7 @@ export class HudManager { private readonly callbacks: { onToggleAutomap: () => void onWaypointTeleport: (act: number, slug: string, levelId?: number) => void - onCastTownPortal?: () => void + onCastTownPortal?: (source?: 'tbk' | 'tsc', item?: UiInventoryItem) => boolean | void onDropItemToGround?: (item: UiInventoryItem, mousePos?: { x: number; y: number }) => void onDropGoldToGround?: (amount: number, mousePos?: { x: number; y: number }) => void }, @@ -873,7 +873,7 @@ export class HudManager { this.callbacks.onWaypointTeleport(act, slug, levelId) }, onOpenCube: () => this.toggleLeftPanel('cube'), - onCastTownPortal: () => this.callbacks.onCastTownPortal?.(), + onCastTownPortal: (source, item) => this.callbacks.onCastTownPortal?.(source, item), inventory: this.inventory, isShiftClick: e.shiftKey, isRightClick: e.button === 2, @@ -973,7 +973,7 @@ export class HudManager { pt.y, { onOpenCube: () => this.toggleLeftPanel('cube'), - onCastTownPortal: () => this.callbacks.onCastTownPortal?.(), + onCastTownPortal: (source, item) => this.callbacks.onCastTownPortal?.(source, item), onDropGold: (amt) => { const dropped = this.inventory.dropGold(amt) if (dropped > 0) { @@ -981,7 +981,7 @@ export class HudManager { } }, }, - e.button as 0 | 2, + e.button === 2 ? 2 : 0, { stashItems: this.worldPanels.stashItems, cubeItems: this.worldPanels.cubeItems, diff --git a/src/ui/inventory.ts b/src/ui/inventory.ts index cd0daf1..671d5ae 100644 --- a/src/ui/inventory.ts +++ b/src/ui/inventory.ts @@ -1022,6 +1022,11 @@ export function setTomeQuantity(item: UiInventoryItem, newQty: number): UiInvent return item } +export function withTomeQuantity(item: UiInventoryItem, quantity: number): UiInventoryItem { + const cloned: UiInventoryItem = { ...item, stats: [...item.stats] } + return setTomeQuantity(cloned, quantity) +} + export function isUiItemUnidentified(item: UiInventoryItem): boolean { return Boolean( item.identified === false || @@ -1357,7 +1362,7 @@ export class InventoryPanel { containerList: GridPlacement[], callbacks?: { onOpenCube?: () => void - onCastTownPortal?: () => void + onCastTownPortal?: (source?: 'tbk' | 'tsc', item?: UiInventoryItem) => boolean | void }, ): boolean { if (this.cursorItem !== null) return false @@ -1369,19 +1374,26 @@ export class InventoryPanel { if (code === 'tbk') { const qty = getTomeQuantity(placed.item) if (qty <= 0) return false - setTomeQuantity(placed.item, qty - 1) - callbacks?.onCastTownPortal?.() + const castOk = callbacks?.onCastTownPortal?.('tbk', placed.item) + if (castOk !== false) { + setTomeQuantity(placed.item, qty - 1) + } return true } if (code === 'tsc') { - const qty = placed.item.quantity ?? placed.item.rawItem?.quantity ?? 1 - if (qty > 1) { - setTomeQuantity(placed.item, qty - 1) - } else { - const idx = containerList.indexOf(placed) - if (idx !== -1) containerList.splice(idx, 1) + const castOk = callbacks?.onCastTownPortal?.('tsc', placed.item) + if (castOk !== false) { + const qty = placed.item.quantity ?? placed.item.rawItem?.quantity ?? 1 + if (qty > 1) { + setTomeQuantity(placed.item, qty - 1) + } else { + const idx = containerList.indexOf(placed) + if (idx !== -1) containerList.splice(idx, 1) + if (this.hoveredItem?.item.id === placed.item.id) { + this.hoveredItem = null + } + } } - callbacks?.onCastTownPortal?.() return true } if (code === 'ibk' || code === 'isc') { @@ -1443,7 +1455,7 @@ export class InventoryPanel { logicalY: number, callbacks?: { onOpenCube?: () => void - onCastTownPortal?: () => void + onCastTownPortal?: (source?: 'tbk' | 'tsc', item?: UiInventoryItem) => boolean | void onDropGold?: (amount: number) => void }, button: 0 | 2 = 0, diff --git a/src/ui/world-panels.ts b/src/ui/world-panels.ts index 676d32a..8b42ecd 100644 --- a/src/ui/world-panels.ts +++ b/src/ui/world-panels.ts @@ -1477,7 +1477,7 @@ export class WorldPanelsHud { onClose: () => void onWaypointTeleport: (act: number, slug: string, levelId: number) => void onOpenCube?: () => void - onCastTownPortal?: () => void + onCastTownPortal?: (source?: 'tbk' | 'tsc', item?: UiInventoryItem) => boolean | void inventory?: InventoryPanel isShiftClick?: boolean isRightClick?: boolean @@ -1581,7 +1581,7 @@ export class WorldPanelsHud { if (hit && isUsableRightClickItem(hit.item.code)) { callbacks.inventory.usePlacedItemByRightClick(hit, 'cube', this.cubeItems, { onOpenCube: () => callbacks.onOpenCube?.(), - onCastTownPortal: () => callbacks.onCastTownPortal?.(), + onCastTownPortal: (source, item) => callbacks.onCastTownPortal?.(source, item), }) return true } @@ -1671,7 +1671,7 @@ export class WorldPanelsHud { if (hit && isUsableRightClickItem(hit.item.code)) { callbacks.inventory.usePlacedItemByRightClick(hit, 'stash', this.stashItems, { onOpenCube: () => callbacks.onOpenCube?.(), - onCastTownPortal: () => callbacks.onCastTownPortal?.(), + onCastTownPortal: (source, item) => callbacks.onCastTownPortal?.(source, item), }) return true } diff --git a/tests/town-portal.test.ts b/tests/town-portal.test.ts new file mode 100644 index 0000000..601ab16 --- /dev/null +++ b/tests/town-portal.test.ts @@ -0,0 +1,279 @@ +/** + * Unit & Parity Tests for Diablo II v1.13c Tome / Scroll of Town Portal & Town Portal Lifecycle (Issue #394). + */ + +import { describe, expect, it, vi } from 'vitest' +import { existsSync, readFileSync } from 'node:fs' +import { join } from 'node:path' +import { + TownPortalSlot, + resolveTownPortalSubTile, + TOWN_PORTAL_SUBTILES_BY_VARIANT, + DEFAULT_TOWN_PORTAL_SUBTILES_BY_LEVEL, +} from '../src/game/portal.ts' +import { + InventoryPanel, + INV_GRID_ORIGIN, + STARTER_BAG_ITEMS, + getTomeQuantity, + withTomeQuantity, +} from '../src/ui/inventory.ts' +import { createStarterBagForClass } from '../src/game/class-starter-profiles.ts' +import { OVERLAY_METAS } from '../src/render/overlays-meta.ts' + +describe('Issue #394: Diablo II v1.13c Town Portal & Tome/Scroll of Town Portal', () => { + it('resolves exact 1.13c DS1 Type-2 Object #33 (Objects.txt ID 59) sub-tiles for all 9 town presets across Acts 1..5', () => { + // Act 1 Rogue Encampment variants (TownN1, TownE1, TownS1, TownW1) + expect(resolveTownPortalSubTile(1, '1-act-1-town-townn1')).toEqual({ x: 153, y: 73 }) + expect(resolveTownPortalSubTile(1, '1-act-1-town-towne1')).toEqual({ x: 173, y: 103 }) + expect(resolveTownPortalSubTile(1, '1-act-1-town-towns1')).toEqual({ x: 153, y: 158 }) + expect(resolveTownPortalSubTile(1, '1-act-1-town-townw1')).toEqual({ x: 83, y: 128 }) + // Default Act 1 town (TownS1 south exit to Blood Moor) + expect(resolveTownPortalSubTile(1)).toEqual({ x: 153, y: 158 }) + + // Act 2 Lut Gholein (LutN, LutW) + expect(resolveTownPortalSubTile(40, '40-act-2-town-lutn')).toEqual({ x: 178, y: 53 }) + expect(resolveTownPortalSubTile(40, '40-act-2-town-lutw')).toEqual({ x: 178, y: 53 }) + expect(resolveTownPortalSubTile(40)).toEqual({ x: 178, y: 53 }) + + // Act 3 Kurast Docks (DockTown3) + expect(resolveTownPortalSubTile(75, '75-act-3-town-docktown3')).toEqual({ x: 158, y: 68 }) + expect(resolveTownPortalSubTile(75)).toEqual({ x: 158, y: 68 }) + + // Act 4 The Pandemonium Fortress (Fortress) + expect(resolveTownPortalSubTile(103, '103-act-4-town-fortress')).toEqual({ x: 48, y: 43 }) + expect(resolveTownPortalSubTile(103)).toEqual({ x: 48, y: 43 }) + + // Act 5 Harrogath (townWest) + expect(resolveTownPortalSubTile(109, '109-act-5-town-townwest')).toEqual({ x: 98, y: 23 }) + expect(resolveTownPortalSubTile(109)).toEqual({ x: 98, y: 23 }) + + // Fail-fast on non-town level ID + expect(() => resolveTownPortalSubTile(2)).toThrow(/invalid town levelId/) + expect(Object.keys(TOWN_PORTAL_SUBTILES_BY_VARIANT)).toHaveLength(9) + expect(Object.keys(DEFAULT_TOWN_PORTAL_SUBTILES_BY_LEVEL)).toHaveLength(5) + }) + + it('verifies all 9 town portal sub-tiles land inside valid bounds of baked town preset scenes', () => { + const variantPaths: Array<{ act: number; variant: string; expected: { x: number; y: number } }> = [ + { act: 1, variant: '1-act-1-town-townn1', expected: { x: 153, y: 73 } }, + { act: 1, variant: '1-act-1-town-towne1', expected: { x: 173, y: 103 } }, + { act: 1, variant: '1-act-1-town-towns1', expected: { x: 153, y: 158 } }, + { act: 1, variant: '1-act-1-town-townw1', expected: { x: 83, y: 128 } }, + { act: 2, variant: '40-act-2-town-lutn', expected: { x: 178, y: 53 } }, + { act: 2, variant: '40-act-2-town-lutw', expected: { x: 178, y: 53 } }, + { act: 3, variant: '75-act-3-town-docktown3', expected: { x: 158, y: 68 } }, + { act: 4, variant: '103-act-4-town-fortress', expected: { x: 48, y: 43 } }, + { act: 5, variant: '109-act-5-town-townwest', expected: { x: 98, y: 23 } }, + ] + + for (const { act, variant, expected } of variantPaths) { + const scenePath = join(process.cwd(), 'samples', 'd2-packs', `act${act}`, variant, 'scene.json') + if (!existsSync(scenePath)) continue + const scene = JSON.parse(readFileSync(scenePath, 'utf8')) as { + cellsX: number + cellsY: number + } + const gridW = scene.cellsX * 5 + const gridH = scene.cellsY * 5 + expect(expected.x).toBeGreaterThanOrEqual(0) + expect(expected.x).toBeLessThan(gridW) + expect(expected.y).toBeGreaterThanOrEqual(0) + expect(expected.y).toBeLessThan(gridH) + } + }) + + it('manages TownPortalSlot two-way lifecycle (wilderness -> town keeps portal open; town -> wilderness closes portal per ObjMode.cpp:3245)', () => { + const slot = new TownPortalSlot() + expect(slot.current()).toBeNull() + expect(slot.mouthInLevel(2)).toBeNull() + expect(slot.mouthInLevel(1)).toBeNull() + + slot.cast({ + fromLevelId: 2, + fromX: 80, + fromY: 95, + townLevelId: 1, + townX: 153, + townY: 158, + createdAtMs: 1234, + }) + + // Both wilderness (2) and town (1) mouths are visible + expect(slot.mouthInLevel(2)).toEqual({ + x: 80, + y: 95, + toLevelId: 1, + isTownMouth: false, + createdAtMs: 1234, + }) + expect(slot.mouthInLevel(1)).toEqual({ + x: 153, + y: 158, + toLevelId: 2, + isTownMouth: true, + createdAtMs: 1234, + }) + expect(slot.mouthInLevel(3)).toBeNull() + + // 1. Entering from wilderness (level 2) transports to town (level 1) and keeps the portal open + const toTown = slot.enterFrom(2) + expect(toTown).toEqual({ levelId: 1, x: 153, y: 158 }) + expect(slot.current()).not.toBeNull() + expect(slot.mouthInLevel(1)).not.toBeNull() + + // 2. Entering from town (level 1) transports back to wilderness (level 2) and closes the portal + const backToField = slot.enterFrom(1) + expect(backToField).toEqual({ levelId: 2, x: 80, y: 95 }) + expect(slot.current()).toBeNull() + expect(slot.mouthInLevel(1)).toBeNull() + expect(slot.mouthInLevel(2)).toBeNull() + }) + + it('initializes starter Tome of Town Portal (tbk) and Tome of Identify (ibk) with 20 charges across all classes', () => { + const starterTbk = STARTER_BAG_ITEMS.find(p => p.item.code === 'tbk') + const starterIbk = STARTER_BAG_ITEMS.find(p => p.item.code === 'ibk') + expect(starterTbk?.item.quantity).toBe(20) + expect(starterIbk?.item.quantity).toBe(20) + expect(getTomeQuantity(starterTbk!.item)).toBe(20) + + for (const cls of ['sor', 'nec', 'pal', 'bar', 'ama', 'dru', 'ass'] as const) { + const bag = createStarterBagForClass(cls) + const tbk = bag.find(p => p.item.code === 'tbk') + const ibk = bag.find(p => p.item.code === 'ibk') + expect(tbk?.item.quantity).toBe(20) + expect(ibk?.item.quantity).toBe(20) + } + }) + + it('handles right-clicking tbk / tsc to cast Town Portal and left-clicking tsc onto tbk to refill charges', () => { + const inv = new InventoryPanel() + inv.visible = true + const tbkPlacement = inv.gridItems.find(p => p.item.code === 'tbk')! + expect(tbkPlacement).toBeDefined() + expect(getTomeQuantity(tbkPlacement.item)).toBe(20) + + // Compute pixel coordinates inside the tbk cell at (col=6, row=2) + const tbkClickX = INV_GRID_ORIGIN.x + tbkPlacement.col * INV_GRID_ORIGIN.cellPx + 10 + const tbkClickY = INV_GRID_ORIGIN.y + tbkPlacement.row * INV_GRID_ORIGIN.cellPx + 10 + + // 1. Right-click tbk in town (onCastTownPortal returns false) -> does NOT decrement quantity + const castBlocked = vi.fn(() => false) + expect( + inv.handleClick( + tbkClickX, + tbkClickY, + { onOpenCube: () => {}, onCastTownPortal: castBlocked }, + 2, + ), + ).toBe(true) + expect(castBlocked).toHaveBeenCalledTimes(1) + expect(getTomeQuantity(inv.gridItems.find(p => p.item.code === 'tbk')!.item)).toBe(20) + + // 2. Right-click tbk in wilderness (onCastTownPortal returns true) -> decrements quantity from 20 to 19 + const castOk = vi.fn(() => true) + expect( + inv.handleClick( + tbkClickX, + tbkClickY, + { onOpenCube: () => {}, onCastTownPortal: castOk }, + 2, + ), + ).toBe(true) + expect(castOk).toHaveBeenCalledWith('tbk', expect.objectContaining({ code: 'tbk' })) + expect(getTomeQuantity(inv.gridItems.find(p => p.item.code === 'tbk')!.item)).toBe(19) + + // 3. Left-click a Scroll of Town Portal (tsc) onto tbk -> refills quantity from 19 back to 20 + inv.cursorItem = { + id: 'scroll_tp_1', + code: 'tsc', + name: 'Scroll of Town Portal', + nameZh: '回城卷轴', + baseNameZh: '回城卷轴', + quality: 'normal', + invFile: 'invscrl', + invWidth: 1, + invHeight: 1, + allowedSlots: [], + stats: [], + } + expect(inv.clickGridCell(tbkPlacement.col, tbkPlacement.row)).toBe(true) + expect(inv.cursorItem).toBeNull() + expect(getTomeQuantity(inv.gridItems.find(p => p.item.code === 'tbk')!.item)).toBe(20) + + // 4. Place a standalone Scroll of Town Portal (tsc) into free cell (7, 0) and right-click it + inv.gridItems.push({ + col: 7, + row: 0, + item: { + id: 'scroll_tp_2', + code: 'tsc', + name: 'Scroll of Town Portal', + nameZh: '回城卷轴', + baseNameZh: '回城卷轴', + quality: 'normal', + invFile: 'invscrl', + invWidth: 1, + invHeight: 1, + allowedSlots: [], + stats: [], + }, + }) + const tscClickX = INV_GRID_ORIGIN.x + 7 * INV_GRID_ORIGIN.cellPx + 10 + const tscClickY = INV_GRID_ORIGIN.y + 0 * INV_GRID_ORIGIN.cellPx + 10 + + // Right-click tsc when blocked (in town) -> scroll stays in inventory + expect( + inv.handleClick( + tscClickX, + tscClickY, + { onOpenCube: () => {}, onCastTownPortal: () => false }, + 2, + ), + ).toBe(true) + expect(inv.gridItems.some(p => p.item.id === 'scroll_tp_2')).toBe(true) + + // Right-click tsc in wilderness -> scroll is consumed and removed from inventory + expect( + inv.handleClick( + tscClickX, + tscClickY, + { onOpenCube: () => {}, onCastTownPortal: () => true }, + 2, + ), + ).toBe(true) + expect(inv.gridItems.some(p => p.item.id === 'scroll_tp_2')).toBe(false) + + // 5. Empty tome (0 charges) cannot cast Town Portal, but stays in inventory + const tbkIdx = inv.gridItems.findIndex(p => p.item.code === 'tbk') + inv.gridItems[tbkIdx] = { + ...inv.gridItems[tbkIdx]!, + item: withTomeQuantity(inv.gridItems[tbkIdx]!.item, 0), + } + const castWhenEmpty = vi.fn(() => true) + expect( + inv.handleClick( + tbkClickX, + tbkClickY, + { onOpenCube: () => {}, onCastTownPortal: castWhenEmpty }, + 2, + ), + ).toBe(false) + expect(castWhenEmpty).not.toHaveBeenCalled() + expect(inv.gridItems.some(p => p.item.code === 'tbk')).toBe(true) + }) + + it('bakes authentic Town Portal DCC overlays (OP 15-frame opening + ON 15-frame loop, TR + HD layers)', () => { + for (const key of ['town_portal_op_tr', 'town_portal_op_hd', 'town_portal_on_tr', 'town_portal_on_hd'] as const) { + const meta = OVERLAY_METAS[key] + expect(meta, `Missing OVERLAY_METAS[${key}]`).toBeDefined() + expect(meta!.framesPerDirection).toBe(15) + expect(existsSync(join(process.cwd(), 'public', 'overlays', `${key}.png`))).toBe(true) + expect(existsSync(join(process.cwd(), 'public', 'overlays', `${key}.json`))).toBe(true) + } + expect(OVERLAY_METAS.town_portal_op_tr!.trans).toBe(0) + expect(OVERLAY_METAS.town_portal_op_hd!.trans).toBe(3) + expect(OVERLAY_METAS.town_portal_on_tr!.trans).toBe(0) + expect(OVERLAY_METAS.town_portal_on_hd!.trans).toBe(3) + }) +})