SW Minis Companion 2.9 — larger minis and highlighted movement paths

Extract into your existing app folder, replacing code and keeping your database,
DB/, maps/, cards/, tokens/ and custom/ folders. Include swminis_table.py and
swminis_maps.py along with the other Python files.

NEW IN 2.9
- Default squad limit is 100 points in the VTT, online Create Game dialog and
  server-side room defaults. Saved games and existing room settings keep theirs.
- New map grids default to 34 columns by 22 rows (previously 22 by 34).
  Existing map configurations are preserved; adjust those in Map Editor.
- Small/Medium minis use 1x1 tile, Large 2x2, Huge 3x3. Footprints apply to art,
  hit detection, drag offsets, placement, painted starter-zone validation and
  overlap checks. Size names accept mixed case and surrounding whitespace.
  Large/Huge squads need appropriately sized starter zones. Squad minis cannot
  end a move overlapping another squad mini, or extending outside the map.
- Dragging a mini highlights the grid squares its entire footprint follows in
  its team colour. The trail covers all segments through right-click waypoints.
  The floating token remains translucent. Release clears the trail, even when
  the destination is rejected. Movement distance still counts diagonals as 2.
- The standalone Ruler uses the selected mini's footprint and colour; with no
  mini selected it highlights a one-tile-wide route in the active player's
  colour. Elastic remains the free straight-line guide for manual LOS.
- Trails are movement previews. Terrain, abilities and path legality are still
  adjudicated by players; this does not add automatic pathfinding.

SERVER UPDATE
To use the new server-side default, stop PoachedPhoenix-SWMinis, replace ONLY
swminis_server.py in C:\SWM_server, and restart that task. Keep your working
Caddyfile, startup scripts and data/ (including the server key and identities).
The desktop itself requests 100 points for new rooms even on the older server.

VALIDATION
Linux desktop regression checks cover defaults, Large/Huge hit detection,
collision and edge rejection, full-footprint paths, player-colour rendering,
right-click waypoints, drag offsets on normal/rotated maps and trail cleanup.
The 2.8 desktop/server regressions still pass, including four-player support
and legacy saves. Windows and your actual database/artwork are untested here.
Repeat with QT_QPA_PLATFORM=offscreen python tests/test_controls_vtt.py and
python server/test_lobbies.py. Installer/updater work remains paused.

PREVIOUS RELEASE NOTES

SW Minis Companion 2.8 — controls, four players and painted starter zones

UPDATE YOUR DESKTOP
Back up your project, then extract this ZIP into the existing app folder.
Keep database.py, DB/, cards/, tokens/, maps/ and custom/. Include the new
swminis_controls.py alongside the other Python modules. Launch
MinisCompanion_Qt_database.py. Dependencies are unchanged. This is a code
update; your database and card/token assets remain separate.

WHAT CHANGED
- Squad Builder: left-click a column header to filter; right-click to choose
  ascending or descending sorting. Numeric columns sort by number. Sorting
  persists through filtering and preserves the selected mini.
- Help > Controls (F1) lists mouse gestures and editable keyboard shortcuts.
  Save controls applies them and remembers them per OS user. Restore defaults
  stages the defaults; Save controls applies them. Clear a shortcut to disable
  it. Conflicting shortcuts are rejected. Table and editor shortcuts only
  apply on their own pages; mouse gestures remain fixed.
- Middle-button drag pans both the VTT and map editor without changing tools.
- New Game has a Players selector (2–4). Four-player lobbies put P1/P3 on the
  left and P2/P4 on the right. Each player has a name, team, colour and roster.
  Initiative rolls remain manual. Turn order cycles through surviving players;
  eliminated players are skipped for turns and initiative. Reinforcements,
  markers, round resets and saved games support all four players.
- Map Editor > Paint starter zones paints any shape of grid squares for P1–P4.
  Choose a player's brush and drag to paint. Painting over another player's
  square transfers it. Zone eraser erases the last selected player's squares.
  Painting leaves terrain/edges underneath untouched and supports Undo/Redo.
  Clear painted zones / use corners restores the old corner-zone layout.
- Painted zones override corner settings. Paint a zone for every participating
  player. Large minis must fit their whole footprint inside the selected zone.
  Save the map, then reselect it in the VTT lobby to pick up changes. Existing
  maps without painted zones keep corner starts; four players use four corners.
  Existing two-player game saves remain loadable.
- Multiplayer Create Game / lobby settings accepts 2–4 players. The server
  enforces capacity, including simultaneous joins and attempts to shrink an
  occupied room. Shared online table play is still the next integration stage;
  this update supports four-player LOCAL play and ONLINE waiting rooms.

