Commit graph

162 commits

Author SHA1 Message Date
Erik
b09169ade2 feat: add app-level authentication with login, session cookies, and admin panel
Replace Nginx basic auth with proper user accounts:
- Session cookies via itsdangerous (30-day expiry, httponly, secure)
- Password hashing with bcrypt via passlib
- Login page with AC-themed UI
- Admin page for user management (CRUD)
- AuthMiddleware exempts plugin WS and browser WS endpoints
- Issues/comments author auto-populated from session
- Sidebar shows logged-in username, admin link, and logout
- Seed users: erik (admin), alex, lundberg
- SECRET_KEY env var for cookie signing
2026-04-10 19:45:08 +02:00
Erik
fac5063878 feat: show issue comments inline without toggle 2026-04-10 17:44:52 +02:00
Erik
f96171a345 feat: issues board - add submitter name, comments, and edit support 2026-04-10 17:36:08 +02:00
Erik
21e72b438f fix: use content-type instead of path for no-cache detection
Root "/" path doesn't match .html ending. Checking the response's
content-type header catches index.html served via html=True and is
more robust for any URL that returns HTML/JS/CSS/JSON.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:59:03 +02:00
Erik
4fe0977b71 fix: also apply no-cache to root path serving index.html
The StaticFiles path is empty for root "/" which served index.html via
html=True. Include root/directory paths in the no-cache match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:58:13 +02:00
Erik
994bc618db fix: force browser revalidation for JS/CSS/HTML static files
FastAPI StaticFiles sets Last-Modified/ETag but no Cache-Control, so
browsers use heuristic caching and can serve stale code after git pull.

Subclass StaticFiles to add 'Cache-Control: no-cache, must-revalidate'
on .html/.js/.css/.json files. ETag/Last-Modified still work, so
revalidation returns efficient 304 Not Modified when unchanged.

Other assets (images, fonts, tile textures) are unaffected and cache
normally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:57:00 +02:00
Erik
604d4376b4 feat: two-step issue resolution (resolve then delete)
- New PATCH /issues/{id} endpoint to toggle resolved flag
- Add resolved:false to new issues
- Frontend: click "✓ Resolve" marks issue green with strikethrough
- Resolved issues show "↺ Reopen" and "🗑 Delete" buttons
- Delete requires confirmation
- Sort: unresolved first, then resolved
- Issues persist until explicitly deleted

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:48:20 +02:00
Erik
f2b43fce0b fix: store openissues.json in bind-mounted static/ dir
Was stored at /app/openissues.json (ephemeral container filesystem).
Moved to /app/static/openissues.json which is bind-mounted to the
host at ./static/, persisting across container rebuilds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 19:32:28 +02:00
Erik
80cfbfdfca fix: compact player sidebar layout for 5 buttons
- Add buttons as 6th grid row instead of extra element below grid
- Reduce stat pill padding and font size (4px→2px, 0.75rem→0.7rem)
- Reduce grid gap (6px→4px row, 12px→8px col) and item padding
- Unify all 5 button styles (Chat/Stats/Inventory/Char/Radar) with
  shared compact sizing, individual colors preserved
- flex-wrap on buttons container as safety for narrow sidebars

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:52:46 +02:00
Erik
ee775a7e71 style: move version to top-left corner, white text
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 13:07:47 +02:00
Erik
38ca6ead12 feat: version display + issues board
Version: CalVer + git hash shown in top-right corner of main page.
Built via Docker ARG BUILD_VERSION at build time. Served via /api-version.

Issues Board: shared notepad window for tracking issues with plugin,
overlord, nav files, macros. Stored in openissues.json on server.
- GET/POST/DELETE /issues endpoints
- Draggable window matching Chat/Radar pattern
- Category tags (plugin, overlord, nav, macro, other) with colors
- Add/resolve issues through the UI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:53:06 +02:00
Erik
c4856dc701 feat: compute base item values by reversing active spell buffs
Extract spell effect mappings from Dictionaries.cs into spell_effects.json.
During item ingestion, compute_base_values() reverses active enchantment
effects to get true base stats:
- base_armor_level: armor without Impenetrability buffs
- base_max_damage: damage without Blood Drinker buffs
- base_attack_bonus: attack without Heart Seeker buffs
- base_melee_defense_bonus: defense without Defender buffs
- base_elemental_damage_vs_monsters: elemental without Spirit Drinker
- base_mana_conversion_bonus: mana conv without Hermetic Link

