Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 99 additions & 6 deletions docs/PC.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ darkchronicle [options]
| `--frames N` | exit with status 0 after frame N of the main loop. N is a positive integer |
| `--screenshot PATH` | with `--frames`: write the last frame to PATH as a PNG on exit. A failed write exits with status 1 |
| `--screenshot-display N` | with `--screenshot`: also write N interpolated display frames of that frame, as `<stem>-display-<k>.png` for k = 0 to N-1 |
| `--screenshot-fps` | with `--screenshot`: draw the FPS counter into the image, from a presented frame at window size. With `--offscreen`, nothing is presented: the image is read back from the display image instead |
| `--screenshot-fps` | with `--screenshot`: draw the FPS counter and any menu pointer into the image, from a presented frame at window size. With `--offscreen`, nothing is presented: the image is read back from the display image instead |
| `--input SCRIPT` | drive the pads from an input script at start-up. A bad script exits with status 2 |
| `--display-per-tick N` | also render N interpolated display frames per clock tick, discarded. N is a positive integer |
| `--show-fps` | draw the FPS counter on presented frames, headless too |
Expand Down Expand Up @@ -652,9 +652,15 @@ Continue, a file-row click and its confirmation using a copied flat-save fixture
`title-mouse-newgame.input` clicks New Game and reaches costume selection.
File-list clicks wait through the retail cursor-settling delay before confirming.

Shops support hovering and clicking the goods list and bag grid. The wheel moves
through goods or bag rows; in a buy/sell quantity prompt it changes the quantity
within the game's limits. The quantity arrows, number panel, and localized Quit
Shops support hovering and clicking the goods list and bag grid. The wheel acts
on the pane under the pointer: a goods list or bag longer than its window scrolls
one row a notch with the retail eased scroll, stopping at its ends, and the cursor
takes the entry that settles under the pointer, or stays in view; a list that
fits moves its cursor a row. An empty goods list ignores the wheel and the bag
keeps the cursor, as it does for the D-pad. Rows still sliding out of the window
cannot be hovered; `tools/input/shop-mouse-wheel.input` replays both panes at 1920x1080.
In a buy/sell quantity prompt the wheel changes the quantity within the game's
limits. The quantity arrows, number panel, and localized Quit
button accept clicks, and right click cancels. Item popups, stat grids, the ITEM
page and PC SETTINGS use the shared pointer adapters described below. Some
secondary destination screens still retain only their existing controls.
Expand All @@ -667,6 +673,66 @@ pointer immediately. Ordinary dialogue choices share the message adapter;
the rendered confirmation replays and drawn-message unit tests cover that input
path, but campaign dialogue choices still need a dedicated replay.

Hover and the wheel play the menu's retail cursor-move sound once for each
change of its cursor, never while the target stays the same. Where the mouse
moves a cursor through the retail key step (`MenuMouseMove`, a synthesized
D-pad press, or a cursor the step compares after the hook: the root menu, file
lists, Options rows, Help, the floor map, message choices and the ITEM page's
bag and panels), that step plays it. Adapters that set a cursor themselves call
`MenuMouseCursorSound`, which plays at most once a tick: shops, item popups,
the title menu, Make, Monster Transform, Character portraits and Cedric's
board, Options choices, the ITEM page's command and build-up lists, and a move
to the same index on another ITEM panel. A shop wheel notch or arrow click
that changes the pane or leaves Quit also presses Up or Down. The retail step
sounds that press only if it moves, so at a list end or quantity limit the
shop adapter sounds the change instead. Fishing rod stats are the ITEM
cursor, so only the retail check sounds them. PC SETTINGS rows stay silent, as
they are with keys.

### Character, Options and Help mouse