UPDATE YOUR ALREADY DEPLOYED SERVER
For your C:\SWM_server installation, update ONLY swminis_server.py from the
ZIP's server folder. Stop PoachedPhoenix-SWMinis first, replace that file,
then start PoachedPhoenix-SWMinis again and check /health. Connected players
will reconnect; waiting rooms clear on restart. Keep data/, the access key,
identities database, .venv, startup scripts and your existing Caddyfile.
Do not rerun Install-Proxy.ps1 or overwrite the Caddyfile: your HTTP 8080
configuration and working HTTPS proxy do not need to change.

VALIDATION FOR 2.8
Repeat checks on Linux: QT_QPA_PLATFORM=offscreen python tests/test_controls_vtt.py
Server checks: python server/test_lobbies.py

Linux Qt offscreen checks used synthetic minis/maps for numeric sorting,
filter/selection retention, editable and persisted shortcuts, text-input
safety, conflict rejection, middle panning on both views, painted-zone
transfer/erase/undo/redo/save/load, full-footprint deployment validation,
2/3/4-player manual initiative, four-player deployment/turns, skipping an
eliminated team, four-player saves and legacy two-player saves. UI was inspected
at 1200x800. Server tests exercised real WebSockets, authentication, reconnect,
concurrent joins, four-seat capacity, fifth-player rejection, occupied-size
protection, host-only settings and old-client configuration compatibility.
Windows and your actual database/assets have not been runtime-tested here.
Installer/updater work remains paused for the planned discussion.

EARLIER RELEASE NOTES (historical)

SW Minis Companion 2.7-dev — lobby and local play

INSTALL
Back up your existing project folder. Extract these Python files into that
folder, replacing files with the same names. Keep your existing database.py,
DB/, maps/, cards/, tokens/, and custom/ folders. This is a code update, not a
standalone distribution; the uploaded project did not include those assets.
Launch MinisCompanion_Qt_database.py (MinisCompanion.py is the old Tkinter app).

On EndeavourOS, use a Linux Python virtual environment. A Windows-created
virtual environment cannot be reused. The code uses paths relative to the app.
If you need a fresh environment, from your project folder run:
  python -m venv .venv-linux
  source .venv-linux/bin/activate
  python -m pip install PySide6 Pillow fpdf2 PyPDF2
  python MinisCompanion_Qt_database.py

LOBBY
New Game opens the lobby directly. Select a configured map and points limit
above the map. Each side has its own Load Team (PDF), colour selector, and
roster. Both teams can load independently. Drag roster minis into their team's
starting zone. Play Now explains missing teams, over-budget squads, or unplaced minis.
It asks for confirmation if either squad is at least 10 points below the limit. Changing maps clears deployment positions and scenario objects
and keeps loaded rosters. Changing the limit does not discard loaded rosters.

Configure maps, grid calibration, terrain, starting-zone size, and opposite
corners in Map Editor; Save Map before selecting the map in the lobby.
Older map configs default to six-square zones, reduced for small maps.
Maps without a saved configuration must be configured in the editor first.

PLAY — SCREEN SPACE
During normal play, the lobby's map selector, points control, map details and
both player panels are hidden. The main navigation auto-collapses when a game
starts or a playing game is loaded. Its menu button still allows manual expand.
Reinforcement placement temporarily shows both player trays; normal play hides
them again. New Game restores lobby controls. Compact event history and a
smaller card strip leave more vertical room for the map.

Rotate map turns the view 90 degrees; use it in either lobby or play to make
portrait maps landscape. Image files, map calibration, terrain and saved token
coordinates remain unchanged. Token artwork and labels remain upright. View
rotation is saved with the game. Map rendering lives in swminis_table.py,
separate from the lobby/game controller in swminis_vtt.py.

Card popups now fit the image to the window with a compact centred HP/Force
header. Force labels are omitted from the table, rosters and card strip for
minis that started with no Force points, including the card popup header.
A Force user still shows FP 0 after spending all points.

PLAY
At the start of a round, Initiative waits for each player to click Roll d20.
First-player selection is available after both results appear. Apply modifiers and
abilities manually, then choose either first player. Ties may be reset and rolled again or resolved manually. Closing the popup keeps play waiting for initiative; its
button reopens the same rolls. End Turn alternates the player and advances the
turn number; activation does not enforce a number of minis per turn.