New columns in ItemCombatStats, exposed in search CTEs.
Frontend: Base Armor and Base Dmg columns (hidden by default, toggle on).
Requires ALTER TABLE migration before deploy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:31:39 +02:00
Erik
77e5a544d1 fix: restore sort click to full th area, not just label span
Sort listener was on .th-label span only, making clickable area too
small. Moved back to full .sortable th element. The × hide button
already uses stopPropagation so it won't trigger sort.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:28:28 +02:00
Erik
84d651ac44 fix: filter garbage weapon_time values (67108882 is flag data, not speed)
Some unidentified items have IntValues[218103835] = 67108882 which is
a bitmask/flags value, not weapon speed. Cap at 100 in extraction and
filter >100 in frontend display. AC weapon speed is typically 0-50.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:18:00 +02:00
Erik
8943133ae3 feat: move column toggles into table headers
Replace separate checkbox bar with inline × buttons in each column
header. Click × to hide a column. Hidden columns appear in a bar
above the table with + buttons to restore them. Sort by clicking
the column label text. Persisted to localStorage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 10:12:01 +02:00
Erik
faff102e09 fix: broken template literal in displayResults caused JS syntax error
Unclosed string on line 570 prevented entire inventory.js from loading,
breaking character list and all search functionality.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 10:06:09 +02:00
Erik
5b706d45e0 feat: add weapon speed, attack bonus, melee defense columns
Backend: add weapon_time and melee_defense_bonus to search CTE.
Frontend: show Speed, Attack Bonus (+%), Melee Def (+%) columns
visible by default. Material/Workmanship hidden by default.
Attack bonus and melee defense shown as percentage offset from 1.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:24:32 +02:00
Erik
0b91f111ad feat: weapon stat columns + column visibility toggles
New columns: Max Damage, Attack Bonus, Material, Workmanship.
All columns now driven by RESULT_COLUMNS config array.
Column visibility toggles bar above results — checkboxes to
show/hide any column, persisted to localStorage.
Coverage column hidden by default.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:22:13 +02:00
Erik
7f7595b5b6 fix: weapon_type filter uses subquery instead of rd table reference
The rd table is only available inside the CTE, not in the outer WHERE.
Use EXISTS subquery against item_raw_data for skill-based weapon type
filtering (same pattern as spell_contains fix).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:43:13 +02:00
Erik
9749eafde4 feat: add weapon type filter (heavy, light, finesse, 2H, bow, crossbow, thrown, caster)
Backend: new weapon_type query parameter on /search/items.
Uses skill ID from IntValues[218103840] for melee types (Heavy=44,
Light=45, Finesse=46, TwoHanded=41) and name matching for missile
sub-types (bow, crossbow, thrown). Caster = ObjectClass 31.

Frontend: dropdown appears when "Weapons" radio selected, hidden otherwise.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:41:07 +02:00
Erik
35a11d0cf1 fix: correct weapon ObjectClass IDs (1, 9, 31 not 6, 7, 8)
DECAL ObjectClass enum: MeleeWeapon=1, MissileWeapon=9, WandStaffOrb=31.
The weapon_only filter was using Food=6, Money=7, Misc=8 — completely
wrong classes. Also removed max_damage>0 requirement so weapons show
even before combat stats are populated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:35:09 +02:00
Erik
1e9dffb65b fix: weapon combat stats extraction + spell_contains SQL bug
Bug 1: Weapon stats (max_damage, attack_bonus, variance, damage_type,
weapon_time, weapon_skill) were read from top-level MyWorldObject fields
which are -1 by default. Now extracted from IntValues/DoubleValues keys
where the plugin actually stores them (218103842, 167772170, etc.).

Bug 2: spell_contains and has_spell filters used direct sp.spell_id
reference which fails in the count query CTE (sp table not available
in outer SELECT). Changed to EXISTS subqueries matching the pattern
already used by legendary_cantrips filter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:24:48 +02:00
Erik
5b26a19666 feat: complete inventory search frontend — weapons, filters, status column
- Add Weapons and Clothing equipment type radio options
- Add Weapon/Combat Stats filter card: damage, attack bonus, crit resist, tinks
- Add Item Properties filter card: material, level req, workmanship, value, burden
- Add Item State filter card: spell text search, bonded, attuned, rare checkboxes
- Add Status column (Equipped/Inventory) to results table
- Remove dead Slot View button and section (no JS handlers existed)
- Update clearAllFields() for all new inputs
- All changes frontend-only — suitbuilder and backend API untouched

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:10:35 +02:00
Erik
8432c5f7c3 fix: match object rotation to cell canvas rotation in dungeons
Two issues caused objects to float relative to dungeon map:
1. rotAngle used (heading + PI) but canvas uses (PI - heading)
   - these differ: sin(x+PI) = -sin(x) vs sin(PI-x) = sin(x)
