# game.rpg.menu
The widget trees for V's menu in Banana 2077, Cyberpunk 2077 2.0 style. It draws one full-screen
panel with four tabs:
- **INVENTORY**: the seven equipment slots (katana, baton and five cyberware slots), a tier-framed
item grid (`M.COLS` × `M.ROWS` visible, scrolling) with category filters, and a detail card.
The card shows the item's effects, a comparison against what is equipped, the salvage yield and
the upgrade cost, with EQUIP / USE, DISASSEMBLE and UPGRADE buttons.
- **CHARACTER**: the five attributes, the perk-tier gates at 4 / 9 / 15 / 20, unspent points, and
the derived stats.
- **PERKS**: the five attribute trees (SOLO, BLADES, ENGINEER, NETRUNNER, HEADHUNTER). Each has
four tiers, requirement links and ranks, plus BUY and RESPEC.
- **SKILLS**: street cred with its title track, and the five level-by-doing skills with their
milestones.
It is a pure builder over `game.rules` state plus a view model. It owns no state and registers no
screen. The `game.rpg.Character` component owns the view model, puts `M.tree(m)` on screen
`rpg_menu` (layer 156), and routes the clicks back in through its `onCallback`.
## API
- `M.tree(m)` returns the whole frame: header (level, eddies, points), tab bar, the active tab's
body, and a footer with that tab's keycaps.
- `M.itemRows(filter)` returns the sorted `{id, count, def}` rows for an inventory filter.
- `M.perkOrder(tree)` returns a tree's perks in tier/column order (this is what `perkSel` indexes).
- `M.perkState(perk)` returns `"maxed" | "owned" | "ready" | "open" | "locked"`.
- `M.primaryLabel(row)` returns `EQUIP | UNEQUIP | USE | INSPECT`.
- `M.tier(id)`, `M.icon(def, color)`, `M.iconKind(def)`, `M.effects(id, def)`,
`M.compare(id, def)`, `M.filterLabel(f)`, and `M.currentItem(m)`.
- Constants: `M.TABS`, `M.ACCENT`, `M.FILTERS`, `M.COLS`, `M.ROWS`.
## View model `m`
| field | meaning |
|---|---|
| `tab` | `"inventory" \| "character" \| "perks" \| "skills"` |
| `msg`, `msgColor` | footer feedback line |
| `filter` | a key from `M.FILTERS`, or `"slot:<slot>"` |
| `items` | `M.itemRows(filter)` |
| `sel`, `top` | selected item (1-based) and first visible grid row (0-based) |
| `focus`, `slotSel` | `"grid" \| "slots"` and the highlighted slot index |
| `attrSel` | highlighted attribute index (CHARACTER) |
| `tree`, `perkSel` | attribute id of the open tree and index into `M.perkOrder(tree)` |
| `respecArmed` | the respec button asks for confirmation |
## Click ids
`menu:close`, `menu:tab:<t>`, `menu:filter:<f>`, `menu:item:<i>`, `menu:slot:<i>`,
`menu:scroll:-1|1`, `menu:act`, `menu:dis`, `menu:up`, `menu:attr:<i>`, `menu:spend:<attr>`,
`menu:tree:<attr>`, `menu:perk:<i>`, `menu:buy`, `menu:respec`.
# shopnav.inputMap
Navigation for Banana 2077's full-screen menus, live only while one is open: the vendor shop
(activated by `Shops`) and V's menu (activated by `game.rpg.Character`, alongside
`game.rpg.charnav` for its extra keys). It suppresses the `hud`, `combat`, `player`, `quests_hud`
and `story` groups, so a press inside a menu never also talks to or interacts with something.
Touch has no bindings: rows, tiles, tabs and buttons are tapped directly.
| action | keyboard | gamepad |
|---|---|---|
| up / down | ArrowUp/W, ArrowDown/S | d-pad up / down |
| left / right | ArrowLeft/A, ArrowRight/D | d-pad left / right |
| confirm | Enter, Space | south |
| back | Escape, Backspace | east |
| tabprev / tabnext | Q / E, Tab | left / right shoulder |
| alt (disassemble / respec in V's menu) | X | west |
| toggle (close V's menu) | I | select |
# character.inputMap
Banana 2077's always-on key for V's menu. The `Character` component activates it while a run is
`playing` (never on the title). It is in the `hud` input group, so any modal that suppresses the HUD
(a shop, the journal, dialogue) stands it down too.
- **menu**: `I`, gamepad `select` (view/back) or touch **BAG** opens the menu on the INVENTORY tab.
Inside the menu, the same keys close it through `shopnav.inputMap`'s `toggle`.
# game.rules
Banana 2077's one shared module: palette, the Peel Kabuki street layout every slice builds to, tuning for the player, baton and enemies, the controls list, the live game state (`R.state`, kept across hot reloads), the event bus (`R.on` / `R.emit`) and the rule functions that change state (`damagePlayer`, `healPlayer`, `addEddies`, `setSunglasses`, `registerTarget`, `hit`, `reportKill`, `setPhase`, `startRun`). Required by every slice; owned by the lead. See `/zero/source/design/spec.md`.
# charnav.inputMap
The extra keys of V's open menu. The `Character` component activates it together with
`game.shops.shopnav` (arrows, Enter, Esc, Q / E, X) while the menu is open, and drops both on close.
It suppresses nothing itself, because shopnav already stands the HUD, combat and walking down.
- **upgrade**: `U` / gamepad `north` (Y) upgrades the selected gear one tier, paying components and eddies.
- **filter**: `F` / gamepad right trigger cycles the inventory filter (ALL, WEAPONS, CYBERWARE, HACKS, SUPPLIES, PARTS, MISC).
Touch has no buttons for these; the UPGRADE button and the filter chips are tapped directly.
# perks
The data behind V's growth in Banana 2077: five attribute perk trees, five skills that level with use, and the street-cred track. The module is pure data plus a few lookups. `game.rules` owns the profile and applies every effect, and the character menu draws the trees from this data.
- `P.trees[attr]`: the name and tagline of each tree. The trees are body SOLO, reflexes BLADES, tech ENGINEER, intelligence NETRUNNER and cool HEADHUNTER.
- `P.list`: 35 perks, 7 per tree. Each perk has an `id`, `tree`, `tier` (1–4, gated by an attribute of 4 / 9 / 15 / 20 through `P.tierGate`), `col`, `ranks`, an optional `req`, and either per-rank stat `mods` (added to `R.stat`) or a `flag` (read by a rules hook). Each also carries a `desc`.
- `P.byId`, `P.byTree[attr]` and `P.gate(perk)` look perks up.
- `P.skills`: five skills (solo, shinobi, engineer, netrunner, headhunter), each with per-level stat mods. Related fields:
- `P.skillXp`: the XP each action gives.
- `P.skillMax`: the level cap, 20.
- `P.skillMilestones`: levels 5/10/15/20, each giving a bonus perk point.
- `P.skillToNext(level)`: the XP needed for the next level.
- Street cred:
- `P.credMax`: the level cap.
- `P.credToNext(level)`: the XP needed for the next level.
- `P.credRewards`: the cred each source gives.
- `P.credTitle(level)`: the title shown for a cred level.
# alt.inputBinding
The selection's second action: in V's menu, X / gamepad west disassembles the selected item on the
INVENTORY tab, or arms (then confirms) a perk respec on the PERKS tab.
# back.inputBinding
close the dialog, or the menu.
# confirm.inputBinding
buy / sell / equip / use the selected row, or accept a dialog.
# down.inputBinding
move the menu selection down.
# left.inputBinding
step left (attribute columns, quantity).
# right.inputBinding
step right (attribute columns, quantity).
# tabnext.inputBinding
next tab.
# tabprev.inputBinding
previous tab.
# toggle.inputBinding
I / gamepad select while V's menu is open: closes it (the always-on BAG binding is suppressed then).
# up.inputBinding
move the menu selection up.
# menu.inputBinding
Opens V's menu (INVENTORY · CHARACTER · PERKS · SKILLS): `I`, gamepad `select`, touch **BAG**.
While the menu is open, the same keys close it through `shopnav.inputMap`'s `toggle`.
# filter.inputBinding
Cycles the inventory filter in V's menu (ALL → WEAPONS → CYBERWARE → HACKS → SUPPLIES → PARTS → MISC): `F` or the gamepad right trigger. Touch taps the filter chips instead.
# upgrade.inputBinding
Upgrades the selected gear one tier in V's menu: `U` or gamepad `north` (Y). Touch taps the UPGRADE button instead.