Click a token to show Activate, Heal, Damage, and (for minis starting with Force
points) Use Force over it. Amount dialogs handle healing, damage, and Force
spending. HP cannot exceed printed HP. Activated minis cannot activate again.
Their artwork becomes monochrome. Right-click offers De-activate plus scenario placement.
Double-click a token to open its card with current HP and Force above it.
The bottom squad-card strip follows the current player; collapse/expand with
its header. Clicking a card opens the larger card view.

When all surviving minis have activated, a new round clears activation and
prompts Initiative. Undo Activation reverses the most recent activation,
including a round rollover, until movement/stat changes/end turn invalidate it.

Glossary uses DB/specialabilities.tsv, DB/forcepowers.tsv, and
DB/commandereffects.tsv. Filter searches titles and descriptions; choose a
header on the left to see its definition on the right. Missing files are
reported in the popup; they are not included in this code update.

Reinforcements opens a mini-name filter and small squad builder. Choose player,
Mini count or Points, and the allowance. Confirm pauses normal play, adds tokens
to that roster, and permits their placement in free spaces anywhere on the map.
Finish placement resumes the previous turn. Cancel reinforcements removes the
pending additions and resumes play. Saved games can resume mid-placement.
Players apply faction, ability, placement, activation and allowance restrictions
from the granting effect manually. The original starting points limit does not
block reinforcements.

Roll d20 opens an animated stylised die and plays sounds/die_landing.wav when
it lands. Sound depends on your operating system's audio support.
MOVEMENT AND RULER
Dragging a placed token shows a 50% transparent copy following the cursor.
The automatic ruler starts from its original square. Keep holding left-click
and right-click to add a waypoint at a corner; continue moving, then release
left-click to place. Right-button release does not end the drag. The original
position remains until the destination is accepted. Escape cancels the drag.
Movement snaps to the nearest grid origin, preserving the grab offset for
large tokens. Waypoints measure the route; they do not enforce path legality.

Ruler mode: left-click to start, move to measure, right-click to add waypoints,
and left-click again to freeze the result. A new left-click starts a new route.
Escape clears it. Distance is the sum of straight grid-distance segments
(each sums horizontal and vertical displacement, so every diagonal step costs 2). Terrain costs and
movement legality remain manual. Both ruler and drag routes work with rotation.

Graveyard lists defeated minis; view their cards or restore at 1 HP to the
previous position if free, for correcting mistakes. Defeated minis leave the map.

Save Game preserves colours, positions, HP, Force, activation, round, turn,
current player, initiative rolls, graveyard and pending reinforcements. Older
game saves remain supported. Dice/event history remains session-only.

SCOPE
LOS, attacks, terrain effects, doors, ability rules, and activation limits are
manual. Network multiplayer and automatic Force renewal are later work.

VALIDATION
Linux Qt offscreen checks covered app launch, deployment, stats, Force control
visibility, activation correction, player turns, automatic rounds, round undo,
graveyard restoration, reinforcement pause/place/cancel/resume and save/load,
malformed-save rejection, glossary search, reinforcement allowance checks,
initiative overrides, die results, current stats in cards, and UI rendering.
Actual database, squad PDFs and artwork were absent from the supplied upload;
those still need testing with your project. Audio could not be heard in the
test environment. Windows has not been runtime-tested.

2.3 checks: playing-table visibility, automatic navigation collapse, all four
view rotations with token hit detection, saved rotation, reinforcement trays,
lobby restoration, Force-label omission, and fitted centred card geometry.

2.4: Player-name fields are editable in the lobby and saved with the game.
Names appear in turn tracking, initiative, reinforcement selection and the
 graveyard. Placed entries in the lobby squad trays are monochrome. Map tokens stay in colour during deployment; activated map tokens still become monochrome.
The map and viewport borders follow the current player's team colour.
Over-budget team loads show an explanation and leave the old team untouched.
Play Now explains missing placement; shortages of 10 or more points prompt Yes/No.
Initiative never rolls automatically; each player clicks their own roll button.
Closing/reopening initiative preserves rolls already made, including one roll.

2.4 checks: names and rotation save/load, over-budget rejection, unplaced-mini
warning, short-team confirmation/cancellation, turn-colour changes, manual
initiative, translucent drag state, waypoint insertion while both buttons are
held, continued drag after right release, total route distance, token drop,
standalone ruler waypoints, and monochrome transparency preservation.

2.5 changes
- Fixed deployment greying: placed squad-tray entries turn monochrome, not map
  tokens. Activated tokens in play still turn monochrome.
- Move preview and automatic ruler trail disappear on left-button release,
  including when the destination is rejected.
- Movement/ruler distances charge 2 squares per diagonal (dx + dy), summed
  across all route segments. Terrain costs and route legality remain manual.