2. Object dy was negated, but 180° heading offset already handles N/S
   - double N/S flip caused objects to drift with heading changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:24:06 +02:00
Erik
6c500f7cdb fix: add 180° heading offset for dungeons (from UB line 1013)
UB applies HeadingToQuaternion(heading - 180) for dungeon rendering.
The layer has Y increasing downward, and the 180° offset flips N/S.
Reverted coordinates to Version 1 (X mirror, Y direct) which had
correct tile connections, and added the 180° heading offset that UB
uses to fix N/S orientation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:17:16 +02:00
Erik
203ae0a4fb fix: revert to Version 1 approach (tiles connected) + just add Y negate
Version 1 (X mirror, Y direct) had correct tile connections but N/S
flipped. Previous attempts to fix N/S also changed rotation handling
which broke tiles. This commit reverts tile processing (no flip),
reverts rotation (exact UB values), and only adds Y negation to
Version 1's working coordinates. No other changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:10:58 +02:00
Erik
8b605a4cae fix: horizontally flip tile images + negate rotation
UB's tiles were authored for a mirrored-X rendering space. Instead of
mirroring coordinates (which breaks positioning), flip each tile image
horizontally during pre-processing and negate the cell rotation angles
to compensate. Cell and object positions remain direct (no mirroring).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:00:57 +02:00
Erik
8d2e74397b fix: remove X mirror, fix rotation float tolerance
UB mirrors both cell positions and player position within layer space,
so relative offset is direct (mirrors cancel out). Removed X negation.
Added float tolerance for rotation quaternion W component comparison
(was using strict equality which fails on floating point values).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:48:07 +02:00
Erik
b067a148f3 fix: flip dungeon Y for north-up, guard COM exceptions
- Negate Y delta for dungeon tiles and objects so north points up
  (AC Y+ = north, canvas Y+ = down)
- Wrap early COM calls in try/catch to prevent RPC_E_SERVERFAULT
  during state transitions (portal loading, etc.)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:43:15 +02:00
