fa3eb59bbe
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 489f59bcce |
Rename the display name from FeNigma to FEnigma
FEnigma contains the whole word "enigma" while still opening on Fe (iron), matching IRON NEST; FeNigma only contained "nigma". The cost is that iron's symbol is Fe, not FE. Code paths are untouched: the Python package stays lowercase `fenigma`, and the git remote URL is unchanged since the repository itself has not been renamed. APP_ID moved too, which is safe -- it is only the GTK application id, with no saved state derived from it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| ff3b89c41b |
Add the map-table vision pipeline
Reads a screenshot of the in-game map table and recovers where on the board it is looking. The scene is a flat table under a perspective camera, so a single homography describes grid<->screen exactly; that is fitted from line evidence (LSD segments, vanishing-point RANSAC, 1-D lattice fits). Line evidence alone cannot finish the job: the 1km cells and the 100m subgrid are locally identical, so it fixes neither scale, axis assignment, axis direction nor phase. Those come from the cell labels -- and the labels are never *detected*, they are correlated where the grid says they must be (9% in from a cell's left edge, 6% down from its top). Blob detection on aerial-photo terrain finds texture, not glyphs; correlating a known template at a known place has no such failure mode. The same score then ranks the geometry hypotheses, since a wrong lattice puts the crop where no label is, so one number resolves scale, axis assignment, direction, phase and anchor together. Markers are found by hostile/friendly colour plus an IoU test against an ideal inscribed diamond, which cut a red-lit shot from 43 false positives to 2 while preserving every hand-verified count. Unit-type classification is present but not yet reliable, and returns unknown rather than guessing. Measured over the fixture set: 7 of 10 solve, each with 100% of its ground-truth points in the correct cell (85/112 overall), residual spread 0.005-0.033 cells. The other three reject cleanly; none has ever produced a plausible-but-wrong grid. Across 122 typewriter screenshots solve() accepted none, which is what makes clipboard routing safe. Fixtures: 10 map shots with hand-transcribed ground truth, plus 10 typewriter shots spanning 262-5366px for routing and future OCR tests. Map shots wider than 2400px (the pipeline's own maximum working width) were downscaled with their coordinates rescaled to match; re-measured afterwards, the results are identical. Typewriter shots stay at native resolution because OCR needs the text legible. Drops docs/map_vision_plan.md and its WIP prototype: the design now lives in the module docstring, next to the code it describes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|||
| e352dff531 |
Map: render entity game icons instead of plain dots once zoomed in
Below ICON_MIN_CELL_PX (42px cell width) everything still draws as the plain colored dot it always has, a game icon at that size would just be an illegible smudge. Past that threshold, Nest/Target/Ally markers switch to the game's own unit icon for their type, drawn as a Cairo surface (raw Cairo draw_func, not GTK widgets, so this loads PNGs directly via cairo.ImageSurface.create_from_png(), cached per path so a repeat draw doesn't re-hit disk). icons.py's target_icon_path(type, is_ally) is the TargetType -> icon file mapping, best-effort guesses the same way the Shell descriptions were (flagged for correction): most types map onto the game's own Enemy_*/Friendly_* unit icons (is_ally picks which set, falling back to Enemy_ if a given type has no Friendly_ counterpart), TANK reuses the Armor_Mechanized artwork (no dedicated tank icon exists), and STRIKE gets its own crosshair (assets/icons/misc/Crosshair.png, not a unit icon at all, a planned impact point) rather than a unit icon. An ambiguous candidate (hollow, dashed-ring marker) never switches to the icon regardless of zoom, an icon there would look more confident about an unconfirmed position than the dashed ring is supposed to convey. Verified with rendered screenshots at both zoom levels: plain dots below the threshold, real icons above it (Tank/Infantry/MarineGarrison/ Nest all confirmed showing their correct icons), and the Strike crosshair specifically. |
|||
| 3b209e743e |
Shell icon picker: fix real sizing bugs, crop icon padding, inline grid for Add Strike
Several rounds of actually looking at the running app instead of just
the code, in order:
- The icon-only shell button on a firing card, and the popover-based
picker, both fought a genuine GTK sizing quirk: Gtk.Picture's natural
size is the source image's full native resolution (512x256) no
matter what set_size_request() says, so the button's own requested
size swung unpredictably depending on layout context (sometimes
comically wide, sometimes squeezed tiny). Fixed by pre-scaling the
actual pixel data with GdkPixbuf first (preserving real aspect ratio)
and wrapping the already-correctly-sized result, nothing left for
the surrounding layout to guess about.
- The shell icon PNGs themselves carry a lot of built-in transparent
padding around the actual artwork. Cropped all of them (except MSTD,
see below) to the same shared bounding box, computed as the union of
every file's real content so nothing gets clipped and every icon
stays aligned the same way.
- MSTD (mustard/YX blister agent) removed from the Shell enum entirely:
its own game icon is stamped 'UNAVAILABLE IN DEMO', it isn't actually
a real selectable shell in the game.
- Extra empty chrome around icon-only buttons turned out to be GTK CSS
specificity, not a missing property: GTK's CSS has no !important at
all (confirmed, its parser rejects it outright), and separately,
Gtk.MenuButton's CSS node is literally named 'menubutton', not
'button', so a 'button.<class>' selector silently matched zero
elements on it. The actual leftover padding lives on MenuButton's
internal child button node, reached with a child-combinator selector
('menubutton.<class> > button').
- The Add Strike dialog's shell picker is now an inline radio-style
grid (build_shell_grid(), Gtk.ToggleButton.set_group()) instead of a
button that opens a submenu popover: it's a 'pick one before
proceeding' dialog with room to just show every option up front,
hiding them behind an extra click didn't earn anything. The firing
card and its tighter row still use the popover version.
- Grid is 3 columns (was 4), sized bigger now that padding is real
content, not just empty canvas.
Also two unrelated but real bugs found and fixed while chasing this,
from actually reproducing what screenshots showed instead of taking
them as pure cosmetic complaints:
- Selecting a firing card shifted every icon/label inside it inward by
2px: only .firing-card-selected had a border, unselected cards had
none at all, so gaining a border on selection shifted the box's
content instead of just changing a color. Border is now reserved at
the same width on every card, always, selection only changes its
color from transparent.
- Changing a target's powder charge visibly shifted the whole card:
the charge segment buttons had no valign, so once the row got taller
(the bigger shell icon next to them), they silently inherited the
default FILL alignment and stretched into ovals instead of staying a
fixed circle. They also relied on plain 'flat'/'suggested-action' for
their off/on look, which draws no border at all when off, making an
unselected segment invisible against the card background. Both fixed
with a dedicated fixed-size, always-outlined CSS class and explicit
valign/halign=CENTER.
- The AZ column's screen position depended on the ELEV value's digit
count (elevation recalculates per charge picked), fixed with a
reserved width_chars on the elevation label.
Verified at each step by actually rendering the affected widget/dialog/
card to a PNG and looking at it (including a real FiringPanel card
before/after a charge change, pixel-diffed to confirm nothing but the
intended fill state moved), not by reasoning about the code alone.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|||
| 5077cf4d14 |
Add game-extracted UI icons: target markers, RP letters, shell set, nest, scout plane
Pulled from the game's own GameAssets/Assets/Texture2D (gitignored as a
whole, not redistributed wholesale) into a tracked assets/icons/ so
they're actually usable in FeNigma's UI instead of us redrawing
equivalents:
- targets/enemy/, targets/friendly/: one marker per game unit type
('Enemy_*.png' / 'Friendly_*.png', the source files spell the latter
'Frendly_*.png', corrected on copy).
- reference_points/: the four lettered RP markers ('Refrence_Point_*.png'
in the source, typo corrected the same way).
- shells/: one icon per Shell enum member (shells.py), named to match
exactly so they're a direct Shell.name lookup, no mapping table
needed. A few source files don't carry the shell's short code in
their name (Mustard Gas_DemoBlocked -> MSTD, Tear Gas -> TEAR,
Propaganda -> PRPG, Phosgene -> PHGN, Nuclear -> ATMC), documented in
assets/icons/README.md.
- nest/IronNest.png: the Iron Nest/FDC unit icon.
- misc/ScoutPlane.png: fits the scout-flight planning feature.
Also commits the (already-made, previously uncommitted) .gitignore
entry for GameAssets itself, which is what makes pulling individual
icons out into a tracked directory sensible instead of contradictory.
|