- Elastic is a separate straight-line visual guide. It does not snap to grid
  cells, measure legal movement, or calculate LOS visibility. Select its icon,
  click any starting point, move, then click to freeze. Next click begins a new
  line. Escape clears it. Elastic and Ruler cannot be active simultaneously.
- Ruler, Elastic, d20 and Graveyard have compact icon buttons with tooltips.
  Existing artwork is preserved in icons/table_icons.png; the new elastic icon
  is icons/elastic.svg. Extract the icons folder with the Python files.

2.5 checks: pixel check for grey placed-tray art and coloured deployment-map art,
icon rendering, diagonal costs and route totals, trail removal after moving,
free unsnapped elastic endpoints, click-to-freeze and mutual tool exclusion.


2.6 — MAP MARKERS AND GENERIC TOKENS
All playing-table buttons share one centred row directly beneath the map.
Round and turn labels sit together below that row.

Right-click the map > Add marker > choose Open door, Locked door, Explosion,
Mine, A, B or C. The current player's colour fills the symbol and its outline;
black stays black. Before initiative, the selected player's colour is used.
The submenu also offers the other player. Markers are half a standard token's
width and height. Drag freely with no grid snapping; right-click a marker to
remove it or change its owner/colour. Delete removes the selected marker.
Markers are visual reminders only: they do not change doors, terrain or rules.
The supplied legend is preserved in icons/marker_symbols.png; colour masks and
all eight team colours are generated dynamically at runtime.

Right-click > Add generic token. Give it a name, maximum HP, starting Force
(default 0), and notes. Choose a generic symbol or filter minis by name for
artwork only. The list contains minis with local token artwork. Choosing a mini
does not copy its stats, abilities, squad membership or cost. The appearance
preview shows the selected artwork. Generic tokens always have a grey border
and a visible name beneath them; they are standard one-square tokens.

Generic tokens snap to the grid when moved. They may share squares with minis
or other scenario tokens, allowing objectives underneath characters. They do
not count toward squad limits, starting-zone placement, victory messages or
automatic round completion. Their activation clears when a new round begins.
In play, single-click gives normal Activate, Heal, Damage, and Use Force
(starting Force > 0) controls. Right-click provides De-activate, Edit, Remove,
and scenario placement. Double-click opens the large notes/name/art/stats
editor. Editing a maximum preserves current HP up to that maximum; disabling
Force clears current Force; newly enabling it grants the chosen starting value.

At 0 HP, a generic token leaves the map and appears in Graveyard. It can be
restored at 1 HP at its original location. Remove is permanent for that game,
whereas Damage/Graveyard provides a reversible way to defeat it.
Creation and movement of generic tokens pause during reinforcement placement;
finish or cancel placement to resume. Markers remain usable during that phase.

Save Game now preserves marker positions and owners, generic appearance,
names, notes, current HP/Force, activation and graveyard state. Older saves load
with empty marker/generic collections. Existing database, artwork and maps
are still supplied by your installation; extract the new swminis_scenario.py
and updated icons folder as well as the other Python files.

2.6 validation: Qt offscreen with synthetic minis, map and artwork checked the
single centred control row with the actual dark theme at 1200 and 900 pixels,
all 56 marker/colour combinations, context actions, unsnapped marker drag,
generic art-only selection/notes/Force visibility/stats/activation/graveyard,
round rollover excluding scenario tokens, diagonal movement and drag cleanup,
rotated hit detection, save/load, old-save defaults and malformed-save rejection.
Python modules compiled successfully. Actual user database/artwork and Windows
remain untested in this environment.


2.7 — SELF-HOSTED MULTIPLAYER LOBBIES
Open Multiplayer from the left navigation or VTT toolbar. Connect to a server,
choose a remembered name, browse online players and open game lobbies, create
or join a two-player room, and change room settings as host. Presence persists
across workspace changes. Automatic connection on app startup is optional.
Server and identity settings are per OS user, so Linux and Windows each retain
their own name/identity even if both launch from the same Windows project folder.

The included server folder is independently deployable on your Windows home
server. Read server/README_SERVER.md for architecture, local testing, DNS,
Caddy HTTPS and Windows startup tasks. It targets minis.poachedphoenix.com and
reuses home.poachedphoenix.com's existing DDNS via a CNAME.

This release implements the network lobby. The VTT table remains local; shared
maps, squads, deployment, tokens, initiative and dice are the next integration
stage. There is no misleading Start button for a table that is not connected.

2.7 tests passed for multiple network clients, seat races, ownership, presence,
name persistence, disconnect/reconnect, server restart and desktop navigation.
Windows scripts and public deployment have not been run in this Linux session.