Erik
3857c0de79 fix: mirror X axis for dungeon tiles to match UB coordinate system
UB uses mirrored X: x = -(cell.X - playerX), direct Y: y = cell.Y - playerY.
Applied same transform to tile rendering, object positioning, and
entity list distance calculations in dungeon mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:31:23 +02:00
Erik
683d1cf337 feat: UB-style tile processing — white transparent, color remapping
Process each tile through canvas pixel manipulation:
- White pixels → transparent (same as UB's MakeTransparent)
- Remap UB's 5 source colors (walls, inner walls, ramps, floors, stairs)
  to readable display colors on dark background
- Black outlines made semi-transparent
- Current floor at 85% opacity, other floors at 12%
- Non-current floors drawn first, current floor on top

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:21:58 +02:00
Erik
06f326cce0 fix: detect PNG vs BMP format in dungeon tiles
361 of 614 tile files have .bmp extension but are actually PNG.
Now detects magic bytes and sets correct MIME type per tile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:18:09 +02:00
Erik
e2982e34b5 feat: render actual dungeon tile textures in radar
Extract 614 UB tile BMPs into dungeon_tiles.json (287KB base64 bundle).
Frontend loads tiles once, then draws them rotated per-cell using
environment IDs. Falls back to colored rectangles if tiles not loaded.
Current floor at 70% opacity, other floors at 15%.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:14:52 +02:00
Erik
b941a29f04 feat: add dungeon map streaming and rendering in radar
- Backend: dungeon_map event handler with permanent in-memory cache
  by landblock ID, request_dungeon_map for late-joining browsers
- Frontend: render dungeon cells as colored rectangles when in dungeon,
  multi-level Z support (current floor bright, others dimmed),
  automatic overworld/dungeon switching based on is_dungeon flag,
  raw physics coordinate positioning for dungeon objects

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:16:36 +02:00
Erik
2f21159acb feat: add dereth.png map background to radar canvas
Draws a rotated/scaled slice of the overworld map behind radar dots.
Map clips to the radar circle, rotates with heading-up mode, and
renders at 40% opacity so dots remain visible on top.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:49:38 +02:00
Erik
2b9aa7f4ae revert: switch back to original dereth.png (6123x6123)
The original high-res map matches GoArrow's in-game map.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:47:14 +02:00
Erik
672819e591 feat: switch to UtilityBelt's acmap.png (2048x2048)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:43:22 +02:00
Erik
f6301a8cab feat: swap map to high-res color-corrected Dereth map
Replace dereth.png with Thwargle's highres_colorCorrect.png (2041x2041).
Same coordinate bounds (-102.1 to 102.1), dimensions read dynamically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:41:47 +02:00
Erik
60eab15fff feat: scroll-wheel zoom and click-to-select in radar
- Replace range dropdown with smooth scroll-wheel zoom on canvas
- Click dot on canvas to select it (white ring + name label)
- Click row in entity list to select on canvas
- Click again to deselect
- Selected row highlighted with blue accent in list
- Auto-scrolls list to keep selected row visible

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:28:09 +02:00
Erik
359d255730 fix: correct compass E/W and object rotation
AC heading is standard clockwise (0=N, 90=E). Both compass labels
and object rotation need positive heading — previous negation broke
the compass while fixing objects. Now both use the same sign.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:20:35 +02:00
Erik
eaa5b5c48d fix: negate AC heading for correct E/W compass orientation
AC's Actions.Heading uses opposite rotation from standard math
angles (confirmed by UtilityBelt's HeadingToQuaternion negation).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:14:51 +02:00
Erik
502467e075 fix: radar compass always heading-up with rotating N/E/S/W labels, fix reopen bug
- Compass is now always heading-up: player facing direction is fixed
  pointing up, N/E/S/W labels rotate around the edge as player turns
- Fix: reopening a closed radar window now resends start_radar command
  so streaming resumes without needing a full page refresh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:07:40 +02:00
Erik
3852cf205e Add real-time radar feature for nearby objects
Browser can open a radar window per character that streams nearby
monsters, players, NPCs, portals, and other objects in real-time.
On-demand activation via start_radar/stop_radar commands through
the existing WebSocket command channel.

- Backend: nearby_objects event handler with in-memory cache and broadcast
- Frontend: canvas mini-map + entity list table in draggable window
- Radar button added to player list alongside Chat/Stats/Inventory/Char

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:01:05 +02:00
erik
c0da36c280 fix: decouple browser broadcast from plugin WebSocket receive loop
🧝‍♂️ Fix 1: The Mailman Story

Imagine you're a mailman delivering letters. Before, you had to
knock on every door and wait for someone to answer before you could
go back to your truck and get more letters.

But your truck keeps getting MORE letters dumped in it! And if
you're stuck waiting at grandma's door... your truck overflows
and letters fall everywhere! 📬💥

The fix: Now you have a magic helper elf! You hand the letters to
the elf and say "you go deliver these!" while you run back to the
truck to grab more. The elf handles the doors, you handle the truck.
Nobody waits! 🧝‍♂️

🍕 Fix 2: The Pizza Party Story

Now let's talk about that elf. The elf had a problem too!

Imagine you have 5 friends at a pizza party and you're handing out
slices. Before, the elf would:

1. Give pizza to Tommy → wait for him to take a bite 🍕
2. Give pizza to Sally → wait for her to take a bite 🍕
3. Give pizza to Bobby → wait for him to take a bite 🍕

So boring! Everyone's just sitting there hungry!

The fix: Now the elf throws ALL the pizza slices at the same time!
🍕🍕🍕🍕🍕 Everyone gets their pizza at once and nobody has to
wait for Tommy to finish chewing!

Yay! 🎉

Technical details:
- Use asyncio.create_task() to fire-and-forget broadcasts
- Use asyncio.gather() to send to all browsers concurrently
- Plugin receive loop no longer blocks on slow browser clients

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:53:59 +00:00
Erik
5c20d40f1f Reduce inventory column gap from 20px to 13px 2026-03-13 20:54:31 +01:00
Erik
0f1fcc1231 Fix active pack indicator: change sidebar/pack-list overflow to visible so yellow frame and arrow show 2026-03-13 20:51:51 +01:00
Erik
0b2fe8fb1e Fix inventory 3-column layout: 20px gaps, fixed 316px left column width 2026-03-13 20:46:49 +01:00
Erik
e02edfde8a fix: increase column gap to 8px 2026-03-13 20:41:43 +01:00
Erik
932a6d8ea7 fix: narrow container column to reduce paperdoll overlap 2026-03-13 20:38:29 +01:00
Erik
cff99f9b87 refactor: 3-column inventory layout (paperdoll+items | packs | mana) 2026-03-13 20:34:36 +01:00