On the Character page, hovering a shown portrait (Max, Monica, the Ridepod,
Monster Transform or the travelling townsperson) moves the retail cursor there,
and clicking it confirms; a click beside the portraits does nothing. While a
character change loads, left clicks do nothing. The change question, the
townsperson's View Status/Send back question, their commands and their
questions take clicks on their drawn choices; when a question opens over a
list that still draws its cursor, the newest window takes the mouse. On
Cedric's repair board, hover and the wheel select an item and only a click on
an item confirms, so a stray click cannot spend his points. Waits that take
any button (the opening, the townsperson's speech) still take any click.

Retail mirrors the hand to point left at Max. The mouse pointer is never
mirrored: the shared pointer already kept the hotspot on the fingertip in either
facing, but a hand whose body jumps across the hotspot between neighbouring
portraits reads as pointing somewhere else, so it keeps its usual facing on
every target.

On the retail Options page, hovering a row's label moves the row cursor and keeps
its choice; hovering a choice button also moves the choice. Clicking a button
selects that setting. The PC SETTINGS label opens that page on click.

In Help, hovering an entry moves the cursor and a click opens it. On an entry's
picture pages the wheel turns pages (down for the next) through the retail
Left/Right keys; a click turns to the next page and right click returns, as Cross
and Circle do. Movies keep their retail controls. Keyboard and controller input
is unchanged on all three pages.

The wheel follows one rule on these pages: in a list longer than its window,
each notch scrolls the list one row and the cursor takes the row that comes under
the pointer, or stays in view (`MenuMouseScroll`; the ITEM page's bag scrolls the
same way, as do the shop's goods list and bag). Elsewhere it moves the cursor,
as in the root menu; the
Character page's portrait map is not a list, so the wheel does nothing there. Options and
Help rows are hit where they are drawn while the list eases to a new scroll, and
only inside the list's scissor (`clip0`): a row sliding under the footer cannot
be clicked, and a visible row above the new scroll still can.

`tools/input/character-mouse.input`, `character-mouse-cedric.input`, `options-mouse.input` (`--jump town:10`)
and `help-mouse.input` (`--jump dungeon:0:1`) replay these at `--window 1920x1080`
with `--fast-load`; their comments give capture frames. `--screenshot-fps`
captures include the menu pointer.

### Mouse follow camera

Mouse motion directly turns the active walking camera around the character. It
Expand Down Expand Up @@ -749,7 +815,8 @@ the mouse. A short click opens commands on release. Swapped items return to the
original slot through the retail return animation. Dropping outside a target or
pressing Mouse2 returns the held item; it does not discard it. Equipment, use,
stack limits and refusal checks remain the game's own. Wheel notches over the
grid scroll rows, stopping at the bag's ends.
grid scroll one row each, stopping at the bag's ends, with the board's retail
eased scroll; the cell that settles under the pointer is selected.

The pointer starts at the retail selection when the mouse takes over. Controller
or keyboard button input returns control to the retail cursor. Mouse counts are
Expand All @@ -769,6 +836,32 @@ outside the menu (1550). `item-menu-mouse-dungeon.input` reaches the dungeon's
Item page and opens Bread's commands by frame 2850. These two scripts also use
1280x720; scale `mouse:dx,dy` counts with the window dimensions for other sizes.

### Make and Monster Transform mouse

On the Make menu, hovering an invention card or a cell of the item board moves
the retail cursor there; hovering the other pane brings it forward as Left and
Right do. Where the panes overlap, the pane in front keeps the pointer. Mouse1
on a card or cell confirms it; a click that brings the other pane forward only
selects. Mouse2 backs out like Circle, and clicks on the background confirm
nothing. The wheel moves the card cursor one row per notch, or scrolls the item
board one row with its retail eased scroll. On the quantity board, hovering Yes
or No selects it, the arrows and the wheel change the count, and Mouse1 on Yes,
No or the count confirms. Result and error messages accept a click. The idea
board, notebook and album pages have no pointer targets: Mouse1 there does
nothing and Mouse2 backs out.

On the Monster Transform screen, hovering a badge selects it and updates the
preview, Mouse1 opens its commands, and the wheel moves one row of badges.
Command, form and Yes/No lists use the shared message choices; the class-change
list accepts hover and click. On a badge's status page the wheel steps through
its forms like L1 and R1, and Mouse1 does nothing. Mouse2 backs out of each
step and closes the box.

The adapters are `port/src/menu_mouse_make.cpp` and `menu_mouse_monster.cpp`;
`MenuMouseMake.*` and `MakeMouse.*` test them. `tools/input/make-menu-mouse.input`
and `monster-transform-mouse.input` replay both screens at 1280x720 with
`--jump town:10 --fast-load`; their comments give capture frames.

### Fixed camera mouse look

`input.mouse_fixed_look` defaults to `true` and appears as **Fixed camera mouse look**
Expand Down Expand Up @@ -918,7 +1011,7 @@ The PAL scripts (`.stb`) hold the NTSC frame counts and convert them while they
- The FPS counter: `video.show_fps` turns it on (F3 and the `fps_toggle` host action flip it; headless only with `--show-fps`). It is drawn through `OverlayRecord`, as a display render's overlay, in the overlay's own font (the Dark Cloud Compendium Community Font baked into `overlay_font.inc`), so no canonical image holds it. The game's message font is not used: its texture lives only in the current mode's texture block (`ReLoadFontTexture` per mode) and `FontTex[0]` dangles across mode changes, so a badge in it would come and go with the modes. Its text is set by `video.fps_detail`; with all fields it reads `FPS 143.9 TICK 60.0/60 DRAWS 412`. TICK counts clock ticks per second, so it reads the tick rate whatever `mgFrameRate` is. DRAWS is the newest list's mesh plus 2D draws. `--log-fps` prints the same text on stderr once a second.
- Interpolation diagnostic: set `KZ_INTERPOLATION_TINT=1` to tint draws on the main presentation image (default off). Green is a matched transformed mesh; cyan is an unmatched or pose-excluded mesh carried by the display camera; red is newest-only geometry; blue is flat 2D or a screen effect; yellow is a depth-tested sprite with reprojected corners. Unchanged matched meshes remain green. This classifies geometry, not all its inputs: texture contents, lighting, fog parameters and sprite motion can still be tick-exact. Alpha tests, coverage, depth and blending are retained, so translucent passes can mix tints. Reusable intermediate render targets keep their original colours; their final composites are tinted on the main image. Canonical renders and ordinary screenshots never receive the tint. Use `--screenshot-display 8` to inspect the diagnostic at eight interpolation phases. Optional `KZ_INTERPOLATION_TRACE=<file>` appends per-draw CSV sections at alpha zero, including matching/cut reasons, texture IDs, camera IDs, target IDs, whether a draw is tinted on the main image, and changed fog/material/projection/local inputs. It writes only while tint is enabled; remove both environment variables after diagnosis.
- Outlined models render into a shared transparent image. Canonical clears and copies retain the retail draw rectangle; presentation scratch clears and replacement vertices cover the full visible extent so the interpolated model/bone pose remains complete under the display camera, including fixed-camera mouse look. Each copy preserves its texture-to-screen offset. Fixed-look current and previous lists preserve presentation vertices and clear rectangles while leaving resource retirement ownership with their source lists. Transparent texels in a depth-writing presentation composite do not write depth. GPU regressions compare a rotating thin part at alpha 0.5 against an independently recorded horizontal pose and complete fixed-look outline pixels at alpha 1 and 0.5 against a direct full-extent reference render; translation, scratch-target reuse and transparent-depth regressions remain covered. `tools/input/area-dungeon-chest-turn.input` with `--jump dungeon:0:1 --fast-load --frames 2518 --screenshot chest.png --screenshot-display 8` exercises the unopened chest during a camera turn. For multi-part NPCs, use `--input tools/input/repro-town-npc-outline.input --jump town:10 --fast-load --frames 278 --window 1280x720 --screenshot woman.png --screenshot-display 8`; the woman's face must remain visible throughout the turn. `--input tools/input/repro-clown-outline.input --frames 27230 --window 1280x720 --screenshot clown.png --screenshot-display 8` checks the clown's face during the prologue camera move.
- `--screenshot-display N` writes N display frames of the screenshot's frame, at alpha k/N from the previous list to the last, as `<stem>-display-<k>.png`. `--screenshot-fps` writes the screenshot with the FPS counter drawn into it, at window size, from a presented frame. With `--offscreen`, nothing is presented, and the image is read back from the display image instead. The counter reaches no other written image.
- `--screenshot-display N` writes N display frames of the screenshot's frame, at alpha k/N from the previous list to the last, as `<stem>-display-<k>.png`. `--screenshot-fps` writes the screenshot with the FPS counter and any visible menu pointer drawn into it, at window size, from a presented frame (`RecordHostOverlay`, shared with presentation). With `--offscreen`, nothing is presented, and the image is read back from the display image instead. Neither reaches any other written image.
- `video.max_fps=0` leaves presentation uncapped; a positive cap paces display starts without catching up in bursts. A due logic tick takes priority. FIFO follows the display's synchronization, while mailbox and immediate depend on device support. Interpolation off presents canonical frames at their game cadence; a high display cap does not increase the logic tick rate.

### Packets
Expand Down
2 changes: 2 additions & 0 deletions port/include/stubs/inventmn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
class mgCMemory;
class CInventDataManage;
class CInventUserData;
class CMenuInvent;
struct SPI_TAG_PARAM;

extern mgCMemory InventTeigiStack asm("Inventmn_RecipeStack");
extern CInventDataManage *InventManagePt asm("Inventmn_RecipeManager");
extern SPI_TAG_PARAM invent_teigi_func[3] asm("Inventmn_RecipeTags");
extern CInventUserData *InventUserDataPtr asm("Inventmn_PhotoData");
extern CMenuInvent *CMenuInventPt asm("MenuMouse_Invent");
3 changes: 3 additions & 0 deletions port/include/stubs/menuchr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
#include <menuchr.hpp>
#include "texture_color.hpp"

extern CMenuChrCngMenu *ChrChangMenuPt asm("MenuMouse_ChrChange");

void PortRetailInitMainCharaBG(int, mgCMemory *, int) asm("MenuChr_InitMainCharaBG");
int PortRetailKeyMainCharaBG() asm("MenuChr_KeyMainCharaBG");
extern CMenuMosSelect *MenuMosSelectPtr asm("MenuMouse_MosSelect");
3 changes: 3 additions & 0 deletions port/include/stubs/menuop.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
extern CSaveMenuClass *SaveMenuPtr asm("MenuMouse_Save");
// Let the PC page wrap the original Options step without replacing its state machine.
extern CMenuOption *CMenuOptionPtr asm("MenuOption_Current");
// The menu pointer reads the option count and the Help list it scrolls.
extern float config_option_num_i asm("MenuOption_Count");
extern CManualMenu *CManualPtr asm("MenuMouse_Manual");
2 changes: 1 addition & 1 deletion port/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Options g_options;
" --screenshot PATH with --frames: write the last frame to PATH as a PNG on exit\n"
" --screenshot-display N with --screenshot: also write N interpolated display frames of that frame\n"
" beside PATH, as PATH-display-K.png for K = 0..N-1\n"
" --screenshot-fps with --screenshot: draw the FPS counter into the written image\n"
" --screenshot-fps with --screenshot: draw the FPS counter and menu pointer into the written image\n"
" --input SCRIPT drive the pads named in SCRIPT from an input script\n"
" --window WxH window size in pixels (default: config.json, then the monitor's)\n"
" --display-per-tick N headless: also render N interpolated display frames per tick (discarded)\n"
Expand Down
Loading