Add match, turn and history views with a dark theme
- Top bar switching between Deck, Match, Turn and History views - Match view: life, player counters, commanders, emblems, zone counts, turn timer and timeouts, land drops used/allowed, play/draw and Bo3 draw counts, with the deck view below - Turn view: per-player and total stats per turn with history, plus whole-game totals and land drops - History: every finished game (colours, winner, who was on the play); click to reopen it in the other views; imports Player-prev.log - Customize menu to show/hide items and an Arrange dialog to reorder deck sections and turn stats, remembered across sessions - Static dark theme with mint accent, rounded corners, larger text - Commanders tracked separately from emblems, with location and tax - Quieter, non-sticky warning for cards lost to MTGA log gaps - Correct Scryfall images for tokens Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7dc2ce0da8
commit
5b3c8c8e63
22 files changed
+2599
-193
No files matched your search
@@ -194,3 +194,34 @@ def test_object_logged_before_its_id_change_is_one_card():
|
||||
t.handle(GreMessages([gsm(3, objects=[card(220, 5005, BATTLEFIELD)])]))
|
||||
t.handle(GreMessages([gsm(4, annotations=[id_changed(210, 220)])]))
|
||||
assert t.opp_seen_match == {5005: 1}
|
||||
|
||||
|
||||
def test_commanders_are_not_emblems():
|
||||
COMMAND, STACK = 26, 27
|
||||
t = MatchTracker()
|
||||
t.handle(GreMessages([{
|
||||
"type": "GREMessageType_ConnectResp", "systemSeatIds": [ME],
|
||||
"connectResp": {"deckMessage": {"deckCards": [1001] * 3, "commanderCards": [8000]}},
|
||||
}]))
|
||||
t.handle(GreMessages([gsm(1, full=True, zones=[
|
||||
zone(COMMAND, "Command", [50, 51, 52]), zone(STACK, "Stack", []), zone(BATTLEFIELD, "Battlefield", []),
|
||||
zone(MY_LIB, "Library", [100, 101, 102], ME), zone(OPP_HAND, "Hand", [], OPP),
|
||||
], objects=[card(50, 8000, COMMAND, ME), card(51, 9000, COMMAND, OPP),
|
||||
card(52, 7777, COMMAND, OPP, otype="Emblem")])]))
|
||||
g = t.game
|
||||
assert g.commander_status(ME) == [(8000, "command zone")]
|
||||
assert g.commander_status(OPP) == [(9000, "command zone")]
|
||||
assert g.emblems(OPP) == {7777: 1}
|
||||
assert g.emblems(ME) == {}
|
||||
assert sum(t.my_library_remaining().values()) == 3 # the commander isn't part of the library
|
||||
|
||||
# Opponent casts their commander from the command zone: it's on the stack, tax goes up.
|
||||
cast = {"type": ["AnnotationType_ZoneTransfer"], "affectedIds": [60], "details": [
|
||||
{"key": "zone_src", "valueInt32": [COMMAND]}, {"key": "zone_dest", "valueInt32": [STACK]},
|
||||
{"key": "category", "valueString": ["CastSpell"]}]}
|
||||
t.handle(GreMessages([gsm(2, annotations=[id_changed(51, 60), cast], zones=[
|
||||
zone(COMMAND, "Command", [50, 52]), zone(STACK, "Stack", [60]),
|
||||
], objects=[card(60, 9000, STACK, OPP)], deleted=[51])]))
|
||||
assert g.commander_status(OPP) == [(9000, "stack")]
|
||||
assert g.commander_tax(OPP) == 2
|
||||
assert g.commander_tax(ME) == 0
|
||||
Reference in new issue
Block a user