diff --git a/.ci/Ubuntu26.04/Dockerfile b/.ci/Ubuntu26.04/Dockerfile
new file mode 100644
index 000000000..7b0cd389f
--- /dev/null
+++ b/.ci/Ubuntu26.04/Dockerfile
@@ -0,0 +1,29 @@
+FROM ubuntu:26.04
+
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ build-essential \
+ ca-certificates \
+ ccache \
+ clang-format \
+ cmake \
+ file \
+ g++ \
+ git \
+ libgl-dev \
+ liblzma-dev \
+ libmariadb-dev-compat \
+ libprotobuf-dev \
+ libqt6multimedia6 \
+ libqt6sql6-mysql \
+ ninja-build \
+ protobuf-compiler \
+ qt6-image-formats-plugins \
+ qt6-l10n-tools \
+ qt6-multimedia-dev \
+ qt6-svg-dev \
+ qt6-tools-dev \
+ qt6-tools-dev-tools \
+ qt6-websockets-dev \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
diff --git a/.ci/release_template.md b/.ci/release_template.md
index b0924b92a..1ce9f4bf7 100644
--- a/.ci/release_template.md
+++ b/.ci/release_template.md
@@ -17,6 +17,7 @@ Available pre-compiled binaries for installation:
• macOS 13+VenturaIntelLinux
+ • Ubuntu 26.04 LTSResolute Racoon
• Ubuntu 24.04 LTSNoble Numbat
• Ubuntu 22.04 LTSJammy Jellyfish
• Debian 13Trixie
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index fc25af67f..88bed3663 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -9,6 +9,9 @@ updates:
- package-ecosystem: "gitsubmodule"
# Look for `.gitmodules` in the `root` directory
directory: "/"
+ ignore:
+ # Ignore updates for vcpkg (Bump to latest tag not working (no SemVer used) & macOS Intel triplet broken with newer releases)
+ - dependency-name: "vcpkg"
# Check for updates once a month
schedule:
interval: "monthly"
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 6843332c6..730dcb06f 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -142,15 +142,21 @@ jobs:
- distro: Ubuntu
version: 22.04
package: DEB
+ test: skip # Running tests on all distros is superfluous
- distro: Ubuntu
version: 24.04
package: DEB
+ - distro: Ubuntu
+ version: 26.04
+ package: DEB
+
name: ${{matrix.distro}} ${{matrix.version}}
needs: configure
runs-on: ubuntu-latest
continue-on-error: ${{matrix.allow-failure == 'yes'}}
+ timeout-minutes: 70
env:
NAME: ${{matrix.distro}}${{matrix.version}}
CACHE: ${{github.workspace}}/.cache/${{matrix.distro}}${{matrix.version}} # directory for caching docker image and ccache
@@ -202,9 +208,10 @@ jobs:
--ccache "$CCACHE_SIZE" $NO_CLIENT
.ci/name_build.sh
- # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342.
+ # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
- name: Delete remote compiler cache (ccache)
if: github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
+ continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}
@@ -265,7 +272,7 @@ jobs:
override_target: 13
make_package: 1
package_suffix: "-macOS13_Intel"
- qt_version: 6.10.*
+ qt_version: 6.11.*
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
cmake_generator: Ninja
@@ -279,7 +286,7 @@ jobs:
type: Release
make_package: 1
package_suffix: "-macOS14"
- qt_version: 6.10.*
+ qt_version: 6.11.*
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
cmake_generator: Ninja
@@ -293,7 +300,7 @@ jobs:
type: Release
make_package: 1
package_suffix: "-macOS15"
- qt_version: 6.10.*
+ qt_version: 6.11.*
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
cmake_generator: Ninja
@@ -305,7 +312,7 @@ jobs:
soc: Apple
xcode: "16.4"
type: Debug
- qt_version: 6.10.*
+ qt_version: 6.11.*
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
cmake_generator: Ninja
@@ -317,7 +324,7 @@ jobs:
type: Release
make_package: 1
package_suffix: "-Win10"
- qt_version: 6.10.*
+ qt_version: 6.11.*
qt_arch: win64_msvc2022_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
cmake_generator: Ninja
@@ -325,6 +332,7 @@ jobs:
name: ${{matrix.os}} ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
needs: configure
runs-on: ${{matrix.runner}}
+ timeout-minutes: 100
env:
CCACHE_DIR: ${{github.workspace}}/.cache/
# Cache size over the entire repo is 10Gi:
@@ -396,6 +404,8 @@ jobs:
if: matrix.os == 'Windows'
uses: jurplel/install-qt-action@v4
with:
+ # qt 6.11.0 only works with aqtinstall directly from git until aqtinstall 3.4 is released
+ aqtsource: git+https://github.com/miurahr/aqtinstall.git
version: ${{ steps.resolve_qt_version.outputs.version }}
arch: ${{matrix.qt_arch}}
modules: ${{matrix.qt_modules}}
@@ -433,9 +443,10 @@ jobs:
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
run: .ci/compile.sh --server --test --vcpkg
- # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342.
+ # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
- name: Delete remote compiler cache (ccache)
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1 && steps.ccache_restore.outputs.cache-hit
+ continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 8da6fc314..975923909 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -564,6 +564,9 @@ if(WIN32)
PATTERN "styles/qopensslbackend.dll"
PATTERN "styles/qschannelbackend.dll"
PATTERN "styles/qwindowsvistastyle.dll"
+ PATTERN "styles/qwindows11style.dll"
+ PATTERN "styles/qmodernwindowsstyle.dll"
+ PATTERN "styles/qmodernwindowsstyled.dll"
PATTERN "tls/qcertonlybackend.dll"
PATTERN "tls/qopensslbackend.dll"
PATTERN "tls/qschannelbackend.dll"
diff --git a/cockatrice/cockatrice_en@source.ts b/cockatrice/cockatrice_en@source.ts
index 9a2f56f07..810b345df 100644
--- a/cockatrice/cockatrice_en@source.ts
+++ b/cockatrice/cockatrice_en@source.ts
@@ -25,12 +25,12 @@
AbstractDlgDeckTextEdit
-
+ &Refresh
-
+ Parse Set Name and Number (if available)
@@ -38,60 +38,60 @@
AbstractTabDeckEditor
-
+ Open in new tab
-
+ Are you sure?
-
+ The decklist has been modified.
Do you want to save the changes?
-
-
-
-
-
-
+
+
+
+
+
+ Error
-
+ Could not open deck at %1
-
+ Could not save remote deck
-
-
+
+ The deck could not be saved.
Please check that the directory is writable and try again.
-
+ Save deck
-
+ The deck could not be saved.
-
+ There are no cards in your deck to be exported
@@ -133,190 +133,168 @@ Please check that the directory is writable and try again.
AppearanceSettingsPage
-
+ seconds
-
+ Error
-
+ Could not create themes directory at '%1'.
-
- Enabling this feature will disable the use of the Printing Selector.
-
-You will not be able to manage printing preferences on a per-deck basis, or see printings other people have selected for their decks.
-
-You will have to use the Set Manager, available through Card Database -> Manage Sets.
-
-Are you sure you would like to enable this feature?
-
-
-
-
- Disabling this feature will enable the Printing Selector.
-
-You can now choose printings on a per-deck basis in the Deck Editor and configure which printing gets added to a deck by default by pinning it in the Printing Selector.
-
-You can also use the Set Manager to adjust custom sort order for printings in the Printing Selector (other sort orders like alphabetical or release date are available).
-
-Are you sure you would like to disable this feature?
-
-
-
-
- Confirm Change
-
-
-
-
+ Theme settings
-
+ Current theme:
-
+ Open themes folder
-
+ Home tab background source:
-
+ Home tab background shuffle frequency:
-
+ Disabled
-
+
+ Display card name of background in bottom right:
+
+
+
+ Menu settings
-
+ Show keyboard shortcuts in right-click menus
-
+ Show game filter toolbar above list in room tab
-
+ Card rendering
-
+ Display card names on cards having a picture
-
+ Auto-Rotate cards with sideways layout
-
+ Override all card art with personal set preference (Pre-ProviderID change behavior)
-
+ Bump sets that the deck contains cards from to the top in the printing selector
-
+ Scale cards on mouse over
-
+ Use rounded card corners
-
+ Minimum overlap percentage of cards on the stack and in vertical hand
-
+ Maximum initial height for card view window:
-
-
+
+ rows
-
+ Maximum expanded height for card view window:
-
+ Card counters
-
+ Counter %1
-
+ Hand layout
-
+ Display hand horizontally (wastes space)
-
+ Enable left justification
-
+ Table grid layout
-
+ Invert vertical coordinate
-
+ Minimum player count for multi-column layout:
-
+ Maximum font size for information displayed on cards:
@@ -324,7 +302,12 @@ Are you sure you would like to disable this feature?
ArchidektApiResponseDeckDisplayWidget
-
+
+ Back to results
+
+
+
+ Open Deck in Deck Editor
@@ -643,22 +626,22 @@ This is only saved for moderators and cannot be seen by the banned person.
CardInfoPictureWidget
-
+ View related cards
-
+ Add card to deck
-
+ Mainboard
-
+ Sideboard
@@ -694,124 +677,124 @@ This is only saved for moderators and cannot be seen by the banned person.
CardMenu
-
+ Re&veal to...
-
+ &All players
-
+ View related cards
-
+ Token:
-
+ All tokens
-
+ &Select All
-
+ S&elect Row
-
+ S&elect Column
-
+ &Play
-
+ &Hide
-
+ Play &Face Down
-
+ &Tap / UntapTurn sideways or back again
-
- Toggle &normal untapping
+
+ Skip &untapping
-
+ T&urn OverTurn face up/face down
-
+ &Peek at card face
-
+ &Clone
-
+ Attac&h to card...
-
+ Unattac&h
-
+ &Draw arrow...
-
+ &Set annotation...
-
+ Ca&rd counters
-
+ &Add counter (%1)
-
+ &Remove counter (%1)
-
+ &Set counters (%1)...
@@ -827,133 +810,133 @@ This is only saved for moderators and cannot be seen by the banned person.
CardZoneLogic
-
+ their handnominative
-
+ %1's handnominative
-
+ their librarylook at zone
-
+ %1's librarylook at zone
-
+ of their librarytop cards of zone,
-
+ of %1's librarytop cards of zone
-
+ their libraryreveal zone
-
+ %1's libraryreveal zone
-
+ their libraryshuffle
-
+ %1's libraryshuffle
-
+ their librarynominative
-
-
- %1's library
- nominative
-
-
+ %1's library
+ nominative
+
+
+
+ their graveyardnominative
-
+ %1's graveyardnominative
-
+ their exilenominative
-
+ %1's exilenominative
-
-
- their sideboard
- look at zone
-
-
-
-
- %1's sideboard
- look at zone
-
- their sideboard
- nominative
+ look at zone%1's sideboard
+ look at zone
+
+
+
+
+ their sideboardnominative
-
+
+ %1's sideboard
+ nominative
+
+
+
+ their custom zone '%1'nominative
-
+ %1's custom zone '%2'nominative
@@ -1015,7 +998,7 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorCardDatabaseDockWidget
-
+ Card Database
@@ -1023,7 +1006,7 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorCardInfoDockWidget
-
+ Card Info
@@ -1046,32 +1029,32 @@ This is only saved for moderators and cannot be seen by the banned person.
-
+ Select Printing
-
+ Show on EDHRec (Commander)
-
+ Show on EDHRec (Card)
-
+ Show Related cards
-
+ Add card to &maindeck
-
+ Add card to &sideboard
@@ -1079,32 +1062,32 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorDeckDockWidget
-
+ Loading Database...
-
+ Banner Card
-
+ Main Type
-
+ Mana Cost
-
+ Colors
-
+ Select Printing
@@ -1177,17 +1160,17 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorFilterDockWidget
-
+ Filters
-
+ &Clear all filters
-
+ Delete selected
@@ -1310,7 +1293,7 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorPrintingSelectorDockWidget
-
+ Printing Selector
@@ -1318,166 +1301,166 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorSettingsPage
-
-
+
+ Update Spoilers
-
-
+
+ Success
-
+ Download URLs have been reset.
-
+ Downloaded card pictures have been reset.
-
+ Error
-
+ One or more downloaded card pictures could not be cleared.
-
+ Add URL
-
-
+
+ URL:
-
-
+
+ Edit URL
-
+ Network Cache Size:
-
+ Redirect Cache TTL:
-
+ How long cached redirects for urls are valid for.
-
+ Picture Cache Size:
-
+ Add New URL
-
+ Remove URL
-
+ Day(s)
-
+ Updating...
-
+ Choose path
-
+ URL Download Priority
-
+ Spoilers
-
+ Download Spoilers Automatically
-
+ Spoiler Location:
-
+ Last Change
-
+ Spoilers download automatically on launch
-
+ Press the button to manually update without relaunching
-
+ Do not close settings until manual update is complete
-
+ Download card pictures on the fly
-
+ How to add a custom URL
-
+ Delete Downloaded Images
-
+ Reset Download URLs
-
+ On-disk cache for downloaded pictures
-
+ In-memory cache for pictures not currently on screen
@@ -1485,32 +1468,32 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckListHistoryManagerWidget
-
+ Undo
-
+ Redo
-
+ Undo/Redo history
-
+ Click on an entry to revert to that point in the history.
-
+ [redo]
-
+ [undo]
@@ -1518,27 +1501,27 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckListModel
-
+ Count
-
+ Set
-
+ Number
-
+ Provider ID
-
+ Card
@@ -1546,12 +1529,12 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckLoader
-
+ Common deck formats (%1)
-
+ All files (*.*)
@@ -1648,94 +1631,94 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckPreviewWidget
-
+ Banner Card
-
+ Open in deck editor
-
+ Edit Tags
-
+ Rename Deck
-
+ Save Deck to Clipboard
-
+ Annotated
-
+ Annotated (No set info)
-
+ Not Annotated
-
+ Not Annotated (No set info)
-
+ Rename File
-
+ Delete File
-
+ Set Banner Card
-
-
+
+ New name:
-
-
+
+ Error
-
+ Rename failed
-
+ Delete file
-
+ Are you sure you want to delete the selected file?
-
+ Delete failed
@@ -1768,32 +1751,32 @@ This is only saved for moderators and cannot be seen by the banned person.
-
+ Added (%1): %2 (%3) %4
-
+ Moved to %1 1 × "%2" (%3)
-
+ Removed "%1" (all copies)
-
+ %1 1 × "%2" (%3)
-
+ Added
-
+ Removed
@@ -1860,29 +1843,29 @@ This is only saved for moderators and cannot be seen by the banned person.
-
-
+
+ Error
-
+ The selected file could not be loaded.
-
+ Deck is greater than maximum file size.
-
+ Are you sure you want to force start?
This will kick all non-ready players from the game.
-
+ Cockatrice
@@ -2374,17 +2357,17 @@ To remove your current avatar, confirm without choosing a new image.
DlgEditDeckInClipboard
-
+ Edit deck in clipboard
-
+ Error
-
+ Invalid deck list.
@@ -2884,17 +2867,17 @@ Make sure to enable the 'Token' set in the "Manage sets" dia
DlgLoadDeckFromClipboard
-
+ Load deck from clipboard
-
+ Error
-
+ Invalid deck list.
@@ -2902,43 +2885,43 @@ Make sure to enable the 'Token' set in the "Manage sets" dia
DlgLoadDeckFromWebsite
-
+ Paste a link to a decklist site here to import it.
(Archidekt, Deckstats, Moxfield, and TappedOut are supported.)
-
-
-
-
-
+
+
+
+
+ Load Deck from Website
-
+ No parser available for this deck provider.
(Archidekt, Deckstats, Moxfield, and TappedOut are supported.)
-
+ Network error: %1
-
+ Received empty deck data.
-
+ Failed to parse deck data: %1
-
+ The provided URL is not recognized as a valid deck URL.
Valid deck URLs look like this:
@@ -2957,40 +2940,73 @@ https://tappedout.net/mtg-decks/your-deck-name/
+
+ DlgLocalGameOptions
+
+
+ Players:
+
+
+
+
+ General
+
+
+
+
+ Starting life total:
+
+
+
+
+ Game setup options
+
+
+
+
+ Remember settings
+
+
+
+
+ Local game options
+
+
+DlgMoveTopCardsUntil
-
+ Card name (or search expressions):
-
+ Number of hits:
-
+ Auto play hits
-
+ Put top cards on stack until...
-
+ No cards matching the search expression exists in the card database. Proceed anyways?
-
+ Cockatrice
-
+ Invalid filter
@@ -3151,12 +3167,12 @@ Your email will be used to verify your account.
DlgSettings
-
+ Unknown Error loading card database
-
+ Your card database is invalid.
Cockatrice may not function correctly with an invalid database
@@ -3167,7 +3183,7 @@ Would you like to change your database location setting?
-
+ Your card database version is too old.
This can cause problems loading card information or images
@@ -3178,7 +3194,7 @@ Would you like to change your database location setting?
-
+ Your card database did not finish loading
Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues with your cards.xml attached
@@ -3187,21 +3203,21 @@ Would you like to change your database location setting?
-
+ File Error loading your card database.
Would you like to change your database location setting?
-
+ Your card database was loaded but contains no cards.
Would you like to change your database location setting?
-
+ Unknown card database load status
Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues
@@ -3210,59 +3226,59 @@ Would you like to change your database location setting?
-
-
-
+
+
+ Error
-
+ The path to your deck directory is invalid. Would you like to go back and set the correct path?
-
+ The path to your card pictures directory is invalid. Would you like to go back and set the correct path?
-
+ Settings
-
+ General
-
+ Appearance
-
+ User Interface
-
+ Card Sources
-
+ Chat
-
+ Sound
-
+ Shortcuts
@@ -3575,67 +3591,67 @@ You may have to manually download the new version.
DrawProbabilityWidget
-
+ Draw Probability
-
+ Probability of drawing
-
+ Card Name
-
+ Type
-
+ Subtype
-
+ Mana Value
-
+ At least
-
+ Exactly
-
+ card(s) having drawn at least
-
+ cards
-
+ Category
-
+ Qty
-
+ Odds (%)
@@ -4089,143 +4105,143 @@ You may have to manually download the new version.
GeneralSettingsPage
-
+ Reset all paths
-
+ All paths have been reset
-
-
-
-
-
-
-
+
+
+
+
+
+
+ Choose path
-
+ Personal settings
-
+ Language:
-
+ Paths (editing disabled in portable mode)
-
+ Paths
-
+ How to help with translations
-
+ Decks directory:
-
+ Filters directory:
-
+ Replays directory:
-
+ Pictures directory:
-
+ Card database:
-
+ Custom database directory:
-
+ Token database:
-
+ Update channel
-
+ Check for client updates on startup
-
+ Check for card database updates on startup
-
+ Don't check
-
+ Prompt for update
-
+ Always update in the background
-
+ Check for card database updates every
-
+ days
-
+ Notify if a feature supported by the server is missing in my client
-
+ Automatically run Oracle when running a new version of Cockatrice
-
+ Show tips on startup
-
+ Last update check on %1 (%2 days ago)
@@ -4233,47 +4249,47 @@ You may have to manually download the new version.
GraveyardMenu
-
+ &Graveyard
-
+ &View graveyard
-
+ &Move graveyard to...
-
+ &Top of library
-
+ &Bottom of library
-
+ &All players
-
+ &Hand
-
+ &Exile
-
+ Reveal random card to...
@@ -4281,88 +4297,88 @@ You may have to manually download the new version.
HandMenu
-
+ &Hand
-
+ &View hand
-
+ Sort hand by...
-
+ Name
-
+ Type
-
+ Mana Value
-
+ Take &mulligan (Choose hand size)
-
+ Take mulligan (Same hand size)
-
+ Take mulligan (Hand size - 1)
-
+ &Move hand to...
-
+ &Top of library
-
+ &Bottom of library
-
+ &Graveyard
-
+ &Exile
-
+ &Reveal hand to...
-
-
+
+ All players
-
+ Reveal r&andom card to...
@@ -4370,52 +4386,52 @@ You may have to manually download the new version.
HomeWidget
-
+ Create New Deck
-
+ Browse Decks
-
+ Browse Card Database
-
+ Browse EDHRec
-
+ Browse Archidekt
-
+ View Replays
-
+ Quit
-
+ Connecting...
-
+ Connect
-
+ Play
@@ -4423,193 +4439,213 @@ You may have to manually download the new version.
LibraryMenu
-
+ &Library
-
+ &View library
-
+ View &top cards of library...
-
+ View bottom cards of library...
-
+ Reveal &library to...
-
+ Lend library to...
-
+ Reveal &top cards to...
-
+ &Top of library...
-
+ &Bottom of library...
-
+ &Always reveal top card
-
+ &Always look at top card
-
+ &Open deck in deck editor
-
+ &Draw card
-
+ D&raw cards...
-
+ &Undo last draw
-
+ Shuffle
-
+ &Play top card
-
+ Play top card &face down
-
+ Put top card on &bottom
-
+ Move top card to grave&yard
-
+ Move top card to e&xile
-
+ Move top cards to &graveyard...
-
+
+ Move top cards to graveyard face down...
+
+
+
+ Move top cards to &exile...
-
+
+ Move top cards to exile face down...
+
+
+
+ Put top cards on stack &until...
-
+ Shuffle top cards...
-
+ &Draw bottom card
-
+ D&raw bottom cards...
-
+ &Play bottom card
-
+ Play bottom card &face down
-
+ Move bottom card to grave&yard
-
+ Move bottom card to e&xile
-
+ Move bottom cards to &graveyard...
-
+
+ Move bottom cards to graveyard face down...
+
+
+
+ Move bottom cards to &exile...
-
+
+ Move bottom cards to exile face down...
+
+
+
+ Put bottom card on &top
-
+ Shuffle bottom cards...
-
-
+
+ &All players
-
+ Reveal top cards of library
-
+ Number of cards: (max. %1)
@@ -4703,18 +4739,8 @@ Will now login.
-
- Number of players
-
-
-
-
- Please enter the number of players.
-
-
-
-
-
+
+ Player %1
@@ -4817,8 +4843,8 @@ Will now login.
-
-
+
+ Error
@@ -5219,63 +5245,63 @@ Local version is %1, remote version is %2.
-
+ New Version
-
+ Congratulations on updating to Cockatrice %1!
Oracle will now launch to update your card database.
-
+ Cockatrice installed
-
+ Congratulations on installing Cockatrice %1!
Oracle will now launch to install the initial card database.
-
+ Card database
-
+ Cockatrice is unable to load the card database.
Do you want to update your card database now?
If unsure or first time user, choose "Yes"
-
-
+
+ Yes
-
-
+
+ No
-
+ Open settings
-
+ New sets found
-
+ %n new set(s) found in the card database
Set code(s): %1
Do you want to enable it/them?
@@ -5285,81 +5311,81 @@ Do you want to enable it/them?
-
+ View sets
-
+ Welcome
-
+ Hi! It seems like you're running this version of Cockatrice for the first time.
All the sets in the card database have been enabled.
Read more about changing the set order or disabling specific sets and consequent effects in the "Manage Sets" dialog.
-
-
+
+ Information
-
+ A card database update is already running.
-
+ Unable to run the card database updater:
-
+ Card database update running.
-
+ Failed to start. The file might be missing, or permissions might be incorrect.
-
+ The process crashed some time after starting successfully.
-
+ Timed out. The process took too long to respond. The last waitFor...() function timed out.
-
+ An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.
-
+ An error occurred when attempting to read from the process. For example, the process may not be running.
-
+ Unknown error occurred.
-
+ The card database updater exited with an error:
%1
-
+ This server supports additional features that your client doesn't have.
This is most likely not a problem, but this message might mean there is a new version of Cockatrice available or this server is running a custom or pre-release version.
@@ -5367,54 +5393,54 @@ To update your client, go to Help -> Check for Updates.
-
-
-
-
-
+
+
+
+
+ Load sets/cards
-
+ Selected file cannot be found.
-
+ You can only import XML databases at this time.
-
+ The new sets/cards have been added successfully.
Cockatrice will now reload the card database.
-
+ Sets/cards failed to import.
-
-
-
+
+
+ Reset Password
-
+ Your password has been reset successfully, you can now log in using the new credentials.
-
+ Failed to reset user account password, please contact the server operator to reset your password.
-
+ Activation request received, please check your email for an activation token.
@@ -5465,7 +5491,7 @@ Cockatrice will now reload the card database.
ManaBaseWidget
-
+ Mana Base
@@ -5619,277 +5645,297 @@ Cockatrice will now reload the card database.
MessageLogWidget
-
+ from play
-
+ from their graveyard
-
+ from exile
-
+ from their hand
-
+ the top card of %1's library
-
+ the top card of their library
-
+ from the top of %1's library
-
+ from the top of their library
-
+ the bottom card of %1's library
-
+ the bottom card of their library
-
+ from the bottom of %1's library
-
+ from the bottom of their library
-
+ from %1's library
-
+ from their library
-
+ from sideboard
-
+ from the stack
-
+ from custom zone '%1'
-
+ %1 is now keeping the top card %2 revealed.
-
+ %1 is not revealing the top card %2 any longer.
-
+ %1 can now look at top card %2 at any time.
-
+ %1 no longer can look at top card %2 at any time.
-
+ %1 attaches %2 to %3's %4.
-
+ %1 has conceded the game.
-
+ %1 has unconceded the game.
-
+ %1 has restored connection to the game.
-
+ %1 has lost connection to the game.
-
+ %1 points from their %2 to themselves.
-
+ %1 points from their %2 to %3.
-
+ %1 points from %2's %3 to themselves.
-
+ %1 points from %2's %3 to %4.
-
+ %1 points from their %2 to their %3.
-
+ %1 points from their %2 to %3's %4.
-
+ %1 points from %2's %3 to their own %4.
-
+ %1 points from %2's %3 to %4's %5.
-
+ %1 creates a face down token.
-
+ %1 creates token: %2%3.
-
+ %1 has loaded a deck (%2).
-
+ %1 has loaded a deck with %2 sideboard cards (%3).
-
+ %1 destroys %2.
-
+ a card
-
+ %1 gives %2 control over %3.
-
+ %1 puts %2 into play%3 face down.
-
+ %1 puts %2 into play%3.
-
+
+ %1 puts %2%3 into their graveyard face down.
+
+
+
+ %1 puts %2%3 into their graveyard.
+
+
+ %1 exiles %2%3 face down.
+
+ %1 exiles %2%3.
-
+ %1 moves %2%3 to their hand.
-
+ %1 puts %2%3 into their library.
-
+ %1 puts %2%3 onto the bottom of their library.
-
+ %1 puts %2%3 on top of their library.
-
+ %1 puts %2%3 into their library %4 cards from the top.
-
+ %1 moves %2%3 to sideboard.
-
+
+ %1 plays %2%3 face down.
+
+
+
+ %1 plays %2%3.
-
+
+ %1 moves %2%3 to custom zone '%4' face down.
+
+
+
+ %1 moves %2%3 to custom zone '%4'.
-
+ %1 tries to draw from an empty library
-
+ %1 draws %2 card(s).
@@ -5897,12 +5943,12 @@ Cockatrice will now reload the card database.
-
+ %1 is looking at %2.
-
+ %1 is looking at the %4 %3 card(s) %2.top card for singular, top %3 cards for plural
@@ -5911,72 +5957,72 @@ Cockatrice will now reload the card database.
-
+ bottom
-
+ top
-
+ %1 turns %2 face-down.
-
+ %1 turns %2 face-up.
-
+ The game has been closed.
-
+ The game has started.
-
+ You are flooding the game. Please wait a couple of seconds.
-
+ %1 has joined the game.
-
+ %1 is now watching the game.
-
+ You have been kicked out of the game.
-
+ %1 has left the game (%2).
-
+ %1 is not watching the game any more (%2).
-
+ %1 is not ready to start the game any more.
-
+ %1 shuffles their deck and draws a new hand of %2 card(s).
@@ -5984,28 +6030,28 @@ Cockatrice will now reload the card database.
-
+ %1 shuffles their deck and draws a new hand.
-
+ You are watching a replay of game #%1.
-
+ %1 is ready to start the game.
-
+ cardsan unknown amount of cards
-
+ %1 card(s)a card for singular, %1 cards for plural
@@ -6014,107 +6060,107 @@ Cockatrice will now reload the card database.
-
+ %1 lends %2 to %3.
-
+ %1 reveals %2 to %3.
-
+ %1 reveals %2.
-
+ %1 randomly reveals %2%3 to %4.
-
+ %1 randomly reveals %2%3.
-
+ %1 peeks at face down card #%2.
-
+ %1 peeks at face down card #%2: %3.
-
+ %1 reveals %2%3 to %4.
-
+ %1 reveals %2%3.
-
+ %1 reversed turn order, now it's %2.
-
+ reversed
-
+ normal
-
+ Heads
-
+ Tails
-
+ %1 flipped a coin. It landed as %2.
-
+ %1 rolls a %2 with a %3-sided die.
-
+ %1 flips %2 coins. There are %3 heads and %4 tails.
-
+ %1 rolls a %2-sided dice %3 times: %4.
-
+ %1's turn.
-
+ %1 sets annotation of %2 to %3.
-
+ %1 places %2 "%3" counter(s) on %4 (now %5).
@@ -6122,7 +6168,7 @@ Cockatrice will now reload the card database.
-
+ %1 removes %2 "%3" counter(s) from %4 (now %5).
@@ -6130,97 +6176,97 @@ Cockatrice will now reload the card database.
-
+ %1 sets counter %2 to %3 (%4%5).
-
+ %1 sets %2 to not untap normally.
-
+ %1 sets %2 to untap normally.
-
+ %1 removes the PT of %2.
-
+ %1 changes the PT of %2 from nothing to %4.
-
+ %1 changes the PT of %2 from %3 to %4.
-
+ %1 has locked their sideboard.
-
+ %1 has unlocked their sideboard.
-
+ %1 taps their permanents.
-
+ %1 untaps their permanents.
-
+ %1 taps %2.
-
+ %1 untaps %2.
-
+ %1 shuffles %2.
-
+ %1 shuffles the bottom %3 cards of %2.
-
+ %1 shuffles the top %3 cards of %2.
-
+ %1 shuffles cards %3 - %4 of %2.
-
+ %1 unattaches %2.
-
+ %1 undoes their last draw.
-
+ %1 undoes their last draw (%2).
@@ -6228,110 +6274,110 @@ Cockatrice will now reload the card database.
MessagesSettingsPage
-
+ Word1 Word2 Word3
-
+ Add New Message
-
+ Edit Message
-
+ Remove Message
-
+ Add message
-
-
+
+ Message:
-
+ Edit message
-
+ Chat settings
-
+ Custom alert words
-
+ Enable chat mentions
-
+ Enable mention completer
-
+ In-game message macros
-
+ How to use in-game message macros
-
+ Ignore chat room messages sent by unregistered users
-
+ Ignore private messages sent by unregistered users
-
-
+
+ Invert text color
-
+ Enable desktop notifications for private messages
-
+ Enable desktop notification for mentions
-
+ Enable room message history on join
-
-
+
+ (Color is hexadecimal)
-
+ Separate words with a space, alphanumeric characters only
@@ -6344,32 +6390,37 @@ Cockatrice will now reload the card database.
-
+ &Top of library in random order
-
+ X cards from the top of library...
-
+ &Bottom of library in random order
-
+
+ T&able
+
+
+
+ &Hand
-
+ &Graveyard
-
+ &Exile
@@ -6511,57 +6562,57 @@ Cockatrice will now reload the card database.
PhasesToolbar
-
+ Untap step
-
+ Upkeep step
-
+ Draw step
-
+ First main phase
-
+ Beginning of combat step
-
+ Declare attackers step
-
+ Declare blockers step
-
+ Combat damage step
-
+ End of combat step
-
+ Second main phase
-
+ End of turn step
@@ -6578,134 +6629,138 @@ Cockatrice will now reload the card database.
PlayerActions
-
+ View top cards of library
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ Number of cards: (max. %1)
-
+ View bottom cards of library
-
+ Shuffle top cards of library
-
+ Shuffle bottom cards of library
-
+ Draw hand
-
+ 0 and lower are in comparison to current hand size
-
+ Draw cards
+
+
+
+
+
+ grave
+
+
- Move top cards to grave
+
+
+
+ exile
-
- Move top cards to exile
+
+ Move top cards to %1
-
- Move bottom cards to grave
+
+ Move bottom cards to %1
-
- Move bottom cards to exile
-
-
-
-
+ Draw bottom cards
-
-
+
+ C&reate another %1 token
-
+ Create tokens
-
-
+
+ Number:
-
+ Place card X cards from top of library
-
+ Which position should this card be placed:
-
+ (max. %1)
-
+ Change power/toughness
-
+ Change stats to:
-
+ Set annotation
-
+ Please enter the new annotation:
-
+ Set counters
@@ -6713,48 +6768,65 @@ Cockatrice will now reload the card database.
PlayerMenu
-
+ Player "%1"
-
+ &Counters
+
+
+ PrintingDisabledInfoWidget
-
- S&ay
+
+ The Printing Selector is disabled because you have currently enabled the setting to override all selected printings with personal set preferences.
+
+This setting means you'll only see the default printing for each card, instead of being able to select a printing, and will not see the printings other people have selected.
+
+
+
+
+
+
+ Enable printings againPrintingSelector
-
+ Display Navigation Buttons
+
+
+ Printing Selector
+
+ PrintingSelectorCardOverlayWidget
-
+ Preference
-
+ Pin Printing
-
+ Unpin Printing
-
+ Show Related cards
@@ -6803,17 +6875,25 @@ Cockatrice will now reload the card database.
-
-
+
+ Descending
-
+ Ascending
+
+ PrintingSelectorPlaceholderWidget
+
+
+ Select a card to view its available printings
+
+
+PtMenu
@@ -6952,6 +7032,33 @@ Cockatrice will now reload the card database.
A .cod version of this deck already exists. Overwrite it?
+
+
+ Enabling this feature will disable the use of the Printing Selector.
+
+You will not be able to manage printing preferences on a per-deck basis, or see printings other people have selected for their decks.
+
+You will have to use the Set Manager, available through Card Database -> Manage Sets.
+
+Are you sure you would like to enable this feature?
+
+
+
+
+ Disabling this feature will enable the Printing Selector.
+
+You can now choose printings on a per-deck basis in the Deck Editor and configure which printing gets added to a deck by default by pinning it in the Printing Selector.
+
+You can also use the Set Manager to adjust custom sort order for printings in the Printing Selector (other sort orders like alphabetical or release date are available).
+
+Are you sure you would like to disable this feature?
+
+
+
+
+ Confirm Change
+
+ QPlatformTheme
@@ -7100,37 +7207,37 @@ Cockatrice will now reload the card database.
RfgMenu
-
+ &Exile
-
+ &View exile
-
+ &Move exile to...
-
+ &Top of library
-
+ &Bottom of library
-
+ &Hand
-
+ &Graveyard
@@ -7173,6 +7280,14 @@ Cockatrice will now reload the card database.
+
+ SayMenu
+
+
+ S&ay
+
+
+SequenceEdit
@@ -7237,53 +7352,53 @@ Cockatrice will now reload the card database.
ShortcutSettingsPage
-
-
+
+ Restore all default shortcuts
-
+ Do you really want to restore all default shortcuts?
-
+ Clear all default shortcuts
-
+ Do you really want to clear all shortcuts?
-
+ Section:
-
+ Action:
-
+ Shortcut:
-
+ How to set custom shortcuts
-
+ Clear all shortcuts
-
+ Search by shortcut name
@@ -7350,27 +7465,27 @@ Please check your shortcut settings!
SoundSettingsPage
-
+ Enable &sounds
-
+ Current sounds theme:
-
+ Test system sound engine
-
+ Sound settings
-
+ Master volume
@@ -7586,59 +7701,123 @@ Please check your shortcut settings!
TabArchidekt
-
-
+
+
+ Desc.
-
- Asc.
+
+
+ AND
-
-
- Any Bracket
+
+
+ Require ALL selected colors
-
- Deck name contains...
+
+
+ Deck name...
-
- Owner name contains...
+
+
+ Owner...
+
+
+
+
+
+ Packages
+
+
+
+
+
+ Advanced Filters
- Disabled
+ Bracket:
-
+
+
+ Any
+
+
+
+
+
+ Contains card...
+
+
+
+
+
+ Commander...
+
+
+
+
+
+ Tag...
+
+
+
+
+
+ Deck Size
+
+
+
+
+ Cards:
+
+
+
+
+
+ Asc.
+
+
+
+
+ Sort by:
+
+
+
+
+ Filter by:
+
+
+
+
+ Display Settings
+
+
+
+
+ Search
-
+
+ Formats
-
- Min. # of Cards:
-
-
-
-
- Page:
-
-
-
-
+ Archidekt:
@@ -7646,60 +7825,52 @@ Please check your shortcut settings!
TabDeckEditor
-
+ Card Info
-
+ Deck
-
+ Filters
-
+ &View
-
+ Card Database
-
+ Printing
-
-
-
-
-
+ Visible
-
-
-
-
-
+ Floating
-
+ Reset layout
-
+ Deck: %1
@@ -7707,61 +7878,55 @@ Please check your shortcut settings!
TabDeckEditorVisual
-
+ Visual Deck: %1
-
+ &Visual Deck Editor
-
-
+
+ Card Info
-
-
+
+ Deck
-
-
+
+ Filters
-
+ &View
-
+ Printing
-
-
-
-
+ Visible
-
-
-
-
+ Floating
-
+ Reset layout
@@ -7826,7 +7991,7 @@ Please check your shortcut settings!
-
+ New folder
@@ -7907,18 +8072,18 @@ Please enter a name:
-
+ Delete remote decks
-
+ Are you sure you want to delete the selected decks?
-
+ Name of new folder:
@@ -7936,12 +8101,12 @@ Please enter a name:
-
+ Error
-
+ Could not open deck at %1
@@ -7990,197 +8155,191 @@ Please enter a name:
TabGame
-
-
-
+
+
+ Replay
-
-
+
+ Game
-
-
+
+ Player List
-
-
+
+ Card Info
-
-
+
+ Messages
-
-
+
+ Replay Timeline
-
+ &Phases
-
+ &Game
-
+ Next &phase
-
+ Next phase with &action
-
+ Next &turn
-
+ Reverse turn order
-
+ &Remove all local arrows
-
+ Rotate View Cl&ockwise
-
+ Rotate View Co&unterclockwise
-
+ Game &information
-
+ Un&concede
-
-
-
+
+
+ &Concede
-
+ &Leave game
-
+ C&lose replay
-
+ &Focus Chat
-
+ &Say:
-
+ Selected cards
-
+ &View
-
-
-
-
+ Visible
-
-
-
-
+ Floating
-
+ Reset layout
-
+ Concede
-
+ Are you sure you want to concede this game?
-
+ Unconcede
-
+ You have already conceded. Do you want to return to this game?
-
+ Leave game
-
+ Are you sure you want to leave this game?
-
+ A player has joined game #%1
-
+ %1 has joined the game
-
+ You have been kicked out of the game.
@@ -9280,142 +9439,152 @@ Please refrain from engaging in this activity or further actions may be taken ag
UserInterfaceSettingsPage
-
+ General interface settings
-
+ &Double-click cards to play them (instead of single-click)
-
+ &Clicking plays all selected cards (instead of just the clicked card)
-
+ &Play all nonlands onto the stack (not the battlefield) by default
-
+ Do not delete &arrows inside of subphases
-
+ Close card view window when last card is removed
-
+ Auto focus search bar when card view window is opened
-
+ Annotate card text on tokens
-
-
- Use tear-off menus, allowing right click menus to persist on screen
-
-
-
-
- Notifications settings
-
-
-
-
- Enable notifications in taskbar
-
-
-
-
- Notify in the taskbar for game events while you are spectating
-
-
-
-
- Notify in the taskbar when users in your buddy list connect
-
-
-
-
- Animation settings
-
-
-
-
- &Tap/untap animation
-
-
-
-
- Deck editor/storage settings
-
-
-
-
- Open deck in new tab by default
-
-
- Use visual deck storage in game lobby
+ Show selection counter during drag selection
- Use selection animation for Visual Deck Storage
+ Show total selection counter
+
+
+
+
+ Use tear-off menus, allowing right click menus to persist on screen
- When adding a tag in the visual deck storage to a .txt deck:
+ Notifications settings
+
+
+
+
+ Enable notifications in taskbar
- do nothing
+ Notify in the taskbar for game events while you are spectating
+
+
+
+
+ Notify in the taskbar when users in your buddy list connect
- ask to convert to .cod
+ Animation settings
+
+
+
+
+ &Tap/untap animation
- always convert to .cod
+ Deck editor/storage settings
- Default deck editor type
+ Open deck in new tab by default
- Classic Deck Editor
+ Use visual deck storage in game lobby
- Visual Deck Editor
-
-
-
-
- Replay settings
+ Use selection animation for Visual Deck Storage
+ When adding a tag in the visual deck storage to a .txt deck:
+
+
+
+
+ do nothing
+
+
+
+
+ ask to convert to .cod
+
+
+
+
+ always convert to .cod
+
+
+
+
+ Default deck editor type
+
+
+
+
+ Classic Deck Editor
+
+
+
+
+ Visual Deck Editor
+
+
+
+
+ Replay settings
+
+
+
+ Buffer time for backwards skip via shortcut:
@@ -9479,23 +9648,24 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayColorFilterWidget
-
- Mode: Exact Match
+
+ Exact match
+
+
+
+
+ Includes
- Mode: Includes
+ Include / Exclude
+ Mode: Includes
-
- Mode: Include/Exclude
-
-
-
-
- Filter mode (AND/OR/NOT conjunctions of filters)
+
+ How selected and unselected colors are combined in the filter
@@ -9522,25 +9692,108 @@ Please refrain from engaging in this activity or further actions may be taken ag
+
+ VisualDatabaseDisplayFilterToolbarWidget
+
+
+ Sort by
+
+
+
+
+ Filter by
+
+
+
+
+ Save and load filters
+
+
+
+
+ Filter by exact card name
+
+
+
+
+ Filter by card main-type
+
+
+
+
+ Filter by card sub-type
+
+
+
+
+ Filter by set
+
+
+
+
+ Filter by format legality
+
+
+
+
+ Save/Load
+
+
+
+
+ Name
+
+
+
+
+ Main Type
+
+
+
+
+ Sub Type
+
+
+
+
+ Sets
+
+
+
+
+ Formats
+
+
+VisualDatabaseDisplayFormatLegalityFilterWidget
-
+
+ Show formats with at least:
+
+
+
+
+ cards
+
+
+
+ Do not display formats with less than this amount of cards in the database
-
+ Filter mode (AND/OR/NOT conjunctions of filters)
-
+ Mode: Exact Match
-
+ Mode: Includes
@@ -9548,22 +9801,32 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayMainTypeFilterWidget
-
+
+ Show main types with at least:
+
+
+
+
+ cards
+
+
+
+ Do not display card main-types with less than this amount of cards in the database
-
+ Filter mode (AND/OR/NOT conjunctions of filters)
-
+ Mode: Exact Match
-
+ Mode: Includes
@@ -9599,7 +9862,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayRecentSetFilterSettingsWidget
-
+ Filter to most recent sets
@@ -9607,19 +9870,19 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplaySetFilterWidget
-
+ Search sets...
-
-
+
+ Mode: Exact Match
-
-
+
+ Mode: Includes
@@ -9627,27 +9890,37 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplaySubTypeFilterWidget
-
+ Search subtypes...
-
+
+ Show sub types with at least:
+
+
+
+
+ cards
+
+
+
+ Do not display card sub-types with less than this amount of cards in the database
-
+ Filter mode (AND/OR/NOT conjunctions of filters)
-
+ Mode: Exact Match
-
+ Mode: Includes
@@ -9661,52 +9934,22 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ Visual
-
+ Loading database ...
-
+ Clear all filters
-
- Sort by:
-
-
-
-
- Filter by:
-
-
-
-
- Save and load filters
-
-
-
-
- Filter by exact card name
-
-
-
-
- Filter by card sub-type
-
-
-
-
- Filter by set
-
-
-
-
+ Table
@@ -9714,56 +9957,64 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDeckDisplayOptionsWidget
-
+ Group by:
-
+ Change how cards are divided into categories/groups.
-
+ Sort by:
-
+ Click and drag to change the sort order within the groups
-
+ Configure how cards are sorted within their groups
-
-
+
+ Toggle Layout: Overlap
-
+ Change how cards are displayed within zones (i.e. overlapped or fully visible.)
-
+ Toggle Layout: Flat
+
+ VisualDeckEditorPlaceholderWidget
+
+
+ Add cards using the search bar or database tab to have them appear here
+
+
+VisualDeckEditorSampleHandWidget
-
+ Draw a new sample hand
-
+ Sample hand size
@@ -9771,17 +10022,17 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDeckEditorWidget
-
+ Type a card name here for suggestions from the database...
-
+ Quick search and add card
-
+ Search for closest match in the database (with auto-suggestions) and add preferred printing to the deck on pressing enter
@@ -9797,47 +10048,52 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDeckStorageQuickSettingsWidget
-
+ Show Folders
-
+ Show Tag Filter
-
+
+ Show Color Identity
+
+
+
+ Show Tags On Deck Previews
-
+ Show Banner Card Selection Option
-
+ Draw unused Color Identities
-
+ Unused Color Identities Opacity
-
+ Deck tooltip:
-
+ None
-
+ Filepath
@@ -9938,133 +10194,133 @@ Please refrain from engaging in this activity or further actions may be taken ag
WndSets
-
+ Move selected set to the top
-
+ Move selected set up
-
+ Move selected set down
-
+ Move selected set to the bottom
-
+ Search by set name, code, or type
-
+ Default order
-
+ Restore original art priority order
-
+ Enable all sets
-
+ Disable all sets
-
+ Enable selected set(s)
-
+ Disable selected set(s)
-
+ Deck Editor
-
+ Use CTRL+A to select all sets in the view.
-
+ Only cards in enabled sets will appear in the card list of the deck editor.
-
+ Image priority is decided in the following order:
-
+ first the CUSTOM Folder (%1), then the Enabled Sets in this dialog (Top to Bottom)%1 is a link to the wiki
-
+ Include cards rebalanced for Alchemy [requires restart]
-
+ Card Art
-
+ How to use custom card art
-
+ Hints
-
+ Note
-
+ Sorting by column allows you to find a set while not changing set priority.
-
+ To enable ordering again, click the column header until this message disappears.
-
+ Use the current sorting as the set priority instead
-
+ Sorts the set priority using the same column
-
+ Manage sets
@@ -10072,72 +10328,72 @@ Please refrain from engaging in this activity or further actions may be taken ag
ZoneViewWidget
-
+ Search by card name (or search expressions)
-
+ Ungrouped
-
+ Group by Type
-
+ Group by Mana Value
-
+ Group by Color
-
+ Unsorted
-
+ Sort by Name
-
+ Sort by Type
-
+ Sort by Mana Cost
-
+ Sort by Colors
-
+ Sort by P/T
-
+ Sort by Set
-
+ shuffle when closing
-
+ pile view
@@ -10172,7 +10428,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ Deck Editor
@@ -10253,7 +10509,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ Replays
@@ -10405,7 +10661,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ Reset Layout
@@ -10826,7 +11082,8 @@ Please refrain from engaging in this activity or further actions may be taken ag
- Toggle Untap
+ Toggle Skip Untapping
+ Toggle Untap
@@ -10846,98 +11103,102 @@ Please refrain from engaging in this activity or further actions may be taken ag
- Attach Card...
+ Play Card, Face Down
- Unattach Card
+ Attach Card...
- Clone Card
+ Unattach Card
- Create Token...
+ Clone Card
- Create All Related Tokens
+ Create Token...
- Create Another Token
+ Create All Related Tokens
- Set Annotation...
+ Create Another Token
- Select All Cards in Zone
+ Set Annotation...
- Select All Cards in Row
+ Select All Cards in Zone
- Select All Cards in Column
+ Select All Cards in Row
- Reveal Selected Cards to All Players
+ Select All Cards in Column
-
- Bottom of Library
+ Reveal Selected Cards to All Players
-
-
-
- Exile
+
+ Bottom of Library
+
+
+
+ Exile
+
+
+
+
-
+ Graveyard
-
+ Hand
-
-
+
+ Top of Library
-
-
+ Battlefield, Face Down
@@ -10973,234 +11234,246 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ Stack
-
+ Graveyard (Multiple)
-
-
+
+
+ Graveyard (Multiple), Face Down
+
+
+
+
+ Exile (Multiple)
-
+
+
+ Exile (Multiple), Face Down
+
+
+
+ Stack Until Found
-
+ Draw Bottom Card
-
+ Draw Multiple Cards from Bottom...
-
+ Draw Arrow...
-
+ Remove Local Arrows
-
+ Leave Game
-
+ Concede
-
+ Roll Dice...
-
+ Shuffle Library
-
+ Shuffle Top Cards of Library
-
+ Shuffle Bottom Cards of Library
-
+ Mulligan
-
+ Mulligan (Same hand size)
-
+ Mulligan (Hand size - 1)
-
+ Draw a Card
-
+ Draw Multiple Cards...
-
+ Undo Draw
-
+ Always Reveal Top Card
-
+ Always Look At Top Card
-
+ Sort Hand by Name
-
+ Sort Hand by Type
-
+ Sort Hand by Mana Value
-
+ Reveal Hand to All Players
-
+ Reveal Random Card to All Players
-
+ Rotate View Clockwise
-
+ Rotate View Counterclockwise
-
+ Unfocus Text Box
-
+ Focus Chat
-
+ Clear Chat
-
+ Refresh
-
+ Skip Forward
-
+ Skip Backward
-
+ Skip Forward by a lot
-
+ Skip Backward by a lot
-
+ Play/Pause
-
+ Toggle Fast Forward
-
+ Home
-
+ Visual Deck Storage
-
+ Deck Storage
-
+ Server
-
+ Account
-
+ Administration
-
+ Logs
diff --git a/cockatrice/src/game/abstract_game.cpp b/cockatrice/src/game/abstract_game.cpp
index 505cd5fde..9216f9174 100644
--- a/cockatrice/src/game/abstract_game.cpp
+++ b/cockatrice/src/game/abstract_game.cpp
@@ -1,8 +1,9 @@
#include "abstract_game.h"
+#include "../interface/widgets/tabs/tab_game.h"
#include "player/player.h"
-AbstractGame::AbstractGame(TabGame *_tab) : tab(_tab)
+AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab)
{
gameMetaInfo = new GameMetaInfo(this);
gameEventHandler = new GameEventHandler(this);
diff --git a/cockatrice/src/game/player/menu/player_menu.cpp b/cockatrice/src/game/player/menu/player_menu.cpp
index 7786ec3fc..0dc381e28 100644
--- a/cockatrice/src/game/player/menu/player_menu.cpp
+++ b/cockatrice/src/game/player/menu/player_menu.cpp
@@ -10,7 +10,7 @@
#include
-PlayerMenu::PlayerMenu(Player *_player) : player(_player)
+PlayerMenu::PlayerMenu(Player *_player) : QObject(_player), player(_player)
{
playerMenu = new TearOffMenu();
diff --git a/cockatrice/src/game/player/menu/player_menu.h b/cockatrice/src/game/player/menu/player_menu.h
index 5fce27158..104c5a930 100644
--- a/cockatrice/src/game/player/menu/player_menu.h
+++ b/cockatrice/src/game/player/menu/player_menu.h
@@ -37,7 +37,7 @@ private slots:
void refreshShortcuts();
public:
- PlayerMenu(Player *player);
+ explicit PlayerMenu(Player *player);
/// Lifecycle methods: delegate to all managedComponents, plus counters separately via player->getCounters().
void retranslateUi();
diff --git a/cockatrice/src/game/player/player_actions.cpp b/cockatrice/src/game/player/player_actions.cpp
index ca0967636..20034df16 100644
--- a/cockatrice/src/game/player/player_actions.cpp
+++ b/cockatrice/src/game/player/player_actions.cpp
@@ -3,6 +3,7 @@
#include "../../interface/widgets/tabs/tab_game.h"
#include "../../interface/widgets/utility/get_text_with_max.h"
#include "../board/card_item.h"
+#include "../client/settings/card_counter_settings.h"
#include "../dialogs/dlg_move_top_cards_until.h"
#include "../dialogs/dlg_roll_dice.h"
#include "../zones/hand_zone.h"
@@ -27,13 +28,15 @@
#include
#include
#include
+#include
#include
#include
// milliseconds in between triggers of the move top cards until action
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
-PlayerActions::PlayerActions(Player *_player) : player(_player), lastTokenTableRow(0), movingCardsUntil(false)
+PlayerActions::PlayerActions(Player *_player)
+ : QObject(_player), player(_player), lastTokenTableRow(0), movingCardsUntil(false)
{
moveTopCardTimer = new QTimer(this);
moveTopCardTimer->setInterval(MOVE_TOP_CARD_UNTIL_INTERVAL);
@@ -1572,23 +1575,34 @@ void PlayerActions::actCardCounterTrigger()
break;
}
case 11: { // set counter with dialog
- bool ok;
player->setDialogSemaphore(true);
- int oldValue = 0;
- if (player->getGameScene()->selectedItems().size() == 1) {
- auto *card = static_cast(player->getGameScene()->selectedItems().first());
- oldValue = card->getCounters().value(counterId, 0);
+ // If a single card is selected, we show the old value in the dialog. Otherwise, we show "x"
+ QList sel = player->getGameScene()->selectedItems();
+ QString oldValueForDlg = "x";
+ if (sel.size() == 1) {
+ auto *card = dynamic_cast(sel.first());
+ oldValueForDlg = QString::number(card->getCounters().value(counterId, 0));
}
- int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Set counters"), tr("Number:"), oldValue,
- 0, MAX_COUNTERS_ON_CARD, 1, &ok);
+
+ auto &cardCounterSettings = SettingsCache::instance().cardCounters();
+ QString counterName = cardCounterSettings.displayName(counterId);
+
+ AbstractCounterDialog dialog(counterName, oldValueForDlg, player->getGame()->getTab());
+ int ok = dialog.exec();
+
player->setDialogSemaphore(false);
if (player->clearCardsToDelete() || !ok) {
return;
}
- for (const auto &item : player->getGameScene()->selectedItems()) {
- auto *card = static_cast(item);
+ for (const auto &item : sel) {
+ auto *card = dynamic_cast(item);
+
+ int oldValue = card->getCounters().value(counterId, 0);
+ Expression exp(oldValue);
+ int number = static_cast(exp.parse(dialog.textValue()));
+
auto *cmd = new Command_SetCardCounter;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
diff --git a/cockatrice/src/game/player/player_event_handler.cpp b/cockatrice/src/game/player/player_event_handler.cpp
index f4c3840e0..5571010d1 100644
--- a/cockatrice/src/game/player/player_event_handler.cpp
+++ b/cockatrice/src/game/player/player_event_handler.cpp
@@ -32,7 +32,7 @@
#include
#include
-PlayerEventHandler::PlayerEventHandler(Player *_player) : player(_player)
+PlayerEventHandler::PlayerEventHandler(Player *_player) : QObject(_player), player(_player)
{
}
diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
index 06a0476c9..dbd51b973 100644
--- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
+++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
@@ -28,6 +28,7 @@ CardPictureLoader::CardPictureLoader() : QObject(nullptr)
connect(&SettingsCache::instance(), &SettingsCache::picDownloadChanged, this,
&CardPictureLoader::picDownloadChanged);
+ qRegisterMetaType();
connect(worker, &CardPictureLoaderWorker::imageLoaded, this, &CardPictureLoader::imageLoaded);
statusBar = new CardPictureLoaderStatusBar(nullptr);
diff --git a/cockatrice/src/interface/theme_manager.cpp b/cockatrice/src/interface/theme_manager.cpp
index 1dc61fdb7..5809ce350 100644
--- a/cockatrice/src/interface/theme_manager.cpp
+++ b/cockatrice/src/interface/theme_manager.cpp
@@ -179,7 +179,7 @@ QBrush ThemeManager::loadExtraBrush(QString fileName, QBrush &fallbackBrush)
static inline QPalette createDarkGreenFusionPalette()
{
- QPalette p;
+ QPalette p = QStyleFactory::create("Fusion")->standardPalette();
// ---------- Core backgrounds ----------
p.setColor(QPalette::Window, QColor(30, 30, 30)); // #ff1e1e1e
@@ -248,7 +248,7 @@ static inline QPalette createDarkGreenFusionPalette()
static inline QPalette createLightGreenFusionPalette()
{
- QPalette p;
+ QPalette p = QStyleFactory::create("Fusion")->standardPalette();
// ---------- Core backgrounds ----------
p.setColor(QPalette::Window, QColor(240, 240, 240)); // #fff0f0f0
@@ -332,13 +332,15 @@ void ThemeManager::themeChangedSlot()
}
if (themeName == FUSION_THEME_NAME) {
- qApp->setStyle(QStyleFactory::create("Fusion"));
+ QStyle *fusionStyle = QStyleFactory::create("Fusion");
+ qApp->setStyle(fusionStyle);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
- QPalette palette;
+ // Start from Fusion's own palette so dark mode is handled correctly,
+ // then apply any tweaks on top of it.
+ QPalette palette = fusionStyle->standardPalette();
if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
}
-
qApp->setPalette(palette);
#endif
} else if (themeName == FUSION_THEME_NAME_LIGHT) {
@@ -348,7 +350,7 @@ void ThemeManager::themeChangedSlot()
qApp->setStyle(QStyleFactory::create("Fusion"));
qApp->setPalette(createDarkGreenFusionPalette());
} else {
- qApp->setStyle(defaultStyleName); // setting the style also sets the palette
+ qApp->setStyle(QStyleFactory::create(defaultStyleName)); // setting the style also sets the palette
}
if (dirPath.isEmpty()) {
diff --git a/cockatrice/src/interface/widgets/deck_analytics/resizable_panel.cpp b/cockatrice/src/interface/widgets/deck_analytics/resizable_panel.cpp
index a0c971a75..f7bb5ac35 100644
--- a/cockatrice/src/interface/widgets/deck_analytics/resizable_panel.cpp
+++ b/cockatrice/src/interface/widgets/deck_analytics/resizable_panel.cpp
@@ -20,7 +20,6 @@ ResizablePanel::ResizablePanel(const QString &_typeId, AbstractAnalyticsPanelWid
frame = new QFrame(this);
frame->setFrameShape(QFrame::Box);
frame->setLineWidth(2);
- frame->setStyleSheet("border: none;");
auto *frameLayout = new QVBoxLayout(frame);
frameLayout->setContentsMargins(0, 0, 0, 0);
@@ -30,15 +29,13 @@ ResizablePanel::ResizablePanel(const QString &_typeId, AbstractAnalyticsPanelWid
frameLayout->addWidget(analyticsPanel);
dropIndicator = new QFrame(frame);
- dropIndicator->setStyleSheet("background-color: #3daee9;");
dropIndicator->setFixedHeight(3);
dropIndicator->hide(); // hidden by default
dropIndicator->raise(); // make sure it's above children
selectionOverlay = new QFrame(frame);
- selectionOverlay->setStyleSheet("background-color: rgba(61,174,233,50);"); // semi-transparent blue
- selectionOverlay->hide(); // hidden by default
- selectionOverlay->raise(); // make sure it is above children
+ selectionOverlay->hide(); // hidden by default
+ selectionOverlay->raise(); // make sure it is above children
selectionOverlay->setAttribute(Qt::WA_TransparentForMouseEvents);
// Bottom bar with drag button and resize handle
@@ -51,24 +48,41 @@ ResizablePanel::ResizablePanel(const QString &_typeId, AbstractAnalyticsPanelWid
dragButton = new QPushButton("☰", bottomBar);
dragButton->setFixedSize(40, 8);
dragButton->setCursor(Qt::OpenHandCursor);
- dragButton->setStyleSheet("QPushButton { "
- "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #4a4a4a, stop:1 #3a3a3a); "
- "border: none; color: #888; font-size: 10px; }"
- "QPushButton:hover { background: #5a5a5a; }");
bottomLayout->addWidget(dragButton);
// Resize handle fills the rest
resizeHandle = new QWidget(bottomBar);
resizeHandle->setFixedHeight(8);
resizeHandle->setCursor(Qt::SizeVerCursor);
- resizeHandle->setStyleSheet("background: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
- "stop:0 #3a3a3a, stop:1 #2a2a2a);");
bottomLayout->addWidget(resizeHandle, 1);
frameLayout->addWidget(bottomBar);
mainLayout->addWidget(frame);
+ const QPalette &pal = QApplication::palette();
+ QColor mid = pal.color(QPalette::Mid);
+ QColor dark = pal.color(QPalette::Dark);
+ QColor midLight = pal.color(QPalette::Midlight);
+ QColor shadow = pal.color(QPalette::Shadow);
+ QColor placeholderText = pal.color(QPalette::PlaceholderText);
+
+ frame->setStyleSheet("QFrame { border: none; }");
+
+ dropIndicator->setStyleSheet("QFrame { background-color: #3daee9; }");
+
+ selectionOverlay->setStyleSheet("QFrame { background-color: rgba(61,174,233,50); }");
+
+ dragButton->setStyleSheet(QString("QPushButton { "
+ "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 %1, stop:1 %2); "
+ "border: none; color: %3; font-size: 10px; }"
+ "QPushButton:hover { background: %4; }")
+ .arg(mid.name(), dark.name(), placeholderText.name(), midLight.name()));
+
+ resizeHandle->setStyleSheet(QString("QWidget { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
+ "stop:0 %1, stop:1 %2); }")
+ .arg(dark.name(), shadow.name()));
+
// Set size policy
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
diff --git a/cockatrice/src/interface/widgets/tabs/tab_replays.cpp b/cockatrice/src/interface/widgets/tabs/tab_replays.cpp
index 2db9e83c5..570677ada 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_replays.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_replays.cpp
@@ -30,6 +30,8 @@
#include
#include
+inline Q_LOGGING_CATEGORY(TabReplaysLog, "replays_tab");
+
TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo)
: Tab(_tabSupervisor), client(_client)
{
@@ -265,9 +267,11 @@ void TabReplays::actOpenLocalReplay()
f.close();
GameReplay *replay = new GameReplay;
- replay->ParseFromArray(_data.data(), _data.size());
-
- emit openReplay(replay);
+ if (replay->ParseFromArray(_data.data(), _data.size())) {
+ emit openReplay(replay);
+ } else {
+ qCWarning(TabReplaysLog) << "could not parse replay!";
+ }
}
}
@@ -379,9 +383,12 @@ void TabReplays::openRemoteReplayFinished(const Response &r)
const Response_ReplayDownload &resp = r.GetExtension(Response_ReplayDownload::ext);
GameReplay *replay = new GameReplay;
- replay->ParseFromString(resp.replay_data());
+ if (replay->ParseFromString(resp.replay_data())) {
- emit openReplay(replay);
+ emit openReplay(replay);
+ } else {
+ qCWarning(TabReplaysLog) << "could not parse remote replay!";
+ }
}
void TabReplays::actDownload()
diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp
index fbba6c3f5..86e6c1534 100644
--- a/cockatrice/src/interface/window_main.cpp
+++ b/cockatrice/src/interface/window_main.cpp
@@ -84,6 +84,7 @@
const QString MainWindow::appName = "Cockatrice";
const QStringList MainWindow::fileNameFilters = QStringList() << QObject::tr("Cockatrice card database (*.xml)")
<< QObject::tr("All files (*.*)");
+inline Q_LOGGING_CATEGORY(MainWindowLog, "main_window");
/**
* Replaces the tab-specific menus that are shown in the menuBar.
@@ -277,9 +278,11 @@ void MainWindow::actWatchReplay()
file.close();
replay = new GameReplay;
- replay->ParseFromArray(buf.data(), buf.size());
-
- tabSupervisor->openReplay(replay);
+ if (replay->ParseFromArray(buf.data(), buf.size())) {
+ tabSupervisor->openReplay(replay);
+ } else {
+ qCWarning(MainWindowLog) << "failed to parse replay!";
+ }
}
void MainWindow::localGameEnded()
diff --git a/cockatrice/translations/cockatrice_en_US.ts b/cockatrice/translations/cockatrice_en_US.ts
index c74e63114..254ead590 100644
--- a/cockatrice/translations/cockatrice_en_US.ts
+++ b/cockatrice/translations/cockatrice_en_US.ts
@@ -23,12 +23,12 @@
AbstractDlgDeckTextEdit
-
+ &Refresh&Refresh
-
+ Parse Set Name and Number (if available)Parse Set Name and Number (if available)
@@ -36,62 +36,62 @@
AbstractTabDeckEditor
-
+ Open in new tabOpen in new tab
-
+ Are you sure?Are you sure?
-
+ The decklist has been modified.
Do you want to save the changes?The decklist has been modified.
Do you want to save the changes?
-
-
-
-
-
-
+
+
+
+
+
+ ErrorError
-
+ Could not open deck at %1Could not open deck at %1
-
+ Could not save remote deckCould not save remote deck
-
-
+
+ The deck could not be saved.
Please check that the directory is writable and try again.The deck could not be saved.
Please check that the directory is writable and try again.
-
+ Save deckSave deck
-
+ The deck could not be saved.The deck could not be saved.
-
+ There are no cards in your deck to be exportedThere are no cards in your deck to be exported
@@ -133,202 +133,168 @@ Please check that the directory is writable and try again.
AppearanceSettingsPage
-
+ seconds seconds
-
+ ErrorError
-
+ Could not create themes directory at '%1'.Could not create themes directory at '%1'.
-
- Enabling this feature will disable the use of the Printing Selector.
-
-You will not be able to manage printing preferences on a per-deck basis, or see printings other people have selected for their decks.
-
-You will have to use the Set Manager, available through Card Database -> Manage Sets.
-
-Are you sure you would like to enable this feature?
- Enabling this feature will disable the use of the Printing Selector.
-
-You will not be able to manage printing preferences on a per-deck basis, or see printings other people have selected for their decks.
-
-You will have to use the Set Manager, available through Card Database -> Manage Sets.
-
-Are you sure you would like to enable this feature?
-
-
-
- Disabling this feature will enable the Printing Selector.
-
-You can now choose printings on a per-deck basis in the Deck Editor and configure which printing gets added to a deck by default by pinning it in the Printing Selector.
-
-You can also use the Set Manager to adjust custom sort order for printings in the Printing Selector (other sort orders like alphabetical or release date are available).
-
-Are you sure you would like to disable this feature?
- Disabling this feature will enable the Printing Selector.
-
-You can now choose printings on a per-deck basis in the Deck Editor and configure which printing gets added to a deck by default by pinning it in the Printing Selector.
-
-You can also use the Set Manager to adjust custom sort order for printings in the Printing Selector (other sort orders like alphabetical or release date are available).
-
-Are you sure you would like to disable this feature?
-
-
-
- Confirm Change
- Confirm Change
-
-
-
+ Theme settingsTheme settings
-
+ Current theme:Current theme:
-
+ Open themes folderOpen themes folder
-
+ Home tab background source:Home tab background source:
-
+ Home tab background shuffle frequency:Home tab background shuffle frequency:
-
+ DisabledDisabled
-
+
+ Display card name of background in bottom right:
+ Display card name of background in bottom right:
+
+
+ Menu settingsMenu settings
-
+ Show keyboard shortcuts in right-click menusShow keyboard shortcuts in right-click menus
-
+ Show game filter toolbar above list in room tabShow game filter toolbar above list in room tab
-
+ Card renderingCard rendering
-
+ Display card names on cards having a pictureDisplay card names on cards having a picture
-
+ Auto-Rotate cards with sideways layoutAuto-Rotate cards with sideways layout
-
+ Override all card art with personal set preference (Pre-ProviderID change behavior)Override all card art with personal set preference (Pre-ProviderID change behavior)
-
+ Bump sets that the deck contains cards from to the top in the printing selectorBump sets that the deck contains cards from to the top in the printing selector
-
+ Scale cards on mouse overScale cards on mouse over
-
+ Use rounded card cornersUse rounded card corners
-
+ Minimum overlap percentage of cards on the stack and in vertical handMinimum overlap percentage of cards on the stack and in vertical hand
-
+ Maximum initial height for card view window:Maximum initial height for card view window:
-
-
+
+ rows rows
-
+ Maximum expanded height for card view window:Maximum expanded height for card view window:
-
+ Card countersCard counters
-
+ Counter %1Counter %1
-
+ Hand layoutHand layout
-
+ Display hand horizontally (wastes space)Display hand horizontally (wastes space)
-
+ Enable left justificationEnable left justification
-
+ Table grid layoutTable grid layout
-
+ Invert vertical coordinateInvert vertical coordinate
-
+ Minimum player count for multi-column layout:Minimum player count for multi-column layout:
-
+ Maximum font size for information displayed on cards:Maximum font size for information displayed on cards:
@@ -336,7 +302,12 @@ Are you sure you would like to disable this feature?
ArchidektApiResponseDeckDisplayWidget
-
+
+ Back to results
+ Back to results
+
+
+ Open Deck in Deck EditorOpen Deck in Deck Editor
@@ -656,22 +627,22 @@ This is only saved for moderators and cannot be seen by the banned person.
CardInfoPictureWidget
-
+ View related cardsView related cards
-
+ Add card to deckAdd card to deck
-
+ MainboardMainboard
-
+ SideboardSideboard
@@ -707,124 +678,124 @@ This is only saved for moderators and cannot be seen by the banned person.
CardMenu
-
+ Re&veal to...Re&veal to...
-
+ &All players&All players
-
+ View related cardsView related cards
-
+ Token: Token:
-
+ All tokensAll tokens
-
+ &Select All&Select All
-
+ S&elect RowS&elect Row
-
+ S&elect ColumnS&elect Column
-
+ &Play&Play
-
+ &Hide&Hide
-
+ Play &Face DownPlay &Face Down
-
+ &Tap / UntapTurn sideways or back again&Tap / Untap
-
- Toggle &normal untapping
- Toggle &normal untapping
+
+ Skip &untapping
+ Skip &untapping
-
+ T&urn OverTurn face up/face downT&urn Over
-
+ &Peek at card face&Peek at card face
-
+ &Clone&Clone
-
+ Attac&h to card...Attac&h to card...
-
+ Unattac&hUnattac&h
-
+ &Draw arrow...&Draw arrow...
-
+ &Set annotation...&Set annotation...
-
+ Ca&rd countersCa&rd counters
-
+ &Add counter (%1)&Add counter (%1)
-
+ &Remove counter (%1)&Remove counter (%1)
-
+ &Set counters (%1)...&Set counters (%1)...
@@ -840,133 +811,133 @@ This is only saved for moderators and cannot be seen by the banned person.
CardZoneLogic
-
+ their handnominativetheir hand
-
+ %1's handnominative%1's hand
-
+ their librarylook at zonetheir library
-
+ %1's librarylook at zone%1's library
-
+ of their librarytop cards of zone,of their library
-
+ of %1's librarytop cards of zoneof %1's library
-
+ their libraryreveal zonetheir library
-
+ %1's libraryreveal zone%1's library
-
+ their libraryshuffletheir library
-
+ %1's libraryshuffle%1's library
-
-
- their library
- nominative
- their library
-
-
-
- %1's library
- nominative
- %1's library
-
+ their library
+ nominative
+ their library
+
+
+
+ %1's library
+ nominative
+ %1's library
+
+
+ their graveyardnominativetheir graveyard
-
+ %1's graveyardnominative%1's graveyard
-
+ their exilenominativetheir exile
-
+ %1's exilenominative%1's exile
-
-
- their sideboard
- look at zone
- their sideboard
-
-
-
- %1's sideboard
- look at zone
- %1's sideboard
- their sideboard
- nominative
+ look at zonetheir sideboard%1's sideboard
+ look at zone
+ %1's sideboard
+
+
+
+ their sideboard
+ nominative
+ their sideboard
+
+
+
+ %1's sideboardnominative%1's sideboard
-
+ their custom zone '%1'nominativetheir custom zone '%1'
-
+ %1's custom zone '%2'nominative%1's custom zone '%2'
@@ -1028,7 +999,7 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorCardDatabaseDockWidget
-
+ Card DatabaseCard Database
@@ -1036,7 +1007,7 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorCardInfoDockWidget
-
+ Card InfoCard Info
@@ -1059,32 +1030,32 @@ This is only saved for moderators and cannot be seen by the banned person.Add to Sideboard
-
+ Select PrintingSelect Printing
-
+ Show on EDHRec (Commander)Show on EDHRec (Commander)
-
+ Show on EDHRec (Card)Show on EDHRec (Card)
-
+ Show Related cardsShow Related cards
-
+ Add card to &maindeckAdd card to &maindeck
-
+ Add card to &sideboardAdd card to &sideboard
@@ -1092,32 +1063,32 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorDeckDockWidget
-
+ Loading Database...Loading Database...
-
+ Banner CardBanner Card
-
+ Main TypeMain Type
-
+ Mana CostMana Cost
-
+ ColorsColors
-
+ Select PrintingSelect Printing
@@ -1190,17 +1161,17 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorFilterDockWidget
-
+ FiltersFilters
-
+ &Clear all filters&Clear all filters
-
+ Delete selectedDelete selected
@@ -1323,7 +1294,7 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorPrintingSelectorDockWidget
-
+ Printing SelectorPrinting Selector
@@ -1331,166 +1302,166 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckEditorSettingsPage
-
-
+
+ Update SpoilersUpdate Spoilers
-
-
+
+ SuccessSuccess
-
+ Download URLs have been reset.Download URLs have been reset.
-
+ Downloaded card pictures have been reset.Downloaded card pictures have been reset.
-
+ ErrorError
-
+ One or more downloaded card pictures could not be cleared.One or more downloaded card pictures could not be cleared.
-
+ Add URLAdd URL
-
-
+
+ URL:URL:
-
-
+
+ Edit URLEdit URL
-
+ Network Cache Size:Network Cache Size:
-
+ Redirect Cache TTL:Redirect Cache TTL:
-
+ How long cached redirects for urls are valid for.How long cached redirects for urls are valid for.
-
+ Picture Cache Size:Picture Cache Size:
-
+ Add New URLAdd New URL
-
+ Remove URLRemove URL
-
+ Day(s)Day(s)
-
+ Updating...Updating...
-
+ Choose pathChoose path
-
+ URL Download PriorityURL Download Priority
-
+ SpoilersSpoilers
-
+ Download Spoilers AutomaticallyDownload Spoilers Automatically
-
+ Spoiler Location:Spoiler Location:
-
+ Last ChangeLast Change
-
+ Spoilers download automatically on launchSpoilers download automatically on launch
-
+ Press the button to manually update without relaunchingPress the button to manually update without relaunching
-
+ Do not close settings until manual update is completeDo not close settings until manual update is complete
-
+ Download card pictures on the flyDownload card pictures on the fly
-
+ How to add a custom URLHow to add a custom URL
-
+ Delete Downloaded ImagesDelete Downloaded Images
-
+ Reset Download URLsReset Download URLs
-
+ On-disk cache for downloaded picturesOn-disk cache for downloaded pictures
-
+ In-memory cache for pictures not currently on screenIn-memory cache for pictures not currently on screen
@@ -1498,32 +1469,32 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckListHistoryManagerWidget
-
+ UndoUndo
-
+ RedoRedo
-
+ Undo/Redo historyUndo/Redo history
-
+ Click on an entry to revert to that point in the history.Click on an entry to revert to that point in the history.
-
+ [redo] [redo]
-
+ [undo] [undo]
@@ -1531,27 +1502,27 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckListModel
-
+ CountCount
-
+ SetSet
-
+ NumberNumber
-
+ Provider IDProvider ID
-
+ CardCard
@@ -1559,12 +1530,12 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckLoader
-
+ Common deck formats (%1)Common deck formats (%1)
-
+ All files (*.*)All files (*.*)
@@ -1661,94 +1632,94 @@ This is only saved for moderators and cannot be seen by the banned person.
DeckPreviewWidget
-
+ Banner CardBanner Card
-
+ Open in deck editorOpen in deck editor
-
+ Edit TagsEdit Tags
-
+ Rename DeckRename Deck
-
+ Save Deck to ClipboardSave Deck to Clipboard
-
+ AnnotatedAnnotated
-
+ Annotated (No set info)Annotated (No set info)
-
+ Not AnnotatedNot Annotated
-
+ Not Annotated (No set info)Not Annotated (No set info)
-
+ Rename FileRename File
-
+ Delete FileDelete File
-
+ Set Banner CardSet Banner Card
-
-
+
+ New name:New name:
-
-
+
+ ErrorError
-
+ Rename failedRename failed
-
+ Delete fileDelete file
-
+ Are you sure you want to delete the selected file?Are you sure you want to delete the selected file?
-
+ Delete failedDelete failed
@@ -1781,32 +1752,32 @@ This is only saved for moderators and cannot be seen by the banned person.Set format to %1
-
+ Added (%1): %2 (%3) %4Added (%1): %2 (%3) %4
-
+ Moved to %1 1 × "%2" (%3)Moved to %1 1 × "%2" (%3)
-
+ Removed "%1" (all copies)Removed "%1" (all copies)
-
+ %1 1 × "%2" (%3)%1 1 × "%2" (%3)
-
+ AddedAdded
-
+ RemovedRemoved
@@ -1873,30 +1844,30 @@ This is only saved for moderators and cannot be seen by the banned person.Sideboard locked
-
-
+
+ ErrorError
-
+ The selected file could not be loaded.The selected file could not be loaded.
-
+ Deck is greater than maximum file size.Deck is greater than maximum file size.
-
+ Are you sure you want to force start?
This will kick all non-ready players from the game.Are you sure you want to force start?
This will kick all non-ready players from the game.
-
+ CockatriceCockatrice
@@ -2391,17 +2362,17 @@ To remove your current avatar, confirm without choosing a new image.
DlgEditDeckInClipboard
-
+ Edit deck in clipboardEdit deck in clipboard
-
+ ErrorError
-
+ Invalid deck list.Invalid deck list.
@@ -2902,17 +2873,17 @@ Make sure to enable the 'Token' set in the "Manage sets" dia
DlgLoadDeckFromClipboard
-
+ Load deck from clipboardLoad deck from clipboard
-
+ ErrorError
-
+ Invalid deck list.Invalid deck list.
@@ -2920,45 +2891,45 @@ Make sure to enable the 'Token' set in the "Manage sets" dia
DlgLoadDeckFromWebsite
-
+ Paste a link to a decklist site here to import it.
(Archidekt, Deckstats, Moxfield, and TappedOut are supported.)Paste a link to a decklist site here to import it.
(Archidekt, Deckstats, Moxfield, and TappedOut are supported.)
-
-
-
-
-
+
+
+
+
+ Load Deck from WebsiteLoad Deck from Website
-
+ No parser available for this deck provider.
(Archidekt, Deckstats, Moxfield, and TappedOut are supported.)No parser available for this deck provider.
(Archidekt, Deckstats, Moxfield, and TappedOut are supported.)
-
+ Network error: %1Network error: %1
-
+ Received empty deck data.Received empty deck data.
-
+ Failed to parse deck data: %1Failed to parse deck data: %1
-
+ The provided URL is not recognized as a valid deck URL.
Valid deck URLs look like this:
@@ -2983,40 +2954,73 @@ https://tappedout.net/mtg-decks/your-deck-name/
Load deck
+
+ DlgLocalGameOptions
+
+
+ Players:
+ Players:
+
+
+
+ General
+ General
+
+
+
+ Starting life total:
+ Starting life total:
+
+
+
+ Game setup options
+ Game setup options
+
+
+
+ Remember settings
+ Remember settings
+
+
+
+ Local game options
+ Local game options
+
+DlgMoveTopCardsUntil
-
+ Card name (or search expressions):Card name (or search expressions):
-
+ Number of hits:Number of hits:
-
+ Auto play hitsAuto play hits
-
+ Put top cards on stack until...Put top cards on stack until...
-
+ No cards matching the search expression exists in the card database. Proceed anyways?No cards matching the search expression exists in the card database. Proceed anyways?
-
+ CockatriceCockatrice
-
+ Invalid filterInvalid filter
@@ -3178,12 +3182,12 @@ Your email will be used to verify your account.
DlgSettings
-
+ Unknown Error loading card databaseUnknown Error loading card database
-
+ Your card database is invalid.
Cockatrice may not function correctly with an invalid database
@@ -3200,7 +3204,7 @@ You may need to rerun oracle to update your card database.
Would you like to change your database location setting?
-
+ Your card database version is too old.
This can cause problems loading card information or images
@@ -3217,7 +3221,7 @@ Usually this can be fixed by rerunning oracle to to update your card database.
Would you like to change your database location setting?
-
+ Your card database did not finish loading
Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues with your cards.xml attached
@@ -3230,7 +3234,7 @@ Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues with you
Would you like to change your database location setting?
-
+ File Error loading your card database.
Would you like to change your database location setting?
@@ -3239,7 +3243,7 @@ Would you like to change your database location setting?
Would you like to change your database location setting?
-
+ Your card database was loaded but contains no cards.
Would you like to change your database location setting?
@@ -3248,7 +3252,7 @@ Would you like to change your database location setting?
Would you like to change your database location setting?
-
+ Unknown card database load status
Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues
@@ -3261,59 +3265,59 @@ Please file a ticket at https://github.com/Cockatrice/Cockatrice/issues
Would you like to change your database location setting?
-
-
-
+
+
+ ErrorError
-
+ The path to your deck directory is invalid. Would you like to go back and set the correct path?The path to your deck directory is invalid. Would you like to go back and set the correct path?
-
+ The path to your card pictures directory is invalid. Would you like to go back and set the correct path?The path to your card pictures directory is invalid. Would you like to go back and set the correct path?
-
+ SettingsSettings
-
+ GeneralGeneral
-
+ AppearanceAppearance
-
+ User InterfaceUser Interface
-
+ Card SourcesCard Sources
-
+ ChatChat
-
+ SoundSound
-
+ ShortcutsShortcuts
@@ -3630,67 +3634,67 @@ You may have to manually download the new version.
DrawProbabilityWidget
-
+ Draw ProbabilityDraw Probability
-
+ Probability of drawingProbability of drawing
-
+ Card NameCard Name
-
+ TypeType
-
+ SubtypeSubtype
-
+ Mana ValueMana Value
-
+ At leastAt least
-
+ ExactlyExactly
-
+ card(s) having drawn at leastcard(s) having drawn at least
-
+ cardscards
-
+ CategoryCategory
-
+ QtyQty
-
+ Odds (%)Odds (%)
@@ -4138,143 +4142,143 @@ You may have to manually download the new version.
GeneralSettingsPage
-
+ Reset all pathsReset all paths
-
+ All paths have been resetAll paths have been reset
-
-
-
-
-
-
-
+
+
+
+
+
+
+ Choose pathChoose path
-
+ Personal settingsPersonal settings
-
+ Language:Language:
-
+ Paths (editing disabled in portable mode)Paths (editing disabled in portable mode)
-
+ PathsPaths
-
+ How to help with translationsHow to help with translations
-
+ Decks directory:Decks directory:
-
+ Filters directory:Filters directory:
-
+ Replays directory:Replays directory:
-
+ Pictures directory:Pictures directory:
-
+ Card database:Card database:
-
+ Custom database directory:Custom database directory:
-
+ Token database:Token database:
-
+ Update channelUpdate channel
-
+ Check for client updates on startupCheck for client updates on startup
-
+ Check for card database updates on startupCheck for card database updates on startup
-
+ Don't checkDon't check
-
+ Prompt for updatePrompt for update
-
+ Always update in the backgroundAlways update in the background
-
+ Check for card database updates everyCheck for card database updates every
-
+ days days
-
+ Notify if a feature supported by the server is missing in my clientNotify if a feature supported by the server is missing in my client
-
+ Automatically run Oracle when running a new version of CockatriceAutomatically run Oracle when running a new version of Cockatrice
-
+ Show tips on startupShow tips on startup
-
+ Last update check on %1 (%2 days ago)Last update check on %1 (%2 days ago)
@@ -4282,47 +4286,47 @@ You may have to manually download the new version.
GraveyardMenu
-
+ &Graveyard&Graveyard
-
+ &View graveyard&View graveyard
-
+ &Move graveyard to...&Move graveyard to...
-
+ &Top of library&Top of library
-
+ &Bottom of library&Bottom of library
-
+ &All players&All players
-
+ &Hand&Hand
-
+ &Exile&Exile
-
+ Reveal random card to...Reveal random card to...
@@ -4330,88 +4334,88 @@ You may have to manually download the new version.
HandMenu
-
+ &Hand&Hand
-
+ &View hand&View hand
-
+ Sort hand by...Sort hand by...
-
+ NameName
-
+ TypeType
-
+ Mana ValueMana Value
-
+ Take &mulligan (Choose hand size)Take &mulligan (Choose hand size)
-
+ Take mulligan (Same hand size)Take mulligan (Same hand size)
-
+ Take mulligan (Hand size - 1)Take mulligan (Hand size - 1)
-
+ &Move hand to...&Move hand to...
-
+ &Top of library&Top of library
-
+ &Bottom of library&Bottom of library
-
+ &Graveyard&Graveyard
-
+ &Exile&Exile
-
+ &Reveal hand to...&Reveal hand to...
-
-
+
+ All playersAll players
-
+ Reveal r&andom card to...Reveal r&andom card to...
@@ -4419,52 +4423,52 @@ You may have to manually download the new version.
HomeWidget
-
+ Create New DeckCreate New Deck
-
+ Browse DecksBrowse Decks
-
+ Browse Card DatabaseBrowse Card Database
-
+ Browse EDHRecBrowse EDHRec
-
+ Browse ArchidektBrowse Archidekt
-
+ View ReplaysView Replays
-
+ QuitQuit
-
+ Connecting...Connecting...
-
+ ConnectConnect
-
+ PlayPlay
@@ -4472,193 +4476,213 @@ You may have to manually download the new version.
LibraryMenu
-
+ &Library&Library
-
+ &View library&View library
-
+ View &top cards of library...View &top cards of library...
-
+ View bottom cards of library...View bottom cards of library...
-
+ Reveal &library to...Reveal &library to...
-
+ Lend library to...Lend library to...
-
+ Reveal &top cards to...Reveal &top cards to...
-
+ &Top of library...&Top of library...
-
+ &Bottom of library...&Bottom of library...
-
+ &Always reveal top card&Always reveal top card
-
+ &Always look at top card&Always look at top card
-
+ &Open deck in deck editor&Open deck in deck editor
-
+ &Draw card&Draw card
-
+ D&raw cards...D&raw cards...
-
+ &Undo last draw&Undo last draw
-
+ ShuffleShuffle
-
+ &Play top card&Play top card
-
+ Play top card &face downPlay top card &face down
-
+ Put top card on &bottomPut top card on &bottom
-
+ Move top card to grave&yardMove top card to grave&yard
-
+ Move top card to e&xileMove top card to e&xile
-
+ Move top cards to &graveyard...Move top cards to &graveyard...
-
+
+ Move top cards to graveyard face down...
+ Move top cards to graveyard face down...
+
+
+ Move top cards to &exile...Move top cards to &exile...
-
+
+ Move top cards to exile face down...
+ Move top cards to exile face down...
+
+
+ Put top cards on stack &until...Put top cards on stack &until...
-
+ Shuffle top cards...Shuffle top cards...
-
+ &Draw bottom card&Draw bottom card
-
+ D&raw bottom cards...D&raw bottom cards...
-
+ &Play bottom card&Play bottom card
-
+ Play bottom card &face downPlay bottom card &face down
-
+ Move bottom card to grave&yardMove bottom card to grave&yard
-
+ Move bottom card to e&xileMove bottom card to e&xile
-
+ Move bottom cards to &graveyard...Move bottom cards to &graveyard...
-
+
+ Move bottom cards to graveyard face down...
+ Move bottom cards to graveyard face down...
+
+
+ Move bottom cards to &exile...Move bottom cards to &exile...
-
+
+ Move bottom cards to exile face down...
+ Move bottom cards to exile face down...
+
+
+ Put bottom card on &topPut bottom card on &top
-
+ Shuffle bottom cards...Shuffle bottom cards...
-
-
+
+ &All players&All players
-
+ Reveal top cards of libraryReveal top cards of library
-
+ Number of cards: (max. %1)Number of cards: (max. %1)
@@ -4756,18 +4780,8 @@ Will now login.
Will now login.
-
- Number of players
- Number of players
-
-
-
- Please enter the number of players.
- Please enter the number of players.
-
-
-
-
+
+ Player %1Player %1
@@ -4870,8 +4884,8 @@ Will now login.
-
-
+
+ ErrorError
@@ -5279,36 +5293,36 @@ Local version is %1, remote version is %2.
Show/Hide
-
+ New VersionNew Version
-
+ Congratulations on updating to Cockatrice %1!
Oracle will now launch to update your card database.Congratulations on updating to Cockatrice %1!
Oracle will now launch to update your card database.
-
+ Cockatrice installedCockatrice installed
-
+ Congratulations on installing Cockatrice %1!
Oracle will now launch to install the initial card database.Congratulations on installing Cockatrice %1!
Oracle will now launch to install the initial card database.
-
+ Card databaseCard database
-
+ Cockatrice is unable to load the card database.
Do you want to update your card database now?
If unsure or first time user, choose "Yes"
@@ -5317,29 +5331,29 @@ Do you want to update your card database now?
If unsure or first time user, choose "Yes"
-
-
+
+ YesYes
-
-
+
+ NoNo
-
+ Open settingsOpen settings
-
+ New sets foundNew sets found
-
+ %n new set(s) found in the card database
Set code(s): %1
Do you want to enable it/them?
@@ -5350,17 +5364,17 @@ Set codes: %1
Do you want to enable them?
-
+ View setsView sets
-
+ WelcomeWelcome
-
+ Hi! It seems like you're running this version of Cockatrice for the first time.
All the sets in the card database have been enabled.
Read more about changing the set order or disabling specific sets and consequent effects in the "Manage Sets" dialog.
@@ -5369,65 +5383,65 @@ All the sets in the card database have been enabled.
Read more about changing the set order or disabling specific sets and consequent effects in the "Manage Sets" dialog.
-
-
+
+ InformationInformation
-
+ A card database update is already running.A card database update is already running.
-
+ Unable to run the card database updater: Unable to run the card database updater:
-
+ Card database update running.Card database update running.
-
+ Failed to start. The file might be missing, or permissions might be incorrect.Failed to start. The file might be missing, or permissions might be incorrect.
-
+ The process crashed some time after starting successfully.The process crashed some time after starting successfully.
-
+ Timed out. The process took too long to respond. The last waitFor...() function timed out.Timed out. The process took too long to respond. The last waitFor...() function timed out.
-
+ An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.
-
+ An error occurred when attempting to read from the process. For example, the process may not be running.An error occurred when attempting to read from the process. For example, the process may not be running.
-
+ Unknown error occurred.Unknown error occurred.
-
+ The card database updater exited with an error:
%1The card database updater exited with an error:
%1
-
+ This server supports additional features that your client doesn't have.
This is most likely not a problem, but this message might mean there is a new version of Cockatrice available or this server is running a custom or pre-release version.
@@ -5438,55 +5452,55 @@ This is most likely not a problem, but this message might mean there is a new ve
To update your client, go to Help -> Check for Updates.
-
-
-
-
-
+
+
+
+
+ Load sets/cardsLoad sets/cards
-
+ Selected file cannot be found.Selected file cannot be found.
-
+ You can only import XML databases at this time.You can only import XML databases at this time.
-
+ The new sets/cards have been added successfully.
Cockatrice will now reload the card database.The new sets/cards have been added successfully.
Cockatrice will now reload the card database.
-
+ Sets/cards failed to import.Sets/cards failed to import.
-
-
-
+
+
+ Reset PasswordReset Password
-
+ Your password has been reset successfully, you can now log in using the new credentials.Your password has been reset successfully, you can now log in using the new credentials.
-
+ Failed to reset user account password, please contact the server operator to reset your password.Failed to reset user account password, please contact the server operator to reset your password.
-
+ Activation request received, please check your email for an activation token.Activation request received, please check your email for an activation token.
@@ -5537,7 +5551,7 @@ Cockatrice will now reload the card database.
ManaBaseWidget
-
+ Mana BaseMana Base
@@ -5691,590 +5705,610 @@ Cockatrice will now reload the card database.
MessageLogWidget
-
+ from play from play
-
+ from their graveyard from their graveyard
-
+ from exile from exile
-
+ from their hand from their hand
-
+ the top card of %1's librarythe top card of %1's library
-
+ the top card of their librarythe top card of their library
-
+ from the top of %1's library from the top of %1's library
-
+ from the top of their library from the top of their library
-
+ the bottom card of %1's librarythe bottom card of %1's library
-
+ the bottom card of their librarythe bottom card of their library
-
+ from the bottom of %1's library from the bottom of %1's library
-
+ from the bottom of their library from the bottom of their library
-
+ from %1's library from %1's library
-
+ from their library from their library
-
+ from sideboard from sideboard
-
+ from the stack from the stack
-
+ from custom zone '%1' from custom zone '%1'
-
+ %1 is now keeping the top card %2 revealed.%1 is now keeping the top card %2 revealed.
-
+ %1 is not revealing the top card %2 any longer.%1 is not revealing the top card %2 any longer.
-
+ %1 can now look at top card %2 at any time.%1 can now look at top card %2 at any time.
-
+ %1 no longer can look at top card %2 at any time.%1 no longer can look at top card %2 at any time.
-
+ %1 attaches %2 to %3's %4.%1 attaches %2 to %3's %4.
-
+ %1 has conceded the game.%1 has conceded the game.
-
+ %1 has unconceded the game.%1 has unconceded the game.
-
+ %1 has restored connection to the game.%1 has restored connection to the game.
-
+ %1 has lost connection to the game.%1 has lost connection to the game.
-
+ %1 points from their %2 to themselves.%1 points from their %2 to themselves.
-
+ %1 points from their %2 to %3.%1 points from their %2 to %3.
-
+ %1 points from %2's %3 to themselves.%1 points from %2's %3 to themselves.
-
+ %1 points from %2's %3 to %4.%1 points from %2's %3 to %4.
-
+ %1 points from their %2 to their %3.%1 points from their %2 to their %3.
-
+ %1 points from their %2 to %3's %4.%1 points from their %2 to %3's %4.
-
+ %1 points from %2's %3 to their own %4.%1 points from %2's %3 to their own %4.
-
+ %1 points from %2's %3 to %4's %5.%1 points from %2's %3 to %4's %5.
-
+ %1 creates a face down token.%1 creates a face down token.
-
+ %1 creates token: %2%3.%1 creates token: %2%3.
-
+ %1 has loaded a deck (%2).%1 has loaded a deck (%2).
-
+ %1 has loaded a deck with %2 sideboard cards (%3).%1 has loaded a deck with %2 sideboard cards (%3).
-
+ %1 destroys %2.%1 destroys %2.
-
+ a carda card
-
+ %1 gives %2 control over %3.%1 gives %2 control over %3.
-
+ %1 puts %2 into play%3 face down.%1 puts %2 into play%3 face down.
-
+ %1 puts %2 into play%3.%1 puts %2 into play%3.
-
+
+ %1 puts %2%3 into their graveyard face down.
+ %1 puts %2%3 into their graveyard face down.
+
+
+ %1 puts %2%3 into their graveyard.%1 puts %2%3 into their graveyard.
+
+
+ %1 exiles %2%3 face down.
+ %1 exiles %2%3 face down.
+ %1 exiles %2%3.%1 exiles %2%3.
-
+ %1 moves %2%3 to their hand.%1 moves %2%3 to their hand.
-
+ %1 puts %2%3 into their library.%1 puts %2%3 into their library.
-
+ %1 puts %2%3 onto the bottom of their library.%1 puts %2%3 onto the bottom of their library.
-
+ %1 puts %2%3 on top of their library.%1 puts %2%3 on top of their library.
-
+ %1 puts %2%3 into their library %4 cards from the top.%1 puts %2%3 into their library %4 cards from the top.
-
+ %1 moves %2%3 to sideboard.%1 moves %2%3 to sideboard.
-
+
+ %1 plays %2%3 face down.
+ %1 plays %2%3 face down.
+
+
+ %1 plays %2%3.%1 plays %2%3.
-
+
+ %1 moves %2%3 to custom zone '%4' face down.
+ %1 moves %2%3 to custom zone '%4' face down.
+
+
+ %1 moves %2%3 to custom zone '%4'.%1 moves %2%3 to custom zone '%4'.
-
+ %1 tries to draw from an empty library%1 tries to draw from an empty library
-
+ %1 draws %2 card(s).%1 draws %2 card.%1 draws %2 cards.
-
+ %1 is looking at %2.%1 is looking at %2.
-
+ %1 is looking at the %4 %3 card(s) %2.top card for singular, top %3 cards for plural%1 is looking at the %4 %3 card %2.%1 is looking at the %4 %3 cards %2.
-
+ bottombottom
-
+ toptop
-
+ %1 turns %2 face-down.%1 turns %2 face-down.
-
+ %1 turns %2 face-up.%1 turns %2 face-up.
-
+ The game has been closed.The game has been closed.
-
+ The game has started.The game has started.
-
+ You are flooding the game. Please wait a couple of seconds.You are flooding the game. Please wait a couple of seconds.
-
+ %1 has joined the game.%1 has joined the game.
-
+ %1 is now watching the game.%1 is now watching the game.
-
+ You have been kicked out of the game.You have been kicked out of the game.
-
+ %1 has left the game (%2).%1 has left the game (%2).
-
+ %1 is not watching the game any more (%2).%1 is not watching the game any more (%2).
-
+ %1 is not ready to start the game any more.%1 is not ready to start the game any more.
-
+ %1 shuffles their deck and draws a new hand of %2 card(s).%1 shuffles their deck and draws a card.%1 shuffles their deck and draws a new hand of %2 cards.
-
+ %1 shuffles their deck and draws a new hand.%1 shuffles their deck and draws a new hand.
-
+ You are watching a replay of game #%1.You are watching a replay of game #%1.
-
+ %1 is ready to start the game.%1 is ready to start the game.
-
+ cardsan unknown amount of cardscards
-
+ %1 card(s)a card for singular, %1 cards for pluralone card%1 cards
-
+ %1 lends %2 to %3.%1 lends %2 to %3.
-
+ %1 reveals %2 to %3.%1 reveals %2 to %3.
-
+ %1 reveals %2.%1 reveals %2.
-
+ %1 randomly reveals %2%3 to %4.%1 randomly reveals %2%3 to %4.
-
+ %1 randomly reveals %2%3.%1 randomly reveals %2%3.
-
+ %1 peeks at face down card #%2.%1 peeks at face down card #%2.
-
+ %1 peeks at face down card #%2: %3.%1 peeks at face down card #%2: %3.
-
+ %1 reveals %2%3 to %4.%1 reveals %2%3 to %4.
-
+ %1 reveals %2%3.%1 reveals %2%3.
-
+ %1 reversed turn order, now it's %2.%1 reversed turn order, now it's %2.
-
+ reversedreversed
-
+ normalnormal
-
+ HeadsHeads
-
+ TailsTails
-
+ %1 flipped a coin. It landed as %2.%1 flipped a coin. It landed as %2.
-
+ %1 rolls a %2 with a %3-sided die.%1 rolls a %2 with a %3-sided die.
-
+ %1 flips %2 coins. There are %3 heads and %4 tails.%1 flips %2 coins. There are %3 heads and %4 tails.
-
+ %1 rolls a %2-sided dice %3 times: %4.%1 rolls a %2-sided dice %3 times: %4.
-
+ %1's turn.%1's turn.
-
+ %1 sets annotation of %2 to %3.%1 sets annotation of %2 to %3.
-
+ %1 places %2 "%3" counter(s) on %4 (now %5).%1 places %2 "%3" counter on %4 (now %5).%1 places %2 "%3" counters on %4 (now %5).
-
+ %1 removes %2 "%3" counter(s) from %4 (now %5).%1 removes %2 "%3" counter from %4 (now %5).%1 removes %2 "%3" counters from %4 (now %5).
-
+ %1 sets counter %2 to %3 (%4%5).%1 sets counter %2 to %3 (%4%5).
-
+ %1 sets %2 to not untap normally.%1 sets %2 to not untap normally.
-
+ %1 sets %2 to untap normally.%1 sets %2 to untap normally.
-
+ %1 removes the PT of %2.%1 removes the PT of %2.
-
+ %1 changes the PT of %2 from nothing to %4.%1 changes the PT of %2 from nothing to %4.
-
+ %1 changes the PT of %2 from %3 to %4.%1 changes the PT of %2 from %3 to %4.
-
+ %1 has locked their sideboard.%1 has locked their sideboard.
-
+ %1 has unlocked their sideboard.%1 has unlocked their sideboard.
-
+ %1 taps their permanents.%1 taps their permanents.
-
+ %1 untaps their permanents.%1 untaps their permanents.
-
+ %1 taps %2.%1 taps %2.
-
+ %1 untaps %2.%1 untaps %2.
-
+ %1 shuffles %2.%1 shuffles %2.
-
+ %1 shuffles the bottom %3 cards of %2.%1 shuffles the bottom %3 cards of %2.
-
+ %1 shuffles the top %3 cards of %2.%1 shuffles the top %3 cards of %2.
-
+ %1 shuffles cards %3 - %4 of %2.%1 shuffles cards %3 - %4 of %2.
-
+ %1 unattaches %2.%1 unattaches %2.
-
+ %1 undoes their last draw.%1 undoes their last draw.
-
+ %1 undoes their last draw (%2).%1 undoes their last draw (%2).
@@ -6282,110 +6316,110 @@ Cockatrice will now reload the card database.
MessagesSettingsPage
-
+ Word1 Word2 Word3Word1 Word2 Word3
-
+ Add New MessageAdd New Message
-
+ Edit MessageEdit Message
-
+ Remove MessageRemove Message
-
+ Add messageAdd message
-
-
+
+ Message:Message:
-
+ Edit messageEdit message
-
+ Chat settingsChat settings
-
+ Custom alert wordsCustom alert words
-
+ Enable chat mentionsEnable chat mentions
-
+ Enable mention completerEnable mention completer
-
+ In-game message macrosIn-game message macros
-
+ How to use in-game message macrosHow to use in-game message macros
-
+ Ignore chat room messages sent by unregistered usersIgnore chat room messages sent by unregistered users
-
+ Ignore private messages sent by unregistered usersIgnore private messages sent by unregistered users
-
-
+
+ Invert text colorInvert text color
-
+ Enable desktop notifications for private messagesEnable desktop notifications for private messages
-
+ Enable desktop notification for mentionsEnable desktop notification for mentions
-
+ Enable room message history on joinEnable room message history on join
-
-
+
+ (Color is hexadecimal)(Color is hexadecimal)
-
+ Separate words with a space, alphanumeric characters onlySeparate words with a space, alphanumeric characters only
@@ -6398,32 +6432,37 @@ Cockatrice will now reload the card database.
Move to
-
+ &Top of library in random order&Top of library in random order
-
+ X cards from the top of library...X cards from the top of library...
-
+ &Bottom of library in random order&Bottom of library in random order
-
+
+ T&able
+ T&able
+
+
+ &Hand&Hand
-
+ &Graveyard&Graveyard
-
+ &Exile&Exile
@@ -6565,57 +6604,57 @@ Cockatrice will now reload the card database.
PhasesToolbar
-
+ Untap stepUntap step
-
+ Upkeep stepUpkeep step
-
+ Draw stepDraw step
-
+ First main phaseFirst main phase
-
+ Beginning of combat stepBeginning of combat step
-
+ Declare attackers stepDeclare attackers step
-
+ Declare blockers stepDeclare blockers step
-
+ Combat damage stepCombat damage step
-
+ End of combat stepEnd of combat step
-
+ Second main phaseSecond main phase
-
+ End of turn stepEnd of turn step
@@ -6632,134 +6671,138 @@ Cockatrice will now reload the card database.
PlayerActions
-
+ View top cards of libraryView top cards of library
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ Number of cards: (max. %1)Number of cards: (max. %1)
-
+ View bottom cards of libraryView bottom cards of library
-
+ Shuffle top cards of libraryShuffle top cards of library
-
+ Shuffle bottom cards of libraryShuffle bottom cards of library
-
+ Draw handDraw hand
-
+ 0 and lower are in comparison to current hand size0 and lower are in comparison to current hand size
-
+ Draw cardsDraw cards
+
+
+
+
+
+ grave
+ grave
+
- Move top cards to grave
- Move top cards to grave
+
+
+
+ exile
+ exile
-
- Move top cards to exile
- Move top cards to exile
+
+ Move top cards to %1
+ Move top cards to %1
-
- Move bottom cards to grave
- Move bottom cards to grave
+
+ Move bottom cards to %1
+ Move bottom cards to %1
-
- Move bottom cards to exile
- Move bottom cards to exile
-
-
-
+ Draw bottom cardsDraw bottom cards
-
-
+
+ C&reate another %1 tokenC&reate another %1 token
-
+ Create tokensCreate tokens
-
-
+
+ Number:Number:
-
+ Place card X cards from top of libraryPlace card X cards from top of library
-
+ Which position should this card be placed:Which position should this card be placed:
-
+ (max. %1)(max. %1)
-
+ Change power/toughnessChange power/toughness
-
+ Change stats to:Change stats to:
-
+ Set annotationSet annotation
-
+ Please enter the new annotation:Please enter the new annotation:
-
+ Set countersSet counters
@@ -6767,48 +6810,69 @@ Cockatrice will now reload the card database.
PlayerMenu
-
+ Player "%1"Player "%1"
-
+ &Counters&Counters
+
+
+ PrintingDisabledInfoWidget
-
- S&ay
- S&ay
+
+ The Printing Selector is disabled because you have currently enabled the setting to override all selected printings with personal set preferences.
+
+This setting means you'll only see the default printing for each card, instead of being able to select a printing, and will not see the printings other people have selected.
+
+
+ The Printing Selector is disabled because you have currently enabled the setting to override all selected printings with personal set preferences.
+
+This setting means you'll only see the default printing for each card, instead of being able to select a printing, and will not see the printings other people have selected.
+
+
+
+
+
+ Enable printings again
+ Enable printings againPrintingSelector
-
+ Display Navigation ButtonsDisplay Navigation Buttons
+
+
+ Printing Selector
+ Printing Selector
+ PrintingSelectorCardOverlayWidget
-
+ PreferencePreference
-
+ Pin PrintingPin Printing
-
+ Unpin PrintingUnpin Printing
-
+ Show Related cardsShow Related cards
@@ -6857,17 +6921,25 @@ Cockatrice will now reload the card database.
Release Date
-
-
+
+ DescendingDescending
-
+ AscendingAscending
+
+ PrintingSelectorPlaceholderWidget
+
+
+ Select a card to view its available printings
+ Select a card to view its available printings
+
+PtMenu
@@ -7006,6 +7078,45 @@ Cockatrice will now reload the card database.
A .cod version of this deck already exists. Overwrite it?A .cod version of this deck already exists. Overwrite it?
+
+
+ Enabling this feature will disable the use of the Printing Selector.
+
+You will not be able to manage printing preferences on a per-deck basis, or see printings other people have selected for their decks.
+
+You will have to use the Set Manager, available through Card Database -> Manage Sets.
+
+Are you sure you would like to enable this feature?
+ Enabling this feature will disable the use of the Printing Selector.
+
+You will not be able to manage printing preferences on a per-deck basis, or see printings other people have selected for their decks.
+
+You will have to use the Set Manager, available through Card Database -> Manage Sets.
+
+Are you sure you would like to enable this feature?
+
+
+
+ Disabling this feature will enable the Printing Selector.
+
+You can now choose printings on a per-deck basis in the Deck Editor and configure which printing gets added to a deck by default by pinning it in the Printing Selector.
+
+You can also use the Set Manager to adjust custom sort order for printings in the Printing Selector (other sort orders like alphabetical or release date are available).
+
+Are you sure you would like to disable this feature?
+ Disabling this feature will enable the Printing Selector.
+
+You can now choose printings on a per-deck basis in the Deck Editor and configure which printing gets added to a deck by default by pinning it in the Printing Selector.
+
+You can also use the Set Manager to adjust custom sort order for printings in the Printing Selector (other sort orders like alphabetical or release date are available).
+
+Are you sure you would like to disable this feature?
+
+
+
+ Confirm Change
+ Confirm Change
+ QPlatformTheme
@@ -7154,37 +7265,37 @@ Cockatrice will now reload the card database.
RfgMenu
-
+ &Exile&Exile
-
+ &View exile&View exile
-
+ &Move exile to...&Move exile to...
-
+ &Top of library&Top of library
-
+ &Bottom of library&Bottom of library
-
+ &Hand&Hand
-
+ &Graveyard&Graveyard
@@ -7227,6 +7338,14 @@ Cockatrice will now reload the card database.
Games
+
+ SayMenu
+
+
+ S&ay
+ S&ay
+
+SequenceEdit
@@ -7291,53 +7410,53 @@ Cockatrice will now reload the card database.
ShortcutSettingsPage
-
-
+
+ Restore all default shortcutsRestore all default shortcuts
-
+ Do you really want to restore all default shortcuts?Do you really want to restore all default shortcuts?
-
+ Clear all default shortcutsClear all default shortcuts
-
+ Do you really want to clear all shortcuts?Do you really want to clear all shortcuts?
-
+ Section:Section:
-
+ Action:Action:
-
+ Shortcut:Shortcut:
-
+ How to set custom shortcutsHow to set custom shortcuts
-
+ Clear all shortcutsClear all shortcuts
-
+ Search by shortcut nameSearch by shortcut name
@@ -7406,27 +7525,27 @@ Please check your shortcut settings!
SoundSettingsPage
-
+ Enable &soundsEnable &sounds
-
+ Current sounds theme:Current sounds theme:
-
+ Test system sound engineTest system sound engine
-
+ Sound settingsSound settings
-
+ Master volumeMaster volume
@@ -7642,59 +7761,123 @@ Please check your shortcut settings!
TabArchidekt
-
-
+
+
+ Desc.Desc.
-
+
+
+ AND
+ AND
+
+
+
+
+ Require ALL selected colors
+ Require ALL selected colors
+
+
+
+
+ Deck name...
+ Deck name...
+
+
+
+
+ Owner...
+ Owner...
+
+
+
+
+ Packages
+ Packages
+
+
+
+
+ Advanced Filters
+ Advanced Filters
+
+
+
+ Bracket:
+ Bracket:
+
+
+
+
+ Any
+ Any
+
+
+
+
+ Contains card...
+ Contains card...
+
+
+
+
+ Commander...
+ Commander...
+
+
+
+
+ Tag...
+ Tag...
+
+
+
+
+ Deck Size
+ Deck Size
+
+
+
+ Cards:
+ Cards:
+
+
+
+ Asc.Asc.
-
-
- Any Bracket
- Any Bracket
+
+ Sort by:
+ Sort by:
-
- Deck name contains...
- Deck name contains...
+
+ Filter by:
+ Filter by:
-
- Owner name contains...
- Owner name contains...
+
+ Display Settings
+ Display Settings
-
- Disabled
- Disabled
-
-
-
+
+ SearchSearch
-
+
+ FormatsFormats
-
- Min. # of Cards:
- Min. # of Cards:
-
-
-
- Page:
- Page:
-
-
-
+ Archidekt: Archidekt:
@@ -7702,60 +7885,52 @@ Please check your shortcut settings!
TabDeckEditor
-
+ Card InfoCard Info
-
+ DeckDeck
-
+ FiltersFilters
-
+ &View&View
-
+ Card DatabaseCard Database
-
+ PrintingPrinting
-
-
-
-
-
+ VisibleVisible
-
-
-
-
-
+ FloatingFloating
-
+ Reset layoutReset layout
-
+ Deck: %1Deck: %1
@@ -7763,61 +7938,55 @@ Please check your shortcut settings!
TabDeckEditorVisual
-
+ Visual Deck: %1Visual Deck: %1
-
+ &Visual Deck Editor&Visual Deck Editor
-
-
+
+ Card InfoCard Info
-
-
+
+ DeckDeck
-
-
+
+ FiltersFilters
-
+ &View&View
-
+ PrintingPrinting
-
-
-
-
+ VisibleVisible
-
-
-
-
+ FloatingFloating
-
+ Reset layoutReset layout
@@ -7882,7 +8051,7 @@ Please check your shortcut settings!
-
+ New folderNew folder
@@ -7964,18 +8133,18 @@ Please enter a name:
Are you sure you want to delete the selected files?
-
+ Delete remote decksDelete remote decks
-
+ Are you sure you want to delete the selected decks?Are you sure you want to delete the selected decks?
-
+ Name of new folder:Name of new folder:
@@ -7993,12 +8162,12 @@ Please enter a name:
Visual Deck Storage
-
+ ErrorError
-
+ Could not open deck at %1Could not open deck at %1
@@ -8047,197 +8216,191 @@ Please enter a name:
TabGame
-
-
-
+
+
+ ReplayReplay
-
-
+
+ GameGame
-
-
+
+ Player ListPlayer List
-
-
+
+ Card InfoCard Info
-
-
+
+ MessagesMessages
-
-
+
+ Replay TimelineReplay Timeline
-
+ &Phases&Phases
-
+ &Game&Game
-
+ Next &phaseNext &phase
-
+ Next phase with &actionNext phase with &action
-
+ Next &turnNext &turn
-
+ Reverse turn orderReverse turn order
-
+ &Remove all local arrows&Remove all local arrows
-
+ Rotate View Cl&ockwiseRotate View Cl&ockwise
-
+ Rotate View Co&unterclockwiseRotate View Co&unterclockwise
-
+ Game &informationGame &information
-
+ Un&concedeUn&concede
-
-
-
+
+
+ &Concede&Concede
-
+ &Leave game&Leave game
-
+ C&lose replayC&lose replay
-
+ &Focus Chat&Focus Chat
-
+ &Say:&Say:
-
+ Selected cardsSelected cards
-
+ &View&View
-
-
-
-
+ VisibleVisible
-
-
-
-
+ FloatingFloating
-
+ Reset layoutReset layout
-
+ ConcedeConcede
-
+ Are you sure you want to concede this game?Are you sure you want to concede this game?
-
+ UnconcedeUnconcede
-
+ You have already conceded. Do you want to return to this game?You have already conceded. Do you want to return to this game?
-
+ Leave gameLeave game
-
+ Are you sure you want to leave this game?Are you sure you want to leave this game?
-
+ A player has joined game #%1A player has joined game #%1
-
+ %1 has joined the game%1 has joined the game
-
+ You have been kicked out of the game.You have been kicked out of the game.
@@ -9340,142 +9503,152 @@ Please refrain from engaging in this activity or further actions may be taken ag
UserInterfaceSettingsPage
-
+ General interface settingsGeneral interface settings
-
+ &Double-click cards to play them (instead of single-click)&Double-click cards to play them (instead of single-click)
-
+ &Clicking plays all selected cards (instead of just the clicked card)&Clicking plays all selected cards (instead of just the clicked card)
-
+ &Play all nonlands onto the stack (not the battlefield) by default&Play all nonlands onto the stack (not the battlefield) by default
-
+ Do not delete &arrows inside of subphasesDo not delete &arrows inside of subphases
-
+ Close card view window when last card is removedClose card view window when last card is removed
-
+ Auto focus search bar when card view window is openedAuto focus search bar when card view window is opened
-
+ Annotate card text on tokensAnnotate card text on tokens
-
+
+ Show selection counter during drag selection
+ Show selection counter during drag selection
+
+
+
+ Show total selection counter
+ Show total selection counter
+
+
+ Use tear-off menus, allowing right click menus to persist on screenUse tear-off menus, allowing right click menus to persist on screen
-
+ Notifications settingsNotifications settings
-
+ Enable notifications in taskbarEnable notifications in taskbar
-
+ Notify in the taskbar for game events while you are spectatingNotify in the taskbar for game events while you are spectating
-
+ Notify in the taskbar when users in your buddy list connectNotify in the taskbar when users in your buddy list connect
-
+ Animation settingsAnimation settings
-
+ &Tap/untap animation&Tap/untap animation
-
+ Deck editor/storage settingsDeck editor/storage settings
-
+ Open deck in new tab by defaultOpen deck in new tab by default
-
+ Use visual deck storage in game lobbyUse visual deck storage in game lobby
-
+ Use selection animation for Visual Deck StorageUse selection animation for Visual Deck Storage
-
+ When adding a tag in the visual deck storage to a .txt deck:When adding a tag in the visual deck storage to a .txt deck:
-
+ do nothingdo nothing
-
+ ask to convert to .codask to convert to .cod
-
+ always convert to .codalways convert to .cod
-
+ Default deck editor typeDefault deck editor type
-
+ Classic Deck EditorClassic Deck Editor
-
+ Visual Deck EditorVisual Deck Editor
-
+ Replay settingsReplay settings
-
+ Buffer time for backwards skip via shortcut:Buffer time for backwards skip via shortcut:
@@ -9539,24 +9712,25 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayColorFilterWidget
-
- Mode: Exact Match
- Mode: Exact Match
+
+ Exact match
+ Exact match
+
+
+
+ Includes
+ Includes
- Mode: Includes
- Mode: Includes
+ Include / Exclude
+ Mode: Includes
+ Include / Exclude
-
- Mode: Include/Exclude
- Mode: Include/Exclude
-
-
-
- Filter mode (AND/OR/NOT conjunctions of filters)
- Filter mode (AND/OR/NOT conjunctions of filters)
+
+ How selected and unselected colors are combined in the filter
+ How selected and unselected colors are combined in the filter
@@ -9582,25 +9756,108 @@ Please refrain from engaging in this activity or further actions may be taken ag
Enter filename...
+
+ VisualDatabaseDisplayFilterToolbarWidget
+
+
+ Sort by
+ Sort by
+
+
+
+ Filter by
+ Filter by
+
+
+
+ Save and load filters
+ Save and load filters
+
+
+
+ Filter by exact card name
+ Filter by exact card name
+
+
+
+ Filter by card main-type
+ Filter by card main-type
+
+
+
+ Filter by card sub-type
+ Filter by card sub-type
+
+
+
+ Filter by set
+ Filter by set
+
+
+
+ Filter by format legality
+ Filter by format legality
+
+
+
+ Save/Load
+ Save/Load
+
+
+
+ Name
+ Name
+
+
+
+ Main Type
+ Main Type
+
+
+
+ Sub Type
+ Sub Type
+
+
+
+ Sets
+ Sets
+
+
+
+ Formats
+ Formats
+
+VisualDatabaseDisplayFormatLegalityFilterWidget
-
+
+ Show formats with at least:
+ Show formats with at least:
+
+
+
+ cards
+ cards
+
+
+ Do not display formats with less than this amount of cards in the databaseDo not display formats with less than this amount of cards in the database
-
+ Filter mode (AND/OR/NOT conjunctions of filters)Filter mode (AND/OR/NOT conjunctions of filters)
-
+ Mode: Exact MatchMode: Exact Match
-
+ Mode: IncludesMode: Includes
@@ -9608,22 +9865,32 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayMainTypeFilterWidget
-
+
+ Show main types with at least:
+ Show main types with at least:
+
+
+
+ cards
+ cards
+
+
+ Do not display card main-types with less than this amount of cards in the databaseDo not display card main-types with less than this amount of cards in the database
-
+ Filter mode (AND/OR/NOT conjunctions of filters)Filter mode (AND/OR/NOT conjunctions of filters)
-
+ Mode: Exact MatchMode: Exact Match
-
+ Mode: IncludesMode: Includes
@@ -9659,7 +9926,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplayRecentSetFilterSettingsWidget
-
+ Filter to most recent setsFilter to most recent sets
@@ -9667,19 +9934,19 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplaySetFilterWidget
-
+ Search sets...Search sets...
-
-
+
+ Mode: Exact MatchMode: Exact Match
-
-
+
+ Mode: IncludesMode: Includes
@@ -9687,27 +9954,37 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDatabaseDisplaySubTypeFilterWidget
-
+ Search subtypes...Search subtypes...
-
+
+ Show sub types with at least:
+ Show sub types with at least:
+
+
+
+ cards
+ cards
+
+
+ Do not display card sub-types with less than this amount of cards in the databaseDo not display card sub-types with less than this amount of cards in the database
-
+ Filter mode (AND/OR/NOT conjunctions of filters)Filter mode (AND/OR/NOT conjunctions of filters)
-
+ Mode: Exact MatchMode: Exact Match
-
+ Mode: IncludesMode: Includes
@@ -9721,52 +9998,22 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ VisualVisual
-
+ Loading database ...Loading database ...
-
+ Clear all filtersClear all filters
-
- Sort by:
- Sort by:
-
-
-
- Filter by:
- Filter by:
-
-
-
- Save and load filters
- Save and load filters
-
-
-
- Filter by exact card name
- Filter by exact card name
-
-
-
- Filter by card sub-type
- Filter by card sub-type
-
-
-
- Filter by set
- Filter by set
-
-
-
+ TableTable
@@ -9774,56 +10021,64 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDeckDisplayOptionsWidget
-
+ Group by:Group by:
-
+ Change how cards are divided into categories/groups.Change how cards are divided into categories/groups.
-
+ Sort by:Sort by:
-
+ Click and drag to change the sort order within the groupsClick and drag to change the sort order within the groups
-
+ Configure how cards are sorted within their groupsConfigure how cards are sorted within their groups
-
-
+
+ Toggle Layout: OverlapToggle Layout: Overlap
-
+ Change how cards are displayed within zones (i.e. overlapped or fully visible.)Change how cards are displayed within zones (i.e. overlapped or fully visible.)
-
+ Toggle Layout: FlatToggle Layout: Flat
+
+ VisualDeckEditorPlaceholderWidget
+
+
+ Add cards using the search bar or database tab to have them appear here
+ Add cards using the search bar or database tab to have them appear here
+
+VisualDeckEditorSampleHandWidget
-
+ Draw a new sample handDraw a new sample hand
-
+ Sample hand sizeSample hand size
@@ -9831,17 +10086,17 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDeckEditorWidget
-
+ Type a card name here for suggestions from the database...Type a card name here for suggestions from the database...
-
+ Quick search and add cardQuick search and add card
-
+ Search for closest match in the database (with auto-suggestions) and add preferred printing to the deck on pressing enterSearch for closest match in the database (with auto-suggestions) and add preferred printing to the deck on pressing enter
@@ -9857,47 +10112,52 @@ Please refrain from engaging in this activity or further actions may be taken ag
VisualDeckStorageQuickSettingsWidget
-
+ Show FoldersShow Folders
-
+ Show Tag FilterShow Tag Filter
-
+
+ Show Color Identity
+ Show Color Identity
+
+
+ Show Tags On Deck PreviewsShow Tags On Deck Previews
-
+ Show Banner Card Selection OptionShow Banner Card Selection Option
-
+ Draw unused Color IdentitiesDraw unused Color Identities
-
+ Unused Color Identities OpacityUnused Color Identities Opacity
-
+ Deck tooltip:Deck tooltip:
-
+ NoneNone
-
+ FilepathFilepath
@@ -9998,133 +10258,133 @@ Please refrain from engaging in this activity or further actions may be taken ag
WndSets
-
+ Move selected set to the topMove selected set to the top
-
+ Move selected set upMove selected set up
-
+ Move selected set downMove selected set down
-
+ Move selected set to the bottomMove selected set to the bottom
-
+ Search by set name, code, or typeSearch by set name, code, or type
-
+ Default orderDefault order
-
+ Restore original art priority orderRestore original art priority order
-
+ Enable all setsEnable all sets
-
+ Disable all setsDisable all sets
-
+ Enable selected set(s)Enable selected set(s)
-
+ Disable selected set(s)Disable selected set(s)
-
+ Deck EditorDeck Editor
-
+ Use CTRL+A to select all sets in the view.Use CTRL+A to select all sets in the view.
-
+ Only cards in enabled sets will appear in the card list of the deck editor.Only cards in enabled sets will appear in the card list of the deck editor.
-
+ Image priority is decided in the following order:Image priority is decided in the following order:
-
+ first the CUSTOM Folder (%1), then the Enabled Sets in this dialog (Top to Bottom)%1 is a link to the wikifirst the CUSTOM Folder (%1), then the Enabled Sets in this dialog (Top to Bottom)
-
+ Include cards rebalanced for Alchemy [requires restart]Include cards rebalanced for Alchemy [requires restart]
-
+ Card ArtCard Art
-
+ How to use custom card artHow to use custom card art
-
+ HintsHints
-
+ NoteNote
-
+ Sorting by column allows you to find a set while not changing set priority.Sorting by column allows you to find a set while not changing set priority.
-
+ To enable ordering again, click the column header until this message disappears.To enable ordering again, click the column header until this message disappears.
-
+ Use the current sorting as the set priority insteadUse the current sorting as the set priority instead
-
+ Sorts the set priority using the same columnSorts the set priority using the same column
-
+ Manage setsManage sets
@@ -10132,72 +10392,72 @@ Please refrain from engaging in this activity or further actions may be taken ag
ZoneViewWidget
-
+ Search by card name (or search expressions)Search by card name (or search expressions)
-
+ UngroupedUngrouped
-
+ Group by TypeGroup by Type
-
+ Group by Mana ValueGroup by Mana Value
-
+ Group by ColorGroup by Color
-
+ UnsortedUnsorted
-
+ Sort by NameSort by Name
-
+ Sort by TypeSort by Type
-
+ Sort by Mana CostSort by Mana Cost
-
+ Sort by ColorsSort by Colors
-
+ Sort by P/TSort by P/T
-
+ Sort by SetSort by Set
-
+ shuffle when closingshuffle when closing
-
+ pile viewpile view
@@ -10232,7 +10492,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ Deck EditorDeck Editor
@@ -10313,7 +10573,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ ReplaysReplays
@@ -10465,7 +10725,7 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ Reset LayoutReset Layout
@@ -10886,8 +11146,9 @@ Please refrain from engaging in this activity or further actions may be taken ag
- Toggle Untap
- Toggle Untap
+ Toggle Skip Untapping
+ Toggle Untap
+ Toggle Skip Untapping
@@ -10906,98 +11167,102 @@ Please refrain from engaging in this activity or further actions may be taken ag
+ Play Card, Face Down
+ Play Card, Face Down
+
+
+ Attach Card...Attach Card...
-
+ Unattach CardUnattach Card
-
+ Clone CardClone Card
-
+ Create Token...Create Token...
-
+ Create All Related TokensCreate All Related Tokens
-
+ Create Another TokenCreate Another Token
-
+ Set Annotation...Set Annotation...
-
+ Select All Cards in ZoneSelect All Cards in Zone
-
+ Select All Cards in RowSelect All Cards in Row
-
+ Select All Cards in ColumnSelect All Cards in Column
-
+ Reveal Selected Cards to All PlayersReveal Selected Cards to All Players
-
-
+
+ Bottom of LibraryBottom of Library
-
+
-
-
+
+ ExileExile
-
+
-
+ GraveyardGraveyard
-
+ HandHand
-
-
+
+ Top of LibraryTop of Library
-
-
+ Battlefield, Face DownBattlefield, Face Down
@@ -11033,234 +11298,246 @@ Please refrain from engaging in this activity or further actions may be taken ag
-
+ StackStack
-
+ Graveyard (Multiple)Graveyard (Multiple)
-
-
+
+
+ Graveyard (Multiple), Face Down
+ Graveyard (Multiple), Face Down
+
+
+
+ Exile (Multiple)Exile (Multiple)
-
+
+
+ Exile (Multiple), Face Down
+ Exile (Multiple), Face Down
+
+
+ Stack Until FoundStack Until Found
-
+ Draw Bottom CardDraw Bottom Card
-
+ Draw Multiple Cards from Bottom...Draw Multiple Cards from Bottom...
-
+ Draw Arrow...Draw Arrow...
-
+ Remove Local ArrowsRemove Local Arrows
-
+ Leave GameLeave Game
-
+ ConcedeConcede
-
+ Roll Dice...Roll Dice...
-
+ Shuffle LibraryShuffle Library
-
+ Shuffle Top Cards of LibraryShuffle Top Cards of Library
-
+ Shuffle Bottom Cards of LibraryShuffle Bottom Cards of Library
-
+ MulliganMulligan
-
+ Mulligan (Same hand size)Mulligan (Same hand size)
-
+ Mulligan (Hand size - 1)Mulligan (Hand size - 1)
-
+ Draw a CardDraw a Card
-
+ Draw Multiple Cards...Draw Multiple Cards...
-
+ Undo DrawUndo Draw
-
+ Always Reveal Top CardAlways Reveal Top Card
-
+ Always Look At Top CardAlways Look At Top Card
-
+ Sort Hand by NameSort Hand by Name
-
+ Sort Hand by TypeSort Hand by Type
-
+ Sort Hand by Mana ValueSort Hand by Mana Value
-
+ Reveal Hand to All PlayersReveal Hand to All Players
-
+ Reveal Random Card to All PlayersReveal Random Card to All Players
-
+ Rotate View ClockwiseRotate View Clockwise
-
+ Rotate View CounterclockwiseRotate View Counterclockwise
-
+ Unfocus Text BoxUnfocus Text Box
-
+ Focus ChatFocus Chat
-
+ Clear ChatClear Chat
-
+ RefreshRefresh
-
+ Skip ForwardSkip Forward
-
+ Skip BackwardSkip Backward
-
+ Skip Forward by a lotSkip Forward by a lot
-
+ Skip Backward by a lotSkip Backward by a lot
-
+ Play/PausePlay/Pause
-
+ Toggle Fast ForwardToggle Fast Forward
-
+ HomeHome
-
+ Visual Deck StorageVisual Deck Storage
-
+ Deck StorageDeck Storage
-
+ ServerServer
-
+ AccountAccount
-
+ AdministrationAdministration
-
+ LogsLogs
diff --git a/libcockatrice_card/libcockatrice/card/printing/exact_card.h b/libcockatrice_card/libcockatrice/card/printing/exact_card.h
index 01c61a3a1..74fc75da3 100644
--- a/libcockatrice_card/libcockatrice/card/printing/exact_card.h
+++ b/libcockatrice_card/libcockatrice/card/printing/exact_card.h
@@ -114,5 +114,6 @@ public:
*/
void emitPixmapUpdated() const;
};
+Q_DECLARE_METATYPE(ExactCard)
#endif // EXACT_CARD_H
diff --git a/libcockatrice_network/libcockatrice/network/client/remote/remote_client.cpp b/libcockatrice_network/libcockatrice/network/client/remote/remote_client.cpp
index 4b5d3f1b8..3e3ec889d 100644
--- a/libcockatrice_network/libcockatrice/network/client/remote/remote_client.cpp
+++ b/libcockatrice_network/libcockatrice/network/client/remote/remote_client.cpp
@@ -390,14 +390,18 @@ void RemoteClient::readData()
return;
ServerMessage newServerMessage;
- newServerMessage.ParseFromArray(inputBuffer.data(), messageLength);
-
- qCDebug(RemoteClientLog).noquote() << "IN" << getSafeDebugString(newServerMessage);
+ bool ok = newServerMessage.ParseFromArray(inputBuffer.data(), messageLength);
inputBuffer.remove(0, messageLength);
messageInProgress = false;
- processProtocolItem(newServerMessage);
+ if (ok) {
+ qCDebug(RemoteClientLog).noquote() << "IN" << getSafeDebugString(newServerMessage);
+
+ processProtocolItem(newServerMessage);
+ } else {
+ qCDebug(RemoteClientLog) << "parsing error!";
+ }
if (getStatus() == StatusDisconnecting) // use thread-safe getter
doDisconnectFromServer();
@@ -408,11 +412,13 @@ void RemoteClient::websocketMessageReceived(const QByteArray &message)
{
lastDataReceived = timeRunning;
ServerMessage newServerMessage;
- newServerMessage.ParseFromArray(message.data(), message.length());
+ if (newServerMessage.ParseFromArray(message.data(), message.length())) {
+ qCDebug(RemoteClientLog).noquote() << "IN" << getSafeDebugString(newServerMessage);
- qCDebug(RemoteClientLog).noquote() << "IN" << getSafeDebugString(newServerMessage);
-
- processProtocolItem(newServerMessage);
+ processProtocolItem(newServerMessage);
+ } else {
+ qCDebug(RemoteClientLog) << "parsing error!";
+ }
}
void RemoteClient::sendCommandContainer(const CommandContainer &cont)
@@ -426,19 +432,27 @@ void RemoteClient::sendCommandContainer(const CommandContainer &cont)
qCDebug(RemoteClientLog).noquote() << "OUT" << getSafeDebugString(cont);
QByteArray buf;
+ bool ok;
if (usingWebSocket) {
buf.resize(size);
- cont.SerializeToArray(buf.data(), size);
- websocket->sendBinaryMessage(buf);
+ ok = cont.SerializeToArray(buf.data(), size);
+ if (ok) {
+ websocket->sendBinaryMessage(buf);
+ }
} else {
buf.resize(size + 4);
- cont.SerializeToArray(buf.data() + 4, size);
- buf.data()[3] = (unsigned char)size;
- buf.data()[2] = (unsigned char)(size >> 8);
- buf.data()[1] = (unsigned char)(size >> 16);
- buf.data()[0] = (unsigned char)(size >> 24);
+ ok = cont.SerializeToArray(buf.data() + 4, size);
+ if (ok) {
+ buf.data()[3] = (unsigned char)size;
+ buf.data()[2] = (unsigned char)(size >> 8);
+ buf.data()[1] = (unsigned char)(size >> 16);
+ buf.data()[0] = (unsigned char)(size >> 24);
- socket->write(buf);
+ socket->write(buf);
+ }
+ }
+ if (!ok) {
+ qCDebug(RemoteClientLog) << "transmit error!";
}
}
diff --git a/libcockatrice_protocol/libcockatrice/protocol/debug_pb_message.cpp b/libcockatrice_protocol/libcockatrice/protocol/debug_pb_message.cpp
index f0c3448b5..718487c18 100644
--- a/libcockatrice_protocol/libcockatrice/protocol/debug_pb_message.cpp
+++ b/libcockatrice_protocol/libcockatrice/protocol/debug_pb_message.cpp
@@ -101,6 +101,10 @@ QString getSafeDebugString(const ::google::protobuf::Message &message)
#endif // GOOGLE_PROTOBUF_VERSION > 3004000
std::string debug_string;
- printer.PrintToString(message, &debug_string);
- return QString::number(size) + " bytes " + QString::fromStdString(debug_string);
+ bool ok = printer.PrintToString(message, &debug_string);
+ if (ok) {
+ return QString::number(size) + " bytes " + QString::fromStdString(debug_string);
+ } else {
+ return "[could not convert message to string]";
+ }
}
diff --git a/libcockatrice_utility/libcockatrice/utility/expression.cpp b/libcockatrice_utility/libcockatrice/utility/expression.cpp
index 3b2e815d1..42073670c 100644
--- a/libcockatrice_utility/libcockatrice/utility/expression.cpp
+++ b/libcockatrice_utility/libcockatrice/utility/expression.cpp
@@ -20,7 +20,7 @@ peg::parser math(R"(
NUMBER <- < '-'? [0-9]+ >
NAME <- < [a-z][a-z0-9]* >
- VARIABLE <- < [x] >
+ VARIABLE <- < [xX] >
FUNCTION <- NAME '(' EXPRESSION ( [,\n] EXPRESSION )* ')'
%whitespace <- [ \t\r]*
diff --git a/oracle/oracle_en@source.ts b/oracle/oracle_en@source.ts
index 53ad27b4d..943b44a97 100644
--- a/oracle/oracle_en@source.ts
+++ b/oracle/oracle_en@source.ts
@@ -278,7 +278,7 @@
OracleImporter
-
+ Dummy set containing tokens
@@ -286,7 +286,7 @@
OracleWizard
-
+ Oracle Importer
diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp
index d585842f6..b5d7b9856 100644
--- a/oracle/src/oracleimporter.cpp
+++ b/oracle/src/oracleimporter.cpp
@@ -360,13 +360,13 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
}
// split cards are considered a single card, enqueue for later merging
- if (layout == "split" || layout == "aftermath" || layout == "adventure") {
+ if (layout == "split" || layout == "aftermath" || layout == "adventure" || layout == "prepare") {
auto _faceName = getStringPropertyFromMap(card, "faceName");
SplitCardPart split(_faceName, text, properties, printingInfo);
auto found_iter = splitCards.find(name + numProperty);
if (found_iter == splitCards.end()) {
splitCards.insert(name + numProperty, {{split}, name});
- } else if (layout == "adventure") {
+ } else if (layout == "adventure" || layout == "prepare") {
found_iter->first.insert(0, split);
} else {
found_iter->first.append(split);
diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h
index e83958d73..5bf352594 100644
--- a/oracle/src/oracleimporter.h
+++ b/oracle/src/oracleimporter.h
@@ -22,6 +22,7 @@ const QMap setTypePriorities{
{"archenemy", CardSet::PriorityReprint},
{"arsenal", CardSet::PriorityReprint},
{"box", CardSet::PriorityReprint},
+ {"eternal", CardSet::PriorityReprint},
{"from_the_vault", CardSet::PriorityReprint},
{"masterpiece", CardSet::PriorityReprint},
{"masters", CardSet::PriorityReprint},
diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp
index 9d32a993b..2edb9e561 100644
--- a/oracle/src/oraclewizard.cpp
+++ b/oracle/src/oraclewizard.cpp
@@ -21,6 +21,10 @@ OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent)
// define a dummy context that will be used where needed
QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
+#ifdef Q_OS_WIN
+ setWizardStyle(QWizard::ModernStyle);
+#endif
+
QString oracleSettingsFile = SettingsCache::instance().getSettingsPath() + "oracle.ini";
settings = new QSettings(oracleSettingsFile, QSettings::IniFormat, this);
diff --git a/servatrice/src/isl_interface.cpp b/servatrice/src/isl_interface.cpp
index bcf71a98a..692a0fdba 100644
--- a/servatrice/src/isl_interface.cpp
+++ b/servatrice/src/isl_interface.cpp
@@ -3,6 +3,7 @@
#include "main.h"
#include "server_logger.h"
+#include
#include
#include
#include
@@ -21,6 +22,8 @@
#include
#include
+inline Q_LOGGING_CATEGORY(IslInterfaceLog, "isl_interface");
+
void IslInterface::sharedCtor(const QSslCertificate &cert, const QSslKey &privateKey)
{
socket = new QSslSocket(this);
@@ -113,10 +116,11 @@ void IslInterface::initServer()
socket->startServerEncryption();
if (!socket->waitForEncrypted(5000)) {
QList sslErrors(socket->sslHandshakeErrors());
- if (sslErrors.isEmpty())
- qDebug() << "[ISL] SSL handshake timeout, terminating connection";
- else
- qDebug() << "[ISL] SSL errors:" << sslErrors;
+ if (sslErrors.isEmpty()) {
+ qCDebug(IslInterfaceLog) << "SSL handshake timeout, terminating connection";
+ } else {
+ qCWarning(IslInterfaceLog) << "SSL errors:" << sslErrors;
+ }
deleteLater();
return;
}
@@ -157,7 +161,7 @@ void IslInterface::initServer()
server->islLock.lockForWrite();
if (server->islConnectionExists(serverId)) {
- qDebug() << "[ISL] Duplicate connection to #" << serverId << "terminating connection";
+ qCDebug(IslInterfaceLog) << "Duplicate connection to #" << serverId << "terminating connection";
deleteLater();
} else {
transmitMessage(message);
@@ -180,27 +184,28 @@ void IslInterface::initClient()
expectedErrors.append(QSslError(QSslError::SelfSignedCertificate, peerCert));
socket->ignoreSslErrors(expectedErrors);
- qDebug() << "[ISL] Connecting to #" << serverId << ":" << peerAddress << ":" << peerPort;
+ qCDebug(IslInterfaceLog) << "Connecting to #" << serverId << ":" << peerAddress << ":" << peerPort;
socket->connectToHostEncrypted(peerAddress, peerPort, peerHostName);
if (!socket->waitForConnected(5000)) {
- qDebug() << "[ISL] Socket error:" << socket->errorString();
+ qCDebug(IslInterfaceLog) << "Socket error:" << socket->errorString();
deleteLater();
return;
}
if (!socket->waitForEncrypted(5000)) {
QList sslErrors(socket->sslHandshakeErrors());
- if (sslErrors.isEmpty())
- qDebug() << "[ISL] SSL handshake timeout, terminating connection";
- else
- qDebug() << "[ISL] SSL errors:" << sslErrors;
+ if (sslErrors.isEmpty()) {
+ qCDebug(IslInterfaceLog) << "SSL handshake timeout, terminating connection";
+ } else {
+ qCWarning(IslInterfaceLog) << "SSL errors:" << sslErrors;
+ }
deleteLater();
return;
}
server->islLock.lockForWrite();
if (server->islConnectionExists(serverId)) {
- qDebug() << "[ISL] Duplicate connection to #" << serverId << "terminating connection";
+ qCDebug(IslInterfaceLog) << "Duplicate connection to #" << serverId << "terminating connection";
deleteLater();
return;
}
@@ -242,17 +247,21 @@ void IslInterface::readClient()
return;
IslMessage newMessage;
- newMessage.ParseFromArray(inputBuffer.data(), messageLength);
+ bool ok = newMessage.ParseFromArray(inputBuffer.data(), messageLength);
inputBuffer.remove(0, messageLength);
messageInProgress = false;
- processMessage(newMessage);
+ if (ok) {
+ processMessage(newMessage);
+ } else {
+ qCWarning(IslInterfaceLog) << "parsing error!";
+ }
} while (!inputBuffer.isEmpty());
}
void IslInterface::catchSocketError(QAbstractSocket::SocketError socketError)
{
- qDebug() << "[ISL] Socket error:" << socketError;
+ qCWarning(IslInterfaceLog) << "Socket error:" << socketError;
server->islLock.lockForWrite();
server->removeIslInterface(serverId);
@@ -270,7 +279,10 @@ void IslInterface::transmitMessage(const IslMessage &item)
unsigned int size = static_cast(item.ByteSize());
#endif
buf.resize(size + 4);
- item.SerializeToArray(buf.data() + 4, size);
+ if (!item.SerializeToArray(buf.data() + 4, size)) {
+ qCWarning(IslInterfaceLog) << "transmit error!";
+ return;
+ }
buf.data()[3] = (unsigned char)size;
buf.data()[2] = (unsigned char)(size >> 8);
buf.data()[1] = (unsigned char)(size >> 16);
@@ -368,7 +380,7 @@ void IslInterface::processSessionEvent(const SessionEvent &event, qint64 session
QReadLocker clientsLocker(&server->clientsLock);
Server_AbstractUserInterface *client = server->getUsersBySessionId().value(sessionId);
if (!client) {
- qDebug() << "IslInterface::processSessionEvent: session id" << sessionId << "not found";
+ qCDebug(IslInterfaceLog) << "IslInterface::processSessionEvent: session id" << sessionId << "not found";
break;
}
const Event_GameJoined &gameJoined = event.GetExtension(Event_GameJoined::ext);
@@ -382,7 +394,8 @@ void IslInterface::processSessionEvent(const SessionEvent &event, qint64 session
QReadLocker clientsLocker(&server->clientsLock);
Server_AbstractUserInterface *client = server->getUsersBySessionId().value(sessionId);
if (!client) {
- qDebug() << "IslInterface::processSessionEvent: session id" << sessionId << "not found";
+ qCWarning(IslInterfaceLog)
+ << "IslInterface::processSessionEvent: session id" << sessionId << "not found";
break;
}
@@ -430,7 +443,7 @@ void IslInterface::processRoomCommand(const CommandContainer &cont, qint64 sessi
void IslInterface::processMessage(const IslMessage &item)
{
- qDebug() << getSafeDebugString(item);
+ qCDebug(IslInterfaceLog) << getSafeDebugString(item);
switch (item.message_type()) {
case IslMessage::ROOM_COMMAND_CONTAINER: {
diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp
index fa9b14f31..bce3542e8 100644
--- a/servatrice/src/servatrice_database_interface.cpp
+++ b/servatrice/src/servatrice_database_interface.cpp
@@ -7,12 +7,15 @@
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+inline Q_LOGGING_CATEGORY(DatabaseInterfaceLog, "database_interface");
+
Servatrice_DatabaseInterface::Servatrice_DatabaseInterface(int _instanceId, Servatrice *_server)
: instanceId(_instanceId), sqlDatabase(QSqlDatabase()), server(_server)
{
@@ -56,17 +59,16 @@ bool Servatrice_DatabaseInterface::openDatabase()
sqlDatabase.close();
const QString poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
- qDebug().noquote() << QString("[%1] Opening database...").arg(poolStr);
+ qCDebug(DatabaseInterfaceLog).noquote() << poolStr << "Opening database...";
if (!sqlDatabase.open()) {
- qCritical() << QString("[%1] Error opening database: %2").arg(poolStr).arg(sqlDatabase.lastError().text());
+ qCCritical(DatabaseInterfaceLog) << poolStr << "Error opening database:" << sqlDatabase.lastError().text();
return false;
}
QSqlQuery *versionQuery = prepareQuery("select version from {prefix}_schema_version limit 1");
if (!execSqlQuery(versionQuery)) {
- qCritical() << QString("[%1] Error opening database: unable to load database schema version (hint: ensure the "
- "cockatrice_schema_version exists)")
- .arg(poolStr);
+ qCCritical(DatabaseInterfaceLog) << poolStr << "Error opening database: unable to load database schema version"
+ << "(hint: ensure the cockatrice_schema_version exists)";
return false;
}
@@ -74,24 +76,21 @@ bool Servatrice_DatabaseInterface::openDatabase()
const int dbversion = versionQuery->value(0).toInt();
const int expectedversion = DATABASE_SCHEMA_VERSION;
if (dbversion < expectedversion) {
- qCritical() << QString("[%1] Error opening database: the database schema version is too old, you need to "
- "run the migrations to update it from version %2 to version %3")
- .arg(poolStr)
- .arg(dbversion)
- .arg(expectedversion);
+ qCCritical(DatabaseInterfaceLog) << poolStr
+ << "Error opening database: the database schema version is too old, you "
+ "need to run the migrations to update it from version"
+ << dbversion << "to version" << expectedversion;
return false;
} else if (dbversion > expectedversion) {
- qCritical() << QString("[%1] Error opening database: the database schema version %2 is too new, you need "
- "to update servatrice (this servatrice actually uses version %3)")
- .arg(poolStr)
- .arg(dbversion)
- .arg(expectedversion);
+ qCCritical(DatabaseInterfaceLog) << poolStr << "Error opening database: the database schema version"
+ << dbversion << "is too new, you need to update servatrice"
+ << "(this servatrice actually uses version" << expectedversion << ")";
return false;
}
} else {
- qCritical() << QString("[%1] Error opening database: unable to load database schema version (hint: ensure the "
- "cockatrice_schema_version contains a single record)")
- .arg(poolStr);
+ qCCritical(DatabaseInterfaceLog) << poolStr
+ << "Error opening database: unable to load database schema version (hint: "
+ "ensure the cockatrice_schema_version contains a single record)";
return false;
}
@@ -114,9 +113,7 @@ bool Servatrice_DatabaseInterface::checkSql()
if (query.lastError().isValid()) {
const auto &poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
- qCritical() << QString("[%1] Error executing query: %2, resetting connection")
- .arg(poolStr)
- .arg(query.lastError().text());
+ qCCritical(DatabaseInterfaceLog) << poolStr << "Error executing query:" << query.lastError().text();
sqlDatabase.close();
return openDatabase();
@@ -145,7 +142,7 @@ bool Servatrice_DatabaseInterface::execSqlQuery(QSqlQuery *query)
if (query->exec())
return true;
const QString poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
- qCritical() << QString("[%1] Error executing query: %2").arg(poolStr).arg(query->lastError().text());
+ qCCritical(DatabaseInterfaceLog) << poolStr << "Error executing query:" << query->lastError().text();
sqlDatabase.close();
openDatabase();
return false;
@@ -252,7 +249,8 @@ bool Servatrice_DatabaseInterface::registerUser(const QString &userName,
query->bindValue(":token", token);
if (!execSqlQuery(query)) {
- qDebug() << "Failed to insert user: " << query->lastError() << " sql: " << query->lastQuery();
+ qCWarning(DatabaseInterfaceLog) << "Failed to insert user: " << query->lastError()
+ << " sql: " << query->lastQuery();
return false;
}
@@ -270,8 +268,8 @@ bool Servatrice_DatabaseInterface::activateUser(const QString &userName, const Q
activateQuery->bindValue(":username", userName);
activateQuery->bindValue(":token", token);
if (!execSqlQuery(activateQuery)) {
- qDebug() << "Account activation failed: SQL error." << activateQuery->lastError()
- << " sql: " << activateQuery->lastQuery();
+ qCWarning(DatabaseInterfaceLog) << "Account activation failed: SQL error." << activateQuery->lastError()
+ << " sql: " << activateQuery->lastQuery();
return false;
}
@@ -284,7 +282,8 @@ bool Servatrice_DatabaseInterface::activateUser(const QString &userName, const Q
query->bindValue(":userName", userName);
if (!execSqlQuery(query)) {
- qDebug() << "Failed to activate user: " << query->lastError() << " sql: " << query->lastQuery();
+ qCWarning(DatabaseInterfaceLog)
+ << "Failed to activate user: " << query->lastError() << " sql: " << query->lastQuery();
return false;
}
@@ -326,7 +325,7 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
prepareQuery("select password_sha512, active from {prefix}_users where name = :name");
passwordQuery->bindValue(":name", user);
if (!execSqlQuery(passwordQuery)) {
- qDebug("Login denied: SQL error");
+ qCWarning(DatabaseInterfaceLog) << "Login denied: SQL error";
return NotLoggedIn;
}
@@ -334,7 +333,7 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
const QString correctPasswordSha512 = passwordQuery->value(0).toString();
const bool userIsActive = passwordQuery->value(1).toBool();
if (!userIsActive) {
- qDebug("Login denied: user not active");
+ qCWarning(DatabaseInterfaceLog) << "Login denied: user not active";
return UserIsInactive;
}
QString hashedPassword;
@@ -344,14 +343,14 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
hashedPassword = password;
}
if (correctPasswordSha512 == hashedPassword) {
- qDebug("Login accepted: password right");
+ qCDebug(DatabaseInterfaceLog) << "Login accepted: password right";
return PasswordRight;
} else {
- qDebug("Login denied: password wrong");
+ qCDebug(DatabaseInterfaceLog) << "Login denied: password wrong";
return NotLoggedIn;
}
} else {
- qDebug("Login accepted: unknown user");
+ qCDebug(DatabaseInterfaceLog) << "Login accepted: unknown user";
return UnknownUser;
}
}
@@ -369,7 +368,7 @@ bool Servatrice_DatabaseInterface::checkUserIsBanned(const QString &ipAddress,
return false;
if (!checkSql()) {
- qDebug("Failed to check if user is banned. Database invalid.");
+ qCWarning(DatabaseInterfaceLog) << "Failed to check if user is banned. Database invalid.";
return false;
}
@@ -400,7 +399,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIdBanned(const QString &clientId,
idBanQuery->bindValue(":id", clientId);
idBanQuery->bindValue(":id2", clientId);
if (!execSqlQuery(idBanQuery)) {
- qDebug() << "Id ban check failed: SQL error." << idBanQuery->lastError();
+ qCWarning(DatabaseInterfaceLog) << "Id ban check failed: SQL error." << idBanQuery->lastError();
return false;
}
@@ -410,7 +409,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIdBanned(const QString &clientId,
if ((secondsLeft > 0) || permanentBan) {
banReason = idBanQuery->value(2).toString();
banSecondsRemaining = permanentBan ? 0 : secondsLeft;
- qDebug() << "User is banned by client id" << clientId;
+ qCDebug(DatabaseInterfaceLog) << "User is banned by client id" << clientId;
return true;
}
}
@@ -428,7 +427,7 @@ bool Servatrice_DatabaseInterface::checkUserIsNameBanned(const QString &userName
nameBanQuery->bindValue(":name1", userName);
nameBanQuery->bindValue(":name2", userName);
if (!execSqlQuery(nameBanQuery)) {
- qDebug() << "Name ban check failed: SQL error" << nameBanQuery->lastError();
+ qCWarning(DatabaseInterfaceLog) << "Name ban check failed: SQL error" << nameBanQuery->lastError();
return false;
}
@@ -438,7 +437,7 @@ bool Servatrice_DatabaseInterface::checkUserIsNameBanned(const QString &userName
if ((secondsLeft > 0) || permanentBan) {
banReason = nameBanQuery->value(2).toString();
banSecondsRemaining = permanentBan ? 0 : secondsLeft;
- qDebug() << "Username" << userName << "is banned by name";
+ qCDebug(DatabaseInterfaceLog) << "Username" << userName << "is banned by name";
return true;
}
}
@@ -464,7 +463,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIpBanned(const QString &ipAddress,
ipBanQuery->bindValue(":address", ipAddress);
ipBanQuery->bindValue(":address2", ipAddress);
if (!execSqlQuery(ipBanQuery)) {
- qDebug() << "IP ban check failed: SQL error." << ipBanQuery->lastError();
+ qCWarning(DatabaseInterfaceLog) << "IP ban check failed: SQL error." << ipBanQuery->lastError();
return false;
}
@@ -474,7 +473,7 @@ bool Servatrice_DatabaseInterface::checkUserIsIpBanned(const QString &ipAddress,
if ((secondsLeft > 0) || permanentBan) {
banReason = ipBanQuery->value(2).toString();
banSecondsRemaining = permanentBan ? 0 : secondsLeft;
- qDebug() << "User is banned by address" << ipAddress;
+ qCDebug(DatabaseInterfaceLog) << "User is banned by address" << ipAddress;
return true;
}
}
@@ -865,12 +864,17 @@ void Servatrice_DatabaseInterface::storeGameInformation(const QString &roomName,
const unsigned int size = static_cast(replayList[i]->ByteSize());
#endif
blob.resize(size);
- replayList[i]->SerializeToArray(blob.data(), size);
+ qulonglong replayId = replayList[i]->replay_id();
+ if (replayList[i]->SerializeToArray(blob.data(), size)) {
- replayIds.append(QVariant((qulonglong)replayList[i]->replay_id()));
- replayGameIds.append(gameInfo.game_id());
- replayDurations.append(replayList[i]->duration_seconds());
- replayBlobs.append(blob);
+ replayIds.append(QVariant(replayId));
+ replayGameIds.append(gameInfo.game_id());
+ replayDurations.append(replayList[i]->duration_seconds());
+ replayBlobs.append(blob);
+ } else {
+ qCWarning(DatabaseInterfaceLog)
+ << "failed to serialise replay, id:" << replayId << "game:" << gameInfo.game_id();
+ }
}
{
@@ -1017,7 +1021,7 @@ bool Servatrice_DatabaseInterface::changeUserPassword(const QString &user,
passwordQuery->bindValue(":name", user);
if (!execSqlQuery(passwordQuery)) {
- qDebug("Change password denied: SQL error");
+ qCWarning(DatabaseInterfaceLog) << "Change password denied: SQL error";
return false;
}
@@ -1084,7 +1088,7 @@ void Servatrice_DatabaseInterface::updateUsersLastLoginData(const QString &userN
QSqlQuery *query = prepareQuery("select id from {prefix}_users where name = :user_name");
query->bindValue(":user_name", userName);
if (!execSqlQuery(query)) {
- qDebug("Failed to locate user id when updating users last login data: SQL Error");
+ qCWarning(DatabaseInterfaceLog) << "Failed to locate user id when updating users last login data: SQL Error";
return;
}
@@ -1133,7 +1137,7 @@ QList Servatrice_DatabaseInterface::getUserBanHistory(const QStr
query->bindValue(":user_name", userName);
if (!execSqlQuery(query)) {
- qDebug("Failed to collect ban history information: SQL Error");
+ qCWarning(DatabaseInterfaceLog) << "Failed to collect ban history information: SQL Error";
return results;
}
@@ -1168,7 +1172,7 @@ bool Servatrice_DatabaseInterface::addWarning(const QString userName,
query->bindValue(":warn_reason", warningReason);
query->bindValue(":client_id", clientID);
if (!execSqlQuery(query)) {
- qDebug("Failed to collect create warning history information: SQL Error");
+ qCWarning(DatabaseInterfaceLog) << "Failed to collect create warning history information: SQL Error";
return false;
}
@@ -1189,7 +1193,7 @@ QList Servatrice_DatabaseInterface::getUserWarnHistory(const
query->bindValue(":user_id", userID);
if (!execSqlQuery(query)) {
- qDebug("Failed to collect warning history information: SQL Error");
+ qCWarning(DatabaseInterfaceLog) << "Failed to collect warning history information: SQL Error";
return results;
}
@@ -1296,7 +1300,7 @@ QList Servatrice_DatabaseInterface::getMessageLogHistory
}
if (!execSqlQuery(query)) {
- qDebug("Failed to collect log history information: SQL Error");
+ qCWarning(DatabaseInterfaceLog) << "Failed to collect log history information: SQL Error";
return results;
}
@@ -1324,7 +1328,8 @@ int Servatrice_DatabaseInterface::checkNumberOfUserAccounts(const QString &email
query->bindValue(":user_email", email);
if (!execSqlQuery(query)) {
- qDebug("Failed to identify the number of users accounts for users email address: SQL Error");
+ qCWarning(DatabaseInterfaceLog)
+ << "Failed to identify the number of users accounts for users email address: SQL Error";
return 0;
}
diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp
index 619d36d3a..41e61ddec 100644
--- a/servatrice/src/serversocketinterface.cpp
+++ b/servatrice/src/serversocketinterface.cpp
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -83,6 +84,10 @@
#include
#include
+inline Q_LOGGING_CATEGORY(AbstractServerSocketInterfaceLog, "abstract_server_socket_interface");
+inline Q_LOGGING_CATEGORY(TcpServerSocketInterfaceLog, "tcp_server_socket_interface");
+inline Q_LOGGING_CATEGORY(WebsocketServerSocketInterfaceLog, "websocket_server_socket_interface");
+
static const int protocolVersion = 14;
AbstractServerSocketInterface::AbstractServerSocketInterface(Servatrice *_server,
@@ -130,7 +135,7 @@ bool AbstractServerSocketInterface::initSession()
void AbstractServerSocketInterface::catchSocketError(QAbstractSocket::SocketError socketError)
{
- qDebug() << "Socket error:" << socketError;
+ qCWarning(AbstractServerSocketInterfaceLog) << "Socket error:" << socketError;
prepareDestroy();
}
@@ -1100,7 +1105,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdBanFromServer(const Com
clientIdQuery->bindValue(":client_id", nameFromStdString(cmd.clientid()));
sqlInterface->execSqlQuery(clientIdQuery);
if (!sqlInterface->execSqlQuery(clientIdQuery)) {
- qDebug("ClientID username ban lookup failed: SQL Error");
+ qCWarning(AbstractServerSocketInterfaceLog) << "ClientID username ban lookup failed: SQL Error";
} else {
while (clientIdQuery->next()) {
userName = clientIdQuery->value(0).toString();
@@ -1152,7 +1157,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
{
QString userName = nameFromStdString(cmd.user_name());
QString clientId = nameFromStdString(cmd.clientid());
- qDebug() << "Got register command for user:" << userName;
+ qCDebug(AbstractServerSocketInterfaceLog) << "Got register command for user:" << userName;
bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool();
if (!registrationEnabled) {
@@ -1289,7 +1294,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C
country, !requireEmailActivation);
if (regSucceeded) {
- qDebug() << "Accepted register command for user:" << userName;
+ qCDebug(AbstractServerSocketInterfaceLog) << "Accepted register command for user:" << userName;
if (requireEmailActivation) {
QSqlQuery *query =
sqlInterface->prepareQuery("insert into {prefix}_activation_emails (name) values(:name)");
@@ -1337,7 +1342,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdActivateAccount(const C
clientId = "UNKNOWN";
if (sqlInterface->activateUser(userName, token)) {
- qDebug() << "Accepted activation for user" << userName;
+ qCDebug(AbstractServerSocketInterfaceLog) << "Accepted activation for user" << userName;
if (servatrice->getEnableRegistrationAudit())
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
@@ -1345,7 +1350,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdActivateAccount(const C
return Response::RespActivationAccepted;
} else {
- qDebug() << "Failed activation for user" << userName;
+ qCDebug(AbstractServerSocketInterfaceLog) << "Failed activation for user" << userName;
if (servatrice->getEnableRegistrationAudit())
sqlInterface->addAuditRecord(userName.simplified(), this->getAddress(), clientId.simplified(),
@@ -1493,7 +1498,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordRequest(c
const QString userName = nameFromStdString(cmd.user_name());
const QString clientId = nameFromStdString(cmd.clientid());
- qDebug() << "Received reset password request from user:" << userName;
+ qCDebug(AbstractServerSocketInterfaceLog) << "Received reset password request from user:" << userName;
if (!servatrice->getEnableForgotPassword()) {
if (servatrice->getEnableForgotPasswordAudit())
@@ -1575,7 +1580,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdForgotPasswordReset(con
Q_UNUSED(rc);
QString userName = nameFromStdString(cmd.user_name());
QString clientId = nameFromStdString(cmd.clientid());
- qDebug() << "Received reset password reset from user:" << userName;
+ qCDebug(AbstractServerSocketInterfaceLog) << "Received reset password reset from user:" << userName;
if (!sqlInterface->doesForgotPasswordExist(userName)) {
if (servatrice->getEnableForgotPasswordAudit())
@@ -1626,7 +1631,7 @@ AbstractServerSocketInterface::cmdForgotPasswordChallenge(const Command_ForgotPa
const QString userName = nameFromStdString(cmd.user_name());
const QString clientId = nameFromStdString(cmd.clientid());
- qDebug() << "Received reset password challenge from user:" << userName;
+ qCDebug(AbstractServerSocketInterfaceLog) << "Received reset password challenge from user:" << userName;
if (!servatrice->getEnableForgotPasswordChallenge()) {
if (servatrice->getEnableForgotPasswordAudit()) {
@@ -1971,13 +1976,16 @@ void TcpServerSocketInterface::flushOutputQueue()
unsigned int size = static_cast(item.ByteSize());
#endif
buf.resize(size + 4);
- item.SerializeToArray(buf.data() + 4, size);
- buf.data()[3] = (unsigned char)size;
- buf.data()[2] = (unsigned char)(size >> 8);
- buf.data()[1] = (unsigned char)(size >> 16);
- buf.data()[0] = (unsigned char)(size >> 24);
- // In case socket->write() calls catchSocketError(), the mutex must not be locked during this call.
- writeToSocket(buf);
+ if (item.SerializeToArray(buf.data() + 4, size)) {
+ buf.data()[3] = (unsigned char)size;
+ buf.data()[2] = (unsigned char)(size >> 8);
+ buf.data()[1] = (unsigned char)(size >> 16);
+ buf.data()[0] = (unsigned char)(size >> 24);
+ // In case socket->write() calls catchSocketError(), the mutex must not be locked during this call.
+ writeToSocket(buf);
+ } else {
+ qCWarning(TcpServerSocketInterfaceLog) << "serialisation error!";
+ }
totalBytes += size + 4;
locker.relock();
@@ -2010,41 +2018,48 @@ void TcpServerSocketInterface::readClient()
return;
CommandContainer newCommandContainer;
+ bool ok;
try {
- newCommandContainer.ParseFromArray(inputBuffer.data(), messageLength);
+ ok = newCommandContainer.ParseFromArray(inputBuffer.data(), messageLength);
} catch (std::exception &e) {
- qDebug() << "Caught std::exception in" << __FILE__ << __LINE__ <<
+ qCWarning(TcpServerSocketInterfaceLog) << "Caught std::exception in" << __FILE__ << __LINE__ <<
#ifdef _MSC_VER // Visual Studio
- __FUNCTION__;
+ __FUNCTION__
#else
- __PRETTY_FUNCTION__;
+ __PRETTY_FUNCTION__
#endif
- qDebug() << "Exception:" << e.what();
- qDebug() << "Message coming from:" << getAddress();
- qDebug() << "Message length:" << messageLength;
- qDebug() << "Message content:" << inputBuffer.toHex();
+ << Qt::endl
+ << "Exception:" << e.what() << Qt::endl
+ << "Message coming from:" << getAddress() << Qt::endl
+ << "Message length:" << messageLength << Qt::endl
+ << "Message content:" << inputBuffer.toHex();
} catch (...) {
- qDebug() << "Unhandled exception in" << __FILE__ << __LINE__ <<
+ qCWarning(TcpServerSocketInterfaceLog) << "Unhandled exception in" << __FILE__ << __LINE__ <<
#ifdef _MSC_VER // Visual Studio
- __FUNCTION__;
+ __FUNCTION__
#else
- __PRETTY_FUNCTION__;
+ __PRETTY_FUNCTION__
#endif
- qDebug() << "Message coming from:" << getAddress();
+ << Qt::endl
+ << "Message coming from:" << getAddress();
}
-
inputBuffer.remove(0, messageLength);
messageInProgress = false;
- // dirty hack to make v13 client display the correct error message
- if (handshakeStarted)
- processCommandContainer(newCommandContainer);
- else if (!newCommandContainer.has_cmd_id()) {
- handshakeStarted = true;
- if (!initTcpSession())
- prepareDestroy();
+ if (ok) {
+ // dirty hack to make v13 client display the correct error message
+ if (handshakeStarted)
+ processCommandContainer(newCommandContainer);
+ else if (!newCommandContainer.has_cmd_id()) {
+ handshakeStarted = true;
+ if (!initTcpSession())
+ prepareDestroy();
+ }
+ // end of hack
+ } else {
+ qCWarning(TcpServerSocketInterfaceLog) << "parsing error!";
}
- // end of hack
+
} while (!inputBuffer.isEmpty());
}
@@ -2172,9 +2187,12 @@ void WebsocketServerSocketInterface::flushOutputQueue()
unsigned int size = static_cast(item.ByteSize());
#endif
buf.resize(size);
- item.SerializeToArray(buf.data(), size);
- // In case socket->write() calls catchSocketError(), the mutex must not be locked during this call.
- writeToSocket(buf);
+ if (item.SerializeToArray(buf.data(), size)) {
+ // In case socket->write() calls catchSocketError(), the mutex must not be locked during this call.
+ writeToSocket(buf);
+ } else {
+ qCWarning(TcpServerSocketInterfaceLog) << "serialisation error!";
+ }
totalBytes += size;
locker.relock();
@@ -2190,30 +2208,37 @@ void WebsocketServerSocketInterface::binaryMessageReceived(const QByteArray &mes
servatrice->incRxBytes(message.size());
CommandContainer newCommandContainer;
+ bool ok;
try {
- newCommandContainer.ParseFromArray(message.data(), message.size());
+ ok = newCommandContainer.ParseFromArray(message.data(), message.size());
} catch (std::exception &e) {
- qDebug() << "Caught std::exception in" << __FILE__ << __LINE__ <<
+ qCWarning(WebsocketServerSocketInterfaceLog) << "Caught std::exception in" << __FILE__ << __LINE__ <<
#ifdef _MSC_VER // Visual Studio
- __FUNCTION__;
+ __FUNCTION__
#else
- __PRETTY_FUNCTION__;
+ __PRETTY_FUNCTION__
#endif
- qDebug() << "Exception:" << e.what();
- qDebug() << "Message coming from:" << getAddress();
- qDebug() << "Message length:" << message.size();
- qDebug() << "Message content:" << message.toHex();
+ << Qt::endl
+ << "Exception:" << e.what() << Qt::endl
+ << "Message coming from:" << getAddress() << Qt::endl
+ << "Message length:" << message.size() << Qt::endl
+ << "Message content:" << message.toHex();
} catch (...) {
- qDebug() << "Unhandled exception in" << __FILE__ << __LINE__ <<
+ qCWarning(WebsocketServerSocketInterfaceLog) << "Unhandled exception in" << __FILE__ << __LINE__ <<
#ifdef _MSC_VER // Visual Studio
- __FUNCTION__;
+ __FUNCTION__
#else
- __PRETTY_FUNCTION__;
+ __PRETTY_FUNCTION__
#endif
- qDebug() << "Message coming from:" << getAddress();
+ << Qt::endl
+ << "Message coming from:" << getAddress();
}
- processCommandContainer(newCommandContainer);
+ if (ok) {
+ processCommandContainer(newCommandContainer);
+ } else {
+ qCWarning(WebsocketServerSocketInterfaceLog) << "parsing error!";
+ }
}
bool AbstractServerSocketInterface::isPasswordLongEnough(const int passwordLength)