Compare commits

..

559 Commits

Author SHA1 Message Date
RickyRister
b1fca404b7 Bump to 2.10.2 for hotfix release (#5785) 2025-04-03 00:24:11 -04:00
HypersonicWalrus
b6e6328e6a Modified setup_addfirstadmin script to bring it up to date to current cockatrice_users table (#5784)
Co-authored-by: Ben Boelens <bboelens@pop-os.tailc0350.ts.net>
2025-04-03 00:18:31 -04:00
tooomm
ecf0327378 Improve list of release binaries (#5783) 2025-04-03 00:17:44 -04:00
github-actions[bot]
787c551f5f Update translation source strings (#5781)
Co-authored-by: github-actions <github-actions@github.com>
2025-04-03 00:17:25 -04:00
RickyRister
d662152088 Change default log level to info (#5779)
* update qtlogging.ini

* bump some qCDebug to qCInfo and qCWarning
2025-04-03 00:17:10 -04:00
Basile Clement
2fcdb52157 fix: Use isRebalanced to detect Arena cards (#5778)
* fix: Use isRebalanced to detect Arena cards

In #5759 we introduced a setting (off by default) to disable the use of
Arena cards. This was done by checking the `isOnlineOnly` property of
the card, which accidentally also disabled online *printings* of cards
that otherwise exist in paper (e.g. Vintage Masters).

This PR does the same thing but uses the `isRebalanced` property
instead, which is `true` for Arena cards only and should have been used
from the start. This setting does not impact online-only printings such
as Vintage Masters. The settings is still on by default.

* Update setting to mention Alchemy rather than Arena
2025-04-03 00:16:38 -04:00
ZeldaZach
70f2a32fad Bump to 2.11.0 for beta releases 2025-03-27 21:34:03 -04:00
github-actions[bot]
37356317a4 Update translation files (#5775)
Co-authored-by: github-actions <github-actions@github.com>
2025-03-27 21:31:05 -04:00
RickyRister
08f3a56285 Fix crash when right click floating card info window (#5773) 2025-03-27 00:54:34 +00:00
RickyRister
5af71d1c2e Hardcode default log level for FlowWidget/FlowLayout (#5769) 2025-03-26 01:23:23 +00:00
Basile Clement
1ada5ea424 fix: Always prefer local cards if available (#5762)
* Try to better reproduce pre-provider ID behavior

If "override all card art with personal preference" setting is set, look
for custom art for all sets instead of just the most preferred set.

* Warning when using both custom art and the printing selector

* QDirIterator::nextFileInfo is Qt 6.3+

* Translation
2025-03-26 01:23:09 +00:00
transifex-integration[bot]
91ee6097d2 Translate oracle/oracle_en@source.ts in it (#5770)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'it'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-03-24 22:11:47 +00:00
Zach H
a4b0cddcf8 Revert "Disable CardMenu iff no items selected (#5376)" (#5768)
This reverts commit b4036c8671.
2025-03-23 19:04:24 -04:00
RickyRister
9bc6ae1567 Fix delete action in filters not working (#5765)
* Fix delete action in filters not working

* move filterRemove under slots
2025-03-23 12:03:56 -04:00
Basile Clement
c71685b261 Add option to disable card rounding (#5760)
* Add option to disable card rounding

* Effing mocks

* format

* Get rid of cardCornerRadius property
2025-03-22 01:07:52 -04:00
Basile Clement
0ae7d01234 Hide arena only cards (#5759)
* Add settings (default: true) to ignore online-only cards

* Use QAbstractButton::toggled

Also, fix dbconverter build

* Mocks mocks mocks

* Update dlg_manage_sets.cpp

* translations

* Update dlg_manage_sets.cpp

---------

Co-authored-by: Zach H <zahalpern+github@gmail.com>
2025-03-22 01:07:42 -04:00
RickyRister
345606846f Enable shortcuts for the remaining export deck actions (#5761) 2025-03-21 02:49:02 +00:00
RickyRister
9decf78d2d Fix typo in comment about accepted decklist file formats (#5754) 2025-03-21 00:31:38 +00:00
Basile Clement
a6f2e69e1a vds: Allow editing tags more than once (#5752)
`refreshTags` is not connecting the signal to open the dialog to edit
the tags, so tags can only be edited once for a given deck.

Fix by only having the logic for creating the "Edit tags" button once
and call it from `connectDeckList`.
2025-03-21 00:31:25 +00:00
Basile Clement
76fa87c63e Fix StackZone crash when divideCardSpaceInZone overflows (#5751)
The divideCardSpaceInZone function introduced in #4930 is buggy and
sometimes returns an index that is too large for the current zone, which
causes us to call `cards.at(index)` with an `index` that's bigger than
the amount of cards.

This is the bug that #5609 intended to fix but was improperly diagnosed.
Remove part of #5609 as the cases it is guarding against (e.g. null card
pointer) cannot actually happen.
2025-03-21 00:30:46 +00:00
RickyRister
2e01dfd23a Remember past entries in "reveal card until X" window (#5755) 2025-03-21 00:29:59 +00:00
RickyRister
99376e75d6 Support exporting to decklist.xyz website (#5756)
* Support exporting to decklist.xyz

* fix typo
2025-03-21 00:28:15 +00:00
Basile Clement
be28d50997 Revert "Use native hover events (#5722)" (#5757)
This reverts commit e4f40a82a2.

This change had unintended consequences in the hover behavior, reverting
for now.
2025-03-21 00:25:20 +00:00
Basile Clement
d03f5388d4 Update translations (#5758) 2025-03-21 00:23:26 +00:00
Zach H
48123c8822 Revert "Display visual feedback of where cards will go (#5737)" (#5750)
This reverts commit a7641a571f.
2025-03-19 01:53:35 +00:00
RickyRister
0fa744f6ec Consolidate accepted decklist file extensions (#5749)
* Consolidate accepted decklist file extensions

* rename the other const
2025-03-19 01:53:14 +00:00
RickyRister
42301d4f1a Filter out non-deck files when building VDS (#5748) 2025-03-18 22:22:36 +00:00
RickyRister
6c19254abd Fix AttachTo tokens not having card info (#5747) 2025-03-18 22:22:16 +00:00
RickyRister
b5c5d221c4 Remove redundant "show unused color identities" settings (#5745)
* move setting to vds settings menu

* emit signal on change

* rename setting
2025-03-18 22:21:28 +00:00
Basile Clement
c219d8bdbb hotfix: Remove menus when closing game (#5744)
Version of #5740 that doesn't leave freed `QMenu`s lying around.
2025-03-17 22:54:16 -04:00
Basile Clement
4812508afc DeckEditor: Initialize the modified flag (#5743)
C++ does not require compilers to zero-initialize value types, so
depending on the platform (here: Linux), the deck editor starts up with
an uninitialized value in the `modified` flag, which is usually not
zero.
2025-03-17 21:43:14 -04:00
RickyRister
57b9f0e54c Add CONFIGURE_DEPENDS to the cmake (#5739) 2025-03-17 02:43:11 +00:00
RickyRister
0d2061365c Fix edit deck in clipboard clearing values (#5732)
* Fix edit deck in clipboard clearing values

* fix build failures
2025-03-16 23:30:12 +00:00
RickyRister
4d8a124822 Rename save to clipboard actions in DeckPreviewWidget (#5738) 2025-03-16 23:19:57 +00:00
Basile Clement
a7641a571f Display visual feedback of where cards will go (#5737)
This is part of the code from #4974, including an improved drag-and-drop
API and its use to display visual feedback of card destination on the
board.

It does not include the improved logic for pushing cards around as I
still need to figure out edge cases there - the logic for choosing where
cards go is not changed, so some of the artifacts described in #4817
and #4975 (particularly around multi-card) are still present.
2025-03-16 23:19:39 +00:00
BruebachL
bd28e04635 Reintroduce unused color identity opacity (#5733)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-16 23:05:38 +00:00
Basile Clement
37382dea44 Close the TabGames when closing the TabSupervisor (#5735)
* Close the `TabGame`s when closing the `TabSupervisor`

This ensures that we go through the same code path (in terms of Qt
events) when closing the whole supervisor as when closing a single tab.
Also, use the `close` event instead of the `hide` event to detect when
we are closing a game.

Fixes #5697

* Compat with old Qt versions

* Old Qt, reloaded

* Review: use hideEvent and call super
2025-03-16 23:05:04 +00:00
Basile Clement
57a8960841 Add declaration for setAttrRecur (#5734) 2025-03-16 23:02:31 +00:00
RickyRister
6b4ae8308a Reduce tag display widget spacing (#5731)
* Reduce tag display widget spacing

* Reduce bottom margin in deck dock
2025-03-16 23:02:06 +00:00
Basile Clement
2739550087 Use enum for ThemeManager brushes (#5730)
* Use enum for ThemeManager brushes

This patch introduces an enum to distinguish the different brushes that
can be set by the theme (hand, stack, etc.) and generic functions taking
the enum rather than having one copy of each function for each brush.

This is preliminary work before merging StackZone and HandZone to
simplify #4974.

* Include <array> header

* Header spacing
2025-03-16 23:01:25 +00:00
Basile Clement
4ada011632 game: Automatic update of arrow position (#5729)
Currently, zones must keep track of which cards they move in order to
manually call `updatePath` on arrows.

This patch sets the `ItemSendsScenePositionChanges` flag on
`ArrowTarget`s to automatically update arrow positions without requiring
zones to keep track of that information.
2025-03-16 22:58:06 +00:00
RickyRister
c99afe7956 Optimize cipt parsing by early returning (#5727) 2025-03-15 21:23:41 +00:00
RickyRister
b58b85dc0f Re-add old names for mana value property to oracle (#5711) 2025-03-15 19:13:13 +00:00
BruebachL
a407c8b956 Reintroduce ability to display unused mana symbol widgets. (#5726)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-15 19:11:46 +00:00
Basile Clement
1851f71850 Remove revealedCard flag from CardItem (#5723)
It is no longer used since #5254.
2025-03-15 19:09:14 +00:00
Basile Clement
e4f40a82a2 Use native hover events (#5722)
* Use native hover events

* Update cockatrice/src/game/cards/abstract_card_item.cpp

* Reorder

---------

Co-authored-by: Zach H <zahalpern+github@gmail.com>
2025-03-15 19:07:51 +00:00
Basile Clement
b9900e67a6 nix: Add development utilities to shell.nix (#5725)
- Remove hardening flags to allow debug builds (otherwise GCC complains
   because nix adds the FORTIFY_SOURCE flag, which is not compatible
   with -O0)

 - Allow ninja as build system

 - Add clang-tools dependency for LSP support
2025-03-15 19:03:26 +00:00
RickyRister
7d558edb3e Fix banner and tags not resetting on blank new deck (#5721)
* Fix bannerWidget not resetting when opening new blank deck

* also reset tags
2025-03-15 18:44:51 +00:00
RickyRister
eb4b1c2a07 Fix extra .cod in "save deck as" default name (#5720) 2025-03-15 18:44:03 +00:00
RickyRister
087f88146d Make internal updater failure message more user-friendly (#5718) 2025-03-15 05:19:07 +00:00
RickyRister
3a11ccb854 Update cipt parsing (#5712)
* refactor

* move thing out

* write unit tests

* get thing to work

* optimization?

* fix build failure
2025-03-14 21:44:13 -04:00
tooomm
068465143b Update CONTRIBUTING file (#5701)
* Update CONTRIBUTING.md

* cleanup

* Update CONTRIBUTING.md
2025-03-14 21:43:43 -04:00
tooomm
1f0846297f websocket is our default port/connection (#5679) 2025-03-14 21:43:11 -04:00
RickyRister
4a0e0ed954 Automatically find all files for cockatrice_SOURCES (#5716)
* Use GLOB_RECURSIVE to find all source files

* fix code style

---------

Co-authored-by: Zach H <zahalpern+github@gmail.com>
2025-03-14 21:42:56 -04:00
RickyRister
4b7d1ebb59 Refactor: split card_database into two files (#5715)
* make the duplicate

* restore original

* Refactor: split card_database into two files
2025-03-14 00:02:10 +00:00
RickyRister
ec536126b9 Compute deck hashes lazily (#5707)
* Calculate deck hashes lazily

* rename
2025-03-11 21:43:21 -04:00
Zach H
9b00bdcaea Merge pull request #5710 from lilyhuang-github/i18n
Change prebuild.js to allow i18n-default.json indentation to exist
2025-03-11 21:00:53 -04:00
Lily
da17c68830 Change prebuild.js to allow i18n-default.json indentation to exist 2025-03-11 19:59:20 -04:00
Zach H
badfb483b2 Merge pull request #5703 from RickyRister/5699-fix-printing
Show correct printing for top card of library
2025-03-10 20:45:05 -04:00
Zach H
fafe636b7c Merge pull request #5702 from RickyRister/rename-export-actions
Rename some save to clipboard actions
2025-03-10 20:44:33 -04:00
RickyRister
ef15aa2dcd Show correct printing for top card of library 2025-03-09 05:40:03 -07:00
RickyRister
2d44c9ad2f Rename some save to clipboard actions 2025-03-08 20:02:32 -08:00
RickyRister
0a1d0f650f Enable shortcuts for new save to clipboard actions (#5700)
* Enable shortcuts for new save to clipboard actions

* rename shortcut
2025-03-08 22:41:58 -05:00
RickyRister
2ba7c1ff9a Fix incorrect deck modified state (#5698) 2025-03-08 02:16:59 +00:00
RickyRister
0ecf6298a3 Add actions for shuffle top/bottom X cards (#5695)
* Add actions for shuffle top/bottom X cards

* fix typo

* move shuffle actions into existing menus
2025-03-08 01:48:48 +00:00
RickyRister
1d11bb19b8 Fix view bottom cards using the wrong default (#5696) 2025-03-07 16:17:40 -05:00
RickyRister
ff7f31ca33 add "Set Banner Card" action to VDS right-click menu (#5692) 2025-03-05 21:05:34 -05:00
RickyRister
6bb9ae92bf Update recently opened decks regardless of where the deck is opened from (#5691) 2025-03-05 21:04:53 -05:00
ZeldaZach
5238087ddf Parent bannerCardLabel to avoid popups 2025-03-04 22:45:53 -05:00
RickyRister
08bb18cefe Fix VDS filters not applying after refresh (#5662)
* reapply sort and filters after each reset

* fix unflatten folder still not applying afterwards
2025-03-05 00:57:28 +00:00
RickyRister
ecbdd32a2d Reduce redundant recursion in VDS (#5664)
* remove recursion from flattenFolderStructure

findChildren is already recursive by default

* only trigger the top-level updateVisibility on filter update

Every folder widget was connecting the filter update signals to their updateVisibility, but updateVisibility is already recursive.
That means a bunch of redundant updateVisibility calls happen every time a filter update signal is emitted

* reduce redundant recursion in updateVisibility

findChildren is recursive by default, so only the top-level updateVisibility needs to loop through the found children

* delete now-unused signals
2025-03-05 00:56:31 +00:00
RickyRister
2f415dcc6e Add action to Edit Deck via Clipboard (#5681)
* implement functionality in dlg

* add action to deck editor

* refactor and comments

* is this refactor even a good idea?

* remove the friend class stuff

* reorder

* add option for not annotated
2025-03-05 00:55:05 +00:00
BruebachL
8fc1b22889 Use the new mana symbols. (#5687)
* Use the new mana symbols.

* Fixup some thangs.

* Lint.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-05 00:53:42 +00:00
BruebachL
85a50ce9d5 Generic mana symbols. (#5685)
* Generic mana symbols.

* Update black mana symbol skull and symbol color.

* Update white mana symbol contrast.

* Update black mana symbol contrast.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-03 13:12:09 -05:00
BruebachL
b706e26a32 Fix image quality when fractional scaling is applied. (#5684)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-03 08:40:12 -05:00
BruebachL
15725c67c7 Fix banner widget buddy being uninitialized. (#5686)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-03 08:38:27 -05:00
RickyRister
d8da4473e2 add rename and delete actions to VDS right-click menu (#5683) 2025-03-03 08:35:50 -05:00
RickyRister
e1964f21de Fix memory leaks from DeckLoader usage (#5665)
* add comment

* stack allocate DeckLoader for loading tags

* deckModel now takes ownership of DeckLoader

* fix remaining

* add comment
2025-03-02 18:57:30 -05:00
RickyRister
87c5d07807 Switch current tab when opening a single-instance tab (#5651) 2025-03-02 09:30:55 -05:00
lilyhuang-github
3d0f4868df Focus tab for quit game dialog (#5670) 2025-03-02 09:29:17 -05:00
BruebachL
56bd11794e Set modification state correctly. (#5678)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-02 09:28:16 -05:00
BruebachL
e541b9d572 Silence picture loader warnings for null pixmaps by introducing checks. (#5677)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-02 09:27:52 -05:00
RickyRister
a7e8c1f59b Make BannerWidget's dropdown icon more robust (#5676)
* Make BannerWidget's dropdown icon more robust

* use isHidden

Otherwise, it doesn't work correctly if the BannerWidget is offscreen

* don't show icon if there's no buddy
2025-03-02 09:26:03 -05:00
BruebachL
ec452aabe2 Fallback to regular card name search in case the providerId one fails for the database display widget. (#5673)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-03-01 09:22:00 -05:00
RickyRister
2a9599eed8 refactor saveDeckToClipboard in AbstractTabDeckEditor (#5671)
* refactor saveDeckToClipboard in AbstractTabDeckEditor

* make deckloader functions const

* use const

* move method into DeckLoader
2025-03-01 09:21:31 -05:00
RickyRister
58a2b7ff39 Fix move to top of library shuffling an extra card (#5672)
* Fix move to top of library shuffling an extra card

* Update cockatrice/src/game/player/player.cpp

---------

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2025-03-01 13:32:07 +01:00
RickyRister
448903efe3 Add tip of the day for Expand Card View Window (#5666) 2025-02-28 11:29:09 -05:00
BruebachL
d76e8f9146 Clamp all DeckPreviewWidget children to the card size on resize. (#5669)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-28 11:10:40 -05:00
BruebachL
3620664a9f Cache correct providerId cards on deck load (#5668)
* Implement new method for DeckList to return cardlist with providerId, a new carddatabase method to fetch a cardlist with name and providerId and changed PictureLoader to use providerId versions of cards for caching.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-28 11:10:06 -05:00
lilyhuang-github
7ff43f15fc Add hint on version downloading (#5663) 2025-02-27 23:34:32 -05:00
lilyhuang-github
e271e6ecf8 Implement advertisement to FAQ page align right (#5657) 2025-02-27 23:34:06 -05:00
BruebachL
93d28717e0 Abstract deck editor (#5646)
* Generify TabDeckEditor.

* Connect dockTopLevelChanged signals.

* Connect eventFilters.

* Remove comments.

* Fix ze build (accidentally deleted a line)

* Fix some pointer chaining.

* Be a lot saner about some signals/slots, as in, individual Deck Editor widgets now internally determine their CardInfo and then simply communicate this to the DeckEditor

* Lint.

* DeckDock can handle its own menu.

* DeckDock can handle its own decrement.

* DeckDock now notifies the deck editor on deck change, instead of individually modifying menu items and modification status.

* Rename.

* Include pixelmap generator for icon.

* Directly use an AbstractTabDeckEditor as parent.

* Move clearing database filter into signal/slot relation.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-27 10:57:58 -05:00
RickyRister
6df97a156f Change "include folder name in VDS search" into a setting (#5659)
* add new setting

* implement thing
2025-02-26 12:01:30 -05:00
BruebachL
05d06f9016 Sort Tags in TagFilterWidget (#5660)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-26 11:59:59 -05:00
RickyRister
e8574641b0 use new rename icon in replays tab (#5658) 2025-02-26 00:14:27 -05:00
RickyRister
9ac13018c6 include folder name in VDS search when folders are enabled (#5637) 2025-02-25 18:39:34 -05:00
RickyRister
06b25f1cfc add "edit tags" to VDS right-click menu (#5631)
* refactor: move openTagEditDlg up a level

* add edit tags to menu

* set DeleteOnClose attribute on menu

* fix build failure
2025-02-25 18:38:55 -05:00
RickyRister
6f5d369416 Add folder dropdown icons to VDS (#5632)
* add svg

* update pixmap cache

* get icon to work

* hide icon when not clickable

* use consistent naming

* use expandOnly because apparently that leads to higher image quality
2025-02-25 18:36:48 -05:00
RickyRister
4543038fd8 add "open in deck editor" to VDS right-click menu (#5634) 2025-02-25 18:35:56 -05:00
RickyRister
345f8b772c show error message when open deck fails in VDS (#5642) 2025-02-25 18:33:16 -05:00
RickyRister
47311b1dfd Expand/shrink card view window on double click (#5652) 2025-02-25 18:32:45 -05:00
RickyRister
21e22ed5fb Destroy VDS in game lobby once game starts (#5643)
* push back setting change

* rename method and make it public

* destroy vds on game start
2025-02-25 18:31:44 -05:00
RickyRister
0d6497fcdc Fix banner card changing when opening deck in new tab (#5649) 2025-02-25 18:30:53 -05:00
RickyRister
bfaeeb5aea fix transform from non-table zones not moving card (#5648) 2025-02-25 18:30:38 -05:00
RickyRister
b46667f6db Fix memory leak when refreshing VDS (#5647)
* parent deckLoader

* leave comment
2025-02-25 18:30:20 -05:00
RickyRister
49932ee6f8 Fix segfault when oracle reads card without "num" field (#5654) 2025-02-25 18:29:43 -05:00
RickyRister
57e37e8f4d Allow loading local xml file in oracle (#5655) 2025-02-25 18:29:27 -05:00
RickyRister
af68a95964 Add rename action to deck storage tab (#5656)
* add icon

* add rename action
2025-02-25 18:29:07 -05:00
RickyRister
959a268f91 Mark deck as modified when banner card is changed (#5641)
* Mark deck as modified when banner card is changed

* set modified inside setBannerCard
2025-02-22 13:56:48 +00:00
RickyRister
77a3515470 Always download macOS 13 version on intel macs (#5630)
* Always download macOS 13 version for intel macs

* use contains instead of regex
2025-02-18 22:27:17 +00:00
BruebachL
6a008acb2b Enhance card update error description. (#5638)
* Enhance card update error description.

* Enhance card update error description.

* Lint.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-18 22:20:06 +00:00
RickyRister
247e1aff83 Also parse "colors" field in xml (#5635) 2025-02-18 20:04:59 +00:00
RickyRister
3df4efebaa Revert file watcher in VDS (#5636) 2025-02-18 20:04:37 +00:00
RickyRister
5c8d1f3cff Make AttachTo tokens work from non-table zones (#5629)
* move card to play before creating attached token

* leave comment

* hardcode createCard target zone to table

To get attached token from graveyard/exile to work
2025-02-16 17:02:45 -05:00
Zach H
01d5e58a5f Change Sorting Order of User List (#5626)
* 1) Online Users > Offline Users
* 2) Admins, judge/vip/donator status ignored
* 3) Moderators, judge/vip/donator status ignored
* 4) Judges
* 5) VIPs
* 6) Donators
* 7) Everyone else
2025-02-16 04:35:28 +00:00
RickyRister
a28300ac42 add "save deck to clipboard" to VDS right click menu (#5625) 2025-02-16 04:18:47 +00:00
RickyRister
0666483756 refactor saveDeckToClipboard in TabDeckEditor (#5623) 2025-02-16 02:43:44 +00:00
RickyRister
abca5514af support right-click menu in VDS (#5622)
* support right-click menu in VDS

* move methods around
2025-02-16 02:43:20 +00:00
RickyRister
2247c66ea6 refactor how double click signal gets passed up in VDS (#5621) 2025-02-15 19:06:11 -05:00
RickyRister
3b638598ad fix load remote deck window being empty (#5613) 2025-02-15 21:05:33 +00:00
RickyRister
63e3e3ceb1 refactor and add missing log categories to ReleaseChannel (#5615)
* adding missing log categories

* refactor version lookup

* refactor OS checking code
2025-02-15 21:05:12 +00:00
BruebachL
23f4c9c4e4 Tags in deck editor (#5608) 2025-02-12 03:18:00 +00:00
Zach H
356b00e8c7 Fix Ricky Crash (#5609) 2025-02-12 01:39:41 +00:00
RickyRister
8916e049bd fix printing selector dropdown not working on mac (#5606) 2025-02-11 04:42:31 +00:00
ZeldaZach
287b4a5597 Bump to 2.10.1 2025-02-10 23:26:35 -05:00
RickyRister
d77ee00e70 Fix crash when VDS show tags is unchecked (#5605)
* Fix crash when VDS show tags is unchecked

* revert the refactor since I don't know if there's a reason they did it that way
2025-02-11 04:24:08 +00:00
ZeldaZach
18ac4c2bd4 Set Release Name: Omenpath 2025-02-10 16:41:18 -05:00
Zach H
2dc614c6b7 Add new Tips of the Day (#5603)
- Thanks WargiCorgi!
2025-02-10 21:22:26 +00:00
BruebachL
7c9bf75393 Overhaul quick settings for VDS and PrintingSelector (#5602)
* Move show folders option next to the search bar.

* Add a new settings button and settings popup, move the folder visibility checkbox there and the ability to hide tags.

* Make popup not close when interacting with child widgets.

* Fix mocks.

* Include cog icon.

* Move PrintingSelector Display options to new quick settings widget.

* Adjust size before first show so as to not overflow.

* Add option to hide card size slider in VDS.

* Qt5 support.

* Fix some warnings by containerizing layouts because addChildLayout is silly.

* Fix an incorrect slot/signal assignment.

* Correct sub-categories for settings to persist them.

* Shuffle some slots and signals around to distinguish between the tag filter and the tags on the deck preview widgets.

* Add a quick setting to draw unused color identities and center them.

* Respect the setting on startup.

* Move card size slider to the quick settings menu.

* Move PrintingSelector card size slider to quick menu, adjust other layout from other options.

* Improve layout, add a gray border.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-10 16:50:08 +00:00
transifex-integration[bot]
d1102939a2 Translate cockatrice_en@source.ts in pt_BR (#5601)
100% translated source file: 'cockatrice_en@source.ts'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-02-09 22:12:38 +00:00
Zach H
cb060f43b5 Prevent server crash if DB is down and game is attempted to be created (#5600) 2025-02-09 22:11:00 +00:00
transifex-integration[bot]
80bd783d54 Updates for project Cockatrice and language de (#5595)
* Translate cockatrice/cockatrice_en@source.ts in de

100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'de'.

* Translate cockatrice/cockatrice_en@source.ts in de

100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'de'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-02-09 19:16:27 +01:00
tooomm
82b147d235 uniform artifact naming (#5592) 2025-02-09 12:40:07 +00:00
Zach H
6944f5f81c Put Logging config on MacOS (#5591) 2025-02-09 12:39:09 +00:00
danbopes
8cbfe85ed4 Fix db reconnecting issues (#5590)
See:

c1b0d50237 (diff-02a32f437187bd4cbfab74877100fee0cfc669dab2c05418681a3557c2cf73f2R109)

We should be checking to see if the query is notActive. In this case, we're literally closing and reopening the connection to the database every time `checkSql()` is called, which is called in numerous places.
2025-02-09 12:12:16 +00:00
Zach H
eb2c71d381 Fix MacOS Finding releases (#5589) 2025-02-09 02:26:04 -05:00
RickyRister
86161185d9 Use local-aware compare in VDS file name sort (#5588) 2025-02-09 04:38:48 +00:00
RickyRister
79bf3adb2a Re-sort decks in VDS after toggling show folders (#5587) 2025-02-09 04:38:22 +00:00
Zach H
07ca243d48 Update QT_LOGGING_CONF if not set (#5578) 2025-02-08 16:10:45 +00:00
Zach H
edaca772c5 Support logging config on install (#5577)
* Support logging config on install

* Support logging config on install
2025-02-08 16:10:37 +00:00
ZeldaZach
b30b72b7c3 Fix building & logging out 2025-02-07 14:19:53 -05:00
RickyRister
57eab3d48a turn off flow_widget logger (#5576) 2025-02-07 15:36:41 +00:00
RickyRister
2c6e7d4d3a Add option to hide folder structure in Visual Deck Storage (#5575) 2025-02-07 15:36:24 +00:00
RickyRister
9ec621a1ae fix wrong size flag bounding rect on linux (#5573)
* fix flag bounding box on linux

* use the non-deprecated macro
2025-02-07 06:21:56 +00:00
RickyRister
23223e10b5 actually delete VDS when hiding it in game lobby (#5572) 2025-02-07 05:20:42 +00:00
github-actions[bot]
94129607e5 Update translation source strings (#5571)
Co-authored-by: github-actions <github-actions@github.com>
2025-02-07 04:59:23 +00:00
RickyRister
d951b082c4 Add setting to hide visual deck storage in game lobby (#5570) 2025-02-06 13:44:33 +00:00
RickyRister
1ee0e87ba7 remove debug log that was accidentally left in (#5569) 2025-02-06 13:43:37 +00:00
Zach H
67091fff9c Fixup custom theme image loading (#5568) 2025-02-06 13:40:10 +00:00
Zach H
9b4f51d1e4 Increase Icon Size in User Lists (#5567) 2025-02-06 05:51:19 +00:00
Zach H
a6649d5401 Add Judge Pawns (+ Resize Donator Pawns) (#5566) 2025-02-06 05:51:01 +00:00
RickyRister
b509eed3e0 support shortcuts for tab menu actions (#5564)
* support shortcuts for tab menu actions

* refactor

* add migration
2025-02-06 04:00:43 +00:00
RickyRister
12ae7a9eeb Ignore unknown shortcut names in settings (#5565) 2025-02-06 04:00:31 +00:00
fluidvanadium
e6e3333673 Deck limit (#5559)
* increased MAX_FILE_LENGTH

* set MAX_FILE_LENGTH to about 2 megabytes
2025-02-04 22:22:15 +00:00
RickyRister
218ed726b6 Fix wrong position and scaling of svg pixmaps when zoomed out (#5563)
* fix scaling for player icon profile pic

* fix scaling for other svgs
2025-02-04 22:22:05 +00:00
RickyRister
0503fe589c fix playericon missing in local games (#5562) 2025-02-04 05:53:52 +00:00
Zach H
e599c6bdac Mods/Admins/PrivLevels not subject to server idle timeout policy (#5561) 2025-02-04 05:20:20 +00:00
Zach H
c2292c11a6 Support Purple Heart for Donators (#5560) 2025-02-04 05:06:05 +00:00
RickyRister
ec9feb9f50 fix wrong size flag bounding rect on windows (#5556)
* fix wrong size flag bounding rect on windows

* fix the values
2025-02-03 05:43:58 +00:00
RickyRister
9680e47bbc Deprecate userlevels icons (#5555)
* map old info to colors

* move caching up a level

* delete userlevels folder

* remove default vip color
2025-02-03 05:43:48 +00:00
RickyRister
f782bd709a preserve image quality when scaling svg (#5554)
* preserve image quality when scaling svg

* fix missing colorless counter

* do it in a way that doesn't cause warnings to be logged
2025-02-03 02:50:21 +00:00
RickyRister
c00b41f3bd add logging category for remote_client (#5553)
* add logging category for remote_client

* remove ifdef QT_DEBUG
2025-02-03 01:57:34 +00:00
BruebachL
94e2d64e55 Update sort order on VDS load. (#5552)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-02 20:16:38 +00:00
Zach H
4535a70b57 Define qtlogging.ini location (#5551) 2025-02-02 19:27:14 +00:00
BruebachL
6c1b7c83ec Debounce writing the setting to cache when adjusting card sizes. (#5550)
* Debounce writing the setting to cache when adjusting card sizes.

* Lint.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-02 18:45:26 +00:00
Zach H
f0adafb275 Reconnect Servatrice if DB Connection Dies (#5548) 2025-02-02 18:25:01 +00:00
BruebachL
9dd60d74d1 Hotfix VDS sizing scrollArea widget incorrectly when created while not visible by setting size in showEvent (#5547)
* Only resize on folder widget to make sure it doesn't squish the loading indicator.

* Clamp scrollArea widget to viewport width on showEvent to prevent widget being instantiated with wrong width when not visible.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-02-02 17:36:56 +00:00
RickyRister
1de09deb59 Fix size and image quality issues with new user icons (#5546) 2025-02-02 15:08:23 +00:00
BruebachL
a0b52ce450 Implement folder support for VDS. (#5545) 2025-02-02 15:08:04 +00:00
RickyRister
95cea0f191 Add custom server-side pawn colors (#5543) 2025-02-02 03:25:25 +00:00
RickyRister
0fc05e15cd pass ServerInfo_User down the chain (#5542) 2025-02-02 01:04:49 +00:00
RickyRister
26c0cdc072 Make settings window scrollable (#5539) 2025-02-01 05:03:30 +00:00
RickyRister
b1b48d50f3 move deck conversion settings into deck settings group (#5538) 2025-02-01 04:32:12 +00:00
Zach H
349c18aa6a Fix Crash with "c:" in deck editor (#5537) 2025-02-01 04:32:01 +00:00
Zach H
b956fd4bac Fix windows deck searching (#5536) 2025-02-01 04:13:46 +00:00
RickyRister
34e0130b90 fix view transform button disappearing on click (#5535) 2025-02-01 03:31:09 +00:00
BruebachL
33d8edeb9a Get file format from name. (#5532)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-27 19:41:29 -05:00
RickyRister
5d1e905255 remove refreshTree call in remote model's constructors (#5533) 2025-01-27 19:40:59 -05:00
RickyRister
51c542aa04 Disable add to deck submenu if no deck editor tabs are open (#5530)
* refactor

* just have the deck name

* clean up submenu parenting

* disable add to deck menu if no deck editor tabs are open
2025-01-26 10:24:09 -05:00
BruebachL
4d791f4d7a Edhrec tab (#5512)
---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: Zach H <zahalpern+github@gmail.com>
2025-01-25 22:29:27 +00:00
RickyRister
aee68f8b00 add missing override and explicit specifiers in common (#5527) 2025-01-25 14:06:03 +00:00
RickyRister
b911ea6e28 add missing override and explicit specifiers in src/server (#5526) 2025-01-25 14:05:25 +00:00
RickyRister
a41e7c75c1 add missing override and explicit specifiers in src/deck and src/utility (#5525)
* add missing override and explicit specifiers in src/deck

* add missing override and explicit specifiers in src/utility
2025-01-25 14:05:00 +00:00
RickyRister
9f729bf636 add missing override and explicit specifiers in src/dialogs (#5524) 2025-01-25 14:04:26 +00:00
RickyRister
42e4c14a82 add missing override and explicit specifiers in src/client (#5523) 2025-01-25 14:03:54 +00:00
Zach H
37a0c00b3f Support right-click on game list menu (#5522) 2025-01-25 14:03:29 +00:00
Zach H
f6c31bf901 Invert "Show" games, so all games are visible by default (#5521) 2025-01-25 07:03:36 +00:00
Zach H
b48fe8b99c Better capitalization & Deck open first (#5520) 2025-01-25 05:45:44 +00:00
RickyRister
19b758591b Allow offline Replays tab (#5519) 2025-01-25 05:44:48 +00:00
Zach H
ec6a23de56 Support more indices (#5505)
* Support more indices

* Support more indices
2025-01-25 04:16:41 +00:00
BruebachL
ce416df3fb Add a dialog to prompt user to convert to .cod format if trying to apply tags to a .txt deck. (#5514)
* Add a dialog to prompt user to convert to .cod format if trying to apply tags to a .txt deck.

* Lint mocks.

* Address comments, move dialog to appropriate folder.

* Unlint.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-25 03:20:30 +00:00
BruebachL
4e96157091 Flow Layout fixes (#5515)
* Flow Layout fixes.

* Remove some comments.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-25 03:17:39 +00:00
RickyRister
f428148f64 Allow offline Deck Storage tab (#5518)
* make deck storage tab no longer close on disconnect

* add method for clearing remote decklist model

* handle connect/disconnect in deck storage tab
2025-01-25 03:16:40 +00:00
RickyRister
e8b1e3ef0c don't autoclose card view if single card gets dragged into same zone (#5517)
* rename canResize param to toNewZone

* pass toNewZone down

* don't autoclose card view if card gets dragged into same zone
2025-01-25 02:08:28 +00:00
RickyRister
085f0dd26c reduce unnecessary CardItem creation in ViewZone addCard process (#5513) 2025-01-24 05:13:08 +00:00
BruebachL
1d2ab8d3d3 Convert lastLoaded timestamp into proper QDateTime for correct comparison. (#5506)
* Convert lastLoaded timestamp into proper QDateTime for correct comparison.

* Reintroduce null check.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-22 12:58:19 +00:00
RickyRister
66e2e7a473 add missing override and explicit specifiers to all classes in src/game (#5511) 2025-01-22 12:57:56 +00:00
RickyRister
af161f00b7 Remove spacing in CardInfoWidget caused by invisible view transformation button (#5510) 2025-01-22 12:55:21 +00:00
RickyRister
420cca2402 fix after merge to use ZoneView::close (#5509) 2025-01-20 22:43:05 -05:00
RickyRister
97fdf11c8f Add setting to auto close card view when empty (#5502) 2025-01-21 03:08:01 +00:00
RickyRister
aeb1b9fb4f Fix segfault when game is closed while card view window is open (#5507) 2025-01-21 03:06:55 +00:00
RickyRister
b004e91aa4 fix segfault when bottoming card in deck view (#5508) 2025-01-21 03:06:00 +00:00
Zach H
090cc8c144 Support more indices (#5503) 2025-01-20 01:42:24 -05:00
tooomm
0467fae51b Add label to swap button (#5501) 2025-01-19 17:26:25 +00:00
BruebachL
aa24502129 Move logging from QDebug to QCDebug and introduce LoggingCategories. (#5491)
* Move logging from QDebug to QCDebug and introduce LoggingCategories.

* Lint.

* Unlint like one change.

* Remove .debug category since this is autofilled by Qt and used to differentiate between QCDebug and QCWarning and QCError.

* Uncomment defaults, include main category.

* Make PictureLoader logging a bit more useful.

* Lint...?

* Address comments.

* Clean up some unnecessary classes in logging statements.

* Add a new message format to the logging handler.

* Lint.

* Lint.

* Support Windows in Regex

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2025-01-19 13:14:23 +00:00
BruebachL
e752578d15 Add a button to easily view the transformed version of a card. (#5498)
* Add a button to easily view the transformed version of a card.

* Minor reword

* Minor fix

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2025-01-19 12:59:53 +00:00
BruebachL
724db755af Hide load from remote button in local games (#5499)
* Hide load from remote button in local games.

* Minor fix

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2025-01-19 12:59:33 +00:00
BruebachL
ec0caaf421 Give deckList a signal to emit when the tags change and hook up the display widget to that. (#5497)
* Give deckList a signal to emit when the tags change and hook up the display widget to that.

* Reload from file when loading a visual deck to ensure latest changes propagate to the decklist.

* Eliminate loadVisualDeck and use loadDeckFromFile instead.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-19 12:32:39 +00:00
Zach H
55b490ade0 Generate PDBs for Windows Builds (#5494) 2025-01-18 07:54:01 +00:00
ZeldaZach
1392bdd258 Fix Windows 7 Crash Dump 2025-01-18 00:33:30 -05:00
Zach H
648c96ac3d Allow Moderators to Grant Replay & Activate in TabAdmin (#5492) 2025-01-18 02:23:24 +00:00
Zach H
d3a1538af3 Fix Windows Crash Reporter (#5493)
* Fix Windows Crash Reporter

* Fix NSIS template
2025-01-18 02:23:05 +00:00
RickyRister
2bc71095dd get UserListProxy from TabSupervisor instead of passing it in the constructor (#5490) 2025-01-17 15:27:52 +00:00
RickyRister
92a903b035 fix chat messages not showing in the client (#5489) 2025-01-17 03:11:13 -05:00
transifex-integration[bot]
cd373edf3d Translate cockatrice_en@source.ts in pt_BR (#5487)
100% translated source file: 'cockatrice_en@source.ts'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-17 07:41:59 +00:00
RickyRister
ca2d438cda fix sideboard not being re-locked on load deck (#5486) 2025-01-17 05:25:01 +00:00
RickyRister
c148c8df7f replace foreach macro with standard for each loop (#5485) 2025-01-17 05:18:15 +00:00
Zach H
0cbad25385 General Cleanup of Unused Assets (#5484) 2025-01-17 05:08:53 +00:00
ZeldaZach
7b94d5d501 Better sanitization of pointers 2025-01-17 00:05:08 -05:00
RickyRister
ee938342f3 Change visible buttons in game lobby depending on if deck is loaded (#5480)
* rename method

* delete unused method

* refactor

* increase margins

* change visible buttons depending on if deck is loaded

* correctly send the ReadyStart command on unload

* fix force start button still being visible
2025-01-17 04:52:33 +00:00
Zach H
cb64a5eea0 Populate TabAccount if reopened (#5483) 2025-01-17 04:28:18 +00:00
BruebachL
80165c28a9 Add options to include/exclude set name and collector number during clipboard import/export. (#5482)
* Add options to include/exclude set name and collector number during clipboard import/export.

* Missing parentheses in action label.

* Revert the silliest lint in the world.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-17 02:38:01 +00:00
ZeldaZach
315c224f24 Fix crash on add/edit tags 2025-01-16 00:54:34 -05:00
ZeldaZach
55f624b634 Hide Loading Msg in VDE when not relevant 2025-01-16 00:06:25 -05:00
ZeldaZach
82b257b589 Fix index 0 tab not functioning 2025-01-15 23:55:51 -05:00
RickyRister
a51ca9f9cb fix incorrect values in deck editor tab's views menu on init (#5479) 2025-01-16 04:06:56 +00:00
RickyRister
7e19b52926 fix tab-specific menus not present when tab is opened on startup (#5478) 2025-01-16 04:04:15 +00:00
RickyRister
2d02955f8b delete overloaded signal in PendingCommand (#5477)
* remove overloaded signal since no one was using it

* remove usages of qOverload

* turns out new slot/signal syntax can ignore extra params
2025-01-15 13:16:06 +00:00
RickyRister
3a740f0bde group printings together when sorting in card reveal window (#5476) 2025-01-15 13:14:47 +00:00
RickyRister
455d68f9ea Move UserlistProxy to src/server/user and fix capitalization (#5475)
* move file

* fix capitalization
2025-01-15 13:14:16 +00:00
RickyRister
2def02e140 Remember which tabs are open between sessions (#5467) 2025-01-15 06:10:24 +00:00
RickyRister
23bd18a04c fix segfault that happens when account tab is closed (#5474) 2025-01-15 06:10:03 +00:00
RickyRister
d09b9eb533 Rename UserList class to UserListWidget (#5473) 2025-01-15 03:07:36 +00:00
github-actions[bot]
25caae6d0f Update translation files (#5472)
Co-authored-by: github-actions <github-actions@github.com>
2025-01-14 20:28:36 -05:00
BruebachL
a717e715b6 Introduce null checks, add setShortName and collectorNumber to deckList export. (#5471)
* Introduce null checks, add setShortName and collectorNumber to deckList export.

* Lint.

* Lint again.

* Lint AGAIN.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-14 10:54:15 -05:00
BruebachL
c079715c46 Properly check if a duplicate already exists in the list, no longer break loop. (#5470)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-14 10:12:53 -05:00
BruebachL
f6c1253e84 Add a placeholder label to indicate database is still loading. (#5469)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-14 14:19:32 +00:00
BruebachL
8462b6e906 Minor fix to sorted list reconstruction to fix duplication of cards in printing selector. (#5468)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-14 13:59:53 +00:00
RickyRister
cca82f59eb Don't re-sort VisualDeckStorage every time it gets tabbed to (#5466)
* remove showEvent

* refresh cards on init

* fix sort order not immediately being set
2025-01-14 13:58:44 +00:00
RickyRister
81662b7fec Reduce spacing in visual deck storage (#5465)
* move thing

* reduce spacing
2025-01-14 13:52:46 +00:00
RickyRister
d2c2128e9b Rename TabUserLists to TabAccount (#5464)
* rename class

* rename variables
2025-01-14 13:50:08 +00:00
RickyRister
686645c1e4 refactor DeckViewContainer into own file (#5455)
* cut-and-paste

* remove some includes

* move refreshShortcuts

* move deck_view into src/game/deckview

* move deck_view_container to src/game/deckview

* fix build failure
2025-01-14 07:00:09 +00:00
ZeldaZach
9df71fe1e8 Update VCPkg 2025-01-14 01:47:05 -05:00
Zach H
6309e7e318 Fix Windows FlowWidget duplication (#5460)
- Delete the item widget right away, as the delay is too great with deleteLater
2025-01-14 04:33:21 +00:00
Zach H
767e83c879 Disable Force Start for host on load (#5462)
- Fix #5444
2025-01-14 04:33:04 +00:00
RickyRister
78d54b0ef2 Remove unnecessary deck_view.h includes (#5461)
* remove unnecessary deck_view imports

* remove some more imports
2025-01-14 04:32:53 +00:00
BruebachL
497e4f1be0 Add loadFromFileAsync to deckLoader and connect VisualDeckStorageWidget to it. (#5456)
* Add loadFromFileAsync to deckLoader and connect VisualDeckStorageWidget to it.

* Address comments.

* Lint.

* Unlint something.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-14 03:02:33 +00:00
BruebachL
6072df3522 .txt decks reportedly don't get saved when they're loaded. (#5459)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-14 01:51:41 +00:00
BruebachL
ba89495dc0 Refactor Picture Loader (#5457) 2025-01-13 18:52:54 +00:00
RickyRister
a417b049da Make Visual Deck Storage tab be managed by TabSupervisor (#5453)
* remove closeRequest override

* remove visualDeckStorage from WindowMain

* manage visual deck storage in TabSupervisor

* open on startup

* refresh vds on db load finish

* open deck editor tab first on startup
2025-01-13 18:42:58 +00:00
github-actions[bot]
883f1a5c11 Update translation source strings (#5454)
Co-authored-by: github-actions <github-actions@github.com>
2025-01-13 11:08:32 -05:00
BruebachL
dd8ac14f99 Visual deck storage v2 (#5427)
* Restore some button states (ready/sideboard locked) to sensible defaults when unloading a deck.

* Update last loaded timestamp in decklist file and then restore original last modified timestamp if a user requests a deck load.

* Add some todos.

* Loading a deck from local file dialog should swap out scenes, enable unload button.

* Lint.

* Shuffle some classes and signals around.

* More sort options, sort widgets directly.

* Banner cards should respect providerIds.

* Properly updateSortOrder on load.

* Add the color identity to the Deck Preview Widget.

* Properly set sort indices.

* Change replace visualDeckStorageWidget with deckView to be in deckSelectFinished so that it also works on remote deck load.

* Include settings for unused color identities display.

* Change opacity scaling.

* Overload for Qt.

* Lint.

* Lint.

* Include QMouseEvent

* Template because MacOs.

* Include a quick filter for color identities.

* Include a quick filter for color identities.

* Save some space.

* Refactor DeckPreviewWidgets to reside in their own folder.

* Add Deck Loader logging category.

* Introduce a tagging system.

* Add some more default tags.

* Even more default tags.

* Lint.

* Lint a comma.

* Remove extra set of braces.

* Lint some stuff.

* Refresh banner cards when tags are added.

* Lint.

* Wrestle with Qt Checkboxes.

* Lint.

* Adjust some sizes, relayout.

* Address comments.

* Lint.

* Reorder kindred types.

* Add a search bar for tags.

* Remove close button (for now) and change "Add tags ..." to "Edit tags ..."

* Retranslate window title for Deck Tag Manager Dialog.

* Style tag addition widget to be consistent.

* Lint.

* Override paintEvent.

* Override sizeHint

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-12 17:46:22 -05:00
RickyRister
9bd024d39f Make all tabs closable; add tabs menu (#5451)
* make closeRequest call close by default

* make all tabs closable by default

* closeRequest instead of deleteLater on stop

* null out pointer on destroy

* no need to manually null out the tabs anymore

* comment

* pass tabsMenu into ctor

* comment

* implement tabs menu

* fix segfault on close (again)

* remove deck editor action from WindowMain
2025-01-12 16:15:19 -05:00
transifex-integration[bot]
e4611a8616 Translate cockatrice_en@source.ts in en_US (#5452)
100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-12 12:41:05 -05:00
RickyRister
3f41e5dd77 don't close replay tabs and do close message tabs on disconnect (#5450) 2025-01-12 02:47:36 -05:00
RickyRister
a6fc88c79a Always set TabSupervisor as parent in Tab subclasses (#5449)
* refactor closeTab

* always set tab parent to tabSupervisor

* set tabSupervisor parent

* use close instead of deleteLater

* be more clear about overloads
2025-01-12 02:34:11 -05:00
transifex-integration[bot]
3a4ec1062b Translate cockatrice_en@source.ts in pt_BR (#5448)
100% translated source file: 'cockatrice_en@source.ts'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-11 23:41:57 -05:00
RickyRister
7347ba88ac fix segfault on disconnect (#5447)
* add new param to closeRequest

* don't emit signals in dtors

* send closeRequest

* fix build failure

* fix build failure

* see if we can get away with the overloaded triggered

* fix build failure
2025-01-11 22:19:45 -05:00
tooomm
3b544a36a8 Fix button label (#5441) 2025-01-11 21:28:23 -05:00
RickyRister
2851d0c7e6 add override specifier to tab subclasses (#5445) 2025-01-11 21:28:02 -05:00
transifex-integration[bot]
2b296badea Translate cockatrice_en@source.ts in zh-Hans (#5446)
100% translated source file: 'cockatrice_en@source.ts'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-11 21:27:00 -05:00
ZeldaZach
a12c4ee909 Fix MacOS Builds for Non-Main Repo PRs 2025-01-11 21:21:11 -05:00
ZeldaZach
7db9c9115e Fix SoundEngine on Windows (again) 2025-01-11 00:19:00 -05:00
ZeldaZach
503985a080 Initialize audioOutput for SoundEngine 2025-01-11 00:12:32 -05:00
RickyRister
9f466162b0 disable starting life total edit in game information window (#5440) 2025-01-10 23:14:46 -05:00
Zach H
8bea3f8997 Fix sounds on Qt6 (#5439) 2025-01-10 23:10:47 -05:00
RickyRister
1a3df84f0a fix segfault on exit if any closable tabs were open (#5435) 2025-01-10 17:27:26 -05:00
Zach H
2b3c47148e GHA MacOS Only Sign/Notarize if self repo (#5437) 2025-01-10 16:46:05 -05:00
transifex-integration[bot]
59ca4397e2 Translate oracle/oracle_en@source.ts in zh-Hans (#5436)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-10 08:22:58 -05:00
transifex-integration[bot]
98266b0739 Translate oracle/oracle_en@source.ts in yue (#5434)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'yue'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-10 08:22:48 -05:00
Zach H
5a82ff106d Update VCPkg (#5433) 2025-01-09 23:23:00 -05:00
Zach H
2194430019 Sign macOS Releases (#5396) 2025-01-09 22:32:53 -05:00
RickyRister
1f11015a2f Refactor files in src/utility and src/deck to new Qt Slot/Signal syntax (#5432)
* refactor in src/utility

* refactor in src/deck

* fix build failure
2025-01-09 06:33:20 -05:00
RickyRister
c3421669d5 Refactor files in src/game to new Qt Slot/Signal syntax (#5431)
* fix signals in CardDatabaseParser

* update remaining signals

* cleanup

* wait this was always just broken

* fix build failure

* fix build failure

* fix build failure
2025-01-09 06:32:25 -05:00
RickyRister
6e8adddc6d Refactor tab_supervisor to new Qt Slot/Signal syntax (#5430)
* Refactor tab_supervisor to new Qt Slot/Signal syntax

* fix build failure
2025-01-09 06:26:42 -05:00
RickyRister
22a6ded4f0 reduce vertical spacing in visual deck storage (#5422) 2025-01-09 06:25:40 -05:00
transifex-integration[bot]
0d7669db2c Translate cockatrice_en@source.ts in yue (#5428)
100% translated source file: 'cockatrice_en@source.ts'
on 'yue'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-08 19:23:49 -05:00
transifex-integration[bot]
9526bca168 Translate cockatrice/cockatrice_en@source.ts in de (#5429)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-08 19:23:38 -05:00
transifex-integration[bot]
0683431f35 Translate cockatrice_en@source.ts in en_US (#5426)
100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-06 17:31:14 -05:00
github-actions[bot]
70790264b8 Update translation source strings (#5425)
Co-authored-by: github-actions <github-actions@github.com>
2025-01-06 12:42:46 -05:00
transifex-integration[bot]
c8a68c83e3 Translate cockatrice_en@source.ts in yue (#5424)
100% translated source file: 'cockatrice_en@source.ts'
on 'yue'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-06 12:38:58 -05:00
RickyRister
23171f79d0 Refactor window_main to new Qt Slot/Signal syntax (#5423) 2025-01-06 12:38:44 -05:00
RickyRister
b7f05a12a3 get swap cards button to work with multi-selections (#5421) 2025-01-05 22:44:40 -05:00
Zach H
6078dd092a Support viewing the bottom X cards of library (#5410)
* Get cardIds to update properly in bottom view (#5414)

* Get bottom view to update properly when card is inserted into known portion (#5415)

---------

Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
2025-01-05 21:17:18 -05:00
BruebachL
81b85e97df Extend decklist parsing (#5316)
* Extend the decklist parsing from clipboard to also support SetName, CollectorNumber and Foil Status.

* Q_UNUSED foil for now but keep parsing logic for future PR's/compatibility.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-05 21:07:17 -05:00
RickyRister
cc16b8779c improve shortcut search to split by word (#5416) 2025-01-05 19:19:00 -05:00
BruebachL
62f7c7f9ce New visual deck storage (#5290)
* Add TabDeckStorageVisual

* Visual Deck Storage

* Add BannerCard to .cod format, use it in the visual deck storage widget.

* Show filename instead of deckname if deck name is empty.

* Lint.

* Don't delint cmake list through hooks.

* Add deck loading functionality.

* Open Decks on double click, not single click.

* Void event for now.

* Fix build issue with overload?

* Fix build issue with overload?

* Include QDebug.

* Turn the tab into a widget.

* Move the signals down to the widget, move the connections and slots up to the parent widgets.

* No banner card equals an empty CardInfoPtr.

* Add an option to sort by filename or last modified.

* Flip last modified comparison.

* Lint.

* Don't open decks twice in the storage tab.

* Fix unload deck not working by showing/hiding widgets instead of adding/removing to layout.

* Add a search bar.

* Add a card size slider.

* Lint.

* Lint.

* Lint.

* Fix settings mocks.

* No need to QDebug.

* No need to QDebug.

* Member variable.

* Member variable.

* Non-lambda.

* Change set to list conversion.

* Specify overload.

* Include MouseEvent

* Adjust font size dynamically.

* Add an option to show the visual deck storage on database load.

* Fix the close button not working on the tab, add an option to launch the visual deck storage tab to Cockatrice menu.

* Override virtual functions.

* Correct tab text.

* Add a setting to remember last used sorting order for visual deck storage widget.

* Update banner card combo box correctly.

* Fix mocks.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: Zach H <zahalpern+github@gmail.com>
2025-01-05 18:12:20 -05:00
BruebachL
7496e79e8c Add a button to swap the card between mainboard and sideboard to the DeckEditor (#5175)
* Add a button to swap the card between mainboard and sideboard to the deck editor.

* Add new icon to cockatrice.qrc and force update.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-05 17:57:37 -05:00
RickyRister
b8cf3e2cab add ctrl enter as shortcut for ok in load deck from clipboard (#5417) 2025-01-05 17:41:03 -05:00
RickyRister
93fab3d78f Remember last opened directory when loading decks (#5418)
* remember last directory when loading deck

* move shared code into new dlg class
2025-01-05 17:40:20 -05:00
BruebachL
9c38c9ed1b Differentiate logging in order to silence certain modules. (#5419)
* Differentiate logging in order to silence certain modules.

* Lint cmake.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2025-01-05 17:38:51 -05:00
RickyRister
38e99f2e87 implement /card command (#5413) 2025-01-04 02:07:43 +00:00
RickyRister
68226786a2 don't redraw PrintingSelector's FlowWidget unless cards actually changed (#5392) 2025-01-04 01:49:54 +00:00
RickyRister
455cd9717a add menu action to open settings folder (#5412) 2025-01-04 01:49:41 +00:00
RickyRister
fa79c5c36a populate default debug.ini with more values (#5411)
* populate default debug.ini with more values

* move the default debug.ini to a resource
2025-01-03 20:50:30 +00:00
RickyRister
0402d4b853 add debug setting to load deck and ready on join (#5409)
* new property

* refactor deck loading to new method

* another new method

* works now
2025-01-02 17:08:51 -05:00
RickyRister
8a427955e7 Add debug setting to start local game on startup (#5408)
* new properties

* refactor

* start local game on startup

* disable autoconnect
2025-01-02 09:51:59 -05:00
RickyRister
bb4214e28a Make SettingsManager params const ref (#5405)
* pass settingsPath by const ref

* pass params by const ref

* cleanup
2025-01-02 00:33:37 -05:00
RickyRister
f924b04efd add debug settings; option to show cardIds (#5404)
* add debug settings; option to show cardIds

* pass param by const ref

* change group structure again

* create debug.ini if not exists
2025-01-02 00:32:58 -05:00
transifex-integration[bot]
62f60867a9 Translate cockatrice_en@source.ts in pt_BR (#5407)
100% translated source file: 'cockatrice_en@source.ts'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-02 00:32:29 -05:00
transifex-integration[bot]
b5844f1244 Translate cockatrice/cockatrice_en@source.ts in it (#5406)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'it'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-01-01 22:28:42 -05:00
ryder052
8c0093d453 Crashfix for opening Deck editor (#5403)
* CardDatabase::getCards() no longer copies the whole database

---------

Co-authored-by: Jakub Mrowinski <ryder052@outlook.com>
2025-01-01 19:25:04 -05:00
RickyRister
34df4cd060 support multi-select in deck editor (#5397)
* support multiselect in deck editor

* fix crash

* don't reset selection after each action

* maintain old reselecting behavior when changing cards from left side

* fix crash for real (probably)

* maintain reselection behavior when deleting single selection
2025-01-01 00:43:47 -05:00
Zach H
99eea3a662 Improve Database Backup Speed (#5400)
* Support better indexes for Servatrice

- Prevent searching only on msg for logs
2025-01-01 00:28:57 -05:00
Zach H
6e1047032d Keep card annotations on stack (#5399) 2024-12-31 14:08:25 -05:00
transifex-integration[bot]
b2a8748bc6 Translate cockatrice/cockatrice_en@source.ts in it (#5398)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'it'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-31 13:57:14 -05:00
transifex-integration[bot]
ded6d5b8eb Translate cockatrice/cockatrice_en@source.ts in de (#5395)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-30 19:18:00 +00:00
transifex-integration[bot]
832842c20c Translate cockatrice_en@source.ts in en_US (#5394)
100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-30 17:42:32 +00:00
github-actions[bot]
b43e4ae469 Update translation source strings (#5393)
Co-authored-by: github-actions <github-actions@github.com>
2024-12-30 12:38:30 +00:00
Zach H
026afeb885 Support auto-reconnect for Servatrice (#5391)
- Fix #5022
2024-12-30 04:35:32 +00:00
RickyRister
b6793a5e01 fix cards having the wrong printing if rejoin game before card db finishes loading (#5390)
* rename cardInfoUpdated to refreshCardInfo and make it public

* refresh card infos when db finishes loading
2024-12-30 03:25:11 +00:00
moryall
d231264a16 Update Dockerfile Ubuntu version to newest LTS (#5108)
* Update Dockerfile to non-outdated Ubuntu version

1. Updated image to jammy as it is still in it's LTS window. Didn't go with 24.04/Noble as it released after latest version of cockatrice released.
2. Had to add new ARG
3. No qt5-default library, so replaced with qt5-qmake

* Update Dockerfile

Upped from Jammy -> Noble
Upped from Qt5 -> Tt6

* Update Dockerfile - new port

Added Port 4748 for new features

* Update Dockerfile

Changed Noble - > 24.04

* indentation

* remove unused dependencies

---------

Co-authored-by: tooomm <tooomm@users.noreply.github.com>
2024-12-30 01:54:18 +00:00
ryder052
6e02bdec2e Fix crash on replay list sorting, fix error popups on win debug (#5388)
* Fix annoying popups on start

* Fix replay list item parent index calculation #5311

---------

Co-authored-by: Jakub Mrowinski <ryder052@outlook.com>
2024-12-30 01:10:12 +00:00
transifex-integration[bot]
cfaadc40b1 Translate cockatrice_en@source.ts in pt_BR (#5386)
100% translated source file: 'cockatrice_en@source.ts'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-30 00:57:51 +00:00
transifex-integration[bot]
93475b43a5 Updates for project Cockatrice and language it (#5387)
* Translate cockatrice/cockatrice_en@source.ts in it

100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'it'.

* Translate webclient/src/i18n-default.json in it

100% translated source file: 'webclient/src/i18n-default.json'
on 'it'.

* Translate oracle/oracle_en@source.ts in it

100% translated source file: 'oracle/oracle_en@source.ts'
on 'it'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-30 00:57:43 +00:00
RickyRister
3348e051a1 update recently opened decks when saving a new deck (#5389) 2024-12-30 00:57:31 +00:00
Zach H
dad1aea128 Show correct art on middle mouse popup (#5385) 2024-12-29 23:24:32 +00:00
Zach H
dec001114a Clone now clones the exact printing, when possible (#5384) 2024-12-29 23:24:20 +00:00
ZeldaZach
1ce7b9f7de Update number when 'Reveal top cards of library' used 2024-12-29 16:31:13 -05:00
Zach H
2ff99f12d8 Require Admin Permissions to install Cockatrice Windows (#5383)
Fix #5382
2024-12-29 16:22:39 +00:00
tooomm
6679705254 Simpler naming (#5381) 2024-12-29 15:41:30 +00:00
transifex-integration[bot]
7eafac5b1a Translate cockatrice_en@source.ts in en_US (#5377)
100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-29 07:11:02 +00:00
RickyRister
ac3aa949ad add "view related cards" right click menu to card info widget (#5375) 2024-12-29 06:11:12 +00:00
Zach H
b4036c8671 Disable CardMenu iff no items selected (#5376)
- Fix #4372
2024-12-29 06:10:27 +00:00
github-actions[bot]
4e0de1c066 Update translation source strings (#5373)
Co-authored-by: github-actions <github-actions@github.com>
2024-12-29 03:37:53 +00:00
RickyRister
f32890916d don't disable autoconnect on disconnect (#5372)
* don't disable autoconnect on disconnect

* update autoConnect on clicking the checkbox
2024-12-29 03:07:00 +00:00
Zach H
24a0dac420 Fix Windows Portable Crash (#5371) 2024-12-29 03:02:52 +00:00
RickyRister
716bc00533 fix "forgot password" closing connection dialogue on cancel (#5369) 2024-12-29 02:23:58 +00:00
Zach H
32dd18998d Combine card legalities in Oracle (#5370)
- Some printings have different legalities, which cause Oracle to bug out
- Fix #4783
2024-12-29 02:23:39 +00:00
ZeldaZach
5e62069444 Fix Windows Crash due to nullptr 2024-12-28 21:02:10 -05:00
Zach H
bf63dc4ab7 Add option to remove saved sever (#5368)
* Add option to remove saved sever

- Fix #4099
- Removes old method that didn't work
2024-12-29 00:37:49 +00:00
Danny Piper
7679546e30 Add Nix shell (#5362) 2024-12-28 23:52:57 +00:00
Zach H
45b11dc984 Add password reset button label (#5367) 2024-12-28 23:52:14 +00:00
RickyRister
25d21a3da6 refactor: remove ReleaseChannel keeping track of its own indexes (#5366) 2024-12-28 23:51:37 +00:00
Zach H
c8d49b5bf9 Support macOS-15 Builds (#5364) 2024-12-28 23:09:01 +00:00
RickyRister
f737d9a794 fix bug with release channel setting not being remembered (#5365) 2024-12-28 23:08:07 +00:00
RickyRister
df9c5ae53c Check for client updates on startup (#5359) 2024-12-28 21:29:59 +00:00
transifex-integration[bot]
e0829a75d2 Translate cockatrice/cockatrice_en@source.ts in it (#5363)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'it'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-28 21:01:34 +00:00
Zach H
1f58f7e93d Support Mod/Admin Notes Section (#5361) 2024-12-28 18:05:49 +00:00
transifex-integration[bot]
14807ba036 Translate oracle/oracle_en@source.ts in pl (#5360)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'pl'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-28 15:31:16 +00:00
transifex-integration[bot]
75fb3894a6 Translate oracle/oracle_en@source.ts in pt_BR (#5358)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-28 12:08:58 +00:00
github-actions[bot]
18119bd11b Update translation source strings (#5357)
Co-authored-by: github-actions <github-actions@github.com>
2024-12-28 06:33:57 +00:00
RickyRister
4c7796537f Support folder download in deck storage tab (#5356)
* refactor

* support folder download
2024-12-28 06:31:18 +00:00
RickyRister
3452cb01d0 fix replay download not working if replay folder is empty (#5355)
* fix downloading single replays

* fix downloading replay folder
2024-12-28 06:15:25 +00:00
RickyRister
6a151ef97a Add button to open decks folder (#5354) 2024-12-28 05:09:46 +00:00
RickyRister
e3d651668c Add button to open replays folder (#5352) 2024-12-28 05:06:26 +00:00
Zach H
7a5704beaa Support Moderator/Admin force activating users (#5353) 2024-12-28 05:01:31 +00:00
RickyRister
37b78a9a4c change action's text to "unconcede" when player is conceded (#5351) 2024-12-28 00:01:36 +00:00
Zach H
8bc5a9d581 Merge pull request #5350 from Cockatrice/fix_1953
Allow Moderators/Admins to Grant Replay Access
2024-12-27 18:51:11 -05:00
ZeldaZach
57ed162b79 Fix Linter 2024-12-27 18:35:52 -05:00
ZeldaZach
3524231500 Allow Moderators/Admins to Grant Replay Access
- Only to themselves, at this time
- Automatically refreshes feed, no need to re-login
2024-12-27 18:32:39 -05:00
Zach H
5cfe2b4762 Merge pull request #5348 from Cockatrice/set_owner
Establish Card Ownership & Return on Player Leave
2024-12-27 18:26:45 -05:00
ZeldaZach
a8bac1e468 Return Tagged Cards to Owner, if possible, on concede/leave 2024-12-27 18:23:39 -05:00
ZeldaZach
4f798286af Establish Card Ownership Tag 2024-12-27 18:23:09 -05:00
transifex-integration[bot]
8a04b2d69d Translate cockatrice/cockatrice_en@source.ts in de (#5349)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-27 22:26:03 +00:00
transifex-integration[bot]
17893d9747 Translate oracle/oracle_en@source.ts in it (#5347)
100% translated source file: 'oracle/oracle_en@source.ts'
on 'it'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-27 20:13:57 +00:00
ZeldaZach
8af49406cd Un-translate 'ms' 2024-12-27 14:18:44 -05:00
transifex-integration[bot]
3b068b79fe Translate webclient/src/i18n-default.json in fr (#5346)
100% translated source file: 'webclient/src/i18n-default.json'
on 'fr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-27 08:36:06 +00:00
transifex-integration[bot]
ce14e83e78 Translate webclient/src/i18n-default.json in es (#5345)
100% translated source file: 'webclient/src/i18n-default.json'
on 'es'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-27 08:35:58 +00:00
transifex-integration[bot]
f213d6fda7 Translate cockatrice_en@source.ts in en_US (#5344)
100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-27 08:35:48 +00:00
RickyRister
83db00d7a3 reduce vertical spacing in PrintingSelector (#5342) 2024-12-27 08:35:38 +00:00
ZeldaZach
7e9bd88eb4 Fix Shutdown Server 2024-12-27 01:38:21 -05:00
github-actions[bot]
ea716ca440 Update translation source strings (#5343)
Co-authored-by: github-actions <github-actions@github.com>
2024-12-27 06:19:12 +00:00
ZeldaZach
3cd7a04002 Change Settings from Min to Base Size 2024-12-26 23:54:24 -05:00
RickyRister
914002f846 use grid instead of FlowWidget for PrintingSelector display options (#5341)
* use grid instead of FlowWidget for PrintingSelector display options

* remove one level of nesting
2024-12-27 02:08:07 +00:00
Zach H
17b82a186f Add QSet for faster lookups in CardDatabase (#5332) 2024-12-26 19:52:18 -05:00
RickyRister
7a8e957476 allow playing cards directly transformed from hand (#5339) 2024-12-26 19:51:58 -05:00
Zach H
6dfd354973 Support starting games with fewer than max players (#5338) 2024-12-26 18:32:20 -05:00
RickyRister
956c12eb32 remove shortcut workaround; always add card menu to player (#5337)
* remove workaround

* make aCardMenu less innocuous

* make card menus active for all players
2024-12-26 16:49:17 -05:00
RickyRister
d5ae4eed26 Ctrl drag now adds/removes to selection (#5336)
* refactor: clean up to use for-each loop

* track cards in rect so far and toggle isSelected on change

* only clear selection if ctrl isn't held

* fix build errors
2024-12-26 15:08:20 -05:00
RickyRister
ca486e5ed9 Don't display unusable actions in opponent's card menus (#5335) 2024-12-26 10:23:54 -05:00
RickyRister
de63066b0b fix deck storage open deck not working at all when folder is in selection (#5333) 2024-12-26 00:25:30 -05:00
Zach H
c7ca55ceb5 Support Picking Select Art per Card Basis (#5329) 2024-12-25 23:12:06 -05:00
RickyRister
024bef7ded add local rename button to replays tab (#5331) 2024-12-25 22:34:24 -05:00
RickyRister
34d3d60f95 fix text missing from chat macro list's buttons when hidden (#5330)
* fix text missing from chat macro list's buttons when hidden

* turns out you don't need to set tooltip if you already set text
2024-12-25 22:32:53 -05:00
RickyRister
ed907d7c6f Support downloading replay folders (#5325)
* rename old get replay match method to get enclosing

* creat raw getReplayMatch method

* implement thing
2024-12-25 07:33:36 -05:00
RickyRister
9d7fd66546 fix text missing from download url list's buttons when hidden (#5326) 2024-12-25 07:29:55 -05:00
RickyRister
9934841950 make better use of space in download url settings window (#5327) 2024-12-25 07:29:27 -05:00
RickyRister
432fe1100b gitignore all cmake-build folders (#5328) 2024-12-25 07:28:41 -05:00
Zach H
d987628935 Reorder String options for Filtering (#5324) 2024-12-25 00:58:59 -05:00
RickyRister
4c3ceae0e4 open replays on double-click in replays tab (#5323) 2024-12-25 00:34:43 -05:00
RickyRister
2b9d7538bf open decks on double-click in deck storage tab (#5322) 2024-12-25 00:33:48 -05:00
RickyRister
4ca1fc083d add "open recent" menu option to deck editor tab (#5319)
* add "open recent" menu option to deck editor tab

* change texts

* also get it to work with loading from deck storage tab

* add error message when fail to open

* only update recents on successful open

* only update recents on successful open

* reword to "Clear"
2024-12-24 19:55:04 -05:00
BruebachL
e7585271fb The printingSelector should set the deckEditor modified flag on adding/removing cards. (#5321)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-12-24 10:28:58 -05:00
RickyRister
6e6824117d add new folder button to local deck storage tab (#5318)
* add new folder button to local deck storage tab

* allow delete button to delete folders
2024-12-24 00:26:11 -05:00
RickyRister
3e5f2fd8b2 add new folder button to game replays tab (#5317) 2024-12-24 00:23:13 -05:00
RickyRister
6e470d788e Support multi-select for remote decks in deck storage tab (#5315)
* enable multiselection

* support multi open deck

* support multi download

* support multi delete
2024-12-24 00:05:49 -05:00
RickyRister
a40d8092ce support multi-select for local decks in deck storage tab (#5314)
* allow multi-select

* support multi upload

* support multi open deck

* support multi delete deck
2024-12-23 20:41:15 -05:00
RickyRister
0234a70bfd fix bug with uploading unnamed decks ignoring the prompt (#5313) 2024-12-23 20:39:57 -05:00
RickyRister
705b1e0c2b support multi-select for remote replays in game replays tab (#5310) 2024-12-23 20:38:47 -05:00
RickyRister
69379334f9 support multi-select for local replay tab (#5309) 2024-12-23 20:31:58 -05:00
transifex-integration[bot]
12e50a1f2f Translate cockatrice_en@source.ts in en_US (#5308)
100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-23 20:30:17 -05:00
RickyRister
ec17a477be shortcut search now displays all rows in section (#5307) 2024-12-23 20:29:52 -05:00
github-actions[bot]
205e1c7a59 Update translation source strings (#5305)
Co-authored-by: github-actions <github-actions@github.com>
2024-12-22 18:35:34 -05:00
transifex-integration[bot]
ffb60c06cb Translate oracle_en@source.ts in en@pirate [Manual Sync] (#5295)
4% of minimum 3% translated source file: 'oracle_en@source.ts'
on 'en@pirate'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 18:01:02 -05:00
transifex-integration[bot]
2280f59ee6 Translate i18n-default.json in nl [Manual Sync] (#5297)
19% of minimum 3% translated source file: 'i18n-default.json'
on 'nl'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 18:00:44 -05:00
transifex-integration[bot]
0d4dd63edc Translate i18n-default.json in es [Manual Sync] (#5299)
99% of minimum 3% translated source file: 'i18n-default.json'
on 'es'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 18:00:39 -05:00
transifex-integration[bot]
69f1f4c1a5 Translate i18n-default.json in fi [Manual Sync] (#5301)
13% of minimum 3% translated source file: 'i18n-default.json'
on 'fi'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 18:00:35 -05:00
transifex-integration[bot]
d930d9c237 Updates for project Cockatrice and language tr (#5296)
* Translate oracle_en@source.ts in tr [Manual Sync]

36% of minimum 3% translated source file: 'oracle_en@source.ts'
on 'tr'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

* Translate cockatrice_en@source.ts in tr [Manual Sync]

6% of minimum 3% translated source file: 'cockatrice_en@source.ts'
on 'tr'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 18:00:31 -05:00
transifex-integration[bot]
9c782d130f Translate i18n-default.json in pt_BR [Manual Sync] (#5298)
100% translated source file: 'i18n-default.json'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 18:00:13 -05:00
transifex-integration[bot]
f12053f39d Translate i18n-default.json in de [Manual Sync] (#5300)
100% translated source file: 'i18n-default.json'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 18:00:05 -05:00
transifex-integration[bot]
bcf6ca4f87 Translate i18n-default.json in fr [Manual Sync] (#5302)
99% of minimum 3% translated source file: 'i18n-default.json'
on 'fr'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 17:59:55 -05:00
transifex-integration[bot]
46619bb425 Translate i18n-default.json in ru [Manual Sync] (#5303)
14% of minimum 3% translated source file: 'i18n-default.json'
on 'ru'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 17:59:46 -05:00
transifex-integration[bot]
cdd870a129 Translate i18n-default.json in en_US [Manual Sync] (#5304)
100% translated source file: 'i18n-default.json'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 17:59:35 -05:00
transifex-integration[bot]
7a1b7b9438 Updates for project Cockatrice and language it (#5294)
* Translate cockatrice_en@source.ts in it [Manual Sync]

99% of minimum 3% translated source file: 'cockatrice_en@source.ts'
on 'it'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

* Translate i18n-default.json in it [Manual Sync]

100% translated source file: 'i18n-default.json'
on 'it'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 17:59:24 -05:00
transifex-integration[bot]
2183ada1f2 Translate oracle_en@source.ts in cs [Manual Sync] (#5293)
3% of minimum 3% translated source file: 'oracle_en@source.ts'
on 'cs'.

Sync of partially translated files: 
untranslated content is included with an empty translation 
or source language content depending on file format

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-22 17:58:35 -05:00
Zach H
1d9e64ec73 Fix settings dialog tr (#5292) 2024-12-22 17:39:43 -05:00
Zach H
5339be318e Fix "ghosting" of cards sticking on invalid moves (#5289) 2024-12-22 17:35:44 -05:00
Zach H
e1ba39c437 Fix multiple "Selected Cards" in Menu on MacOS (#5288) 2024-12-22 04:33:09 +00:00
BruebachL
07ee271478 Refactor codebase to new Qt Slot/Signal syntax - Pt1 (#5202)
---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2024-12-22 02:01:17 +00:00
RickyRister
4823cce622 Show conflicting shortcut in error message (#5287) 2024-12-22 01:58:55 +00:00
Zach H
23099f7e8b Fix token name highlight on open (#5286) 2024-12-22 01:43:00 +00:00
RickyRister
5bdbd51fa8 implement search bar in shortcuts menu (#5285)
* implement search bar in shortcuts menu

* remove unneeded imports

* use expandAll
2024-12-22 00:21:53 +00:00
BruebachL
a0e5871c6e Fix the image shrinking due to repeated scaling and FP precision loss. (#5284)
* Fix the image shrinking due to repeated scaling and FP precision loss.

* Add a setting for auto-rotating sideways layout cards.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-12-21 22:47:43 +00:00
RickyRister
3cf0904651 add action to select all cards in table row (#5280) 2024-12-21 18:52:19 +00:00
Zach H
2bd06ff0fd Add CrashDump support for Windows OS (#5282) 2024-12-21 18:52:07 +00:00
RickyRister
6ea333d0f1 move SearchLineEdit into custom_line_edit file (#5281) 2024-12-21 05:12:14 +00:00
Zach H
91d2485940 Update PegLib, Fix Database Searching CFG (#5244)
* Support C++20 Standard

* Update peglib.h

* Fix lambdas

* Move from for loops to std::any/all_of

* Support fixed CFG

* Fix Rarity Search to be more accurate
2024-12-21 03:37:08 +00:00
RickyRister
0d99b2bcf4 make unattach shortcut always active (#5278) 2024-12-20 05:56:48 +00:00
RickyRister
a54a424f84 add action to select all cards in column (#5277)
* add action to select all cards in column

* change default shortcut to Ctrl+Shift+C
2024-12-20 03:39:17 +00:00
RickyRister
3514699f5b check that target card is in play before attaching (#5275) 2024-12-19 23:55:04 +00:00
RickyRister
d196988cab allow attached cards to be moved to other zones (#5276) 2024-12-19 23:53:48 +00:00
BruebachL
03aff83135 Add the ability to define starting life total during game creation. (#5174)
* Have the server respect gameType info when setting up zones.

* ServerPlayer::setupZones is now passed the room->getGameTypes();
* ServerPlayer::setupZones now checks if the GameType String includes "Commander" and then sets the life total to 40 instead.

* Formatting.

* Remove debug logging imports.

* Move game option value declarations to dlg_create_game.

* Lint.

* Fix mocks.

* Add a default for backwards compatibility.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-12-19 23:52:47 +00:00
RickyRister
17e6bfaca6 fix bug with multi-attach sometimes only attaching one card (#5272) 2024-12-19 13:38:57 +00:00
Zach H
90281262be Revert "Revert "Rotate split cards (#5264)" (#5269)" (#5273)
This reverts commit d41aa30e10.
2024-12-19 13:25:54 +00:00
RickyRister
5bbc118920 fix bug introduced in #5267 (#5270)
* fix bug introduced in #5267

* remove default args to prevent similar bugs in the future

* add newInstance overload with default properties
2024-12-19 13:17:09 +00:00
ZeldaZach
dde2f8b9ad Bump Win Qt6 6.5.3->6.6.*
- Fix #4968
2024-12-19 01:09:04 -05:00
Zach H
d41aa30e10 Revert "Rotate split cards (#5264)" (#5269)
This reverts commit a5c509981b.
2024-12-19 06:03:48 +00:00
RickyRister
231d0380a7 reword "open deck in new tab" setting (#5268) 2024-12-19 05:52:40 +00:00
BruebachL
a5c509981b Rotate split cards (#5264) 2024-12-19 04:13:45 +00:00
Zach H
71b01e6110 ADD landscapeOrientation field (#5267) 2024-12-19 03:52:34 +00:00
RickyRister
c716f85962 refactor: remove cipt param from Player::playCard (#5266) 2024-12-19 02:46:14 +00:00
BruebachL
245d51caea New printing selector (#5182)
* Squashed Commits

Lint things.

Set focus back to deckView after selecting a card to enable keyboard navigation.

Bump scrollbar to top when selecting a new card.

Update card info on hover.

Layout cleanups

Add +- to buttons.

Merge buttons into card picture.

Cleanup size, min 2 cards by default in rows

Support layout settings config and set min to 525 so two cols are visible by default for printings, when opened

Move Printing Selector to before Deck, and visible true

Null safety for setCard.

Turn down the dropshadow a little.

Make PrintingSelector dockable, don't duplicate sets when bumping them to the front of the list.

When swapping cards between mainboard and sideboard, use preferred printing if no uuid is available (i.e. null).

Reorder includes...

Unwonk an include.

Give the card widget a snazzy drop shadow, appease the linter gods.

Handle jumping between segments

Remember scale factor when initializing new widgets.

Cleanup

Select Card works (Not M->SB tho)

Resize word-wrapped label properly.

Fix the layouting, mostly.

remove tx

Build Fix

Squashed Commits

Load and store redirects properly.

Layouting is fun :)

* Group PrintingSelectorCardDisplayWidgets into distinct containers for alignment purposes.

Override resizeEvent() properly.

Word wrap properly.

Keep widget sizes uniform for aesthetic reasons (grid pattern).

Label stuff, center card picture widget, allow cardSizeSlider to scale down.

Replace cards which have no uuid in the decklist when first selecting a printing.

Add buttons for previous and next card in DeckList.

Add a card size slider.

Move sort options initialization to implementation file.

Explicitly nullptr the parent for the PrintingSelector.

Address PR comments (minor cleanups).

Hook up to the rows removed signal to update card counts properly.

Include QDebug.

Add labels to the mainboard/sideboard button boxes.

Implement a search bar.

Expand node recursively when we add a new card.

Only create image widgets for the printing selector if it is visible in order to not slow down image loading.

Minor Tweaks

Invert decklist export logic to write out setName, collectorNumber, providerId value if it is NOT empty.

Linting.

Update CardCounts properly, update PrintingSelector on Database selection.

Initialize sideboard card count label properly.

Split mainboard/sideboard display and increment/decrement buttons.

Add button to sort all sortOptions by ascending or descending order.

Add option to sort by release date in ascending or descending order.

Add PrintingSelector to database view.

Display placeholder image before loading.

Fix deckEditor crash on mainboard/sideboard swap by correcting column index to providerId instead of shortName.

Include currentZoneName, fix the column when updating from DeckView indexChanged to be UUID and not setShortName so cards are properly fetched again.

The most minor linter change you've ever seen.

Null checks are important.

Linter again.

Linter and refactor to providerId.

Sort properly, (We don't need a map, we need a list, a map won't be ordered right [i.e. 1, 10, 11, 2, 3, 4, ..., 9])

Sort alphabetically or by preference.

Hook printingSelector up to the CardInfoFrameWidget.

Allow info from CardFrame to be retrieved, properly initialize PrintingSelector again.

Refactors to reflect CardInfoPicture becoming CardInfoPictureWidget.

Make PrintingSelector re-usable by introducing setCard().

Make PrintingSelector use the CardFrame, not the database index.

Add a new selector widget for printings.

* Support multiple <set> tags per card within the database

This will allow us to show off all different printings for cards that might appear multiple times in a set (alt arts, Secret Lairs, etc.)

* Support Flip Cards with related art

* Minor Cleanup

* Minor Cleanup

* Release Date DESC default

* Load widgets in batches.

* Refactor local batch variables to be class variables/defines.

* Clear timer on updateDisplay.

* Fix Timer & Builds on Qt5

* Not Override

* Yes Override

* Yes Override

* Lint

* Can't override in function definition.

* Resize setName to picture width on initialization.

Also add a new signal to card_info_picture_widget to emit when the scale factor changes.

Hook this up to the setName resizing method to ensure card size updates trigger it appropriately after initialization.

Clean up unused enter and resize methods that just delegated to base-class.

* Add ability to force preferred set art to be loaded for every card.

* Show related cards from printing selector by right-clicking card image.

* fix build

* Fix UST cards

* Inc QDebug

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix Qt5 Builds

* Fix cards being able to jump between side and mainboard

* Don't hide PrintingSelector button widgets if the deck contains a card from the set.

* Update PrintingSelector properly on DeckListModel::dataChanged

* Add option to disable bumping sets to the front of the list if the deck contains cards from the set.

* Linter behave.

* Linter behave.

* Fix mocks.

* Fix cards without providerIds being counted for all cards.

* Flip preference sort so descending means "Most to least preferred".

* Set the index correctly when removing a non-providerId printing for a providerId printing to avoid jumping to the next card.

* Move the "Next/Previous" card buttons to their own widget.

* Move the card size slider to its own widget.

* Lint the makelist.

* Linter

* Crash fix

* Move the sorting options to their own widget.

* Move the search bar to its own widget.

* Minor cleanup

* Minor cleanup

* Minor cleanup

* Only overwrite card in deck if UUID _and_ Number missing

* Adjust font size when adjusting card size.

* Clean up some imports.

* Pivot to a view options toolbar.

* Persist sort options and change default to 'preference'.

* Lint.

* Remember how many cards were originally in deck when replacing with uuid version.

* Relabel buttons for clarity.

* Fix tests.

* Fix tests properly.

* Fix dbconverter mock.

* Try to wrangle font sizes.

* Update mainboard/sideboard labels correctly.

* Initialize button sizes correctly.

* Label texts are supposed to be white.

* Adjust another deckModel->findCard call to include number parameter.

* Style buttons again.

* Negative currentSize means we don't render the widget yet, return a default value.

* Clean up debug statements.

* Boop the mainboard/sideboard label and the cardCount after a little bit of delay to make sure they initialize at the right size.

* Persist card size slider selection in SettingsCache.

* Good Lint Inc.

* updateCardCount to get white color in initializer

* Make the view display options functional.

* Comment ALL the things.

* Lint the things.

* Brief accidentally nuked some constants.

* Proper Qt slot for checkboxes.

* Don't use timers, Qt provides ShowEvent for anything necessary before the widget is shown.

* Cleanup from Reading

* Cleanup Lints

* Minor

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: Zach Halpern <zahalpern+github@gmail.com>
2024-12-19 02:40:34 +00:00
RickyRister
e588917f6c don't snap already-expanded cardview windows (#5265) 2024-12-19 02:27:40 +00:00
RickyRister
27e5d21b6b fix bug with scrollbar resizing (#5263) 2024-12-18 05:16:47 +00:00
RickyRister
b894b75e6a add clone action to card menu in all zones that it functions in (#5259) 2024-12-18 04:48:06 +00:00
RickyRister
116397cdb3 add option to auto-play "put top card on stack until" hits (#5258)
* rename variables

* implement feature

* readd null check
2024-12-18 04:47:49 +00:00
RickyRister
a6b5abf271 clicking to play can now play all selected (#5254)
* play action now applies to all selected cards

* check card zone before applying action

* fix bug with wonky play from deck

* refactor

* don't play card if it's already on table

* add new setting

* make actPlay and friends public

* implement thing

* refactor card_item
2024-12-18 04:43:17 +00:00
RickyRister
fd5a649246 fix clone shortcut not working on opponent's cards (#5251)
* implement fix

* fix nullptr bug

* also add the selectAll action to the always active shortcuts
2024-12-18 04:41:12 +00:00
RickyRister
e8e57989ba Reload card database action now also reloads the download urls (#5262)
* add sync method to SettingsManager

* sync download urls on reload card database
2024-12-18 04:39:58 +00:00
RickyRister
03db4ccce6 ability to directly attach from other zones (#5250)
* add attach and draw arrow actions to more card menus

* implement attaching from other zones

* disallow attaching from deck

* do nothing if target is already attached

* add null check
2024-12-18 04:38:22 +00:00
RickyRister
c9d5d5609c Double click to untap works when multi-zone select (#5253) 2024-12-17 03:58:25 +00:00
RickyRister
ac16206ddb Add action to select all cards in zone (#5246)
* rip shortcut for aDrawArrow

* implement thing

* add separator below hide

* shorten text by 1 word

* move shortcut to under Playing_Area

* rebind draw arrow shortcut to Alt+A

* remove auto hotkey

* shorten to "Select All"

* add back auto-hotkey
2024-12-16 03:55:47 +00:00
RickyRister
5f8bcbd02d Add keyboard shortcut for "hide" action (#5248)
* implement hide shortcut

* remove parens
2024-12-15 20:34:33 +00:00
RickyRister
a0f74134bb make card view window max initial height configurable (#5236) 2024-12-14 03:02:00 +00:00
Zach H
0463a6fd70 Support Windows Debug Builds (#5242) 2024-12-13 21:58:46 +00:00
RickyRister
a5de633c64 warn if "play top card until" filter expression doesn't match any card in database (#5243)
* make FilterString::check const

* implement thing
2024-12-13 21:58:29 +00:00
RickyRister
b2ad2acff3 improve FilterString validation error message (#5240) 2024-12-13 06:26:58 +00:00
dependabot[bot]
4ee6ff73e0 Bump nanoid from 3.3.4 to 3.3.8 in /webclient (#5239)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.4 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.4...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-13 04:45:05 +00:00
RickyRister
628bdde939 hide action now applies to all selected cards (#5233)
* hide action now applies to all selected cards

* check card zone before applying action

so that we don't nuke cards from existence when we select across multiple zones

* small fixes

* remove redundant loop

* nullcheck view
2024-12-13 04:42:53 +00:00
RickyRister
e9b78c1c59 "Play top cards until" action now has option for number of hits (#5229)
* create new dlg window

* get thing to work

* move validation into dlg

* remove nodiscard

I'll revert this if someone else complains
2024-12-12 14:03:42 +01:00
RickyRister
315cbc0925 fix remaining wonkiness with rewind buffering in replays (#5235) 2024-12-11 10:54:36 +01:00
ebbit1q
69741d858c fix crash using uninitialised memory from #5228 (#5237) 2024-12-11 01:19:53 +00:00
tooomm
20d99a78b6 pretty print translation files (#5234) 2024-12-09 23:46:57 +00:00
RickyRister
2d68393e07 dynamically resize scrollbar when zone view window is resized (#5228) 2024-12-09 19:01:37 +00:00
RickyRister
8cb1470643 add option to show keyboard shortcuts in right click menu (#5225) 2024-12-09 18:58:37 +00:00
dependabot[bot]
8d9b27bf47 Bump path-to-regexp and express in /webclient (#5226)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `path-to-regexp` from 0.1.10 to 0.1.12
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12)

Updates `express` from 4.21.0 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.0...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 18:54:47 +00:00
transifex-integration[bot]
0c5d9f1a7d Translate webclient/src/i18n-default.json in de (#5222)
100% translated source file: 'webclient/src/i18n-default.json'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-09 18:54:32 +00:00
transifex-integration[bot]
a7d88c06c1 Translate webclient/src/i18n-default.json in it (#5223)
100% translated source file: 'webclient/src/i18n-default.json'
on 'it'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-09 18:54:24 +00:00
transifex-integration[bot]
2735000fcf Translate webclient/src/i18n-default.json in pt_BR (#5224)
100% translated source file: 'webclient/src/i18n-default.json'
on 'pt_BR'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-09 18:54:15 +00:00
RickyRister
a39de270cd make rewind buffering timeout configurable (#5227)
* update settingsCache

* implement thing

* add new setting to window

* rename setting

* make it compile on qt5

* fix typo

* somehow changing the order here fixes a bug?

The loaded value was getting clamped to 99
2024-12-09 02:25:10 +00:00
tooomm
10f11213d3 fix indentation again (#5230) 2024-12-09 01:23:45 +00:00
tooomm
3b49cbf73b Rename label (#5232) 2024-12-09 01:23:27 +00:00
Zach H
e4cfe08113 Address weird crash case (#5221)
* Address weird crash case

* Address weird crash case

* remove const
2024-12-05 12:18:41 +01:00
transifex-integration[bot]
fa02cb885c Updates for project Cockatrice and language nl (#5220)
* Translate cockatrice/cockatrice_en@source.ts in nl

100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'nl'.

* Translate oracle/oracle_en@source.ts in nl

100% translated source file: 'oracle/oracle_en@source.ts'
on 'nl'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-03 16:17:54 +01:00
transifex-integration[bot]
69b864fa02 Translate cockatrice_en@source.ts in en_US (#5217)
100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-12-01 19:59:19 -05:00
J. Cameron McDonald
b9ed9a6c0b feat: set prioritization by set type (#5097)
* feat: prefer 'Core' and 'Expansion' sets for prioritization

* rework set prioritization

* clean up priority enum

* formatting

* revert changes to CockatriceXml3Parser

* re-add missing null check

* remove priority fallback ternary from CardSet model

* make defaultSort logic easier to follow

* revert changes to v3 card database xsd

* remove unused invisible priority col from sets dialog

* move draft innovation and duel deck sets to secondary prio

* minor fixes

* change PriorityFallback to 1

* make priority optional in xml

* remove PriorityUndefined and set PriorityFallback to 0

* set priority when not found to PriorityOther

in case a new set type is added it's unlikey we want it sorted first,
it'll probably be a new product so it's probably best to sort it with
the funny things

* simplify sort function

---------

Co-authored-by: tooomm <tooomm@users.noreply.github.com>
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2024-12-01 19:59:00 -05:00
RickyRister
5156495b47 add more sort options (#5214)
* distinguish between groupBy and sortBy options

* add more sort options
2024-11-30 22:32:39 -05:00
RickyRister
b92047bc3f rename and refactor some stuff in ZoneViewWidget (#5213)
* fix QComboBox creation order in retranslateUi

* move bottom row creation closer to where it's used

* rename QGraphicsLinearLayout variables

hFilterbox and hPilebox don't make much sense now

* add comment about #5204
2024-11-30 18:54:55 -05:00
RickyRister
70559d32df fix bug where card view window with single card is too short (#5211)
It was a divide by 0 bug lol
2024-11-30 08:53:30 -05:00
RickyRister
bb84b75db9 fix bug where card view window with pile view is too short (#5212) 2024-11-30 08:53:10 -05:00
transifex-integration[bot]
f634177973 Updates for project Cockatrice and language nl (#5170)
* Translate cockatrice/cockatrice_en@source.ts in nl

100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'nl'.

* Translate cockatrice/cockatrice_en@source.ts in nl

100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'nl'.

* Translate cockatrice/cockatrice_en@source.ts in nl

100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'nl'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-11-30 12:55:06 +01:00
Zach H
e33ff37c82 Pass QTime objects instead of references (#5209)
- References seem to go to 0 in newer Qt versions(?)

https://doc.qt.io/qt-6/qtime.html

> QTime objects should be passed by value rather than by reference to const; they simply package int.
2024-11-30 01:36:38 -05:00
RickyRister
d2bc7f6ac0 get retranslateUi to work with sort options (#5208) 2024-11-30 00:13:17 -05:00
RickyRister
5ef1ca06f5 store sort option in settings as QComboBox index instead of enum value (#5207)
* rename config property

* change default

* functional changes
2024-11-29 22:46:16 -05:00
Zach H
1d8651bc00 Fix Deck Popup Glitchy Rendering (#5204)
- QLabel sizes weren't taken into account until the widget is rendered
- Long QLabels can cause exacerbated issues
- Force refresh after 1ms to take QLabels into account
2024-11-29 12:53:19 -05:00
RickyRister
17eabf2004 add sort options to card view window (#5206)
* refactor to allow for sorting by property of choice

* implement thing

* prevent overlapping sort properties

* enable/disable pile view checkbox if groupBy is off

* fix compiler warnings

* check to disable pile view checkbox on init

* Fix builds on Qt5

* Fix builds on Qt5

---------

Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2024-11-29 12:53:06 -05:00
RickyRister
37bb1367db refactor method for positioning cards in ZoneViewZone (#5203)
* refactor out method for positioning cards in zone view

* rename some variables

* use max/min

* some small formatting stuff
2024-11-28 14:59:31 -05:00
RickyRister
24b5dab456 leave some documentation on Zone classes (#5199)
* leave some documentation on Zone classes

* small refactor

* undo functional change from refactor and clean up comments

* move variables into if block
2024-11-28 14:40:49 -05:00
Zach H
c6bfc8b8ea Fix Qt5 Slot/Signals for QCheckBoxes (#5201) 2024-11-27 22:11:55 +00:00
RickyRister
f2b0fa164e add padding to right side of card reveal window (#5198) 2024-11-27 00:17:37 -05:00
RickyRister
0ca8bdb3a8 refactor CardList (#5197) 2024-11-27 00:15:35 -05:00
RickyRister
a8471f62bc clean up DownloadSettings (#5194)
* refactor DownloadSettings

* only reset to default on first run

* use c++ foreach

* use addItems

* move default urls to static const
2024-11-26 02:12:56 +00:00
tooomm
5f1c03682f macOS version fix + wording (#5189) 2024-11-26 00:05:09 +01:00
RickyRister
3255ed3ffb add menu option to reload card db (#5196) 2024-11-25 07:43:08 +00:00
RickyRister
c51b54c0c5 rename variables for url list layout (#5195) 2024-11-25 06:27:21 +00:00
RickyRister
a3f0807d47 fix error message (#5192)
`QObject::connect: No such slot UserInterfaceSettingsPage::setNotificationEnabled(Qt::CheckState) in /Users/Ricky/GitHub/Cockatrice/cockatrice/src/dialogs/dlg_settings.cpp:448`
2024-11-24 14:52:56 +00:00
RickyRister
27055944df skip tap animation when rewinding (#5168) 2024-11-23 10:40:37 -05:00
Zach H
7b1653034b Bump macos14 XCode to 15.4 (#5188) 2024-11-22 22:52:42 -05:00
dependabot[bot]
39d8ca050f Bump cross-spawn from 7.0.3 to 7.0.6 in /webclient (#5181)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-22 22:22:36 -05:00
Zach H
50274cb66d Change 'custom(VER)' to 'custom-VER' because Fedora mad (#5180) 2024-11-22 22:22:22 -05:00
RickyRister
bd60a9fd2e don't blink highlighted phase when backwards skipping in replays (#5185) 2024-11-22 22:21:54 -05:00
BruebachL
83409c32c4 Cache redirects properly by implementing our own QSettings cache for urls. (#5186)
* Cache redirects properly by implementing our own QSettings cache for urls.

* Load and store redirects properly.

* Set the maximum network cache size from settings value on PictureLoaderWorker instantiation.

* Address comments.

* Lint.

* Adjust debug statements to be in line with existing ones.

* Minor Tweaks

* Make redirect cache ttl a user-adjustable setting.

* Fix Build

* Minor Cleanup

* Minor Cleanup

* Build Fix

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2024-11-22 22:21:26 -05:00
RickyRister
1bc92623dc add "open in new tab" button to decklist confirmation dialogue (#5183)
* refactor to use confirmOpen

* implement extra button in confirmation

* use brackets in one-liner if statements

* refactor save confirmation window into function
2024-11-21 23:24:50 +01:00
BruebachL
f73196841a Multiple Printings per Deck (#5171)
* Refactor CardInfo Widgets to reside in their appropriate folder and to have a clearer naming structure.

* Added Zach's work on storing printing information in the DeckList (#1)

* Change CardInfo's PixmapCacheKey to be the UUID of the preferred set after database loading has finished. Otherwise, and if no UUID of a preferred set is available, default to the card name.

* Refactor CardDatabase *db global variable to singleton CardDatabaseManager.

This commit refactors the global variable CardDatabase *db into a singleton encapsulated by the DatabaseManager class, accessible via DatabaseManager::getInstance(). This change centralizes access to the database instance, improving code modularity and encapsulation, resolving dependencies on main.h for code that requires access to the database instance.

- Added DatabaseManager class with getInstance() method returning a pointer to the singleton CardDatabase.
- Removed global db variable and updated references across the codebase.
 - Thread-safe static initialization for the singleton.

Impact: This refactor should have no functional impact on the application, as it maintains the same interface for accessing the CardDatabase instance. However, the codebase now benefits from improved encapsulation, lifetime management, and thread-safety.

* fixed db issue an renamed sets to set in picture loader

* canibalized zach work and added it to the decklist builder

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>

* Reintroduce some changes lost in the merge.

* Introduce UUID attribute to abstract_card_item, card_item, deck_view_card, server_card and serverinfo_card.

* Have various game events respect the new UUID attribute on instantiation.

* Correct some calls to default to preferred printing.

* DeckList now tries to assign reasonable defaults for UUID and collectorNumber if none are found in loaded DeckLists.
Rename overloaded DeckListModel findChild() function to findCardChildByNameAndUUID() for clarity.

* canibalized zach work and added it to the decklist builder

* Change getPreferredPrintingForCard to getPreferredSetForCard to reflect refactor.

* Properly update and set the DeckEditor's CardFrame to fetch by name and UUID if a card was selected from the decklist.

* Mainboard/Sideboard swaps should respect the UUID from the old zone instead of just blindly adding preferredPrinting.

* If the card info is null, there's no point in trying to look for the sets.

* Don't define methods twice.

* Convenience method to fetch a specific CardInfoPerSet instance for a cardName and a UUID.

* Check if the uuid starts with card_ when comparing.

* Address pull request comments (nullptr checks and additional comments, mostly.)

* Reformat code so the linter will stop yelling at me.

* DeckList no longer pre-populates uuids.

* Update Event_MoveCard to include the card UUID.

* Update Player::MoveCard to include the card UUID.

* Set the uuid when we set the cardName, in terms of hidden zones.

* [TEST/RevertMe] Set the uuid everywhere to test.

* Don't inline setUUID and mimic setName for AbstractCardItem.

* Revert blindly setting uuid for testing.

* Address PR comments (AbstractCardItem).

* Combine if-statement.

* Re-order uuid to visually align with its field number.

* Remove unnecessary new uuid field from event_move_card.

* Remove unused imports.

* Include cardName in the PixmapCacheKey in order to not break double-faced cards.

* Refactor setCode to cardUUID and introduce new cardSetShortName field.

* Override

* Refactor UUID to be providerId and change QString comparisons with empty string to isEmpty().

* Update translations.

* Change parent to be the first argument.

* Pull Parent argument up for CardItem.

* Pull Parent argument up for CardItem.

* Linter.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: LunaticCat <39006478+LunyaticCat@users.noreply.github.com>
Co-authored-by: luna <yannbrun1507@outlook.fr>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2024-11-18 21:56:44 -05:00
RickyRister
86a4b130ff don't open deck in new tab if current tab is blank (#5169) 2024-11-18 11:59:34 +01:00
tooomm
f4e2f117c3 Readme: Remove last Gitter hint (#5178) 2024-11-18 00:27:33 +01:00
BruebachL
8ef92d26c5 Add Utility Layouts and corresponding Widgets (#5177)
* Add FlowWidget class with flexible layout and scroll handling

- Implemented FlowWidget class to organize widgets in a flow layout with scrollable options.
- Integrated QScrollArea to handle overflow with configurable horizontal and vertical scroll policies.
- Incorporated dynamic layout selection (FlowLayout, HorizontalFlowLayout, VerticalFlowLayout) based on scroll policy.

* Add OverlapWidget and OverlapLayout for managing overlapping child widgets

- Implemented the OverlapWidget class to manage child widgets in an overlapping manner, supporting configurable overlap percentage, maximum columns, maximum rows, and layout direction.
- Introduced the OverlapLayout class, which arranges widgets with overlapping positions, allowing flexible stacking based on specified parameters.

* Add OverlapControlWidget.

* Delete FlowLayout items later to allow them to finish their event loop.

* Allow OverlapWidgets to adjust their rows/columns on resize.

* Clamp vertical FlowLayout to any available parent scrollAreas.

* Implement margins and spacing for FlowLayouts.

* Adjust/revert some things.

* Address pull request comments (nullptr checks and additional comments, mostly.)

* Reformat code so the linter will stop yelling at me.

* Remove undefined methods from FlowLayouts.

* Fix the build.

* Revert FlowLayout::takeAt to index check.

* Commits will continue until linter morale improves.

* Fix various warnings in FlowLayout.

* Fix various warnings in FlowLayout.h.

* Fix various warnings in the FlowLayout classes.

* Fix [[nodiscard]] warning.

* Fix more warnings.

* Final round of yellow squiggle fixing.

* Linter formatting.

* Refactor column/row calculation to be more readable.

* Code style.

* Address PR comments.

* Combine if-statements.

* Replace std::math functions with Qt equivalents.

* Fix non-consts and QtMath.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-11-17 13:32:31 -05:00
BruebachL
c8336df49d Refactor Card Info Widgets (#5176)
* Refactor CardInfo Widgets to reside in their appropriate folder and to have a clearer naming structure.

* Add optional HoverToZoom functionality to CardInfoPictureWidget (default: disabled) and utility class to display text over a CardInfoPictureWidget.

* Patch CardInfoWidgets to use the new CardDatabaseManager.

* Add HoverToZoom to CardInfoPictureWithTextOverlayWidget

* Refactors and new signals for CardInfoPictureWidgets.

* Address pull request comments (nullptr checks and additional comments, mostly.)

* Reformat code so the linter will stop yelling at me.

* Linting.

* Fix the build.

* Fix warnings.

* Formatting, const qualifiers.

* Sensibly call the base class's (QWidget) paint event.

* Address PR comments (card picture).

* QT Version check because enterEvent signature changed.

* Linting.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-11-17 10:49:22 -05:00
RickyRister
c2fe3cda35 Add option to open deck in new tab by default (#5143)
* add comments

* add new setting for openDeckInNewTab

* implement open deck in new tab

* rename setting

* fix typo

* set default to false
2024-11-10 18:16:50 -05:00
BruebachL
c54f47efbf Change CardInfo's PixmapCacheKey to be the UUID of the card in the preferred set after database loading has finished. Otherwise, and if no UUID of a preferred set is available, default to the card name. (#5158)
* Change CardInfo's PixmapCacheKey to be the UUID of the preferred set after database loading has finished. Otherwise, and if no UUID of a preferred set is available, default to the card name.

* Clean up some variable names, clarify preferred Set insertion for PictureLoader, use the new CardDatabaseManager.

* Code formatting.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-11-10 17:49:11 -05:00
lumadd
3c40cc4b7d [4191] fix: Move unfocusTextBox and aFocusChat shortcuts to Player group (#5079)
* [4191] fix: Move unfocusTextBox and aFocusChat shortcuts to Player family

* [4191] fix: fix formatting

* Revert "[4191] fix: fix formatting"

This reverts commit 86a4a675f3bc8118d4ba8dd45f408c4e8c348f33.

* Revert "[4191] fix: Move unfocusTextBox and aFocusChat shortcuts to Player family"

This reverts commit 3ec183628df81c48123a8a248d0416c529ee0c8e.

* [4191] fix: Textbox and tab_game shortcut groups cannot conflict with Player group

* Revert "[4191] fix: Textbox and tab_game shortcut groups cannot conflict with Player group"

This reverts commit 36800393339d997df1a932bb798f95d2d387399a.

* [4191] fix: Move unfocusTextBox and aFocusChat shortcuts to Player family

* [4191] fix: Migrate shortcuts if new version is detected

* [4191] fix: formatting

* [4191] fix: Maybe fix build issue on Windows7, Debian11, UbuntuBionic and UbuntuFocal
2024-11-09 19:56:42 +01:00
RickyRister
f0fb77bade move replay-related constants into ReplayTimelineWidget (#5166)
* move constants

* make the existing static const into a constexpr
2024-11-09 11:18:51 +01:00
RickyRister
e894e78346 Do not open card reveal windows when skipping in replays (#5157)
* create EventProcessingOption QFlag

* pass EventProcessingOption all the way down

* implement reveal skipping logic
2024-11-09 02:06:23 +01:00
SlightlyCircuitous
dd04c610ec Remove Fedora 39 Build and Add Fedora 41 Build (#5151)
* Remove Fedora 39 docker file

EOL

* Add Fedora 41 Dockerfile

new release

* Remove Fedora 39, Add Fedora 41 to release template

* Remove Fedora 39, Add Fedora 41 to desktop build

---------

Co-authored-by: tooomm <tooomm@users.noreply.github.com>
2024-11-08 11:32:54 +01:00
tooomm
2e674efe50 Pretty print translation source (#5107) 2024-11-05 22:26:54 +01:00
ebbit1q
4d394c31f9 fix the timezones used for the user info box and add comments (#5162) 2024-11-05 14:54:38 -05:00
tooomm
11d58abbc3 CI: Update build matrix & clean naming (#5040)
---------

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2024-11-05 14:38:33 -05:00
BruebachL
5f4ad87a47 Refactor CardDatabase *db global variable to singleton CardDatabaseManager. (#5159)
* Refactor CardDatabase *db global variable to singleton CardDatabaseManager.

This commit refactors the global variable CardDatabase *db into a singleton encapsulated by the DatabaseManager class, accessible via DatabaseManager::getInstance(). This change centralizes access to the database instance, improving code modularity and encapsulation, resolving dependencies on main.h for code that requires access to the database instance.

- Added DatabaseManager class with getInstance() method returning a pointer to the singleton CardDatabase.
- Removed global db variable and updated references across the codebase.
 - Thread-safe static initialization for the singleton.

Impact: This refactor should have no functional impact on the application, as it maintains the same interface for accessing the CardDatabase instance. However, the codebase now benefits from improved encapsulation, lifetime management, and thread-safety.

* Refactor CardDatabase *db global variable to singleton CardDatabaseManager.

This commit refactors the global variable CardDatabase *db into a singleton encapsulated by the DatabaseManager class, accessible via DatabaseManager::getInstance(). This change centralizes access to the database instance, improving code modularity and encapsulation, resolving dependencies on main.h for code that requires access to the database instance.

- Added DatabaseManager class with getInstance() method returning a pointer to the singleton CardDatabase.
- Removed global db variable and updated references across the codebase.
 - Thread-safe static initialization for the singleton.

Impact: This refactor should have no functional impact on the application, as it maintains the same interface for accessing the CardDatabase instance. However, the codebase now benefits from improved encapsulation, lifetime management, and thread-safety.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-11-05 19:32:59 +01:00
RickyRister
e43a21866c Buffer rewinds from backward skips in replays (#5141)
* split event processing to own method

* implement rewind throttling

* don't throttle backward skips from clicks

* use the term 'buffering' instead

* remove initial backup logic; just always buffer shortcut backward skips

* prevent segfault

* turns out you can just reuse the same one-shot timer

* try scaling timeout based on event count

* rewrite timeout calculation code

* fix linker error
2024-11-05 18:45:42 +01:00
RickyRister
6652012f4c fix bug with phase highlighting in replays (#5161)
* fix bug with incorrectly highlighted phases

* fix new bug with phases continuously darkening

* use preincrement instead of postincrement

* simplify conditional
2024-11-05 18:23:01 +01:00
BruebachL
0c4e8ca290 CardDatabase gains a new signal void cardDatabaseLoadingFinished(), which (#5156)
it will emit in loadCardDatabases(), mirroring the else branch where cardDatabaseLoadingFailed() is emitted.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2024-11-03 23:45:19 +01:00
ebbit1q
230a2c5c62 fix crashes in local games because of using uninitialised pointers (#5147) 2024-10-26 21:03:32 +00:00
ebbit1q
590fb7f533 fix row colors swapping when using back button in replays (#5148)
only happens when there is an uneven amount of rows in the chat
2024-10-26 21:02:51 +00:00
github-actions[bot]
e8b88248f2 Update translation files (#5146) 2024-10-26 19:11:24 +02:00
transifex-integration[bot]
c6ba1b6a4e Translate cockatrice/cockatrice_en@source.ts in de (#5145)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-10-26 14:11:18 +02:00
RickyRister
c4c52bd8c0 Add keyboard shortcuts for skipping forward/backward in replays (#5140)
* split skipToTime into own function

* implement shortcut

* fix shortcut warning bug

* check boundary conditions in skipToTime

* change default fast forward shortcut to .

* implement big skip shortcuts

* remove unnecessary arg in lambda

* change default fast forward shortcut to Ctrl+F

* rename constants

* change default fast forward shortcut to Ctrl+P

* use static const
2024-10-23 14:00:23 +02:00
tooomm
c633a792f5 bump version (#5099) 2024-10-21 18:57:47 -04:00
Zach H
8d5421d9da Add backwards support Qt6.7's checkStateChanged on QCheckBoxes (#5137) 2024-10-20 23:35:34 -04:00
github-actions[bot]
b041f4ace2 Update translation source strings (#5117)
Co-authored-by: github-actions <github-actions@github.com>
2024-10-20 16:18:32 -04:00
RickyRister
d26f96db9e Add keyboard shortcuts for replays (#5136)
* add keyboard shortcut for play/pause

* add keyboard shortcut for fast-forward

* make shortcuts rebindable

* run formatter
2024-10-20 16:41:59 +02:00
LunaticCat
fa999880ee Major Directory Refactoring (#5118)
* refactored cardzone.cpp, added doc and changed if to switch case

* started moving every files into different folders

* remove undercase to match with other files naming convention

* refactored dialog files

* ran format.sh

* refactored client/tabs folder

* refactored client/tabs folder

* refactored client/tabs folder

* refactored client folder

* refactored carddbparser

* refactored dialogs

* Create sonar-project.properties

temporary file for lint

* Create build.yml

temporary file for lint

* removed all files from root directory

* removed all files from root directory

* added current branch to workflow

* fixed most broken import

* fixed issues while renaming files

* fixed oracle importer

* fixed dbconverter

* updated translations

* made sub-folders for client

* removed linter

* removed linter folder

* fixed oracle import

* revert card_zone documentation

* renamed db parser files name and deck_view imports

* fixed dlg file issue

* ran format file and fixed test file

* fixed carddb test files

* moved player folder in game

* updated translations and format files

* fixed peglib import

* format cmake files

* removing vcpkg to try to add it back later

* tried fixing vcpkg file

* renamed filter to filters and moved database parser to cards folder

* reverted translation files

* reverted oracle translated

* Update cockatrice/src/dialogs/dlg_register.cpp

Co-authored-by: tooomm <tooomm@users.noreply.github.com>

* Update cockatrice/src/client/ui/window_main.cpp

Co-authored-by: tooomm <tooomm@users.noreply.github.com>

* removed empty line at file start

* removed useless include from tab_supervisor.cpp

* refactored cardzone.cpp, added doc and changed if to switch case

* started moving every files into different folders

* remove undercase to match with other files naming convention

* refactored dialog files

* ran format.sh

* refactored client/tabs folder

* refactored client folder

* refactored carddbparser

* refactored dialogs

* removed all files from root directory

* Create sonar-project.properties

temporary file for lint

* Create build.yml

temporary file for lint

* added current branch to workflow

* fixed most broken import

* fixed issues while renaming files

* fixed oracle importer

* fixed dbconverter

* updated translations

* made sub-folders for client

* removed linter

* removed linter folder

* fixed oracle import

* revert card_zone documentation

* renamed db parser files name and deck_view imports

* fixed dlg file issue

* ran format file and fixed test file

* fixed carddb test files

* moved player folder in game

* updated translations and format files

* fixed peglib import

* reverted translation files

* format cmake files

* removing vcpkg to try to add it back later

* tried fixing vcpkg file

* pre-updating of cockatrice changes

* removed empty line at file start

* reverted oracle translated

* Update cockatrice/src/dialogs/dlg_register.cpp

Co-authored-by: tooomm <tooomm@users.noreply.github.com>

* Update cockatrice/src/client/ui/window_main.cpp

Co-authored-by: tooomm <tooomm@users.noreply.github.com>

* removed useless include from tab_supervisor.cpp

---------

Co-authored-by: tooomm <tooomm@users.noreply.github.com>
2024-10-20 10:11:35 -04:00
RickyRister
d1e0f9dfc5 fix bug (#5133) 2024-10-19 20:18:35 -04:00
RickyRister
2d86938375 Consolidate play/pause buttons in replays (#5131)
* Consolidate play/pause buttons in replays

* always enable fast forward button

* run formatter
2024-10-19 20:18:01 -04:00
ebbit1q
4865269a73 don't delete "" (#5135) 2024-10-19 13:06:18 +02:00
dependabot[bot]
038ce3dcec Bump send and express in /webclient (#5123)
Bumps [send](https://github.com/pillarjs/send) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.18.2 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.21.0)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-11 04:28:41 +00:00
RickyRister
43b997fe40 follow symlinks when iterating through the custom image folder (#5126) 2024-10-11 04:27:24 +00:00
Polty
44e92f61ca #3945 deck list: Navigation keys (PageUp/Down, Home/End) (#5103)
* #3945 deck list: Navigation keys (PageUp/Down, Home/End) interact with the deck list.

* make Home/End work normally when there is text in the search textbox

* fix debug build, explicit cast from int to Qt::Key enum
2024-10-09 23:11:12 +02:00
Alexander Choi
b4bfa17cee In-game message macros available immediately in active games (#5113)
* In-game message macros available immediately in active games

* fix formatting

* init sayMenu actions with sayMenu as parent
2024-10-09 23:08:57 +02:00
tooomm
500b694cc6 CI: Fix logic in translation action after dependency update (#5124)
* Update translations-pull.yml

* Update translations-push.yml
2024-10-07 18:48:43 +00:00
dependabot[bot]
b998282304 Bump peter-evans/create-pull-request from 6 to 7 (#5110)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6 to 7.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v6...v7)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 20:05:44 +02:00
Alexander Choi
b704216553 fix macro shortcuts so that Ctrl+1 is not double-assigned (#5112) 2024-09-15 16:55:30 -04:00
transifex-integration[bot]
03ec02a749 Translate oracle/oracle_en@source.ts in fi (#5100) 2024-08-30 13:16:22 +02:00
Zach H
248ea82573 Support Game Events (#5087) 2024-08-25 00:31:20 +00:00
ebbit1q
bbe125beee replace cipt check with regex (#5094) 2024-08-25 00:31:01 +00:00
tooomm
95cd1c6f87 CI: Update install-qt-action (#5096) 2024-08-22 01:22:57 +02:00
J. Cameron McDonald
1c2107ae8f docs: fix readme "get involved" links (#5098) 2024-08-17 23:46:16 +02:00
ebbit1q
e826e17c6c add qtimageformats module (#5092)
* add qtimageformats module

* add qt6-image-formats-plugins to apt depends in cmakelists

* too many quotes

* add qt6-qtimageformats to rpm deps
2024-08-16 22:32:22 -04:00
Joseph Insalaco
b111f0921c Admin persistence changes (#5086) 2024-08-16 22:31:57 -04:00
transifex-integration[bot]
090a48515c Updates for project Cockatrice and language en_US (#5088)
* Translate cockatrice_en@source.ts in en_US

100% translated source file: 'cockatrice_en@source.ts'
on 'en_US'.

* Translate oracle/oracle_en@source.ts in en_US

100% translated source file: 'oracle/oracle_en@source.ts'
on 'en_US'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-08-03 14:29:28 +02:00
transifex-integration[bot]
b8555d8c42 Translate cockatrice/cockatrice_en@source.ts in nl (#5089)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'nl'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-08-03 14:16:42 +02:00
Joseph Insalaco
cf1f4f12a9 Updating Session Persistence with all valid persistence calls (#5085)
* Updating Session Persistence with all valid persistence calls

* Spacing fixes

---------

Co-authored-by: Zach H <zahalpern+github@gmail.com>
2024-07-29 17:25:33 +00:00
ebbit1q
ef4413633a fix regression in #4762 to _fill_with_ template (#5083)
fixes #5062
2024-07-29 01:20:50 +00:00
Zach H
c5bb38e907 Add types for Moderator commands (#5084)
* Add types for Moderator commands

* Support User Priv Level & userLevel
2024-07-29 01:16:29 +00:00
github-actions[bot]
9f515fc804 Update translation files (#5080) 2024-07-23 11:53:07 +02:00
Zach H
245edcefdd Add openssl to windows reqs (#5074) 2024-07-13 12:38:43 -04:00
transifex-integration[bot]
153f73c308 Translate cockatrice/cockatrice_en@source.ts in de (#5073)
100% translated source file: 'cockatrice/cockatrice_en@source.ts'
on 'de'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2024-07-13 13:11:03 +00:00
github-actions[bot]
315837b267 Update translation source strings (#5069)
Co-authored-by: github-actions <github-actions@github.com>
2024-07-01 19:04:16 +02:00
Joseph Insalaco
ea8da24215 Webatrice: Adding joined game to persistence layer (#5068)
* Adding joined game to persistence layer

* Linting fixes
2024-06-27 02:06:47 +00:00
Joseph Insalaco
1ab723ca64 Webatrice: Adding game created to persistence layer (#5067) 2024-06-27 01:03:21 +00:00
Joseph Insalaco
f8bc6cf998 Adding remove messages to persistence layer (#5066) 2024-06-27 00:44:40 +00:00
Zach H
8687163cca Add few more interfaces (#5063) 2024-06-25 05:00:45 +00:00
Zach H
e261e16d99 Re-Add ability to share editable deck views (#5060)
- Rolls back 6811819161
- Follow up to adbb607700
2024-06-24 21:52:11 +00:00
Jeremy Letto
bdcd083eea refactor imports (#5058) 2024-06-17 01:00:23 -04:00
Zach H
c4bf9eb61c Cleanup (#5057)
* Add Types

* Add Types
2024-06-17 00:32:36 -04:00
Zach H
0994d10410 More stuff (#5056)
* Skeleton + RemoveMessages

* GameJoinedData
2024-06-16 23:26:03 -04:00
Zach H
291c535edb More web stuff (#5055)
* Add Response.gamesOfuser

* Cleanup and confirm all
2024-06-16 22:48:07 -04:00
ZeldaZach
f04702fdd1 Backwards Compatibility for rolling dice 2024-06-16 21:10:07 -04:00
Zach H
b7fbc12ac0 Allow Judges to see all information, regardless of room settings (#5053) 2024-06-16 19:12:37 -04:00
753 changed files with 126890 additions and 61344 deletions

View File

@@ -1,4 +1,4 @@
FROM fedora:39
FROM fedora:41
RUN dnf install -y \
ccache \

View File

@@ -1,4 +1,4 @@
FROM ubuntu:focal
FROM ubuntu:20.04
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \

View File

@@ -1,4 +1,4 @@
FROM ubuntu:jammy
FROM ubuntu:22.04
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \

View File

@@ -1,4 +1,4 @@
FROM ubuntu:noble
FROM ubuntu:24.04
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \

View File

@@ -1,25 +0,0 @@
FROM ubuntu:bionic
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ccache \
clang-format \
cmake \
file \
g++ \
git \
liblzma-dev \
libmariadb-dev-compat \
libprotobuf-dev \
libqt5multimedia5-plugins \
libqt5sql5-mysql \
libqt5svg5-dev \
libqt5websockets5-dev \
protobuf-compiler \
qt5-default \
qt5-image-formats-plugins \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -189,6 +189,12 @@ fi
if [[ $MAKE_PACKAGE ]]; then
echo "::group::Create package"
if [[ $RUNNER_OS == macOS ]]; then
# Workaround https://github.com/actions/runner-images/issues/7522
echo "killing XProtectBehaviorService"; sudo pkill -9 XProtect >/dev/null || true;
echo "waiting for XProtectBehaviorService kill"; while pgrep "XProtect"; do sleep 3; done;
fi
cmake --build . --target package --config "$BUILDTYPE"
echo "::endgroup::"

17
.ci/macos.entitlements Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<false/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.disable-executable-page-protection</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>

View File

@@ -4,24 +4,30 @@
git push -d origin --REPLACE-WITH-BETA-LIST--
-->
<!-- This list of binaries should be updated every time the ci is changed to
include different targets -->
<!-- This list of binaries should be updated every time the CI is changed to include all targets -->
<pre>
<b>Pre-compiled binaries we serve:</b>
- <kbd>Windows 7+</kbd>
- <kbd>Windows 10+</kbd>
- <kbd>macOS 10.15+</kbd> ("Catalina")
- <kbd>macOS 13+</kbd> ("Ventura")
- <kbd>Ubuntu 18.04 LTS</kbd> ("Bionic Beaver")
- <kbd>Ubuntu 20.04 LTS</kbd> ("Focal Fossa")
- <kbd>Ubuntu 22.04 LTS</kbd> ("Jammy Jellyfish")
- <kbd>Ubuntu 24.04 LTS</kbd> ("Noble Numbat")
- <kbd>Debian 11</kbd> ("Bullseye")
- <kbd>Debian 12</kbd> ("Bookworm")
- <kbd>Fedora 39</kbd>
- <kbd>Fedora 40</kbd>
<kbd>We are also packaged in Arch Linux's official community repository, courtesy of @FFY00</kbd></i>
<kbd>General Linux support is available via a flatpak package (Flathub)</kbd></i>
Available pre-compiled binaries for installation:
<b>Windows</b>
<kbd>Windows 10+</kbd>
<kbd>Windows 7+</kbd>
<b>macOS</b>
<kbd>macOS 15+</kbd> <sub><i>Sequoia</i></sub> <sub>Apple M</sub>
<kbd>macOS 14+</kbd> <sub><i>Sonoma</i></sub> <sub>Apple M</sub>
<kbd>macOS 13+</kbd> <sub><i>Ventura</i></sub> <sub>Intel</sub>
<b>Linux</b>
<kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
• <kbd>Ubuntu 22.04 LTS</kbd> <sub><i>Jammy Jellyfish</i></sub>
• <kbd>Ubuntu 20.04 LTS</kbd> <sub><i>Focal Fossa</i></sub>
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
• <kbd>Debian 11</kbd> <sub><i>Bullseye</i></sub>
• <kbd>Fedora 41</kbd>
• <kbd>Fedora 40</kbd>
<sub>We are also packaged in <kbd>Arch Linux</kbd>'s <a href="https://archlinux.org/packages/extra/x86_64/cockatrice">official extra repository</a>, courtesy of @FFY00.</sub>
<sub>General Linux support is available via a <kbd>flatpak</kbd> package at <a href="https://flathub.org/apps/io.github.Cockatrice.cockatrice">Flathub</a>!</sub>
</pre>
@@ -29,22 +35,24 @@ include different targets -->
We're pleased to announce the newest official release: <kbd>--REPLACE-WITH-RELEASE-TITLE--</kbd>
We hope you enjoy the changes made and we have listed all changes, with their corresponding tickets, since the last version of Cockatrice was released for your convenience.
We hope you enjoy the changes made! All improvements with their corresponding tickets since the last version of Cockatrice are listed in the changelog below.
If you ever encounter a bug, have a suggestion or idea, or feel a need for a developer to look into something, please feel free to [open a ticket](https://github.com/Cockatrice/Cockatrice/issues). ([How to create a GitHub Ticket for Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/How-to-Create-a-GitHub-Ticket-Regarding-Cockatrice))
If you ever encounter a bug, have a suggestion or idea, or feel a need for a developer to look into something, please feel free to [open a ticket](https://github.com/Cockatrice/Cockatrice/issues). ([How to create a Ticket for Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/How-to-Create-a-GitHub-Ticket-Regarding-Cockatrice))
For any information relating to Cockatrice, please take a look at our official site: **https://cockatrice.github.io**
For basic information related to the app and getting started, please take a look at our official site: **https://cockatrice.github.io**
If you'd like to help contribute to Cockatrice in any way, check out our [README](https://github.com/Cockatrice/Cockatrice#get-involved-). We're always available to answer questions you may have on how the program works and how you can provide a meaningful contribution.
If you'd like to help and contribute to Cockatrice in any way, check out our [README](https://github.com/Cockatrice/Cockatrice#get-involved-).
We're always available to answer questions you may have on how the program works and how you can provide a meaningful contribution.
## Upgrading Cockatrice
<!-- this optional section puts a warning banner for problems with updating
> ⚠️ **With this release, we no longer provide a ready-to-install binary for:**
> [!IMPORTANT]
> **With this release, we no longer provide a ready-to-install binary for:**
> --DEPRECATED-OS-HERE--
-->
- Run the internal software updater: <kbd>Help → Check for Client Updates</kbd>
Run the internal software updater: <kbd>Help → Check for Client Updates</kbd>
Don't forget to update your card database right after! (<kbd>Help → Check for Card Updates...</kbd>)
@@ -61,14 +69,14 @@ Remove empty headers when done.
-->
<!-- Highlights of the release -->
### ⚠️ Important:
### 🔖 Highlights:
### ✨ New Features:
### 🐛 Fixed Bugs / Resolved issues:
### 🐛 Fixed Bugs / Resolved Issues:
<!-- Complete list of changes (foldable) -->
<details>
<summary>
📘 <b>Show all changes</b> (--REPLACE-WITH-COMMIT-COUNT-- commits)
<b>Show all changes</b> (--REPLACE-WITH-COMMIT-COUNT-- commits)
</summary>
### User Interface
@@ -89,5 +97,6 @@ Remove empty headers when done.
## Special Thanks
<!-- Personalise this a bit! -->
We continue to find it amazing that so many people contribute their time, knowledge, code, testing and more to the project. We'd like to thank the entire Cockatrice community for their efforts.
It's amazing that so many people contribute their time, knowledge, code, testing and more to the project.
We'd like to thank the entire Cockatrice community for their efforts! 🙏
<!-- We'd like to especially recognize @ZeldaZach, --ADD-CONTRIBUTORS-HERE-- for their help in preparing so many amazing new features for the user base. -->

View File

@@ -7,32 +7,33 @@
<br>
# Contributing to Cockatrice #
First off, thanks for taking the time to contribute to our project! 🎉 ❤ ️✨
The following is a set of guidelines for contributing to Cockatrice. These are
mostly guidelines, not rules. Use your best judgment, and feel free to propose
changes to this document in a pull request.
First off, thanks for taking the time and considering to lend a helping hand to our project! 🎉 ❤ ️✨
> [!NOTE]
> The following is a set of guidelines for contributing to Cockatrice.
> These are mostly guidelines, not rules. Use your best judgment, and feel free to
> propose changes to this document in a pull request.
>
> [![Discord](
> https://img.shields.io/discord/314987288398659595?label=Discord&logo=discord&logoColor=white)](
> https://discord.gg/3Z9yzmA)
> If you'd like to ask questions, get advice, or just want to say "Hi",
> the Cockatrice Development Team uses [Discord](https://discord.gg/ZASRzKu)
> for communications and you can reach out in the `#dev` channel.
# Recommended Setups #
For those developers who like the Linux or MacOS environment, many of our
For those developers on **Linux** or **macOS** environment, many of our
developers like working with a nifty program called [CLion](
https://www.jetbrains.com/clion/). The program's a great asset and one of the
best tools you'll find on these systems, but you're welcomed to use any IDE
you most enjoy.
https://www.jetbrains.com/clion/). The program is a great asset and one of the
best tools you'll find on these systems.
Developers who like Windows development tend to find [Visual Studio](
Developers on **Windows** systems tend to find [Visual Studio](
https://www.visualstudio.com/) the best tool for the job.
[![Discord](https://img.shields.io/discord/314987288398659595?label=Discord&logo=discord&logoColor=white&color=7289da)](https://discord.gg/ZASRzKu)
[![Gitter Chat](https://img.shields.io/gitter/room/Cockatrice/Cockatrice.svg)](https://gitter.im/Cockatrice/Cockatrice)
If you'd like to ask questions, get advice, or just want to say hi,
the Cockatrice Development Team uses [Discord](https://discord.gg/ZASRzKu)
for communications in the #dev channel. If you're not into Discord, we also
have a [Gitter](https://gitter.im/Cockatrice/Cockatrice) channel available,
albeit slightly less active.
But you're welcomed to use any IDE you enjoy most of course!
# Code Style Guide #
@@ -54,7 +55,7 @@ The message will look like this:
*** Then commit and push those changes to this branch. ***
*** Check our CONTRIBUTING.md file for more details. ***
*** ***
*** Thank you ❤️ ***
*** Thank you ❤️ ***
*** ***
***********************************************************
```
@@ -64,7 +65,7 @@ information on our formatting guidelines.
### Compatibility ###
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>.
Cockatrice is currently compiled on all platforms using <kbd>C++20</kbd>.
You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free
to help convert it over!
@@ -78,11 +79,12 @@ or other appropriate conversion.
### Formatting ###
The handy tool `clang-format` can format your code for you, it is available for
almost any environment. A special `.clang-format` configuration file is
almost any environment. A special [`.clang-format`](
https://github.com/Cockatrice/Cockatrice/blob/master/.clang-format) configuration file is
included in the project and is used to format your code.
We've also included a bash script, `format.sh`, that will use clang-format to
format all files in your pr in one go. Use `./format.sh --help` to show a full
format all files in your PR in one go. Use `./format.sh --help` to show a full
help page.
To run clang-format on a single source file simply use the command
@@ -90,10 +92,10 @@ To run clang-format on a single source file simply use the command
clang-format with a specific version number appended,
`find /usr/bin -name clang-format*` should find it for you)
See [the clang-format documentation](
See the [clang-format documentation](
https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
#### Header files ####
#### Header Files ####
Use header files with the extension `.h` and source files with the extension
`.cpp`.
@@ -168,10 +170,10 @@ braces around single line statements is preferred.
See the following example:
```c++
int main()
{ // function or class: own line
if (someCondition) { // control statement: same line
doSomething(); // single line statement, braces preferred
} else if (someOtherCondition1) { // else goes on the same line as a closing brace
{ // function or class: own line
if (someCondition) { // control statement: same line
doSomething(); // single line statement, braces preferred
} else if (someOtherCondition1) { // else goes on the same line as a closing brace
for (int i = 0; i < 100; i++) {
doSomethingElse();
}
@@ -234,7 +236,7 @@ mutating objects.)
When pointers can't be avoided, try to use a smart pointer of some sort, such
as `QScopedPointer`, or, less preferably, `QSharedPointer`.
### Database migrations ###
### Database Migrations ###
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
Everytime the schema gets modified, some other steps are due:
@@ -255,7 +257,7 @@ Ensure that the migration produces the expected effects; e.g. if you add a
new column, make sure the migration places it in the same order as
servatrice.sql.
### Protocol buffer ###
### Protocol Buffer ###
Cockatrice and Servatrice exchange data using binary messages. The syntax of
these messages is defined in the `proto` files in the `common/pb` folder. These
@@ -268,6 +270,7 @@ new clients incompatible to the old server and vice versa.
You can find more information on how we use Protobuf on [our wiki!](
https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
# Reviewing Pull Requests #
After you have finished your changes to the project you should put them on a
@@ -286,6 +289,7 @@ all changes have been approved your pull request will be squashed into a single
commit and merged into the master branch by a team member. Your change will then
be included in the next release 👍
# Translations #
Basic workflow for translations:
@@ -294,16 +298,16 @@ Basic workflow for translations:
3. Maintainer verifies and merges the change;
4. Transifex picks up the new files from GitHub automatically;
5. Translators translate the new untranslated strings on Transifex;
6. Before a release, a maintainer fetches the updated translations from Transifex.
6. Before a release, a maintainer fetches the newest translations from Transifex.
### Using Translations (for developers) ###
All user interface strings inside Cockatrice's source code must be written
in English (US).
Translations to other languages are managed using [Transifex](
https://www.transifex.com/projects/p/cockatrice/).
https://transifex.com/cockatrice/cockatrice/).
Adding a new string to translate is as easy as adding the string in the
Adding a new string for translation is as easy as adding the string in the
`tr("")` function, the string will be picked up as translatable automatically
and translated as needed.
For example, setting the text of a label in the way that the string
@@ -315,9 +319,9 @@ nameLabel.setText(tr("My name is:"));
To translate a string that would have plural forms you can add the amount to
the tr() call, also you can add an extra string as a hint for translators:
```c++
QString message = tr("Everyone draws %n cards", "pop up message", amount);
QString message = tr("Everyone draws %n cards", "english hint for translators", amount);
```
See [QT's wiki on translations](
See [Qt's wiki on translations](
https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals)
If you're about to propose a change that adds or modifies any translatable
@@ -325,7 +329,7 @@ string in the code, you don't need to take care of adding the new strings to
the translation files.<br>
We have an automated process to update our language source files on a schedule
and provide the translators on Transifex with the new contents.<br>
Maintainers can also manually trigger this on demand.
Maintainers can also manually trigger this workflow on demand via GitHub Actions.
### Maintaining Translations (for maintainers) ###
@@ -389,27 +393,27 @@ Now you are ready to commit your changes and open a PR.
</details>
Once the changes get merged, Transifex will pick up the modified files
automatically (checked every few hours) and update their online editor where
automatically (checked every few hours) and update the web editor where
translators will be able to translate the new strings right in the browser.
### Releasing Translations (for maintainers) ###
Before rushing out a new release, a maintainer should fetch the most up to date
Before publishing a new release, a maintainer should fetch the most up to date
translations from Transifex and commit them into the Cockatrice source code.
This can be done manually from the Transifex web interface, but it's quite time
consuming.
As an alternative, you can install the Transifex CLI:
http://docs.transifex.com/developer/client/
We utilize the official GitHub integration to push all languages that are 100%
translated from Transifex to our GitHub repo automatically.
On top, it runs on a quarterly schedule to update changes for incomplete languages.
A synchronisation/update can also be triggered manually from the Transifex web interface
and a translation treshold can be set.
As an alternative, you can install the [Transifex CLI](https://developers.transifex.com/docs/cli).
You'll then be able to use a git-like cli command to push and pull translations
from Transifex to the source code and vice versa.
### Adding Translations (for translators) ###
As a translator you can help translate the new strings on [Transifex](
https://www.transifex.com/projects/p/cockatrice/).
As a translator, you can help to translate new strings on [Transifex](
https://www.transifex.com/projects/p/cockatrice/) to your native language.
Please have a look at the specific [FAQ for translators](
https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
@@ -419,9 +423,9 @@ https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
### Publishing A New Release ###
We use [GitHub Releases](https://github.com/Cockatrice/Cockatrice/releases) to
publish new stable versions and betas.
Whenever a git tag is pushed to the repository github will create a draft
release and upload binaries automatically.
publish new stable versions and beta releases.
Whenever a git tag is pushed to the repository, GitHub will create a draft
release and upload binaries from our CI automatically.
To create a tag, simply do the following:
```bash
@@ -433,18 +437,16 @@ git push $UPSTREAM $TAG_NAME
```
You should define the variables as such:
```
`$UPSTREAM` - the remote for git@github.com:Cockatrice/Cockatrice.git
`$TAG_NAME` should be formatted as:
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
With *MAJ.MIN.PATCH* being the NEXT release version!
```
- `$UPSTREAM`: the remote for `git@github.com:Cockatrice/Cockatrice.git`
- `$TAG_NAME` should be formatted as:
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
With <kbd>MAJ</kbd>.<kbd>MIN</kbd>.<kbd>PATCH</kbd> being the NEXT release version!
This will cause a tagged release to be established on the GitHub repository,
with the binaries being added to the release whenever they are ready.
The release is initially a draft, where the path notes can be edited and after
all is good and ready it can be published on GitHub.
with the binaries being added to the release whenever they are done building in CI.
The release is initially a draft, where the release notes can be edited and after
all is checked and ready, it can be published as GitHub release.
If you use a SemVer tag including "beta", the release that will be created at
GitHub will be marked as a "Pre-release" automatically.
The target of the `.../latest` URL will not be changed in that case, it always
@@ -457,7 +459,7 @@ revoke the tag by doing the following:
git push --delete upstream $TAG_NAME
git tag -d $TAG_NAME
```
You can also do this on GitHub, you'll also want to delete the new release.
You can also do this on GitHub, you'll also want to delete the false release.
In the first lines of [CMakeLists.txt](
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
@@ -468,25 +470,24 @@ coming from the tag title, it's good practice to increment the ones at CMake
after every full release to stress that master is ahead of the last stable
release.
The preferred flow of operation is:
* Just before a release, make sure the version number in CMakeLists.txt is set
to the same release version you are about to tag.
* This is also the time to change the pretty name in CMakeLists.txt called
GIT_TAG_RELEASENAME and commit and push these changes.
* Tag the release following the previously described syntax in order to get it
correctly built and deployed by CI.
* Wait for the configure step to create the release and update the patch
notes.
* Check on the github actions page for build progress which should be the top
listed [here](
- Just before a release, make sure the version number in CMakeLists.txt is set
to the same release version you are about to tag.
- This is also the time to change the pretty name in CMakeLists.txt called
`GIT_TAG_RELEASENAME` and commit and push these changes.
- Tag the release following the previously described syntax in order to get it
correctly built and deployed by CI.
- Wait for the configuration step to create the release and update the patch
notes.
- Check on the GitHub Actions page for build progress which should be the top
listed [here](
https://github.com/Cockatrice/Cockatrice/actions?query=event%3Apush+-branch%3Amaster
).
* When the build has been completed you can verify all uploaded files on the
release are in order and hit the publish button.
* After the release is complete, update the CMake version number again to the
next targeted beta version, typically increasing `PROJECT_VERSION_PATCH` by
one.
- When the build has been completed, you can verify if all uploaded files on the
draft release are included and hit the publish button.
- After the release is complete, update the CMake version number again to the
next targeted beta version, typically increasing `PROJECT_VERSION_PATCH` by
one.
When releasing a new stable version, all previous beta releases (and tags)
should be deleted. This is needed for Cockatrice to update users of the "Beta"
release channel correctly to the latest stable version as well.
should be deleted as well.
This can be done the same way as revoking tags, mentioned above.

View File

@@ -37,13 +37,13 @@ jobs:
shell: bash
run: |
tag_regex='^refs/tags/'
if [[ $GITHUB_EVENT_NAME == pull-request ]]; then # pull request
if [[ $GITHUB_EVENT_NAME == pull-request ]]; then # pull request
sha="${{github.event.pull_request.head.sha}}"
elif [[ $GITHUB_REF =~ $tag_regex ]]; then # release
elif [[ $GITHUB_REF =~ $tag_regex ]]; then # release
sha="$GITHUB_SHA"
tag="${GITHUB_REF/refs\/tags\//}"
echo "tag=$tag" >>"$GITHUB_OUTPUT"
else # push to branch
else # push to branch
sha="$GITHUB_SHA"
fi
echo "sha=$sha" >>"$GITHUB_OUTPUT"
@@ -85,46 +85,52 @@ jobs:
strategy:
fail-fast: false
matrix:
# these names correspond to the files in .ci/$distro
# These names correspond to the files in ".ci/$distro$version"
include:
- distro: ArchLinux
package: skip # we are packaged in arch already
- distro: Arch
package: skip # We are packaged in Arch already
allow-failure: yes
- distro: Debian11
- distro: Debian
version: 11
package: DEB
test: skip # Running tests on all distros is superfluous
- distro: Debian
version: 12
package: DEB
- distro: Debian12
package: DEB
- distro: Fedora
version: 40
package: RPM
test: skip # Running tests on all distros is superfluous
- distro: Fedora39
- distro: Fedora
version: 41
package: RPM
- distro: Fedora40
package: RPM
- distro: Ubuntu
version: 20.04
package: DEB
test: skip # Ubuntu 20.04 has a broken Qt for debug builds
- distro: UbuntuBionic
- distro: Ubuntu
version: 22.04
package: DEB
test: skip # Running tests on all distros is superfluous
- distro: Ubuntu
version: 24.04
package: DEB
- distro: UbuntuFocal
package: DEB
test: skip # UbuntuFocal has a broken qt for debug builds
- distro: UbuntuJammy
package: DEB
test: skip # running tests on all distros is superfluous
- distro: UbuntuNoble
package: DEB
name: ${{matrix.distro}}
name: ${{matrix.distro}} ${{matrix.version}}
needs: configure
runs-on: ubuntu-latest
continue-on-error: ${{matrix.allow-failure == 'yes'}}
env:
NAME: ${{matrix.distro}}
CACHE: /tmp/${{matrix.distro}}-cache # ${{runner.temp}} does not work?
# cache size over the entire repo is 10Gi link:
NAME: ${{matrix.distro}}${{matrix.version}}
CACHE: /tmp/${{matrix.distro}}${{matrix.version}}-cache # ${{runner.temp}} does not work?
# Cache size over the entire repo is 10Gi:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CCACHE_SIZE: 200M
@@ -132,7 +138,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Get cache timestamp
- name: Generate cache timestamp
id: cache_timestamp
shell: bash
run: echo "timestamp=$(date -u '+%Y%m%d%H%M%S')" >>"$GITHUB_OUTPUT"
@@ -143,19 +149,17 @@ jobs:
timestamp: ${{steps.cache_timestamp.outputs.timestamp}}
with:
path: ${{env.CACHE}}
key: docker-${{matrix.distro}}-cache-${{env.timestamp}}
key: docker-${{matrix.distro}}${{matrix.version}}-cache-${{env.timestamp}}
restore-keys: |
docker-${{matrix.distro}}-cache-
docker-${{matrix.distro}}${{matrix.version}}-cache-
- name: Build ${{matrix.distro}} Docker image
- name: Build ${{matrix.distro}} ${{matrix.version}} Docker image
shell: bash
run: source .ci/docker.sh --build
- name: Build debug and test
if: matrix.test != 'skip'
shell: bash
env:
distro: '${{matrix.distro}}'
run: |
source .ci/docker.sh
RUN --server --debug --test --ccache "$CCACHE_SIZE" --parallel 4
@@ -166,8 +170,7 @@ jobs:
shell: bash
env:
BUILD_DIR: build
SUFFIX: '-${{matrix.distro}}'
distro: '${{matrix.distro}}'
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
type: '${{matrix.package}}'
run: |
source .ci/docker.sh
@@ -179,7 +182,7 @@ jobs:
if: matrix.package != 'skip'
uses: actions/upload-artifact@v4
with:
name: ${{matrix.distro}}-package
name: ${{matrix.distro}}${{matrix.version}}-package
path: ${{steps.build.outputs.path}}
if-no-files-found: error
@@ -198,24 +201,38 @@ jobs:
fail-fast: false
matrix:
include:
- target: 12_Monterey_and_13_Ventura
os: macos-12
xcode: "14.0.1"
- target: 13
soc: Intel
os: macos-13
xcode: "14.3.1"
type: Release
core_count: 4
make_package: 1
- target: 14_Sonoma
- target: 14
soc: Apple
os: macos-14
xcode: "15.4"
type: Release
core_count: 3
make_package: 1
- target: 14_Sonoma_Debug
os: macos-14
xcode: "15.4"
- target: 15
soc: Apple
os: macos-15
xcode: "16.2"
type: Release
core_count: 3
make_package: 1
- target: 15
soc: Apple
os: macos-15
xcode: "16.2"
type: Debug
core_count: 3
name: macOS${{matrix.target}}
name: macOS ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
needs: configure
runs-on: ${{matrix.os}}
continue-on-error: ${{matrix.allow-failure == 'yes'}}
@@ -229,31 +246,91 @@ jobs:
- name: Install dependencies using Homebrew
shell: bash
# cmake cannot find the mysql connector
# neither of these works: mariadb-connector-c mysql-connector-c++
# CMake cannot find the MySQL connector
# Neither of these works: mariadb-connector-c mysql-connector-c++
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
run: |
brew update
brew install protobuf qt --force-bottle
- name: Build on Xcode ${{matrix.xcode}}
- name: Build & Sign on Xcode ${{matrix.xcode}}
shell: bash
id: build
env:
BUILDTYPE: '${{matrix.type}}'
MAKE_TEST: 1
MAKE_PACKAGE: '${{matrix.make_package}}'
PACKAGE_SUFFIX: '-macOS-${{matrix.target}}'
# macOS runner actually have only 3 cores
# See https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
run: .ci/compile.sh --server --parallel 3
PACKAGE_SUFFIX: '-macOS${{matrix.target}}_${{matrix.soc}}'
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
# macOS runner have 3 cores usually - only the macos-13 image has 4:
# https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
# https://github.com/actions/runner-images?tab=readme-ov-file#available-images
run: |
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
then
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security default-keychain -s build.keychain
security set-keychain-settings -t 3600 -l build.keychain
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain
fi
.ci/compile.sh --server --parallel ${{matrix.core_count}}
- name: Sign app bundle
if: matrix.make_package
env:
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
run: |
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
then
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
/usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose ${{steps.build.outputs.path}}
fi
- name: Notarize app bundle
if: matrix.make_package
env:
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
run: |
if [[ -n "$MACOS_NOTARIZATION_APPLE_ID" ]]
then
# Store the notarization credentials so that we can prevent a UI password dialog from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$MACOS_NOTARIZATION_APPLE_ID" --team-id "$MACOS_NOTARIZATION_TEAM_ID" --password "$MACOS_NOTARIZATION_PWD"
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
# notarization service
echo "Creating temp notarization archive"
ditto -c -k --keepParent ${{steps.build.outputs.path}} "notarization.zip"
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if
# you're curious
echo "Notarize app"
xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple ${{steps.build.outputs.path}}
fi
- name: Upload artifact
if: matrix.make_package
uses: actions/upload-artifact@v4
with:
name: macOS-${{matrix.target}}-dmg
name: macOS${{matrix.target}}${{ matrix.soc == 'Intel' && '_Intel' || '' }}${{ matrix.type == 'Debug' && '_Debug' || '' }}-package
path: ${{steps.build.outputs.path}}
if-no-files-found: error
@@ -275,13 +352,11 @@ jobs:
- target: 7
qt_version: 5.15.*
qt_arch: msvc2019_64
qt_tools: "tools_opensslv3_x64"
- target: 10
qt_version: 6.5.*
qt_version: 6.6.*
qt_arch: msvc2019_64
qt_tools: "tools_opensslv3_x64"
qt_modules: "qtmultimedia qtwebsockets"
qt_modules: "qtimageformats qtmultimedia qtwebsockets"
name: Windows ${{matrix.target}}
needs: configure
@@ -302,7 +377,7 @@ jobs:
submodules: recursive
- name: Install Qt ${{matrix.qt_version}}
uses: jurplel/install-qt-action@v3
uses: jurplel/install-qt-action@v4
with:
cache: true
setup-python: false
@@ -339,6 +414,15 @@ jobs:
path: ${{steps.build.outputs.path}}
if-no-files-found: error
- name: Upload pdb database
uses: actions/upload-artifact@v4
with:
name: Windows${{matrix.target}}-debug-pdbs
path: |
build/cockatrice/Release/*.pdb
build/servatrice/Release/*.pdb
if-no-files-found: error
- name: Upload to release
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
shell: bash

View File

@@ -32,7 +32,7 @@ jobs:
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
add-paths: |
cockatrice/translations/*.ts
@@ -64,7 +64,7 @@ jobs:
env:
STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: |
if [[ "$STATUS" == "" ]]; then
if [[ "$STATUS" == "none" ]]; then
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!" >> $GITHUB_STEP_SUMMARY
else
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!" >> $GITHUB_STEP_SUMMARY

View File

@@ -56,7 +56,7 @@ jobs:
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
add-paths: |
cockatrice/cockatrice_en@source.ts
@@ -79,7 +79,7 @@ jobs:
env:
STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: |
if [[ "$STATUS" == "" ]]; then
if [[ "$STATUS" == "none" ]]; then
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!" >> $GITHUB_STEP_SUMMARY
else
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!" >> $GITHUB_STEP_SUMMARY

3
.gitignore vendored
View File

@@ -6,10 +6,11 @@ mysql.cnf
.DS_Store
.idea/
*.aps
cmake-build-debug*
cmake-build*
preferences
compile_commands.json
.vs/
.vscode/
.cache
.gdb_history
cockatrice/resources/config/qtlogging.ini

View File

@@ -74,16 +74,16 @@ endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
project("Cockatrice" VERSION 2.9.1)
project("Cockatrice" VERSION 2.10.2)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)
set(GIT_TAG_RELEASENAME "Rings of the Wild")
set(GIT_TAG_RELEASENAME "Omenpath")
endif()
# Use c++17 for all targets
# Use c++20 for all targets
set(CMAKE_CXX_STANDARD
17
20
CACHE STRING "C++ ISO Standard"
)
set(CMAKE_CXX_STANDARD_REQUIRED True)
@@ -140,10 +140,17 @@ endif()
# Define proper compilation flags
if(MSVC)
# Visual Studio: Maximum optimization, disable warning C4251, establish C++17 compatibility
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 /Zc:__cplusplus /std:c++17 /permissive- /W4")
# Generate complete debugging information
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
# Disable Warning C4251, C++20 compatibility, Multi-threaded Builds, Warn Detection, Unwind Semantics, Debug Symbols
set(CMAKE_CXX_FLAGS "/wd4251 /Zc:__cplusplus /std:c++20 /permissive- /W4 /MP /EHsc /Zi")
# Visual Studio: Maximum Optimization, Multi-threaded DLL
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD")
# Visual Studio: No Optimization, Multi-threaded Debug DLL
set(CMAKE_CXX_FLAGS_DEBUG "/Od /MDd")
# Generate PDB, even when in release (So developers can better analyze crash logs)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
add_compile_definitions(_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING)
elseif(CMAKE_COMPILER_IS_GNUCXX)
# linux/gcc, bsd/gcc, windows/mingw
include(CheckCXXCompilerFlag)
@@ -156,7 +163,7 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
endif()
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++20")
endif()
set(ADDITIONAL_DEBUG_FLAGS
@@ -264,13 +271,14 @@ if(UNIX)
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/cockatrice/resources/appicon.icns")
set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeDMGSetup.script")
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/dmgBackground.tif")
set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SignMacApplications.cmake")
else()
# linux
if(CPACK_GENERATOR STREQUAL "RPM")
set(CPACK_RPM_PACKAGE_LICENSE "GPLv2")
set(CPACK_RPM_MAIN_COMPONENT "cockatrice")
if(Qt6_FOUND)
set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt6-qttools, qt6-qtsvg, qt6-qtmultimedia")
set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt6-qttools, qt6-qtsvg, qt6-qtmultimedia, qt6-qtimageformats")
elseif(Qt5_FOUND)
set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt5-qttools, qt5-qtsvg, qt5-qtmultimedia")
endif()
@@ -292,7 +300,7 @@ if(UNIX)
set(CPACK_DEBIAN_PACKAGE_SECTION "games")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice")
if(Qt6_FOUND)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins, qt6-image-formats-plugins")
elseif(Qt5_FOUND)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5")
endif()

View File

@@ -1,19 +1,20 @@
FROM ubuntu:bionic
MAINTAINER Zach Halpern <zahalpern+github@gmail.com>
FROM ubuntu:24.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y\
build-essential\
cmake\
git\
libprotobuf-dev\
libqt5sql5-mysql\
libmysqlclient-dev\
libqt5websockets5-dev\
protobuf-compiler\
qt5-default\
qtbase5-dev\
qttools5-dev-tools\
qttools5-dev
build-essential \
cmake \
file \
g++ \
git \
libmariadb-dev-compat \
libprotobuf-dev \
libqt6sql6-mysql \
qt6-websockets-dev \
protobuf-compiler \
qt6-tools-dev \
qt6-tools-dev-tools
COPY . /home/servatrice/code/
WORKDIR /home/servatrice/code
@@ -25,7 +26,6 @@ RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=
WORKDIR /home/servatrice
EXPOSE 4747
EXPOSE 4748
ENTRYPOINT [ "servatrice", "--log-to-console" ]

View File

@@ -5,7 +5,7 @@
<p align='center'>
<a href="#cockatrice"><b>Cockatrice</b></a> <b>|</b>
<a href="#download-">Download</a> <b>|</b>
<a href="#get-involved--">Get Involved</a> <b>|</b>
<a href="#get-involved-">Get Involved</a> <b>|</b>
<a href="#community-resources">Community</a> <b>|</b>
<a href="#translations-">Translations</a> <b>|</b>
<a href="#build--">Build</a> <b>|</b>
@@ -18,7 +18,7 @@
<br><pre>
<b>To get started, &#8674; [view our webpage](https://cockatrice.github.io/)</b><br>
<b>To get support or suggest changes &#8674; [file an issue](https://github.com/Cockatrice/Cockatrice/issues) ([How?](https://github.com/Cockatrice/Cockatrice/wiki/How-to-Create-a-GitHub-Ticket-Regarding-Cockatrice))</b>
<b>To help with development, see how to [get involved](#get-involved--)</b>
<b>To help with development, see how to [get involved](#get-involved-)</b>
</pre><br>
@@ -42,7 +42,7 @@ Downloads are available for full releases and the current beta version in develo
# Get Involved [![Discord](https://img.shields.io/discord/314987288398659595?label=Discord&logo=discord&logoColor=white)](https://discord.gg/3Z9yzmA)
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with the project or fellow users of the app. The Cockatrice developers are also available on [Gitter](https://gitter.im/Cockatrice/Cockatrice). Come here to talk about the application, features, or just to hang out.<br>
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with the project, contributors or fellow users of the app. Come here to talk about the application, features, or just to hang out.<br>
For support regarding specific servers, please contact that server's admin or forum for support rather than asking here.<br>
To contribute code to the project, please review [the guidelines](https://github.com/Cockatrice/Cockatrice/blob/master/.github/CONTRIBUTING.md).
@@ -128,9 +128,9 @@ First, create an image from the Dockerfile<br>
`cd /path/to/Cockatrice-Repo/`
`docker build -t servatrice .`<br>
And then run it<br>
`docker run -i -p 4747:4747/tcp -t servatrice:latest`<br>
`docker run -i -p 4748:4748 -t servatrice:latest`<br>
>Note: Running this command exposes the TCP port 4747 of the docker container<br>
>Note: Running this command exposes the port 4748 of the docker container<br>
to permit connections to the server.
Find more information on how to use Servatrice with Docker in our [wiki](https://github.com/Cockatrice/Cockatrice/wiki/Setting-up-Servatrice#using-docker).
@@ -145,7 +145,7 @@ docker-compose build # Build the Servatrice image using the same Dockerfile a
docker-compose up # Setup and run both the MySQL server and Servatrice.
```
>Note: Similar to the above Docker setup, this will expose TCP ports 4747 and 4748.
>Note: Similar to the above Docker setup, this will expose port 4748.
>Note: The first time running the docker-compose setup, the MySQL server will take a little time to run the initial setup scripts. Due to this, the Servatrice instance may fail the first few attempts to connect to the database. Servatrice is set to `restart: always` in the docker-compose.yml, which will allow it to continue attempting to start up. Once the MySQL scripts have completed, Servatrice should then connect automatically on the next attempt.

View File

@@ -23,6 +23,7 @@ if(WITH_CLIENT)
Svg
WebSockets
Widgets
Xml
)
endif()
if(WITH_ORACLE)

View File

@@ -5,7 +5,7 @@ OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
!define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
RequestExecutionlevel highest
RequestExecutionlevel admin
SetCompressor LZMA
Var NormalDestDir
@@ -235,6 +235,13 @@ ${If} $PortableMode = 0
WriteUninstaller "$INSTDIR\uninstall.exe"
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
; Enable Windows User-Mode Dumps
; https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps
WriteRegExpandStr HKLM "Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\cockatrice.exe" "DumpFolder" "%LOCALAPPDATA%\CrashDumps\Cockatrice"
WriteRegDWORD HKLM "Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\cockatrice.exe" "DumpCount" "5"
WriteRegDWORD HKLM "Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\cockatrice.exe" "DumpType" "2"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "DisplayIcon" "$INSTDIR\cockatrice.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "DisplayName" "Cockatrice"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "DisplayVersion" "@CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@"

View File

@@ -0,0 +1,27 @@
# This script re-signs all apps after CPack packages them. This is necessary because CPack modifies
# the library references used by Cockatrice to App relative paths, invalidating the code signature.
string(LENGTH "$ENV{MACOS_CERTIFICATE_NAME}" MACOS_CERTIFICATE_NAME_LEN)
if(APPLE AND MACOS_CERTIFICATE_NAME_LEN GREATER 0)
set(APPLICATIONS "cockatrice" "servatrice" "oracle" "dbconverter")
foreach(app_name IN LISTS APPLICATIONS)
set(FULL_APP_PATH "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/${app_name}.app")
message(STATUS "Signing Interior Dynamically Loaded Libraries for ${app_name}.app")
execute_process(COMMAND "find" "${FULL_APP_PATH}" "-name" "*.dylib" OUTPUT_VARIABLE INTERIOR_DLLS)
string(REPLACE "\n" ";" INTERIOR_DLLS_LIST ${INTERIOR_DLLS})
foreach(INTERIOR_DLL IN LISTS INTERIOR_DLLS_LIST)
execute_process(
COMMAND "codesign" "--sign" "$ENV{MACOS_CERTIFICATE_NAME}" "--entitlements" "../.ci/macos.entitlements"
"--options" "runtime" "--force" "--deep" "--timestamp" "--verbose" "${INTERIOR_DLL}"
)
endforeach()
message(STATUS "Signing Exterior Applications ${app_name}.app")
execute_process(
COMMAND "codesign" "--sign" "$ENV{MACOS_CERTIFICATE_NAME}" "--entitlements" "../.ci/macos.entitlements"
"--options" "runtime" "--force" "--deep" "--timestamp" "--verbose" "${FULL_APP_PATH}"
)
endforeach()
endif()

View File

@@ -19,7 +19,7 @@ function(get_commit_id)
PARENT_SCOPE
)
set(PROJECT_VERSION_LABEL
"custom(${GIT_COM_ID})"
"custom-${GIT_COM_ID}"
PARENT_SCOPE
)
endfunction()

View File

@@ -4,134 +4,15 @@
project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(cockatrice_SOURCES
src/abstractcarddragitem.cpp
src/abstractcarditem.cpp
src/abstractclient.cpp
src/abstractcounter.cpp
src/abstractgraphicsitem.cpp
src/arrowitem.cpp
src/arrowtarget.cpp
src/carddatabase.cpp
src/carddatabasemodel.cpp
src/carddbparser/carddatabaseparser.cpp
src/carddbparser/cockatricexml3.cpp
src/carddbparser/cockatricexml4.cpp
src/carddragitem.cpp
src/cardfilter.cpp
src/cardframe.cpp
src/cardinfopicture.cpp
src/cardinfotext.cpp
src/cardinfowidget.cpp
src/carditem.cpp
src/cardlist.cpp
src/cardzone.cpp
src/chatview/chatview.cpp
src/counter_general.cpp
src/customlineedit.cpp
src/deck_loader.cpp
src/decklistmodel.cpp
src/deckstats_interface.cpp
src/deckview.cpp
src/dlg_connect.cpp
src/dlg_create_token.cpp
src/dlg_creategame.cpp
src/dlg_edit_avatar.cpp
src/dlg_edit_password.cpp
src/dlg_edit_tokens.cpp
src/dlg_edit_user.cpp
src/dlg_filter_games.cpp
src/dlg_forgotpasswordchallenge.cpp
src/dlg_forgotpasswordrequest.cpp
src/dlg_forgotpasswordreset.cpp
src/dlg_load_deck_from_clipboard.cpp
src/dlg_load_remote_deck.cpp
src/dlg_manage_sets.cpp
src/dlg_register.cpp
src/dlg_roll_dice.cpp
src/dlg_settings.cpp
src/dlg_tip_of_the_day.cpp
src/dlg_update.cpp
src/dlg_viewlog.cpp
src/filter_string.cpp
src/filterbuilder.cpp
src/filtertree.cpp
src/filtertreemodel.cpp
src/gamescene.cpp
src/gameselector.cpp
src/gamesmodel.cpp
src/gameview.cpp
src/gettextwithmax.cpp
src/handcounter.cpp
src/handle_public_servers.cpp
src/handzone.cpp
src/keysignals.cpp
src/lineeditcompleter.cpp
src/localclient.cpp
src/localserver.cpp
src/localserverinterface.cpp
src/logger.cpp
src/main.cpp
src/messagelogwidget.cpp
src/pending_command.cpp
src/phase.cpp
src/phasestoolbar.cpp
src/pictureloader.cpp
src/pilezone.cpp
src/pixmapgenerator.cpp
src/player.cpp
src/playerlistwidget.cpp
src/playertarget.cpp
src/releasechannel.cpp
src/remoteclient.cpp
src/remotedecklist_treewidget.cpp
src/remotereplaylist_treewidget.cpp
src/replay_timeline_widget.cpp
src/selectzone.cpp
src/sequenceEdit/sequenceedit.cpp
src/setsmodel.cpp
src/settings/carddatabasesettings.cpp
src/settings/downloadsettings.cpp
src/settings/gamefilterssettings.cpp
src/settings/layoutssettings.cpp
src/settings/messagesettings.cpp
src/settings/serverssettings.cpp
src/settings/settingsmanager.cpp
src/settingscache.cpp
src/shortcutssettings.cpp
src/soundengine.cpp
src/spoilerbackgroundupdater.cpp
src/stackzone.cpp
src/tab.cpp
src/tab_account.cpp
src/tab_admin.cpp
src/tab_deck_editor.cpp
src/tab_deck_storage.cpp
src/tab_game.cpp
src/tab_logs.cpp
src/tab_message.cpp
src/tab_replays.cpp
src/tab_room.cpp
src/tab_server.cpp
src/tab_supervisor.cpp
src/tablezone.cpp
src/tappedout_interface.cpp
src/thememanager.cpp
src/tip_of_the_day.cpp
src/translatecountername.cpp
src/update_downloader.cpp
src/user_context_menu.cpp
src/userconnection_information.cpp
src/userinfobox.cpp
src/userlist.cpp
src/window_main.cpp
src/zoneviewwidget.cpp
src/zoneviewzone.cpp
${VERSION_STRING_CPP}
)
file(GLOB_RECURSE cockatrice_CPP_FILES CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp)
set(cockatrice_SOURCES ${cockatrice_CPP_FILES} ${VERSION_STRING_CPP})
add_subdirectory(sounds)
add_subdirectory(themes)
configure_file(
${CMAKE_SOURCE_DIR}/cockatrice/resources/config/qtlogging.ini ${CMAKE_BINARY_DIR}/cockatrice/qtlogging.ini COPYONLY
)
set(cockatrice_RESOURCES cockatrice.qrc)
@@ -252,7 +133,7 @@ if(APPLE)
set(plugin_dest_dir cockatrice.app/Contents/Plugins)
set(qtconf_dest_dir cockatrice.app/Contents/Resources)
# Qt plugins: audio (Qt5), iconengines, imageformats, platforms, printsupport (Qt5), styles, tls (Qt6)
# Qt plugins: audio (Qt5), iconengines, imageformats, multimedia (Qt6), platforms, printsupport (Qt5), styles, tls (Qt6)
install(
DIRECTORY "${QT_PLUGINS_DIR}/"
DESTINATION ${plugin_dest_dir}
@@ -263,12 +144,20 @@ if(APPLE)
PATTERN "audio/*.dylib"
PATTERN "iconengines/*.dylib"
PATTERN "imageformats/*.dylib"
PATTERN "multimedia/*.dylib"
PATTERN "platforms/*.dylib"
PATTERN "printsupport/*.dylib"
PATTERN "styles/*.dylib"
PATTERN "tls/*.dylib"
)
install(
DIRECTORY "${CMAKE_BINARY_DIR}/cockatrice/"
DESTINATION ${qtconf_dest_dir}/
FILES_MATCHING
PATTERN "*.ini"
)
install(
CODE "
file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths]
@@ -303,7 +192,14 @@ if(WIN32)
PATTERN "*.dll"
)
# Qt plugins: audio (Qt5), iconengines, imageformats, platforms, printsupport (Qt5), styles, tls (Qt6)
install(
DIRECTORY "${CMAKE_BINARY_DIR}/cockatrice/"
DESTINATION ./
FILES_MATCHING
PATTERN "*.ini"
)
# Qt plugins: audio (Qt5), iconengines, imageformats, multimedia (Qt6) platforms, printsupport (Qt5), styles, tls (Qt6)
install(
DIRECTORY "${QT_PLUGINS_DIR}/"
DESTINATION ${plugin_dest_dir}
@@ -315,6 +211,7 @@ if(WIN32)
PATTERN "imageformats/*.dll"
PATTERN "mediaservice/dsengine.dll"
PATTERN "mediaservice/wmfengine.dll"
PATTERN "multimedia/*.dll"
PATTERN "platforms/qdirect2d.dll"
PATTERN "platforms/qminimal.dll"
PATTERN "platforms/qoffscreen.dll"

View File

@@ -1,5 +1,5 @@
<RCC>
<qresource prefix="/" >
<qresource prefix="/">
<file>resources/cardback.svg</file>
<file>resources/cockatrice.svg</file>
<file>resources/hand.svg</file>
@@ -13,9 +13,12 @@
<file>resources/icons/arrow_top_green.svg</file>
<file>resources/icons/arrow_up_green.svg</file>
<file>resources/icons/clearsearch.svg</file>
<file>resources/icons/cogwheel.svg</file>
<file>resources/icons/conceded.svg</file>
<file>resources/icons/decrement.svg</file>
<file>resources/icons/delete.svg</file>
<file>resources/icons/dropdown_collapsed.svg</file>
<file>resources/icons/dropdown_expanded.svg</file>
<file>resources/icons/forgot_password.svg</file>
<file>resources/icons/increment.svg</file>
<file>resources/icons/info.svg</file>
@@ -24,16 +27,25 @@
<file>resources/icons/pencil.svg</file>
<file>resources/icons/player.svg</file>
<file>resources/icons/ready_start.svg</file>
<file>resources/icons/reload.svg</file>
<file>resources/icons/remove_row.svg</file>
<file>resources/icons/rename.svg</file>
<file>resources/icons/scales.svg</file>
<file>resources/icons/search.svg</file>
<file>resources/icons/settings.svg</file>
<file>resources/icons/spectator.svg</file>
<file>resources/icons/swap.svg</file>
<file>resources/icons/sync.svg</file>
<file>resources/icons/tab_changed.svg</file>
<file>resources/icons/update.png</file>
<file>resources/icons/view.svg</file>
<file>resources/icons/mana/B.svg</file>
<file>resources/icons/mana/G.svg</file>
<file>resources/icons/mana/R.svg</file>
<file>resources/icons/mana/U.svg</file>
<file>resources/icons/mana/W.svg</file>
<file>resources/config/general.svg</file>
<file>resources/config/appearance.svg</file>
<file>resources/config/interface.svg</file>
@@ -41,6 +53,8 @@
<file>resources/config/deckeditor.svg</file>
<file>resources/config/shorcuts.svg</file>
<file>resources/config/sound.svg</file>
<file>resources/config/debug.ini</file>
<file>resources/config/qtlogging.ini</file>
<file>resources/counters/w.svg</file>
<file>resources/counters/w_highlight.svg</file>
@@ -326,39 +340,42 @@
<file>resources/replay/fastforward.svg</file>
<file>resources/replay/pause.svg</file>
<file>resources/userlevels/normal.svg</file>
<file>resources/userlevels/registered.svg</file>
<file>resources/userlevels/registered_buddy.svg</file>
<file>resources/userlevels/registered_vip.svg</file>
<file>resources/userlevels/registered_vip_buddy.svg</file>
<file>resources/userlevels/registered_donator.svg</file>
<file>resources/userlevels/registered_donator_buddy.svg</file>
<file>resources/userlevels/moderator.svg</file>
<file>resources/userlevels/moderator_buddy.svg</file>
<file>resources/userlevels/moderator_vip.svg</file>
<file>resources/userlevels/moderator_vip_buddy.svg</file>
<file>resources/userlevels/admin.svg</file>
<file>resources/userlevels/admin_buddy.svg</file>
<file>resources/userlevels/admin_vip.svg</file>
<file>resources/userlevels/admin_vip_buddy.svg</file>
<file>resources/usericons/pawn_single.svg</file>
<file>resources/usericons/pawn_double.svg</file>
<file>resources/usericons/pawn_donator_single.svg</file>
<file>resources/usericons/pawn_donator_double.svg</file>
<file>resources/usericons/pawn_judge_single.svg</file>
<file>resources/usericons/pawn_judge_double.svg</file>
<file>resources/usericons/pawn_vip_single.svg</file>
<file>resources/usericons/pawn_vip_double.svg</file>
<file>resources/usericons/star_single.svg</file>
<file>resources/usericons/star_double.svg</file>
<!-- ADD TIP OF THE DAY IMAGES HERE -->
<file>resources/tips/images/accounts_tab.png</file>
<file>resources/tips/images/add_card.png</file>
<file>resources/tips/images/arrows.png</file>
<file>resources/tips/images/card_select.png</file>
<file>resources/tips/images/cockatrice_register.png</file>
<file>resources/tips/images/cockatrice_wiki.png</file>
<file>resources/tips/images/coin_flip.png</file>
<file>resources/tips/images/counter_expression.png</file>
<file>resources/tips/images/discord.png</file>
<file>resources/tips/images/edhrec.png</file>
<file>resources/tips/images/expand_card_view.png</file>
<file>resources/tips/images/face_down.png</file>
<file>resources/tips/images/filter_games.png</file>
<file>resources/tips/images/github_logo.png</file>
<file>resources/tips/images/highlight_cards.png</file>
<file>resources/tips/images/pawns.png</file>
<file>resources/tips/images/setpt.png</file>
<file>resources/tips/images/shortcuts.png</file>
<file>resources/tips/images/syntax_help.png</file>
<file>resources/tips/images/themes.png</file>
<file>resources/tips/images/tip_of_the_day.png</file>
<file>resources/tips/images/token.png</file>
<file>resources/tips/images/updates.png</file>
<file>resources/tips/images/visual_deck_tags.png</file>
<file>resources/tips/tips_of_the_day.xml</file>
<file>resources/help/search.md</file>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
[debug]
showCardId=false
[localgame]
onStartup=false
playerCount=1
;deck\Player 1=path/to/deck
;deck\Player 2=path/to/deck
; Fun Fact: You can assign a deck to your username and it will auto load and ready when you join a server game
;deck\Your Username Here=path/to/deck

View File

@@ -0,0 +1,62 @@
[Rules]
# The default log level is info
*.debug = false
# Uncomment a rule to disable logging for that category,
# or set .debug = true for that category to see debug level logs
# main = false
# qt_translator = false
# window_main.* = false
# release_channel = false
# spoiler_background_updater = false
# theme_manager = false
# sound_engine = false
# tapped_out_interface = false
# tab_game = false
# tab_message = false
# tab_supervisor = false
# dlg_edit_avatar = false
# dlg_settings = false
# dlg_tip_of_the_day = false
# dlg_update = false
# settings_cache = false
# servers_settings = false
# shortcuts_settings = false
# remote_client = false
# player = false
# game_scene = false
# game_scene.player_addition_removal = false
# card_zone = false
# view_zone = false
# user_info_connection = false
# picture_loader = false
# picture_loader.worker = false
# picture_loader.card_back_cache_fail = false
# picture_loader.picture_to_load = false
# deck_loader = false
# card_database = false
# card_database.loading = false
# card_database.loading.success_or_failure = false
# cockatrice_xml.* = false
# cockatrice_xml.xml_3_parser = false
# cockatrice_xml.xml_4_parser = false
# card_info = false
# card_list = false
#flow_layout = false
#flow_widget = false
#flow_widget.size = false
# card_info_picture_widget = false
# pixel_map_generator = false
# filter_string = false

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" width="102.5024mm" height="102.24421mm"
viewBox="0 0 102.5024 102.24421" version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)" sodipodi:docname="cog_wheel.svg"
xmlns="http://www.w3.org/2000/svg">
<sodipodi:namedview id="namedview1" pagecolor="#ffffff" bordercolor="#000000" borderopacity="0.25"
inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" inkscape:zoom="0.66101291"
inkscape:cx="146.74449" inkscape:cy="193.64221" inkscape:window-width="1829"
inkscape:window-height="951" inkscape:window-x="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:current-layer="layer1"/>
<defs id="defs1"/>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-66.148059,-97.377896)">
<g id="g1" transform="translate(-165.09777,-82.009607)">
<g id="g2" transform="matrix(0.26458333,0,0,0.26458333,64.983323,161.37858)">
<path style="fill:#333333;stroke-width:94.4882"
d="m 721.34301,94.413051 40.00966,29.763289 29.51933,-9.27053 14.63768,-46.840589 36.83817,0.48792 13.41787,46.108699 28.29952,9.5145 40.74155,-28.299519 29.0314,21.468599 -15.85748,47.08454 16.58937,23.66426 48.30432,-2.68358 12.93,34.88648 -41.71741,27.07971 -0.48792,29.27536 40.49763,26.10387 -10.2464,34.15459 -48.54834,-0.97584 -18.78502,23.42029 15.85749,45.37681 -28.29952,21.71256 -41.22947,-29.27536 -28.54348,9.75846 -13.66184,47.57246 -38.30194,-0.73188 -14.63768,-48.30435 -27.07971,-9.27054 -40.00966,29.27537 -30.25121,-20.49276 17.32125,-46.35266 -17.80918,-24.64009 -49.76812,3.17149 -11.22222,-34.64251 40.74155,-27.07971 0.48792,-30.00725 -41.71739,-27.32367 12.19807,-32.93479 48.30435,2.68358 20.24879,-24.6401 -17.32126,-47.08455 z"
id="path1"/>
<circle style="fill:#f9f9f9;stroke-width:72.1317" id="path2" cx="822.09906" cy="261.28262"
r="83.434792"/>
<circle style="fill:#4d4d4d;stroke-width:40.5147" id="circle2" cx="822.09906" cy="261.28262"
r="46.863361"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_svg "http://www.w3.org/2000/svg">
<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
]>
<svg version="1.1" id="Layer_1" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="460.5" height="531.74"
viewBox="0 0 460.5 531.74" overflow="visible" enable-background="new 0 0 460.5 531.74" xml:space="preserve">
<polygon fill="#918d8d" points="0.5,0.866 459.5,265.87 0.5,530.874 "/>
</svg>

After

Width:  |  Height:  |  Size: 657 B

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_svg "http://www.w3.org/2000/svg">
<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
]>
<svg version="1.1" id="Layer_1" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="531.74" height="460.5"
viewBox="0 0 531.74 460.5" overflow="visible" enable-background="new 0 0 531.74 460.5" xml:space="preserve">
<polygon fill="#918d8d" points="530.874,0.5 265.87,459.5 0.866,0.5 "/>
</svg>

After

Width:  |  Height:  |  Size: 657 B

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="169.34801mm"
height="169.34801mm"
viewBox="0 0 600 600"
version="1.1"
id="svg1"
sodipodi:docname="B.svg"
inkscape:export-filename="B.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg">
<defs
id="defs1"/>
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm">
<inkscape:page
x="0"
y="0"
width="600"
height="600"
id="page2"
margin="0"
bleed="0"/>
</sodipodi:namedview>
<path
id="Selection"
fill="none"
stroke="#000000"
stroke-width="1"
d="m 275,0.21 c 0,0 42,0 42,0 0,0 19,1.51 19,1.51 29.13,3.58 56.99,10.83 84,22.43 33.64,14.45 59.89,32.91 86.91,57.41 17.38,15.76 34.67,37.56 47.14,57.44 22.78,36.31 37.1,74.56 43.22,117 1.28,8.88 2.72,19.08 2.73,28 0,0 0,34 0,34 0,0 -0.91,10 -0.91,10 -2.36,32.29 -11.93,67.59 -25.4,97 -27.01,58.98 -70.49,105.42 -126.69,137.57 -34.3,19.63 -79.56,33.64 -119,36.52 0,0 -12,0.91 -12,0.91 0,0 -34,0 -34,0 0,0 -10,-0.91 -10,-0.91 -26.57,-1.94 -53.09,-8.27 -78,-17.67 C 163.49,569.9 134.12,553.46 109,532.57 79.87,508.33 54.41,478.39 36.31,445 -5.08,368.65 -11.86,276.57 18.05,195 47.85,113.75 113.21,48.92 194,18.42 213.55,11.04 236.32,5.43 257,2.43 Z"
style="display:inline;fill:#ababab;fill-opacity:1"/>
<path
d="m 299.67889,84.945431 c -118.26949,0 -214.122988,83.892719 -214.122988,187.357619 0,58.63289 30.863828,110.90901 79.041488,145.28579 8.02961,5.77129 12.71356,15.13917 11.29165,25.0089 l -7.86234,55.37086 c -1.17098,8.02962 5.01851,15.22281 13.13176,15.22281 h 64.98968 v -46.83939 c 0,-3.68025 3.01111,-6.69135 6.69135,-6.69135 h 13.38268 c 3.68024,0 6.69135,3.0111 6.69135,6.69135 v 46.83939 h 53.53075 v -46.83939 c 0,-3.68025 3.01111,-6.69135 6.69134,-6.69135 h 13.38269 c 3.68023,0 6.69134,3.0111 6.69134,6.69135 v 46.83939 h 64.98967 c 8.11327,0 14.30275,-7.19319 13.13177,-15.22281 l -7.86234,-55.37086 c -1.4219,-9.78609 3.1784,-19.23761 11.29165,-25.0089 48.17767,-34.37678 79.0415,-86.6529 79.0415,-145.28579 0,-103.4649 -95.8535,-187.357619 -214.123,-187.357619 z M 219.38277,352.59917 c -29.52555,0 -53.53075,-24.0052 -53.53075,-53.53075 0,-29.52555 24.0052,-53.53075 53.53075,-53.53075 29.52555,0 53.53075,24.0052 53.53075,53.53075 0,29.52555 -24.0052,53.53075 -53.53075,53.53075 z m 160.59225,0 c -29.52555,0 -53.53075,-24.0052 -53.53075,-53.53075 0,-29.52555 24.0052,-53.53075 53.53075,-53.53075 29.52555,0 53.53075,24.0052 53.53075,53.53075 0,29.52555 -24.0052,53.53075 -53.53075,53.53075 z"
id="path1"
style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-width:0.836419;stroke-opacity:1"/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
width="169.34801mm"
height="169.34801mm"
viewBox="0 0 600 600"
version="1.1"
id="svg1"
sodipodi:docname="B.svg"
inkscape:export-filename="U.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns="http://www.w3.org/2000/svg">
<defs
id="defs1"/>
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm">
<inkscape:page
x="0"
y="0"
width="600"
height="600"
id="page2"
margin="0"
bleed="0"/>
</sodipodi:namedview>
<path
id="Selection"
fill="none"
stroke="#000000"
stroke-width="1"
d="m 275,0.21 c 0,0 42,0 42,0 0,0 19,1.51 19,1.51 29.13,3.58 56.99,10.83 84,22.43 33.64,14.45 59.89,32.91 86.91,57.41 17.38,15.76 34.67,37.56 47.14,57.44 22.78,36.31 37.1,74.56 43.22,117 1.28,8.88 2.72,19.08 2.73,28 0,0 0,34 0,34 0,0 -0.91,10 -0.91,10 -2.36,32.29 -11.93,67.59 -25.4,97 -27.01,58.98 -70.49,105.42 -126.69,137.57 -34.3,19.63 -79.56,33.64 -119,36.52 0,0 -12,0.91 -12,0.91 0,0 -34,0 -34,0 0,0 -10,-0.91 -10,-0.91 -26.57,-1.94 -53.09,-8.27 -78,-17.67 C 163.49,569.9 134.12,553.46 109,532.57 79.87,508.33 54.41,478.39 36.31,445 -5.08,368.65 -11.86,276.57 18.05,195 47.85,113.75 113.21,48.92 194,18.42 213.55,11.04 236.32,5.43 257,2.43 Z"
style="display:inline;fill:#5f9f56;fill-opacity:1"/>
<path
d="m 488.52401,428.04591 -80.36527,-83.50228 h 30.81218 c 9.06362,0 17.08104,-4.61393 20.90363,-12.05153 3.82262,-7.41912 2.56521,-15.92714 -3.29949,-22.19282 l -78.59482,-83.87142 h 29.06188 c 9.15413,0 17.40291,-4.93688 20.98411,-12.55902 3.54092,-7.50219 1.87106,-16.23169 -4.26525,-22.22053 L 312.83499,83.240199 c -6.06588,-5.951919 -17.38282,-5.951919 -23.45873,0 L 178.44019,191.64831 c -6.13629,5.98884 -7.79612,14.71834 -4.26523,22.22053 3.58119,7.62214 11.84001,12.55902 20.99414,12.55902 h 29.06189 l -78.60489,83.88987 c -5.84454,6.25645 -7.10199,14.75525 -3.28944,22.18361 3.82262,7.42836 11.82996,12.04229 20.90363,12.04229 h 30.81222 l -80.36527,83.50228 c -6.03569,6.26567 -7.40379,14.84754 -3.58117,22.38663 3.7723,7.42839 12.07138,12.22682 21.13497,12.22682 h 129.63669 c 0,0 -36.12127,66.38546 0,62.75824 h 80.45578 c 33.50708,5.78651 0,-62.75824 0,-62.75824 h 129.63668 c 9.06361,0 17.36266,-4.79843 21.13499,-12.22682 3.82262,-7.53909 2.45452,-16.12096 -3.58117,-22.38663 z"
id="ENVIR"
style="fill:#3f6e3a;fill-opacity:1;stroke:#000000;stroke-width:1.09833;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
width="169.34801mm"
height="169.34801mm"
viewBox="0 0 600 600"
version="1.1"
id="svg1"
sodipodi:docname="B.svg"
inkscape:export-filename="B.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns="http://www.w3.org/2000/svg">
<defs
id="defs1"/>
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm">
<inkscape:page
x="0"
y="0"
width="600"
height="600"
id="page2"
margin="0"
bleed="0"/>
</sodipodi:namedview>
<path
id="Selection"
fill="none"
stroke="#000000"
stroke-width="1"
d="m 275,0.21 c 0,0 42,0 42,0 0,0 19,1.51 19,1.51 29.13,3.58 56.99,10.83 84,22.43 33.64,14.45 59.89,32.91 86.91,57.41 17.38,15.76 34.67,37.56 47.14,57.44 22.78,36.31 37.1,74.56 43.22,117 1.28,8.88 2.72,19.08 2.73,28 0,0 0,34 0,34 0,0 -0.91,10 -0.91,10 -2.36,32.29 -11.93,67.59 -25.4,97 -27.01,58.98 -70.49,105.42 -126.69,137.57 -34.3,19.63 -79.56,33.64 -119,36.52 0,0 -12,0.91 -12,0.91 0,0 -34,0 -34,0 0,0 -10,-0.91 -10,-0.91 -26.57,-1.94 -53.09,-8.27 -78,-17.67 C 163.49,569.9 134.12,553.46 109,532.57 79.87,508.33 54.41,478.39 36.31,445 -5.08,368.65 -11.86,276.57 18.05,195 47.85,113.75 113.21,48.92 194,18.42 213.55,11.04 236.32,5.43 257,2.43 Z"
style="display:inline;fill:#c95e46;fill-opacity:1"/>
<path
style="display:inline;fill:#7e3525;fill-opacity:1;stroke:#000000;stroke-width:0.999129;stroke-dasharray:none;stroke-opacity:1"
d="m 278.25473,537.27772 c -22.36635,-1.29637 -48.78648,-8.31223 -69.74195,-18.51997 -47.30139,-23.04123 -75.19872,-59.72004 -85.45343,-112.35234 -2.77041,-14.21911 -2.51753,-48.32296 0.4755,-64.1246 4.84373,-25.57244 17.23939,-55.03329 30.65191,-72.85059 3.74877,-4.97991 16.33133,-18.11906 30.23479,-31.57223 13.09764,-12.67346 26.64745,-26.67202 30.11069,-31.10792 16.66894,-21.35045 26.46602,-44.71272 29.68313,-70.78286 1.93489,-15.67951 0.37962,-45.867231 -3.5802,-69.491071 -0.58906,-3.51428 0.36584,-3.52724 11.47726,-0.15583 36.51454,11.0792 67.37028,34.791071 89.32423,68.643431 9.96686,15.36862 20.07787,39.31263 24.78919,58.70364 2.23257,9.18886 2.53252,44.73878 0.46396,54.98571 -0.75708,3.75024 -1.10086,7.09425 -0.76396,7.43114 1.5021,1.5021 14.63666,-6.65479 21.98002,-13.65016 10.59844,-10.09621 14.32693,-17.61354 15.94714,-32.15254 l 1.16788,-10.47988 3.4626,3.95724 c 26.80954,30.6392 41.75268,56.11528 54.11775,92.26358 11.02075,32.21825 14.93902,62.79297 12.47422,97.33768 -1.88493,26.41774 -10.16486,50.6958 -24.95555,73.17369 -6.31625,9.59901 -30.86306,34.05172 -40.40914,40.25423 -23.44452,15.23295 -50.15355,25.25695 -77.26806,28.99903 -12.48732,1.72336 -38.04339,2.42637 -54.18798,1.49062 z m 48.34948,-30.34196 c 30.78066,-8.0491 53.53846,-30.12825 59.69792,-57.9177 2.48916,-11.23027 2.26087,-34.25269 -0.43747,-44.11787 -5.3998,-19.74181 -9.72931,-26.61651 -30.6237,-48.62658 -16.92925,-17.8332 -21.73398,-24.64464 -25.45673,-36.0889 -2.38622,-7.33554 -2.63126,-9.53814 -2.57644,-23.15876 0.0334,-8.27872 0.486,-17.4607 1.00593,-20.40441 0.75887,-4.29636 0.66928,-5.45812 -0.45409,-5.88919 -2.12997,-0.81736 -16.25071,4.45522 -21.90917,8.1807 -25.69349,16.91641 -42.62753,52.30879 -40.22917,84.07948 0.39046,5.17228 0.2831,8.79277 -0.26071,8.79277 -1.78935,0 -13.49435,-13.46378 -15.34792,-17.65406 -1.03171,-2.33236 -2.15967,-6.42651 -2.50657,-9.09812 -1.00143,-7.71233 -1.60778,-8.14619 -5.46339,-3.90915 -13.31687,14.63425 -24.58113,35.69359 -29.53283,55.21379 -11.75615,46.34414 2.14731,84.38956 37.55813,102.77397 16.56338,8.59931 29.2427,11.25369 51.26679,10.73261 12.58064,-0.29766 17.41119,-0.85366 25.26942,-2.90858 z"
id="path8"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
width="169.34801mm"
height="169.34801mm"
viewBox="0 0 600 600"
version="1.1"
id="svg1"
sodipodi:docname="U.svg"
inkscape:export-filename="U.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns="http://www.w3.org/2000/svg">
<defs
id="defs1"/>
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm">
<inkscape:page
x="0"
y="0"
width="600"
height="600"
id="page2"
margin="0"
bleed="0"/>
</sodipodi:namedview>
<path
id="Selection"
fill="none"
stroke="#000000"
stroke-width="1"
d="m 275,0.21 c 0,0 42,0 42,0 0,0 19,1.51 19,1.51 29.13,3.58 56.99,10.83 84,22.43 33.64,14.45 59.89,32.91 86.91,57.41 17.38,15.76 34.67,37.56 47.14,57.44 22.78,36.31 37.1,74.56 43.22,117 1.28,8.88 2.72,19.08 2.73,28 0,0 0,34 0,34 0,0 -0.91,10 -0.91,10 -2.36,32.29 -11.93,67.59 -25.4,97 -27.01,58.98 -70.49,105.42 -126.69,137.57 -34.3,19.63 -79.56,33.64 -119,36.52 0,0 -12,0.91 -12,0.91 0,0 -34,0 -34,0 0,0 -10,-0.91 -10,-0.91 -26.57,-1.94 -53.09,-8.27 -78,-17.67 C 163.49,569.9 134.12,553.46 109,532.57 79.87,508.33 54.41,478.39 36.31,445 -5.08,368.65 -11.86,276.57 18.05,195 47.85,113.75 113.21,48.92 194,18.42 213.55,11.04 236.32,5.43 257,2.43 Z"
style="display:inline;fill:#4a8fd8;fill-opacity:1"/>
<path
style="display:inline;fill:#3266af;fill-opacity:1;stroke:#000000;stroke-width:1.06525;stroke-opacity:1"
d="m 275.20608,536.5693 c -58.69596,-9.5447 -107.01545,-50.69962 -125.66779,-107.0344 -9.25532,-27.95342 -10.39669,-58.82111 -3.22092,-87.1088 5.31307,-20.94475 9.06296,-28.00552 81.87785,-154.17 38.54798,-66.79109 70.40461,-121.77997 70.79251,-122.19751 1.00535,-1.08215 140.3595,240.63696 145.26785,251.97682 8.6735,20.03855 12.6923,39.82747 12.6923,62.49805 0,44.25387 -16.70161,83.24077 -48.85852,114.0514 -21.46938,20.57055 -45.69209,33.39124 -76.46586,40.47213 -12.83139,2.95245 -42.64639,3.75165 -56.41742,1.51231 z"
id="path2"
sodipodi:nodetypes="ssssssssss"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="169.34801mm"
height="169.34801mm"
viewBox="0 0 600 600"
version="1.1"
id="svg1"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
sodipodi:docname="W.svg"
inkscape:export-filename="W.png"
xmlns="http://www.w3.org/2000/svg">
<defs
id="defs1"/>
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm">
<inkscape:page
x="0"
y="0"
width="600"
height="600"
id="page2"
margin="0"
bleed="0"/>
</sodipodi:namedview>
<path
id="Selection"
fill="none"
stroke="#000000"
stroke-width="1"
d="m 275,0.21 c 0,0 42,0 42,0 0,0 19,1.51 19,1.51 29.13,3.58 56.99,10.83 84,22.43 33.64,14.45 59.89,32.91 86.91,57.41 17.38,15.76 34.67,37.56 47.14,57.44 22.78,36.31 37.1,74.56 43.22,117 1.28,8.88 2.72,19.08 2.73,28 0,0 0,34 0,34 0,0 -0.91,10 -0.91,10 -2.36,32.29 -11.93,67.59 -25.4,97 -27.01,58.98 -70.49,105.42 -126.69,137.57 -34.3,19.63 -79.56,33.64 -119,36.52 0,0 -12,0.91 -12,0.91 0,0 -34,0 -34,0 0,0 -10,-0.91 -10,-0.91 -26.57,-1.94 -53.09,-8.27 -78,-17.67 C 163.49,569.9 134.12,553.46 109,532.57 79.87,508.33 54.41,478.39 36.31,445 -5.08,368.65 -11.86,276.57 18.05,195 47.85,113.75 113.21,48.92 194,18.42 213.55,11.04 236.32,5.43 257,2.43 Z"
style="display:inline;fill:#ffefb3;fill-opacity:1"/>
<path
id="circle8"
d="M 387.28106,302.711 A 85.962512,85.962512 0 0 1 301.31852,388.67353 85.962512,85.962512 0 0 1 215.35597,302.711 85.962512,85.962512 0 0 1 301.31852,216.74844 85.962512,85.962512 0 0 1 387.28106,302.711 Z M 191.75349,358.6114 143.05798,460.97151 245.4181,412.27601 A 121.73882,121.73882 0 0 1 191.75349,358.6114 Z M 178.33753,302.711 c 0,-13.16763 2.23687,-25.83857 5.96271,-38.01232 L 77.71657,302.711 184.30024,340.7233 a 119.25435,119.25435 0 0 1 -5.96271,-38.0123 z m 178.8814,109.56501 102.36011,48.6955 -48.6955,-102.36011 a 121.73882,121.73882 0 0 1 -53.66461,53.66461 z m -55.90041,13.41595 c -13.16762,0 -26.0869,-2.23687 -38.01232,-5.9627 l 38.01232,106.58368 38.01231,-106.58368 a 119.25435,119.25435 0 0 1 -38.01231,5.9627 z m 109.56502,-178.88139 48.6955,-102.36012 -102.36011,48.69551 a 122.98106,122.98106 0 0 1 53.66461,53.66461 z M 245.66643,193.14596 143.30658,144.45045 192.00209,246.81057 a 121.73882,121.73882 0 0 1 53.66434,-53.66461 z M 524.92046,302.711 418.33679,264.69868 a 119.25435,119.25435 0 0 1 0,76.02462 z M 301.31852,179.73 c 13.16761,0 26.0869,2.23688 38.01231,5.96271 L 301.31852,79.109036 263.3062,185.69271 A 119.25435,119.25435 0 0 1 301.31852,179.73 Z"
style="fill:#b4a35e;fill-opacity:1;stroke:#000000;stroke-width:1.09833;stroke-dasharray:none;stroke-opacity:1"/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M586.9,373.6l95.6-84.4c-49.6-39.2-129.4-79.1-198.2-79.1c-134.9,0-248.2,90.5-280.2,212.8L10.6,374.5C64.4,168.3,255.2,15.8,482.5,15.8c126.7,0,258.8,63.7,345.4,141.4l90.8-80.1L990,479.6L586.9,373.6z M317.5,710.8c49.6,39.2,129.4,79.1,198.2,79.1c134.9,0,248.2-90.5,280.2-212.8l193.5,48.5c-53.7,206.2-244.6,358.7-471.9,358.7c-126.7,0-258.8-63.7-345.4-141.4l-90.8,80.1L10,520.4l403.1,106L317.5,710.8z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 797 B

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1200pt" height="1200pt" version="1.1" viewBox="0 0 1200 1200" xmlns="http://www.w3.org/2000/svg">
<path transform="scale(50)" d="m17 16h4v-8h-4" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="2"/>
<path transform="scale(50)" d="m12 8h-9v8h9" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="2"/>
<path transform="scale(50)" d="m6 12h5" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="2"/>
<path transform="scale(50)" d="m20 4h-2c-1.1 0-2 0.9-2 2v12c0 1.1 0.9 2 2 2h2" fill="none" stroke="#000"
stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2"/>
<path transform="scale(50)" d="m12 20h2c1.1 0 2-0.9 2-2v-12c0-1.1-0.9-2-2-2h-2" fill="none" stroke="#000"
stroke-linejoin="round" stroke-miterlimit="10" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 875 B

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000" version="1.1" id="Capa_1"
xmlns="http://www.w3.org/2000/svg"
width="800px" height="800px" viewBox="0 0 71.753 71.753"
xml:space="preserve">
<g>
<path d="M39.798,20.736H28.172v20.738L11.625,41.47V20.736H0L19.899,0.839L39.798,20.736z M51.855,70.914l19.897-19.896H60.129
V30.282l-16.547-0.004v20.74H31.957L51.855,70.914z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -1,99 +1,222 @@
<tips>
<tip>
<title>Tip of the Day</title>
<text>Tip of the Day is a new feature to Cockatrice that allows users to get information about the newest features of the program and some of the most commonly asked questions!</text>
<image>tip_of_the_day.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Suggesting New Tips</title>
<text>You can suggest new Tips of the Day by reaching out to the development team on &lt;a href="https://discord.gg/3Z9yzmA"&gt;Discord&lt;/a&gt;!</text>
<image>discord.png</image>
<date>2023-10-18</date>
</tip>
<tip>
<title>Reporting Bugs</title>
<text>If you encounter a bug while using Cockatrice, you can report the bug to the development team via &lt;a href="https://github.com/cockatrice/cockatrice/issues"&gt;GitHub&lt;a&gt;</text>
<image>github_logo.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>FAQ/Troubleshooting Wiki</title>
<text>You can find answers to the most common questions and some helpful Cockatrice toubleshooting over on the &lt;a href="https://github.com/cockatrice/cockatrice/wiki"&gt;GitHub wiki&lt;a&gt;</text>
<image>cockatrice_wiki.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Register for a Server</title>
<text>Click on either Cockatrice (Windows) or Actions (Mac) and then Register to server... When the dialogue appears, fill out the desired server information.</text>
<image>cockatrice_register.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Drawing Arrows</title>
<text>You can draw arrows of different color by holding a combination of keys!
Right Click: Red Arrow
Shift + Right Click: Green Arrow
Alt + Right Click: Blue Arrow
Cmd + Right Click: Yellow Arrow
</text>
<image>arrows.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Filtering Games</title>
<text>Don't see all the active games? Want to see a smaller selection? Use the Game Filters to change your horizon</text>
<image>filter_games.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Upload Custom Avatar</title>
<text>Want to show off your hippo avatar? Need to update your password? Check out the Accounts Tab for more info!</text>
<image>accounts_tab.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Common Shortcuts</title>
<text>You can find a full list of shortcuts &lt;a href="https://github.com/Cockatrice/Cockatrice/wiki/Custom-Keyboard-Shortcuts"&gt;on the wiki&lt;/a&gt;, but a short list:
&lt;br&gt;Roll a die: CTRL + I
&lt;br&gt;Mulligan: CTRL + M
&lt;br&gt;Draw a card: CTRL + D
&lt;br&gt;Undo a draw: CTRL + SHIFT + D
&lt;br&gt;View Sideboard: CTRL + F3
&lt;br&gt;Change Life: CTRL + L
&lt;br&gt;All shortcuts can be customized via Settings->Shortcuts!
</text>
<image>shortcuts.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Changing Themes</title>
<text>Did you know Cockatrice has custom themes? You can either &lt;a href="https://github.com/Cockatrice/Cockatrice/wiki/Themes"&gt;create one yourself&lt;/a&gt; or use one of the several pre-loaded ones! Go to Settings->Appearance and try them out!</text>
<image>themes.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Flip of the Coin</title>
<text>You can flip a coin instead of rolling a die by rolling a 2 sided die instead!</text>
<image>coin_flip.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Face Down Cards</title>
<text>You can hold Shift while dragging or clicking on a card to have it enter play face down</text>
<image>face_down.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Counter expressions</title>
<text>When setting a counter value, you can type a math expression in the box and the counter will be set to the result.&lt;br&gt;The "x" variable contains the current counter value.</text>
<image>counter_expression.png</image>
<date>2019-02-02</date>
</tip>
<tip>
<title>Power and Toughness</title>
<text>You can add and subtract to a creature's stats.&lt;br&gt;With a card selected, set the power and toughness ( default: ctrl + p ) and enter +3/-1 to increase power by three while decreasing toughness by one.&lt;br&gt;You can also reset it to the original value ( default: ctrl + alt + 0 ).</text>
<image>setpt.png</image>
<date>2019-03-02</date>
</tip>
<tip>
<title>Tip of the Day</title>
<text>Tip of the Day is a feature to Cockatrice that allows users to get information about the newest features of the program and some of the most commonly asked questions!
Check back in with major updates for new tips to be added or old tips to be updated as features are added or expanded upon!
</text>
<image>tip_of_the_day.png</image>
<date>2025-02-10</date>
</tip>
<tip>
<title>Join the Community</title>
<text>You can join the community to find games, interact with other players, suggest new 'Tips of the Day' and provide user feedback to the development or support teams on &lt;a href="https://discord.gg/3Z9yzmA"&gt;Discord&lt;/a&gt;!</text>
<image>discord.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Reporting Bugs and Requesting Features</title>
<text>If you encounter a bug while using Cockatrice, you can report the bug to and request the feature from the development team via &lt;a href="https://github.com/cockatrice/cockatrice/issues"&gt;GitHub&lt;a&gt;</text>
<image>github_logo.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>FAQ/Troubleshooting Wiki</title>
<text>You can find answers to the most common questions and some helpful Cockatrice troubleshooting over on the &lt;a href="https://github.com/cockatrice/cockatrice/wiki"&gt;GitHub wiki&lt;a&gt;</text>
<image>cockatrice_wiki.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Register for a Server</title>
<text>Click on either Cockatrice (Windows) or Actions (Mac) and then Register to server... When the dialogue appears, fill out the desired server information.</text>
<image>cockatrice_register.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Filtering Games</title>
<text>Don't see an open game or want to see a smaller selection? Use the Game Filters to change your horizon!</text>
<image>filter_games.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Common Shortcuts</title>
<text>You can find a full list of default shortcuts &lt;a href="https://github.com/Cockatrice/Cockatrice/wiki/Custom-Keyboard-Shortcuts"&gt;on the wiki&lt;/a&gt; or in Settings -> Shortcuts, but a short list:
&lt;ul&gt;
&lt;li&gt;Roll a die: CMD/CTRL + I&lt;/li&gt;
&lt;li&gt;Mulligan: CMD/CTRL + M&lt;/li&gt;
&lt;li&gt;Draw 1 / X card(s): CMD/CTRL + D / E&lt;/li&gt;
&lt;li&gt;Undo a draw: CMD/CTRL + SHIFT + D&lt;/li&gt;
&lt;li&gt;View Library / Sideboard: F3 / CMD/CTRL + F3&lt;/li&gt;
&lt;li&gt;Change Life: CMD/CTRL + L&lt;/li&gt;
&lt;li&gt;Show Card Info: Middle Mouse Click&lt;/li&gt;
&lt;/ul&gt;
All shortcuts can be customized via Cockatrice -> Settings -> Shortcuts!
</text>
<image>shortcuts.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Power and Toughness</title>
<text>You can add and subtract to a creature's stats.
With a card selected, with the following keybindings:
&lt;ul&gt;
&lt;li&gt;Set P/T to any value: CTRL + P&lt;/li&gt;
&lt;li&gt;+1 or -1 to both to P/T: CMD/CTRL + ALT + '+' or '-'&lt;/li&gt;
&lt;li&gt;+1 or -1 to Power Only: CMD/CTRL + '+' or '-'&lt;/li&gt;
&lt;li&gt;+1 or -1 to Toughness Only: ALT + '+' or '-'&lt;/li&gt;
&lt;li&gt;Set P/T to Default: CMD/CTRL + ALT + 0&lt;/li&gt;
&lt;/ul&gt;
All shortcuts can be customized via Cockatrice -> Settings -> Shortcuts!
</text>
<image>setpt.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Drawing Arrows</title>
<text>You can draw arrows of different color by holding a combination of keys!
&lt;ul&gt;
&lt;li&gt;Right Click: Red Arrow&lt;/li&gt;
&lt;li&gt;SHIFT + Right Click: Green Arrow&lt;/li&gt;
&lt;li&gt;ALT + Right Click: Blue Arrow&lt;/li&gt;
&lt;li&gt;CMD/CTRL + Right Click: Yellow Arrow&lt;/li&gt;
&lt;/ul&gt;
</text>
<image>arrows.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>General Etiquette</title>
<text>When playing on Cockatrice there are general "rules of engagement" for a better play experience for all players.
The following are some of the expectations a player should reasonably expect for how to operate smooth and enjoyable games:
&lt;ul&gt;
&lt;li&gt;Have a "Rule 0" conversation pre-game with your fellow players on the expectations of the game including deck strength, house rules (e.g. no take backs and "may is not must"), etc.&lt;/li&gt;
&lt;li&gt;When rolling your die for turn order, it is often best to create a token with the text of your roll (using CTRL + T and typing the number into "Name") and then tap this token when created to show that you have resolved your mulligans and are ready to start the game.&lt;/li&gt;
&lt;li&gt;Use the phases and steps trackers on the left of the client to show others where in the turn you are and announce when moving between them. (Double Click for the action of this button)&lt;/li&gt;
&lt;li&gt;When your turn is over leave it on your end step and DO NOT HIT PASS. Allow other players to respond if they can, and then if not, let the next player pass to themselves.&lt;/li&gt;
&lt;li&gt;Please treat others kindly and respect as per &lt;a href="https://cockatrice.us/terms.php"&gt;our Terms of Service&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</text>
<image>token.png</image>
<date>2025-02-10</date>
</tip>
<tip>
<title>Flip of the Coin</title>
<text>You can flip a coin instead of rolling a die by rolling a 2 sided die instead!</text>
<image>coin_flip.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Upload Custom Avatar</title>
<text>Want to show off your hippo avatar? Need to update your password? Check out the Accounts Tab for more info!</text>
<image>accounts_tab.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Player Icon Key</title>
<text>Besides your name is a player icon, this is a key for what they mean:
&lt;ul&gt;
&lt;li&gt;Flag: Country of Origin Player Selected&lt;/li&gt;
&lt;li&gt;Purple Heart: Donator (&lt;a href="https://cockatrice.us/donate"&gt;Help support us and donate here!&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Gold Star: VIP (Special Admin Given Role)&lt;/li&gt;
&lt;li&gt;Brown Gavel (Hammer): Judge / Rule's Lawyer&lt;/li&gt;
&lt;li&gt;Black/White Pawn: Moderator (Support for Client Issues)&lt;/li&gt;
&lt;li&gt;Red: Administrator (Sever Operators)&lt;/li&gt;
&lt;/ul&gt;
</text>
<image>pawns.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Changing Themes</title>
<text>Did you know Cockatrice has custom themes? You can either &lt;a href="https://github.com/Cockatrice/Cockatrice/wiki/Themes"&gt;create one yourself&lt;/a&gt; or use one of the several preloaded ones! Go to Settings->Appearance and try them out!</text>
<image>themes.png</image>
<date>2018-03-01</date>
</tip>
<tip>
<title>Face Down Cards</title>
<text>You can hold Shift while dragging or clicking on a card to have it enter play face down.
You can also hold CTRL + SHIFT and click and drag from your library to move bottom card face down as well!
</text>
<image>face_down.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Counter expressions</title>
<text>When setting a counter value, you can type a math expression in the box and the counter will be set to the result.&lt;br&gt;The "x" variable contains the current counter value.</text>
<image>counter_expression.png</image>
<date>2019-02-02</date>
</tip>
<tip>
<title>Select Multiple Cards</title>
<text>You can click and drag in any zone in order to highlight all cards within the created box.
You can also hold CMD/CTRL and clik or click and drag to maintain other previously selected cards while adding others!
You can move, alter and attach multiple highlighted cards at the same time!
Other useful multi-select keybindings:
&lt;ul&gt;
&lt;li&gt;Select All Cards in Zone: CMD/CTRL + A&lt;/li&gt;
&lt;li&gt;Select All Cards in Column: CMD/CTRL + SHIFT + C&lt;/li&gt;
&lt;li&gt;Select All Cards in Row: CMD/CTRL + SHIFT + X&lt;/li&gt;
&lt;/ul&gt;
</text>
<image>highlight_cards.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Auto Cascade and Search Parameters</title>
<text>You can use the default keybind of CMD/CTRL + SHIFT + Y in order to perform auto cascade or similar effects from your library using Scryfall search syntax.
If you are unfamiliar with the syntax you may find it by opening a deck in deck editor and clicking the "i" next to the search bar in order to pull up a list of syntax commands.
This same syntax can be used in the deck editor search bar as well to help you find the best cards for your decks!
</text>
<image>syntax_help.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Visual Deck Storage and Tags</title>
<text>You can now view your saved decks visually with integrated folder,tags and filter support!
Pro Tip: If you want to use emoji's press WinKey + '.' or CTRL + CMD + SPACE on Windows or Mac respectively!
</text>
<image>visual_deck_tags.png</image>
<date>2025-02-09</date>
</tip>
<tip>
<title>Card Selector And Card Preferences</title>
<text>Cockatrice's deck editor now has the ability for players to bling out their decks by selecting the arts for cards on a per-card basis!
You can also have multiple printings of the same card in your deck if you so choose!
Not only that, other players will see the arts you have chosen by default!
If you want to disable this feature for other players: Settings -> Appearance -> Select "Override all card art with personal set preference"
</text>
<image>card_select.png</image>
<date>2025-02-10</date>
</tip>
<tip>
<title>EDHREC Integration</title>
<text>We now have in-client integration for EDHREC, which allows you to right-click on any card name in the deck editor in order to bring up the contextual menu for the card.</text>
<image>edhrec.png</image>
<date>2025-02-10</date>
</tip>
<tip>
<title>Add Cards to Deck</title>
<text>You can now right-click anywhere on a card in any card info view in order to add it to any decks you have open in your tabs.</text>
<image>add_card.png</image>
<date>2025-02-10</date>
</tip>
<tip>
<title>Update Client and Card Database</title>
<text>You can update your client by going to Help and selecting whichever you wish to update.
Client Update: Updates the client (if available) for new features, fixes and changes.
Card Update: Updates card sources for spoilers and new card printings.
Updating your card sources can often fix issues of cards not working or displaying properly, if not, go to Cockatrice -> Settings -> Card Sources -> Update Spoilers
</text>
<image>updates.png</image>
<date>2025-02-10</date>
</tip>
<tip>
<title>Expand Card View Window</title>
<text>Double click on the title bar of the card view window to expand it! Double click again to shrink it back down.
You can configure the initial and expanded heights of the window in the settings, under "Appearance".
</text>
<image>expand_card_view.png</image>
<date>2025-02-27</date>
</tip>
</tips>

View File

@@ -2,20 +2,20 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="registered.svg">
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="pawn_donator_double.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3">
<inkscape:perspective
@@ -226,16 +226,6 @@
offset="1"
id="stop5193-4" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5181-9"
id="linearGradient5436"
x1="12.105612"
y1="1021.5341"
x2="87.549789"
y2="1021.5341"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,-952.36218)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173-1"
@@ -288,6 +278,28 @@
id="linearGradient5799"
xlink:href="#linearGradient5181-9"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2"
id="linearGradient3"
x1="49.889599"
y1="87.971054"
x2="50.103622"
y2="27.668242"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2878408,0,0,1.2878408,-14.204862,937.12313)" />
<linearGradient
id="linearGradient2"
inkscape:collect="always">
<stop
style="stop-color:#8c5fd3;stop-opacity:1;"
offset="0"
id="stop2" />
<stop
style="stop-color:#b284e9;stop-opacity:1;"
offset="0.5"
id="stop1" />
</linearGradient>
</defs>
<sodipodi:namedview
inkscape:document-units="mm"
@@ -297,16 +309,26 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="-150.71429"
inkscape:cy="59.570011"
inkscape:zoom="6.0735294"
inkscape:cx="53.675545"
inkscape:cy="53.922518"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
inkscape:window-width="1147"
inkscape:window-height="1211"
inkscape:window-x="2678"
inkscape:window-y="120"
inkscape:window-maximized="0"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showguides="true">
<sodipodi:guide
position="49.829627,61.114263"
orientation="1,0"
id="guide1"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata4">
<rdf:RDF>
@@ -325,9 +347,20 @@
id="layer1"
transform="translate(0,-952.36218)">
<path
style="fill:url(#linearGradient5436);fill-opacity:1;stroke:black;stroke-width:2.78220295999999980;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="path3597-8" />
id="right" />
<path
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
id="left"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient3);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.77952756;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="m 32.758369,1023.3386 c -11.433625,-11.4486 -17.473759,-17.611 -17.925056,-18.2881 -5.1991493,-7.80033 -4.072462,-18.0055 2.698653,-24.44352 0.714467,-0.67932 1.7595,-1.54783 2.322296,-1.93001 1.523368,-1.0345 4.16292,-2.23825 5.970504,-2.72281 1.443337,-0.38692 1.89368,-0.43006 4.608041,-0.44142 3.235152,-0.0136 4.137158,0.12212 6.533598,0.9827 3.134814,1.12573 4.852536,2.32851 8.590659,6.01531 1.655211,1.63249 3.214977,3.04629 3.466142,3.14178 0.581823,0.22121 1.425484,0.22197 2.004581,0.002 0.248578,-0.0945 1.808341,-1.50526 3.466143,-3.135 3.106188,-3.05362 4.561863,-4.18308 6.729637,-5.22153 5.163233,-2.47341 10.985326,-2.50551 16.312741,-0.0899 2.006474,0.90978 3.995303,2.39379 5.679043,4.16678 1.393273,1.46713 2.577641,3.13214 3.390238,4.83339 1.300107,2.7219 1.79207,4.98307 1.79207,8.23671 0,4.67613 -1.161204,8.04312 -4.066015,11.78952 -0.567611,0.7321 -8.293484,8.5311 -17.668765,17.8362 l -16.660107,16.5352 z"
id="path2"
sodipodi:nodetypes="sssssssssssssssssscs"
inkscape:label="heart" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,229 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="pawn_donator_single.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
id="defs3"><linearGradient
id="linearGradient2"
inkscape:collect="always"><stop
style="stop-color:#8c5fd3;stop-opacity:1;"
offset="0"
id="stop2" /><stop
style="stop-color:#b284e9;stop-opacity:1;"
offset="0.5"
id="stop1" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective5328" /><inkscape:perspective
id="perspective5305"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><linearGradient
id="linearGradient5181"><stop
style="stop-color:#0fbb00;stop-opacity:1;"
offset="0"
id="stop5183" /><stop
style="stop-color:#064400;stop-opacity:1;"
offset="1"
id="stop5185" /></linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-2"
id="radialGradient3606-7"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" /><linearGradient
id="linearGradient3600-2"><stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-4" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-9" /></linearGradient><inkscape:perspective
id="perspective5478"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><linearGradient
id="linearGradient5189"><stop
style="stop-color:#000ec9;stop-opacity:1;"
offset="0"
id="stop5191" /><stop
style="stop-color:#000657;stop-opacity:1;"
offset="1"
id="stop5193" /></linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-4"
id="radialGradient3606-1"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" /><linearGradient
id="linearGradient3600-4"><stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-3" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-5" /></linearGradient><inkscape:perspective
id="perspective5559"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173"
id="linearGradient5179"
x1="167.33386"
y1="178.83276"
x2="244.78181"
y2="178.83276"
gradientUnits="userSpaceOnUse" /><linearGradient
id="linearGradient5173"><stop
style="stop-color:#f50000;stop-opacity:1;"
offset="0"
id="stop5175" /><stop
style="stop-color:#950000;stop-opacity:1;"
offset="1"
id="stop5177" /></linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600"
id="radialGradient5169"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276" /><linearGradient
id="linearGradient3600"><stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604" /></linearGradient><radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
id="radialGradient5574"
xlink:href="#linearGradient3600"
inkscape:collect="always" /><inkscape:perspective
id="perspective5663"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-7"
id="radialGradient3606-8"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" /><linearGradient
id="linearGradient3600-7"><stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602-7" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-6" /></linearGradient><radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
id="radialGradient5676"
xlink:href="#linearGradient3600-7"
inkscape:collect="always" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2"
id="linearGradient3"
x1="49.889599"
y1="87.971054"
x2="50.103622"
y2="27.668242"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2878408,0,0,1.2878408,-14.204016,-15.239682)" /></defs><sodipodi:namedview
inkscape:document-units="mm"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.9195959"
inkscape:cx="55.179583"
inkscape:cy="45.519999"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:window-width="1147"
inkscape:window-height="1211"
inkscape:window-x="3260"
inkscape:window-y="138"
inkscape:window-maximized="0"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showguides="true"><sodipodi:guide
position="50.002551,111.99556"
orientation="1,0"
id="guide3"
inkscape:locked="false" /></sodipodi:namedview><metadata
id="metadata4"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-952.36218)"
style="display:inline"><path
style="display:inline;opacity:1;fill-opacity:1;stroke:#000000;stroke-width:2.7822;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 49.84375,1.71875 C 36.719738,1.71875 26.0625,12.375988 26.0625,25.5 c 0,7.477454 3.475825,14.112734 8.875,18.46875 -10.497549,5.974948 -17.018351,18.227376 -20.625,31.6875 -5.2744126,19.6844 15.911513,22.5625 35.53125,22.5625 19.619736,0 40.705577,-3.2516 35.53125,-22.5625 C 81.693381,61.916246 75.224585,49.827177 64.8125,43.9375 70.181573,39.580662 73.59375,32.953205 73.59375,25.5 c 0,-13.124012 -10.625988,-23.78125 -23.75,-23.78125 z"
id="left"
transform="translate(0,952.36218)" /></g><g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2"><path
style="display:inline;fill:url(#linearGradient3);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.77952756;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="M 32.759215,70.975878 C 21.325591,59.527249 15.285457,53.364742 14.83416,52.687661 9.63501,44.887358 10.761698,34.682189 17.532813,28.244167 c 0.714467,-0.67932 1.7595,-1.547825 2.322296,-1.930012 1.523368,-1.034499 4.16292,-2.238249 5.970504,-2.722807 1.443337,-0.386915 1.89368,-0.430056 4.60804,-0.441421 3.235152,-0.01355 4.137158,0.122126 6.533598,0.982701 3.134814,1.125736 4.852536,2.328512 8.590659,6.015311 1.655211,1.632489 3.214977,3.046293 3.466142,3.141784 0.581823,0.221209 1.425484,0.221963 2.004581,0.0018 0.248578,-0.09451 1.808341,-1.50526 3.466143,-3.135003 3.106188,-3.053615 4.561863,-4.183076 6.729637,-5.221531 5.163233,-2.473409 10.985326,-2.505514 16.312741,-0.08995 2.006474,0.909779 3.995303,2.393791 5.679043,4.166785 1.393273,1.467129 2.577641,3.132133 3.390238,4.833386 1.300107,2.721904 1.79207,4.98307 1.79207,8.23671 0,4.676126 -1.161204,8.043076 -4.066015,11.789548 -0.567611,0.732076 -8.293484,8.531153 -17.668765,17.836181 l -16.660107,16.53525 z"
id="path2"
sodipodi:nodetypes="sssssssssssssssssscs"
inkscape:label="heart" /></g></svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -2,20 +2,20 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="normal.svg">
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="pawn_double.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3">
<inkscape:perspective
@@ -195,66 +195,16 @@
id="stop3604-6" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-7"
id="radialGradient5254"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
cx="324.32715"
cy="131.40274"
fx="324.32715"
r="25.501276"
fy="131.40274"
r="25.501276" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5189-1"
id="linearGradient5394"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
x1="385.03503"
y1="180.09546"
x2="462.48297"
y2="180.09546"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-360.365,847.52359)" />
<linearGradient
id="linearGradient5189-1">
<stop
style="stop-color:#32c8ed;stop-opacity:1;"
offset="0"
id="stop5191-0" />
<stop
style="stop-color:#32c8ed;stop-opacity:1;"
offset="1"
id="stop5193-4" />
</linearGradient>
<linearGradient
y2="180.09546"
x2="462.48297"
y1="180.09546"
x1="385.03503"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-318.22214,876.88769)"
gradientUnits="userSpaceOnUse"
id="linearGradient5411"
xlink:href="#linearGradient5189-1"
id="radialGradient5676"
xlink:href="#linearGradient3600-7"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5189-1"
id="linearGradient5436"
x1="12.105612"
y1="1021.5341"
x2="87.549789"
y2="1021.5341"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5189-1"
id="linearGradient3795"
gradientUnits="userSpaceOnUse"
x1="12.105612"
y1="1021.5341"
x2="87.549789"
y2="1021.5341"
gradientTransform="translate(0,-952.36218)" />
</defs>
<sodipodi:namedview
inkscape:document-units="mm"
@@ -264,16 +214,19 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="-150.71429"
inkscape:cy="59.570011"
inkscape:current-layer="layer1"
inkscape:zoom="5.6"
inkscape:cx="63.214286"
inkscape:cy="46.160714"
inkscape:current-layer="g5249"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
inkscape:window-width="1147"
inkscape:window-height="1211"
inkscape:window-x="2842"
inkscape:window-y="58"
inkscape:window-maximized="0"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" />
<metadata
id="metadata4">
<rdf:RDF>
@@ -291,10 +244,25 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-952.36218)">
<path
style="fill:url(#linearGradient3795);fill-opacity:1;stroke:black;stroke-width:2.78220295999999980;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:1"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="path3597-8" />
<g
id="g5249"
transform="translate(0.53874115,0.90502985)">
<path
style="stroke:#000000;stroke-width:4.45809746000000030;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill-opacity:1"
d="m 49.582319,954.34642 c -12.850034,0 -23.284789,10.43476 -23.284789,23.28479 0,7.32135 3.403263,13.81811 8.689724,18.08319 -10.278401,5.8502 -16.663073,17.8469 -20.19443,31.0259 -5.1178053,19.1 15.207096,22.0401 34.269334,22.0915 l 0,0.031 c 0.290839,0 0.566498,0.031 0.856734,0.031 19.210152,0 39.855802,-3.1837 34.789494,-22.0914 -3.636192,-13.5705 -10.027831,-25.4711 -20.378015,-31.17899 5.208701,-4.26694 8.506139,-10.73278 8.506139,-17.9914 0,-12.85003 -10.404159,-23.28479 -23.254191,-23.28479 z"
id="left"
inkscape:connector-curvature="0" />
<path
fill="none"
style="stroke:#000000;stroke-width:1.97203517px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 50.522358,952.70715 0,95.71425"
id="center"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.71966;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 51.054254,1001.4773 v -45.77683 l 1.097241,0.005 c 3.642211,0.0172 9.170661,2.46935 12.395732,5.49816 4.897489,4.59945 7.421654,10.97001 6.981907,17.62114 -0.389167,5.88609 -2.631878,10.66609 -6.951818,14.81672 l -2.05562,1.97506 2.959813,2.0746 c 3.467097,2.43015 7.403677,6.55065 9.666109,10.11765 3.325898,5.2437 6.79289,13.8355 8.153827,20.2065 2.584451,12.0989 -5.997953,18.2384 -26.592174,19.0232 l -5.655017,0.2154 v -45.7768 z"
id="right"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -2,33 +2,22 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="registered_vip.svg">
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="pawn_judge_double.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3">
<linearGradient
id="linearGradient5181-9-1">
<stop
id="stop4188"
offset="0"
style="stop-color:#ece400;stop-opacity:1" />
<stop
id="stop4190"
offset="1"
style="stop-color:#ec8b00;stop-opacity:1" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
@@ -237,16 +226,6 @@
offset="1"
id="stop5193-4" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5181-9-1"
id="linearGradient5436"
x1="47.268291"
y1="933.14362"
x2="48.665382"
y2="1050.2666"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,-952.36218)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173-1"
@@ -309,15 +288,18 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.2946338"
inkscape:cx="35.27742"
inkscape:cy="65.175571"
inkscape:current-layer="layer1"
inkscape:cx="34.112338"
inkscape:cy="64.964794"
inkscape:current-layer="svg5322"
showgrid="false"
inkscape:window-width="1152"
inkscape:window-height="811"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
inkscape:window-width="1440"
inkscape:window-height="792"
inkscape:window-x="2921"
inkscape:window-y="661"
inkscape:window-maximized="0"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" />
<metadata
id="metadata4">
<rdf:RDF>
@@ -326,7 +308,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@@ -336,9 +318,20 @@
id="layer1"
transform="translate(0,-952.36218)">
<path
style="fill:url(#linearGradient5436);fill-opacity:1;stroke:black;stroke-width:2.78149606;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="path3597-8" />
id="right" />
<path
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
id="left"
inkscape:connector-curvature="0" />
<path
d="m 46.656521,12.167234 18.055171,18.054184 a 6.6081919,6.6078288 0 0 1 -0.126303,9.352065 6.6804126,6.6800456 0 0 1 -8.233169,1.011048 l -7.944268,7.943843 6.463762,6.445343 a 6.9331851,6.9328042 0 0 1 5.741536,2.022073 l 28.057729,28.092294 a 6.9962797,6.9958953 0 0 1 -9.894222,9.893685 L 50.719018,66.907526 A 7.0595711,7.0591833 0 0 1 49.18433,59.270613 l -5.741527,-5.741238 -7.944298,7.943843 A 6.716523,6.7161541 0 0 1 25.134866,69.832263 L 7.079684,51.778091 a 6.716523,6.7161541 0 0 1 8.39566,-10.345064 L 36.31101,20.59853 a 6.716523,6.7161541 0 0 1 10.345612,-8.431329 z"
id="path1-2"
style="display:inline;fill:#e1964c;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.7852;stroke-dasharray:none;stroke-opacity:1"
inkscape:label="gavel"
transform="translate(0,952.36218)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="pawn_judge_single.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
id="defs3"><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective5328" /><inkscape:perspective
id="perspective5305"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><linearGradient
id="linearGradient5181"><stop
style="stop-color:#0fbb00;stop-opacity:1;"
offset="0"
id="stop5183" /><stop
style="stop-color:#064400;stop-opacity:1;"
offset="1"
id="stop5185" /></linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-2"
id="radialGradient3606-7"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" /><linearGradient
id="linearGradient3600-2"><stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-4" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-9" /></linearGradient><inkscape:perspective
id="perspective5478"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><linearGradient
id="linearGradient5189"><stop
style="stop-color:#000ec9;stop-opacity:1;"
offset="0"
id="stop5191" /><stop
style="stop-color:#000657;stop-opacity:1;"
offset="1"
id="stop5193" /></linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-4"
id="radialGradient3606-1"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" /><linearGradient
id="linearGradient3600-4"><stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-3" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-5" /></linearGradient><inkscape:perspective
id="perspective5559"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173"
id="linearGradient5179"
x1="167.33386"
y1="178.83276"
x2="244.78181"
y2="178.83276"
gradientUnits="userSpaceOnUse" /><linearGradient
id="linearGradient5173"><stop
style="stop-color:#f50000;stop-opacity:1;"
offset="0"
id="stop5175" /><stop
style="stop-color:#950000;stop-opacity:1;"
offset="1"
id="stop5177" /></linearGradient><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600"
id="radialGradient5169"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276" /><linearGradient
id="linearGradient3600"><stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604" /></linearGradient><radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
id="radialGradient5574"
xlink:href="#linearGradient3600"
inkscape:collect="always" /><inkscape:perspective
id="perspective5663"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-7"
id="radialGradient3606-8"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" /><linearGradient
id="linearGradient3600-7"><stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602-7" /><stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-6" /></linearGradient><radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
id="radialGradient5676"
xlink:href="#linearGradient3600-7"
inkscape:collect="always" /></defs><sodipodi:namedview
inkscape:document-units="mm"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="58.035715"
inkscape:cy="30.982143"
inkscape:current-layer="svg5322"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1369"
inkscape:window-x="2552"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showguides="true"><sodipodi:guide
position="50.002551,111.99556"
orientation="1,0"
id="guide3"
inkscape:locked="false" /></sodipodi:namedview><metadata
id="metadata4"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-952.36218)"
style="display:inline">
<path
style="display:inline;opacity:1;fill-opacity:1;stroke:#000000;stroke-width:2.7822;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 49.84375,1.71875 C 36.719738,1.71875 26.0625,12.375988 26.0625,25.5 c 0,7.477454 3.475825,14.112734 8.875,18.46875 -10.497549,5.974948 -17.018351,18.227376 -20.625,31.6875 -5.2744126,19.6844 15.911513,22.5625 35.53125,22.5625 19.619736,0 40.705577,-3.2516 35.53125,-22.5625 C 81.693381,61.916246 75.224585,49.827177 64.8125,43.9375 70.181573,39.580662 73.59375,32.953205 73.59375,25.5 c 0,-13.124012 -10.625988,-23.78125 -23.75,-23.78125 z"
id="left"
sodipodi:insensitive="true"
transform="translate(0,952.36218)" />
<path
d="m 46.233565,28.34179 -1.622479,1.622479 a 0.59382712,0.59382712 0 0 1 -0.840444,-0.01135 0.60031703,0.60031703 0 0 1 -0.09086,-0.739851 l -0.713891,-0.71389 -0.579225,0.580848 a 0.62303175,0.62303175 0 0 1 -0.181718,0.515948 l -2.524576,2.521331 a 0.62870157,0.62870157 0 0 1 -0.889118,-0.889117 l 2.522954,-2.521332 a 0.63438908,0.63438908 0 0 1 0.686308,-0.137911 l 0.515949,-0.515947 -0.713891,-0.713892 a 0.603562,0.603562 0 0 1 -0.751204,-0.9313 l 1.622478,-1.62248 a 0.603562,0.603562 0 0 1 0.929682,0.754453 l 1.872338,1.87234 a 0.603562,0.603562 0 0 1 0.7577,0.92968 z"
id="path1-2"
style="display:inline;fill:#e1964c;fill-rule:nonzero;stroke:#000000;stroke-width:0.34015748;stroke-opacity:1;fill-opacity:1;stroke-dasharray:none"
transform="matrix(0,-11.111111,11.111111,0,-268.32014,1478.2316)"
inkscape:label="gavel" /></g></svg>

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -2,20 +2,20 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="vip.svg">
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
sodipodi:docname="pawn_single.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3">
<inkscape:perspective
@@ -194,57 +194,16 @@
offset="1"
id="stop3604-6" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5189-1"
id="linearGradient5394"
<radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
x1="385.03503"
y1="180.09546"
x2="462.48297"
y2="180.09546"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-360.365,847.52359)" />
<linearGradient
id="linearGradient5189-1">
<stop
style="stop-color:#000ec9;stop-opacity:1;"
offset="0"
id="stop5191-0" />
<stop
style="stop-color:#000657;stop-opacity:1;"
offset="1"
id="stop5193-4" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173-1"
id="linearGradient5581"
gradientUnits="userSpaceOnUse"
x1="167.33386"
y1="178.83276"
x2="244.78181"
y2="178.83276"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-149.54484,848.74636)" />
<linearGradient
id="linearGradient5173-1">
<stop
style="stop-color:#ff2700;stop-opacity:1;"
offset="0"
id="stop5175-5" />
<stop
style="stop-color:#ff2700;stop-opacity:1;"
offset="1"
id="stop5177-3" />
</linearGradient>
<linearGradient
y2="178.83276"
x2="244.78181"
y1="178.83276"
x1="167.33386"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-52.401983,877.75333)"
gradientUnits="userSpaceOnUse"
id="linearGradient5598"
xlink:href="#linearGradient5173-1"
id="radialGradient5676"
xlink:href="#linearGradient3600-7"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
@@ -255,16 +214,19 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="-59.166471"
inkscape:cy="4.9508223"
inkscape:zoom="5.6"
inkscape:cx="63.214286"
inkscape:cy="46.160714"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1440"
inkscape:window-height="792"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
inkscape:window-width="1147"
inkscape:window-height="1211"
inkscape:window-x="3185"
inkscape:window-y="44"
inkscape:window-maximized="0"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" />
<metadata
id="metadata4">
<rdf:RDF>
@@ -283,9 +245,9 @@
id="layer1"
transform="translate(0,-952.36218)">
<path
style="fill:#8d5fd3;fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:1"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
id="path3597-8"
id="left"
transform="translate(0,952.36218)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@@ -337,19 +337,19 @@
id="layer1"
transform="translate(0,-952.36218)">
<path
style="fill:#ffffff;fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="path3597-8" />
id="right" />
<path
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 51.28696,1001.834 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938257,6.36366 4.74393,4.9715 6.87913,11.35611 6.16464,18.43328 -0.53702,5.31935 -3.09008,10.59498 -6.83833,14.13074 l -1.94072,1.83069 3.04083,2.20427 c 3.58084,2.5957 7.18975,6.4912 9.55296,10.3116 4.89572,7.9144 9.23593,21.4918 8.50487,26.6055 -0.81312,5.6877 -5.43872,9.6977 -13.62216,11.8093 -3.80822,0.9826 -7.68056,1.4713 -14.763321,1.8633 l -4.471177,0.2474 0,-46.9837 z"
id="path5355"
id="left"
inkscape:connector-curvature="0" />
<path
sodipodi:type="star"
style="fill:url(#linearGradient3425-5);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path3415-0"
id="star"
sodipodi:sides="5"
sodipodi:cx="27.80283"
sodipodi:cy="970.9433"

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -337,14 +337,14 @@
id="layer1"
transform="translate(0,-952.36218)">
<path
style="fill:#ff0000;fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
style="fill-opacity:1;stroke:black;stroke-width:2.78220296;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="path3597-8" />
id="left" />
<path
sodipodi:type="star"
style="fill:url(#linearGradient3425);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path3415"
id="star"
sodipodi:sides="5"
sodipodi:cx="27.80283"
sodipodi:cy="970.9433"

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -114,18 +114,18 @@
inkscape:current-layer="svg2" />
<path
d="M 61.442826,23.621762 38.532402,23.515555 31.556101,0.331013 24.578789,23.515555 1.6673502,23.621765 20.267785,38.422001 10.863888,63.668987 31.556101,47.626631 52.258426,63.668987 42.843404,38.422001 z"
id="path4-9"
id="outline"
style="fill:#000000;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 55.041981,25.814432 36.921945,25.730432 31.404334,7.3935963 25.885923,25.730432 7.7650846,25.814434 22.476316,37.520057 15.0387,57.488097 31.404334,44.800071 47.777965,57.488097 40.331551,37.520057 z"
id="path4"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero"
id="left"
style="fill-opacity:1;fill-rule:nonzero"
inkscape:connector-curvature="0" />
<path
d="M 56.276895,25.211993 37.3433,24.856806 31.486705,5.7742084 c 0.04705,37.4359336 -0.01851,2.6744908 -0.0678,40.1841446 L 48.19932,58.580578 40.956295,37.527792 z"
id="path4-1"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero"
id="right"
style="fill-opacity:1;fill-rule:nonzero"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -109,7 +109,7 @@
inkscape:connector-curvature="0" />
<path
d="M 57.150089,25.064396 37.504323,24.973324 31.522122,5.092503 25.539054,24.973324 5.8924192,25.064399 21.842354,37.75565 13.778482,59.405024 31.522122,45.64865 49.274434,59.405024 41.201022,37.75565 z"
id="path4"
style="fill:url(#linearGradient3756);fill-opacity:1"
id="left"
style="fill-opacity:1"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,301 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="admin.svg">
<defs
id="defs3">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective5328" />
<inkscape:perspective
id="perspective5305"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient5181">
<stop
style="stop-color:#0fbb00;stop-opacity:1;"
offset="0"
id="stop5183" />
<stop
style="stop-color:#064400;stop-opacity:1;"
offset="1"
id="stop5185" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-2"
id="radialGradient3606-7"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" />
<linearGradient
id="linearGradient3600-2">
<stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-4" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-9" />
</linearGradient>
<inkscape:perspective
id="perspective5478"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient5189">
<stop
style="stop-color:#000ec9;stop-opacity:1;"
offset="0"
id="stop5191" />
<stop
style="stop-color:#000657;stop-opacity:1;"
offset="1"
id="stop5193" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-4"
id="radialGradient3606-1"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" />
<linearGradient
id="linearGradient3600-4">
<stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-3" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-5" />
</linearGradient>
<inkscape:perspective
id="perspective5559"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173"
id="linearGradient5179"
x1="167.33386"
y1="178.83276"
x2="244.78181"
y2="178.83276"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient5173">
<stop
style="stop-color:#f50000;stop-opacity:1;"
offset="0"
id="stop5175" />
<stop
style="stop-color:#950000;stop-opacity:1;"
offset="1"
id="stop5177" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600"
id="radialGradient5169"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276" />
<linearGradient
id="linearGradient3600">
<stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604" />
</linearGradient>
<radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
id="radialGradient5574"
xlink:href="#linearGradient3600"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5663"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-7"
id="radialGradient3606-8"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" />
<linearGradient
id="linearGradient3600-7">
<stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602-7" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-6" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5189-1"
id="linearGradient5394"
gradientUnits="userSpaceOnUse"
x1="385.03503"
y1="180.09546"
x2="462.48297"
y2="180.09546"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-360.365,847.52359)" />
<linearGradient
id="linearGradient5189-1">
<stop
style="stop-color:#000ec9;stop-opacity:1;"
offset="0"
id="stop5191-0" />
<stop
style="stop-color:#000657;stop-opacity:1;"
offset="1"
id="stop5193-4" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173-1"
id="linearGradient5436"
x1="12.105612"
y1="1021.5341"
x2="87.549789"
y2="1021.5341"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,-952.36218)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173-1"
id="linearGradient5581"
gradientUnits="userSpaceOnUse"
x1="167.33386"
y1="178.83276"
x2="244.78181"
y2="178.83276"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-149.54484,848.74636)" />
<linearGradient
id="linearGradient5173-1">
<stop
style="stop-color:#ff2700;stop-opacity:1;"
offset="0"
id="stop5175-5" />
<stop
style="stop-color:#ff2700;stop-opacity:1;"
offset="1"
id="stop5177-3" />
</linearGradient>
<linearGradient
y2="178.83276"
x2="244.78181"
y1="178.83276"
x1="167.33386"
gradientTransform="matrix(0.96839241,0,0,0.96839241,-52.401983,877.75333)"
gradientUnits="userSpaceOnUse"
id="linearGradient5598"
xlink:href="#linearGradient5173-1"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
inkscape:document-units="mm"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="-32.045264"
inkscape:cy="65.284297"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-952.36218)">
<path
style="fill:url(#linearGradient5436);fill-opacity:1;stroke:black;stroke-width:2.78220295999999980;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 49.84375 1.71875 C 36.719738 1.71875 26.0625 12.375988 26.0625 25.5 C 26.0625 32.977454 29.538325 39.612734 34.9375 43.96875 C 24.439951 49.943698 17.919149 62.196126 14.3125 75.65625 C 9.0380874 95.34065 30.224013 98.21875 49.84375 98.21875 C 69.463486 98.21875 90.549327 94.96715 85.375 75.65625 C 81.693381 61.916246 75.224585 49.827177 64.8125 43.9375 C 70.181573 39.580662 73.59375 32.953205 73.59375 25.5 C 73.59375 12.375988 62.967762 1.71875 49.84375 1.71875 z "
transform="translate(0,952.36218)"
id="path3597-8" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -1,136 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 64 64"
enable-background="new 0 0 64 64"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="100%"
height="100%"
sodipodi:docname="admin_buddy.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<linearGradient
id="linearGradient3766">
<stop
style="stop-color:#ff2700;stop-opacity:1;"
offset="0"
id="stop3768" />
<stop
style="stop-color:#820000;stop-opacity:1;"
offset="1"
id="stop3770" />
</linearGradient>
<linearGradient
id="linearGradient5225">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5227" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop5229" />
</linearGradient>
<linearGradient
id="linearGradient5219"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5221" />
</linearGradient>
<linearGradient
id="linearGradient3758">
<stop
id="stop3760"
offset="0"
style="stop-color:#0fbb00;stop-opacity:1;" />
<stop
id="stop3762"
offset="1"
style="stop-color:#064400;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3750">
<stop
style="stop-color:#ece400;stop-opacity:1;"
offset="0"
id="stop3752" />
<stop
style="stop-color:#ece400;stop-opacity:0;"
offset="1"
id="stop3754" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3758-7"
id="linearGradient3756-1"
x1="1.960216"
y1="31.261461"
x2="60.456024"
y2="31.261461"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3758-7">
<stop
id="stop3760-4"
offset="0"
style="stop-color:#ece400;stop-opacity:1;" />
<stop
id="stop3762-0"
offset="1"
style="stop-color:#ec8b00;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1028"
id="namedview8"
showgrid="false"
inkscape:zoom="5.2149125"
inkscape:cx="-37.840247"
inkscape:cy="51.245759"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
d="M 61.442826,23.621762 38.532402,23.515555 31.556101,0.331013 24.578789,23.515555 1.6673502,23.621765 20.267785,38.422001 10.863888,63.668987 31.556101,47.626631 52.258426,63.668987 42.843404,38.422001 z"
id="path4-9"
style="fill:#000000;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 57.150089,25.064396 37.504323,24.973324 31.522122,5.092503 25.539054,24.973324 5.8924192,25.064399 21.842354,37.75565 13.778482,59.405024 31.522122,45.64865 49.274434,59.405024 41.201022,37.75565 z"
id="path4"
style="fill:#ff2700;fill-opacity:1;fill-rule:nonzero"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,136 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 64 64"
enable-background="new 0 0 64 64"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="100%"
height="100%"
sodipodi:docname="admin_buddy.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<linearGradient
id="linearGradient3766">
<stop
style="stop-color:#ff2700;stop-opacity:1;"
offset="0"
id="stop3768" />
<stop
style="stop-color:#820000;stop-opacity:1;"
offset="1"
id="stop3770" />
</linearGradient>
<linearGradient
id="linearGradient5225">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5227" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop5229" />
</linearGradient>
<linearGradient
id="linearGradient5219"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5221" />
</linearGradient>
<linearGradient
id="linearGradient3758">
<stop
id="stop3760"
offset="0"
style="stop-color:#0fbb00;stop-opacity:1;" />
<stop
id="stop3762"
offset="1"
style="stop-color:#064400;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3750">
<stop
style="stop-color:#ece400;stop-opacity:1;"
offset="0"
id="stop3752" />
<stop
style="stop-color:#ece400;stop-opacity:0;"
offset="1"
id="stop3754" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3758-7"
id="linearGradient3756-1"
x1="1.960216"
y1="31.261461"
x2="60.456024"
y2="31.261461"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3758-7">
<stop
id="stop3760-4"
offset="0"
style="stop-color:#ece400;stop-opacity:1;" />
<stop
id="stop3762-0"
offset="1"
style="stop-color:#ec8b00;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1028"
id="namedview8"
showgrid="false"
inkscape:zoom="5.2149125"
inkscape:cx="-37.840247"
inkscape:cy="51.245759"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
d="M 61.442826,23.621762 38.532402,23.515555 31.556101,0.331013 24.578789,23.515555 1.6673502,23.621765 20.267785,38.422001 10.863888,63.668987 31.556101,47.626631 52.258426,63.668987 42.843404,38.422001 z"
id="path4-9"
style="fill:#000000;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 57.150089,25.064396 37.504323,24.973324 31.522122,5.092503 25.539054,24.973324 5.8924192,25.064399 21.842354,37.75565 13.778482,59.405024 31.522122,45.64865 49.274434,59.405024 41.201022,37.75565 z"
id="path4"
style="fill:#ff2700;fill-opacity:1;fill-rule:nonzero"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,294 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg5322"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="moderator.svg">
<defs
id="defs3">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective5328" />
<inkscape:perspective
id="perspective5305"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient5181">
<stop
style="stop-color:#0fbb00;stop-opacity:1;"
offset="0"
id="stop5183" />
<stop
style="stop-color:#064400;stop-opacity:1;"
offset="1"
id="stop5185" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-2"
id="radialGradient3606-7"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" />
<linearGradient
id="linearGradient3600-2">
<stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-4" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-9" />
</linearGradient>
<inkscape:perspective
id="perspective5478"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient5189">
<stop
style="stop-color:#000ec9;stop-opacity:1;"
offset="0"
id="stop5191" />
<stop
style="stop-color:#000657;stop-opacity:1;"
offset="1"
id="stop5193" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-4"
id="radialGradient3606-1"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" />
<linearGradient
id="linearGradient3600-4">
<stop
style="stop-color:#ffc33d;stop-opacity:1;"
offset="0"
id="stop3602-3" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-5" />
</linearGradient>
<inkscape:perspective
id="perspective5559"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5173"
id="linearGradient5179"
x1="167.33386"
y1="178.83276"
x2="244.78181"
y2="178.83276"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient5173">
<stop
style="stop-color:#f50000;stop-opacity:1;"
offset="0"
id="stop5175" />
<stop
style="stop-color:#950000;stop-opacity:1;"
offset="1"
id="stop5177" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600"
id="radialGradient5169"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276" />
<linearGradient
id="linearGradient3600">
<stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604" />
</linearGradient>
<radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
id="radialGradient5574"
xlink:href="#linearGradient3600"
inkscape:collect="always" />
<inkscape:perspective
id="perspective5663"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3600-7"
id="radialGradient3606-8"
cx="324.32715"
cy="131.40274"
fx="324.32715"
fy="131.40274"
r="25.501276"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)" />
<linearGradient
id="linearGradient3600-7">
<stop
style="stop-color:#ffc13d;stop-opacity:1;"
offset="0"
id="stop3602-7" />
<stop
style="stop-color:#e09900;stop-opacity:1;"
offset="1"
id="stop3604-6" />
</linearGradient>
<radialGradient
r="25.501276"
fy="131.40274"
fx="324.32715"
cy="131.40274"
cx="324.32715"
gradientTransform="matrix(0.92332021,0.38403097,-0.41592401,1.0000002,78.192026,-120.05314)"
gradientUnits="userSpaceOnUse"
id="radialGradient5676"
xlink:href="#linearGradient3600-7"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
inkscape:document-units="mm"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="63.241533"
inkscape:cy="46.246766"
inkscape:current-layer="g5249"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-952.36218)">
<g
id="g5249"
transform="translate(0.53874115,0.90502985)">
<path
style="fill:#ffffff;stroke:#000000;stroke-width:4.45809746000000030;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill-opacity:1"
d="m 49.582319,954.34642 c -12.850034,0 -23.284789,10.43476 -23.284789,23.28479 0,7.32135 3.403263,13.81811 8.689724,18.08319 -10.278401,5.8502 -16.663073,17.8469 -20.19443,31.0259 -5.1178053,19.1 15.207096,22.0401 34.269334,22.0915 l 0,0.031 c 0.290839,0 0.566498,0.031 0.856734,0.031 19.210152,0 39.855802,-3.1837 34.789494,-22.0914 -3.636192,-13.5705 -10.027831,-25.4711 -20.378015,-31.17899 5.208701,-4.26694 8.506139,-10.73278 8.506139,-17.9914 0,-12.85003 -10.404159,-23.28479 -23.254191,-23.28479 z"
id="path3597-8"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.97203517px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 50.522358,952.70715 0,95.71425"
id="path5303"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 51.062274,1000.5844 0,-46.66155 1.096703,0.005 c 3.640423,0.0175 9.166159,2.51708 12.389647,5.60443 4.895085,4.68835 7.418012,11.18204 6.97848,17.96172 -0.388976,5.99986 -2.630586,10.87224 -6.948405,15.1031 l -2.054611,2.01323 2.95836,2.1147 c 3.465395,2.47714 7.400043,6.67727 9.661364,10.31317 3.324266,5.3451 6.789556,14.1029 8.149825,20.5971 2.583182,12.3327 -5.995009,18.5909 -26.579121,19.3908 l -5.652242,0.2196 0,-46.6616 z"
id="path5343"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 51.062274,1000.5844 0,-46.66155 1.096703,0.005 c 3.711439,0.0179 9.230395,2.54932 12.52612,5.74551 2.710429,2.62858 4.363146,5.23853 5.699734,9.00096 0.930917,2.62048 1.042531,3.35671 1.066373,7.03397 0.02902,4.47725 -0.343832,6.4262 -1.860873,9.72679 -1.358173,2.95494 -2.652341,4.81714 -4.971275,7.15326 l -2.043484,2.05863 2.932618,2.09329 c 6.98445,4.98544 12.210204,12.81934 15.750058,23.61084 3.543721,10.8033 3.39602,15.1985 -0.654452,19.4747 -4.329667,4.571 -11.449354,6.7169 -23.88928,7.2003 l -5.652242,0.2196 0,-46.6616 z"
id="path5345"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 51.062274,1000.5844 0,-46.66155 1.127086,0 c 1.963684,0 6.316627,1.3793 8.624731,2.73288 1.305624,0.76568 3.277555,2.429 4.764529,4.01888 4.347263,4.6481 6.318993,10.15893 5.954049,16.6411 -0.326518,5.79966 -2.122114,9.97998 -6.25177,14.55473 -1.44716,1.60313 -2.388203,2.91735 -2.210758,3.08744 0.169927,0.16289 1.447842,1.10199 2.839812,2.08691 6.268453,4.43531 11.362918,11.94641 14.960201,22.05661 2.740177,7.7013 3.480992,12.7857 2.399253,16.4664 -0.490882,1.6703 -1.040601,2.5538 -2.66191,4.2781 -4.29247,4.5651 -11.326737,6.6778 -23.892981,7.176 l -5.652242,0.2241 0,-46.6616 z"
id="path5347"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 51.062274,1000.5855 0,-46.66265 1.127086,0 c 1.830826,0 6.182017,1.32383 8.427379,2.56398 3.074383,1.69804 7.222246,6.22736 8.789514,9.59784 4.043357,8.69543 2.602054,18.25614 -3.837601,25.45626 -1.482649,1.65774 -2.695724,3.09743 -2.695724,3.19932 0,0.10189 1.186029,0.99046 2.635621,1.97461 3.078254,2.08987 6.81705,5.92344 9.062839,9.29254 3.274171,4.9119 7.232757,14.564 8.731682,21.29 0.646579,2.9014 0.614978,6.1318 -0.08275,8.4594 -0.86467,2.8846 -4.147214,6.2392 -7.573604,7.74 -5.13932,2.251 -10.156844,3.194 -18.763476,3.5265 l -5.820965,0.2249 0,-46.6627 z"
id="path5349"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 51.062274,1000.5853 0,-46.66245 1.164456,0 c 4.764705,0 11.112502,3.49049 14.697127,8.08157 5.260553,6.73756 6.190324,16.72129 2.284493,24.53056 -0.608066,1.21576 -2.304134,3.5367 -3.77148,5.16099 -1.466571,1.62342 -2.603753,3.01808 -2.527074,3.09924 0.07667,0.0811 1.300896,0.95003 2.720481,1.93083 6.904062,4.77006 12.487313,13.40446 16.085176,24.87536 1.733472,5.5268 2.208105,8.1847 2.003089,11.2173 -0.604468,8.9414 -9.318247,13.5855 -26.66658,14.2125 l -5.989688,0.2165 0,-46.6624 z"
id="path5351"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 51.062274,1000.7111 0,-46.78825 1.265427,0.005 c 4.153532,0.0173 9.758512,2.75815 13.295303,6.50137 1.792452,1.89707 2.63621,3.17089 3.798098,5.73397 1.746736,3.85324 2.225454,6.0014 2.225454,9.98629 0,6.50755 -2.416561,12.11247 -7.223569,16.75421 -0.945331,0.91283 -1.642858,1.7317 -1.550059,1.81971 0.0928,0.088 1.155757,0.85585 2.362131,1.70631 3.35942,2.36829 4.992087,3.86859 7.229212,6.64329 3.924869,4.8681 7.249491,11.7229 9.87191,20.3544 1.173448,3.8623 1.289753,4.5994 1.289753,8.1737 0,3.6878 -0.0614,4.0459 -1.001592,5.8425 -1.309266,2.5017 -3.108338,4.122 -6.422247,5.7839 -4.375689,2.1945 -9.62921,3.3669 -16.70364,3.7278 -2.134354,0.1088 -4.905639,0.2757 -6.158413,0.3708 l -2.277768,0.1729 0,-46.7882 z"
id="path5353"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.73577702;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 51.062274,1000.6174 0,-46.98372 1.434151,0.16768 c 5.155008,0.60274 9.462857,2.72154 12.938259,6.36366 4.743924,4.9715 6.879132,11.35611 6.164642,18.43328 -0.537028,5.31935 -3.090083,10.59498 -6.838339,14.13074 l -1.940717,1.83069 3.040832,2.20427 c 3.580837,2.59571 7.189745,6.4912 9.552957,10.3116 4.895721,7.9144 9.235933,21.4918 8.504868,26.6055 -0.813112,5.6877 -5.438715,9.6977 -13.622159,11.8093 -3.808212,0.9826 -7.680557,1.4713 -14.763317,1.8633 l -4.471177,0.2474 0,-46.9837 z"
id="path5355"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,131 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 64 64"
enable-background="new 0 0 64 64"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="100%"
height="100%"
sodipodi:docname="moderator_buddy.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<linearGradient
id="linearGradient5225">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5227" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop5229" />
</linearGradient>
<linearGradient
id="linearGradient5219"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5221" />
</linearGradient>
<linearGradient
id="linearGradient3758">
<stop
id="stop3760"
offset="0"
style="stop-color:#0fbb00;stop-opacity:1;" />
<stop
id="stop3762"
offset="1"
style="stop-color:#064400;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3750">
<stop
style="stop-color:#ece400;stop-opacity:1;"
offset="0"
id="stop3752" />
<stop
style="stop-color:#ece400;stop-opacity:0;"
offset="1"
id="stop3754" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3758-7"
id="linearGradient3756-1"
x1="1.960216"
y1="31.261461"
x2="60.456024"
y2="31.261461"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3758-7">
<stop
id="stop3760-4"
offset="0"
style="stop-color:#ece400;stop-opacity:1;" />
<stop
id="stop3762-0"
offset="1"
style="stop-color:#ec8b00;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1028"
id="namedview8"
showgrid="false"
inkscape:zoom="5.2149125"
inkscape:cx="-26.445493"
inkscape:cy="31.598459"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
d="M 61.442826,23.621762 38.532402,23.515555 31.556101,0.331013 24.578789,23.515555 1.6673502,23.621765 20.267785,38.422001 10.863888,63.668987 31.556101,47.626631 52.258426,63.668987 42.843404,38.422001 z"
id="path4-9"
style="fill:#000000;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 55.041981,25.814432 36.921945,25.730432 31.404334,7.3935963 25.885923,25.730432 7.7650846,25.814434 22.476316,37.520057 15.0387,57.488097 31.404334,44.800071 47.777965,57.488097 40.331551,37.520057 z"
id="path4"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero"
inkscape:connector-curvature="0" />
<path
d="M 56.276895,25.211993 37.3433,24.856806 31.486705,5.7742084 c 0.04705,37.4359336 -0.01851,2.6744908 -0.0678,40.1841446 L 48.19932,58.580578 40.956295,37.527792 z"
id="path4-1"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,137 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 64 64"
enable-background="new 0 0 64 64"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
width="100%"
height="100%"
sodipodi:docname="vip_buddy.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<linearGradient
id="linearGradient3766">
<stop
style="stop-color:#ff2700;stop-opacity:1;"
offset="0"
id="stop3768" />
<stop
style="stop-color:#820000;stop-opacity:1;"
offset="1"
id="stop3770" />
</linearGradient>
<linearGradient
id="linearGradient5225">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5227" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop5229" />
</linearGradient>
<linearGradient
id="linearGradient5219"
osb:paint="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop5221" />
</linearGradient>
<linearGradient
id="linearGradient3758">
<stop
id="stop3760"
offset="0"
style="stop-color:#0fbb00;stop-opacity:1;" />
<stop
id="stop3762"
offset="1"
style="stop-color:#064400;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3750">
<stop
style="stop-color:#ece400;stop-opacity:1;"
offset="0"
id="stop3752" />
<stop
style="stop-color:#ece400;stop-opacity:0;"
offset="1"
id="stop3754" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3758-7"
id="linearGradient3756-1"
x1="1.960216"
y1="31.261461"
x2="60.456024"
y2="31.261461"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3758-7">
<stop
id="stop3760-4"
offset="0"
style="stop-color:#ece400;stop-opacity:1;" />
<stop
id="stop3762-0"
offset="1"
style="stop-color:#ec8b00;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="792"
id="namedview8"
showgrid="false"
inkscape:zoom="5.2149125"
inkscape:cx="14.509163"
inkscape:cy="51.245759"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
d="M 61.442826,23.621762 38.532402,23.515555 31.556101,0.331013 24.578789,23.515555 1.6673502,23.621765 20.267785,38.422001 10.863888,63.668987 31.556101,47.626631 52.258426,63.668987 42.843404,38.422001 z"
id="path4-9"
style="fill:#000000;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 57.150089,25.064396 37.504323,24.973324 31.522122,5.092503 25.539054,24.973324 5.8924192,25.064399 21.842354,37.75565 13.778482,59.405024 31.522122,45.64865 49.274434,59.405024 41.201022,37.75565 z"
id="path4"
style="fill:#8d5fd3;fill-opacity:1;fill-rule:nonzero"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,127 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 64 64"
enable-background="new 0 0 64 64"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
width="100%"
height="100%"
sodipodi:docname="registered_vip_buddy.svg">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10">
<linearGradient
id="linearGradient4153">
<stop
style="stop-color:#ffec79;stop-opacity:1"
offset="0"
id="stop4155" />
<stop
style="stop-color:#f2c15b;stop-opacity:1"
offset="1"
id="stop4157" />
</linearGradient>
<linearGradient
id="linearGradient3758">
<stop
id="stop3760"
offset="0"
style="stop-color:#80d600;stop-opacity:1;" />
<stop
id="stop3762"
offset="1"
style="stop-color:#80d600;stop-opacity:1;" />
</linearGradient>
<linearGradient
id="linearGradient3750">
<stop
style="stop-color:#ece400;stop-opacity:1;"
offset="0"
id="stop3752" />
<stop
style="stop-color:#ece400;stop-opacity:0;"
offset="1"
id="stop3754" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3758-7"
id="linearGradient3756"
x1="31.290251"
y1="-19.003599"
x2="31.135509"
y2="67.496323"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.87626222,0,0,0.87626222,4.174756,4.8555263)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3758-7"
id="linearGradient3756-1"
x1="1.960216"
y1="31.261461"
x2="60.456024"
y2="31.261461"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3758-7">
<stop
id="stop3760-4"
offset="0"
style="stop-color:#ece400;stop-opacity:1;" />
<stop
id="stop3762-0"
offset="1"
style="stop-color:#ec8b00;stop-opacity:1;" />
</linearGradient>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1152"
inkscape:window-height="811"
id="namedview8"
showgrid="false"
inkscape:zoom="7.375"
inkscape:cx="29.258475"
inkscape:cy="35.341768"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
d="M 61.442826,23.621762 38.532402,23.515555 31.556101,0.331013 24.578789,23.515555 1.6673502,23.621765 20.267785,38.422001 10.863888,63.668987 31.556101,47.626631 52.258426,63.668987 42.843404,38.422001 z"
id="path4-9"
style="fill:#000000;fill-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 57.150089,25.064396 37.504323,24.973324 31.522122,5.092503 25.539054,24.973324 5.8924192,25.064399 21.842354,37.75565 13.778482,59.405024 31.522122,45.64865 49.274434,59.405024 41.201022,37.75565 z"
id="path4"
style="fill:url(#linearGradient3756);fill-opacity:1"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -1,738 +0,0 @@
#include "carddatabase.h"
#include "carddbparser/cockatricexml3.h"
#include "carddbparser/cockatricexml4.h"
#include "game_specific_terms.h"
#include "pictureloader.h"
#include "settingscache.h"
#include "spoilerbackgroundupdater.h"
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QMessageBox>
#include <QRegularExpression>
#include <algorithm>
#include <utility>
const char *CardDatabase::TOKENS_SETNAME = "TK";
CardSet::CardSet(const QString &_shortName,
const QString &_longName,
const QString &_setType,
const QDate &_releaseDate)
: shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType)
{
loadSetOptions();
}
CardSetPtr CardSet::newInstance(const QString &_shortName,
const QString &_longName,
const QString &_setType,
const QDate &_releaseDate)
{
CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate));
// ptr->setSmartPointer(ptr);
return ptr;
}
QString CardSet::getCorrectedShortName() const
{
// For Windows machines.
QSet<QString> invalidFileNames;
invalidFileNames << "CON"
<< "PRN"
<< "AUX"
<< "NUL"
<< "COM1"
<< "COM2"
<< "COM3"
<< "COM4"
<< "COM5"
<< "COM6"
<< "COM7"
<< "COM8"
<< "COM9"
<< "LPT1"
<< "LPT2"
<< "LPT3"
<< "LPT4"
<< "LPT5"
<< "LPT6"
<< "LPT7"
<< "LPT8"
<< "LPT9";
return invalidFileNames.contains(shortName) ? shortName + "_" : shortName;
}
void CardSet::loadSetOptions()
{
sortKey = SettingsCache::instance().cardDatabase().getSortKey(shortName);
enabled = SettingsCache::instance().cardDatabase().isEnabled(shortName);
isknown = SettingsCache::instance().cardDatabase().isKnown(shortName);
}
void CardSet::setSortKey(unsigned int _sortKey)
{
sortKey = _sortKey;
SettingsCache::instance().cardDatabase().setSortKey(shortName, _sortKey);
}
void CardSet::setEnabled(bool _enabled)
{
enabled = _enabled;
SettingsCache::instance().cardDatabase().setEnabled(shortName, _enabled);
}
void CardSet::setIsKnown(bool _isknown)
{
isknown = _isknown;
SettingsCache::instance().cardDatabase().setIsKnown(shortName, _isknown);
}
class SetList::KeyCompareFunctor
{
public:
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
{
if (a.isNull() || b.isNull()) {
qDebug() << "SetList::KeyCompareFunctor a or b is null";
return false;
}
return a->getSortKey() < b->getSortKey();
}
};
void SetList::sortByKey()
{
std::sort(begin(), end(), KeyCompareFunctor());
}
int SetList::getEnabledSetsNum()
{
int num = 0;
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && set->getEnabled()) {
++num;
}
}
return num;
}
int SetList::getUnknownSetsNum()
{
int num = 0;
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
++num;
}
}
return num;
}
QStringList SetList::getUnknownSetsNames()
{
QStringList sets = QStringList();
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
sets << set->getShortName();
}
}
return sets;
}
void SetList::enableAllUnknown()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
set->setIsKnown(true);
set->setEnabled(true);
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
set->setEnabled(true);
}
}
}
void SetList::enableAll()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set == nullptr) {
qDebug() << "enabledAll has null";
continue;
}
if (!set->getIsKnownIgnored()) {
set->setIsKnown(true);
}
set->setEnabled(true);
}
}
void SetList::markAllAsKnown()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
set->setIsKnown(true);
set->setEnabled(false);
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
set->setEnabled(true);
}
}
}
void SetList::guessSortKeys()
{
// sort by release date DESC; invalid dates to the bottom.
QDate distantFuture(2050, 1, 1);
int aHundredYears = 36500;
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set.isNull()) {
qDebug() << "guessSortKeys set is null";
continue;
}
QDate date = set->getReleaseDate();
if (date.isNull()) {
set->setSortKey(static_cast<unsigned int>(aHundredYears));
} else {
set->setSortKey(static_cast<unsigned int>(date.daysTo(distantFuture)));
}
}
}
CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
{
}
CardInfo::CardInfo(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
int _tableRow,
bool _upsideDownArt)
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt), tableRow(_tableRow),
upsideDownArt(_upsideDownArt)
{
pixmapCacheKey = QLatin1String("card_") + name;
simpleName = CardInfo::simplifyName(name);
refreshCachedSetNames();
}
CardInfo::~CardInfo()
{
PictureLoader::clearPixmapCache(smartThis);
}
CardInfoPtr CardInfo::newInstance(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
int _tableRow,
bool _upsideDownArt)
{
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
_sets, _cipt, _tableRow, _upsideDownArt));
ptr->setSmartPointer(ptr);
for (const CardInfoPerSet &set : _sets) {
set.getPtr()->append(ptr);
}
return ptr;
}
QString CardInfo::getCorrectedName() const
{
// remove all the characters reserved in windows file paths,
// other oses only disallow a subset of these so it covers all
static const QRegularExpression rmrx(R"(( // |[*<>:"\\?\x00-\x08\x10-\x1f]))");
static const QRegularExpression spacerx(R"([/\x09-\x0f])");
static const QString space(' ');
QString result = name;
// Fire // Ice, Circle of Protection: Red, "Ach! Hans, Run!", Who/What/When/Where/Why, Question Elemental?
return result.remove(rmrx).replace(spacerx, space);
}
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
{
_set->append(smartThis);
sets.insert(_set->getShortName(), _info);
refreshCachedSetNames();
}
void CardInfo::refreshCachedSetNames()
{
QStringList setList;
// update the cached list of set names
for (const auto &set : sets) {
if (set.getPtr()->getEnabled()) {
setList << set.getPtr()->getShortName();
}
}
setsNames = setList.join(", ");
}
QString CardInfo::simplifyName(const QString &name)
{
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
static const QRegularExpression nonAlnum("[^a-z0-9]");
QString simpleName = name.toLower();
// remove spaces and right halves of split cards
simpleName.remove(spaceOrSplit);
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
// with nothing.
simpleName.replace("æ", "ae");
// Replace Jötun Grunt with Jotun Grunt.
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
// remove all non alphanumeric characters from the name
simpleName.remove(nonAlnum);
return simpleName;
}
const QChar CardInfo::getColorChar() const
{
QString colors = getColors();
switch (colors.size()) {
case 0:
return QChar();
case 1:
return colors.at(0);
default:
return QChar('m');
}
}
CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
{
qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
qRegisterMetaType<CardInfoPtr>("CardSetPtr");
// add new parsers here
availableParsers << new CockatriceXml4Parser;
availableParsers << new CockatriceXml3Parser;
for (auto &parser : availableParsers) {
connect(parser, SIGNAL(addCard(CardInfoPtr)), this, SLOT(addCard(CardInfoPtr)), Qt::DirectConnection);
connect(parser, SIGNAL(addSet(CardSetPtr)), this, SLOT(addSet(CardSetPtr)), Qt::DirectConnection);
}
connect(&SettingsCache::instance(), SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabases()));
}
CardDatabase::~CardDatabase()
{
clear();
qDeleteAll(availableParsers);
}
void CardDatabase::clear()
{
clearDatabaseMutex->lock();
QHashIterator<QString, CardInfoPtr> i(cards);
while (i.hasNext()) {
i.next();
if (i.value()) {
removeCard(i.value());
}
}
cards.clear();
simpleNameCards.clear();
sets.clear();
ICardDatabaseParser::clearSetlist();
loadStatus = NotLoaded;
clearDatabaseMutex->unlock();
}
void CardDatabase::addCard(CardInfoPtr card)
{
if (card == nullptr) {
qDebug() << "addCard(nullptr)";
return;
}
// if card already exists just add the new set property
if (cards.contains(card->getName())) {
CardInfoPtr sameCard = cards[card->getName()];
for (const CardInfoPerSet &set : card->getSets()) {
sameCard->addToSet(set.getPtr(), set);
}
return;
}
addCardMutex->lock();
cards.insert(card->getName(), card);
simpleNameCards.insert(card->getSimpleName(), card);
addCardMutex->unlock();
emit cardAdded(card);
}
void CardDatabase::removeCard(CardInfoPtr card)
{
if (card.isNull()) {
qDebug() << "removeCard(nullptr)";
return;
}
for (auto *cardRelation : card->getRelatedCards())
cardRelation->deleteLater();
for (auto *cardRelation : card->getReverseRelatedCards())
cardRelation->deleteLater();
for (auto *cardRelation : card->getReverseRelatedCards2Me())
cardRelation->deleteLater();
removeCardMutex->lock();
cards.remove(card->getName());
simpleNameCards.remove(card->getSimpleName());
removeCardMutex->unlock();
emit cardRemoved(card);
}
CardInfoPtr CardDatabase::getCard(const QString &cardName) const
{
return getCardFromMap(cards, cardName);
}
QList<CardInfoPtr> CardDatabase::getCards(const QStringList &cardNames) const
{
QList<CardInfoPtr> cardInfos;
foreach (QString cardName, cardNames) {
CardInfoPtr ptr = getCardFromMap(cards, cardName);
if (ptr)
cardInfos.append(ptr);
}
return cardInfos;
}
CardInfoPtr CardDatabase::getCardBySimpleName(const QString &cardName) const
{
return getCardFromMap(simpleNameCards, CardInfo::simplifyName(cardName));
}
CardInfoPtr CardDatabase::guessCard(const QString &cardName) const
{
CardInfoPtr temp = getCard(cardName);
if (temp == nullptr) { // get card by simple name instead
temp = getCardBySimpleName(cardName);
if (temp == nullptr) { // still could not find the card, so simplify the cardName too
QString simpleCardName = CardInfo::simplifyName(cardName);
temp = getCardBySimpleName(simpleCardName);
}
}
return temp; // returns nullptr if not found
}
CardSetPtr CardDatabase::getSet(const QString &setName)
{
if (sets.contains(setName)) {
return sets.value(setName);
} else {
CardSetPtr newSet = CardSet::newInstance(setName);
sets.insert(setName, newSet);
return newSet;
}
}
void CardDatabase::addSet(CardSetPtr set)
{
sets.insert(set->getShortName(), set);
}
SetList CardDatabase::getSetList() const
{
SetList result;
QHashIterator<QString, CardSetPtr> i(sets);
while (i.hasNext()) {
i.next();
result << i.value();
}
return result;
}
CardInfoPtr CardDatabase::getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const
{
if (cardMap.contains(cardName))
return cardMap.value(cardName);
return {};
}
LoadStatus CardDatabase::loadFromFile(const QString &fileName)
{
QFile file(fileName);
file.open(QIODevice::ReadOnly);
if (!file.isOpen()) {
return FileError;
}
for (auto parser : availableParsers) {
file.reset();
if (parser->getCanParseFile(fileName, file)) {
file.reset();
parser->parseFile(file);
return Ok;
}
}
return Invalid;
}
LoadStatus CardDatabase::loadCardDatabase(const QString &path)
{
auto startTime = QTime::currentTime();
LoadStatus tempLoadStatus = NotLoaded;
if (!path.isEmpty()) {
loadFromFileMutex->lock();
tempLoadStatus = loadFromFile(path);
loadFromFileMutex->unlock();
}
int msecs = startTime.msecsTo(QTime::currentTime());
qDebug() << "[CardDatabase] loadCardDatabase(): Path =" << path << "Status =" << tempLoadStatus
<< "Cards =" << cards.size() << "Sets =" << sets.size() << QString("%1ms").arg(msecs);
return tempLoadStatus;
}
LoadStatus CardDatabase::loadCardDatabases()
{
reloadDatabaseMutex->lock();
qDebug() << "CardDatabase::loadCardDatabases start";
clear(); // remove old db
loadStatus = loadCardDatabase(SettingsCache::instance().getCardDatabasePath()); // load main card database
loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database
loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database
// find all custom card databases, recursively & following symlinks
// then load them alphabetically
QDirIterator customDatabaseIterator(SettingsCache::instance().getCustomCardDatabasePath(), QStringList() << "*.xml",
QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
QStringList databasePaths;
while (customDatabaseIterator.hasNext()) {
customDatabaseIterator.next();
databasePaths.push_back(customDatabaseIterator.filePath());
}
databasePaths.sort();
for (auto i = 0; i < databasePaths.size(); ++i) {
const auto &databasePath = databasePaths.at(i);
qDebug() << "Loading Custom Set" << i << "(" << databasePath << ")";
loadCardDatabase(databasePath);
}
// AFTER all the cards have been loaded
// resolve the reverse-related tags
refreshCachedReverseRelatedCards();
if (loadStatus == Ok) {
checkUnknownSets(); // update deck editors, etc
qDebug() << "CardDatabase::loadCardDatabases success";
} else {
qDebug() << "CardDatabase::loadCardDatabases failed";
emit cardDatabaseLoadingFailed(); // bring up the settings dialog
}
reloadDatabaseMutex->unlock();
return loadStatus;
}
void CardDatabase::refreshCachedReverseRelatedCards()
{
for (const CardInfoPtr &card : cards)
card->resetReverseRelatedCards2Me();
for (const CardInfoPtr &card : cards) {
if (card->getReverseRelatedCards().isEmpty()) {
continue;
}
foreach (CardRelation *cardRelation, card->getReverseRelatedCards()) {
const QString &targetCard = cardRelation->getName();
if (!cards.contains(targetCard)) {
continue;
}
auto *newCardRelation = new CardRelation(
card->getName(), cardRelation->getAttachType(), cardRelation->getIsCreateAllExclusion(),
cardRelation->getIsVariable(), cardRelation->getDefaultCount(), cardRelation->getIsPersistent());
cards.value(targetCard)->addReverseRelatedCards2Me(newCardRelation);
}
}
}
QStringList CardDatabase::getAllMainCardTypes() const
{
QSet<QString> types;
QHashIterator<QString, CardInfoPtr> cardIterator(cards);
while (cardIterator.hasNext()) {
types.insert(cardIterator.next().value()->getMainCardType());
}
return types.values();
}
void CardDatabase::checkUnknownSets()
{
auto _sets = getSetList();
if (_sets.getEnabledSetsNum()) {
// if some sets are first found on this run, ask the user
int numUnknownSets = _sets.getUnknownSetsNum();
QStringList unknownSetNames = _sets.getUnknownSetsNames();
if (numUnknownSets > 0) {
emit cardDatabaseNewSetsFound(numUnknownSets, unknownSetNames);
} else {
_sets.markAllAsKnown();
}
} else {
// No set enabled. Probably this is the first time running trice
_sets.guessSortKeys();
_sets.sortByKey();
_sets.enableAll();
notifyEnabledSetsChanged();
emit cardDatabaseAllNewSetsEnabled();
}
}
void CardDatabase::enableAllUnknownSets()
{
auto _sets = getSetList();
_sets.enableAllUnknown();
}
void CardDatabase::markAllSetsAsKnown()
{
auto _sets = getSetList();
_sets.markAllAsKnown();
}
void CardDatabase::notifyEnabledSetsChanged()
{
// refresh the list of cached set names
for (const CardInfoPtr &card : cards)
card->refreshCachedSetNames();
// inform the carddatabasemodels that they need to re-check their list of cards
emit cardDatabaseEnabledSetsChanged();
}
bool CardDatabase::saveCustomTokensToFile()
{
QString fileName =
SettingsCache::instance().getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml";
SetNameMap tmpSets;
CardSetPtr customTokensSet = getSet(CardDatabase::TOKENS_SETNAME);
tmpSets.insert(CardDatabase::TOKENS_SETNAME, customTokensSet);
CardNameMap tmpCards;
for (const CardInfoPtr &card : cards) {
if (card->getSets().contains(CardDatabase::TOKENS_SETNAME)) {
tmpCards.insert(card->getName(), card);
}
}
availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
return true;
}
CardRelation::CardRelation(const QString &_name,
AttachType _attachType,
bool _isCreateAllExclusion,
bool _isVariableCount,
int _defaultCount,
bool _isPersistent)
: name(_name), attachType(_attachType), isCreateAllExclusion(_isCreateAllExclusion),
isVariableCount(_isVariableCount), defaultCount(_defaultCount), isPersistent(_isPersistent)
{
}
void CardInfo::resetReverseRelatedCards2Me()
{
foreach (CardRelation *cardRelation, this->getReverseRelatedCards2Me()) {
cardRelation->deleteLater();
}
reverseRelatedCardsToMe = QList<CardRelation *>();
}
// Back-compatibility methods. Remove ASAP
const QString CardInfo::getCardType() const
{
return getProperty(Mtg::CardType);
}
void CardInfo::setCardType(const QString &value)
{
setProperty(Mtg::CardType, value);
}
const QString CardInfo::getCmc() const
{
return getProperty(Mtg::ConvertedManaCost);
}
const QString CardInfo::getColors() const
{
return getProperty(Mtg::Colors);
}
void CardInfo::setColors(const QString &value)
{
setProperty(Mtg::Colors, value);
}
const QString CardInfo::getLoyalty() const
{
return getProperty(Mtg::Loyalty);
}
const QString CardInfo::getMainCardType() const
{
return getProperty(Mtg::MainCardType);
}
const QString CardInfo::getManaCost() const
{
return getProperty(Mtg::ManaCost);
}
const QString CardInfo::getPowTough() const
{
return getProperty(Mtg::PowTough);
}
void CardInfo::setPowTough(const QString &value)
{
setProperty(Mtg::PowTough, value);
}

View File

@@ -1,123 +0,0 @@
#include "cardframe.h"
#include "cardinfopicture.h"
#include "cardinfotext.h"
#include "carditem.h"
#include "main.h"
#include "settingscache.h"
#include <QSplitter>
#include <QVBoxLayout>
#include <utility>
CardFrame::CardFrame(const QString &cardName, QWidget *parent) : QTabWidget(parent), info(nullptr), cardTextOnly(false)
{
setContentsMargins(3, 3, 3, 3);
pic = new CardInfoPicture();
pic->setObjectName("pic");
text = new CardInfoText();
text->setObjectName("text");
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
tab1 = new QWidget(this);
tab2 = new QWidget(this);
tab3 = new QWidget(this);
tab1->setObjectName("tab1");
tab2->setObjectName("tab2");
tab3->setObjectName("tab3");
insertTab(ImageOnlyView, tab1, QString());
insertTab(TextOnlyView, tab2, QString());
insertTab(ImageAndTextView, tab3, QString());
connect(this, SIGNAL(currentChanged(int)), this, SLOT(setViewMode(int)));
tab1Layout = new QVBoxLayout();
tab1Layout->setObjectName("tab1Layout");
tab1Layout->setContentsMargins(0, 0, 0, 0);
tab1Layout->setSpacing(0);
tab1->setLayout(tab1Layout);
tab2Layout = new QVBoxLayout();
tab2Layout->setObjectName("tab2Layout");
tab2Layout->setContentsMargins(0, 0, 0, 0);
tab2Layout->setSpacing(0);
tab2->setLayout(tab2Layout);
splitter = new QSplitter();
splitter->setObjectName("splitter");
splitter->setOrientation(Qt::Vertical);
tab3Layout = new QVBoxLayout();
tab3Layout->setObjectName("tab3Layout");
tab3Layout->setContentsMargins(0, 0, 0, 0);
tab3Layout->setSpacing(0);
tab3Layout->addWidget(splitter);
tab3->setLayout(tab3Layout);
setViewMode(SettingsCache::instance().getCardInfoViewMode());
setCard(db->getCard(cardName));
}
void CardFrame::retranslateUi()
{
setTabText(ImageOnlyView, tr("Image"));
setTabText(TextOnlyView, tr("Description"));
setTabText(ImageAndTextView, tr("Both"));
}
void CardFrame::setViewMode(int mode)
{
if (currentIndex() != mode)
setCurrentIndex(mode);
switch (mode) {
case ImageOnlyView:
case TextOnlyView:
tab1Layout->addWidget(pic);
tab2Layout->addWidget(text);
break;
case ImageAndTextView:
splitter->addWidget(pic);
splitter->addWidget(text);
break;
default:
break;
}
SettingsCache::instance().setCardInfoViewMode(mode);
}
void CardFrame::setCard(CardInfoPtr card)
{
if (info) {
disconnect(info.data(), nullptr, this, nullptr);
}
info = std::move(card);
if (info) {
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clearCard()));
}
text->setCard(info);
pic->setCard(info);
}
void CardFrame::setCard(const QString &cardName)
{
setCard(db->guessCard(cardName));
}
void CardFrame::setCard(AbstractCardItem *card)
{
if (card) {
setCard(card->getInfo());
}
}
void CardFrame::clearCard()
{
setCard((CardInfoPtr) nullptr);
}

View File

@@ -1,66 +0,0 @@
#include "cardinfopicture.h"
#include "carditem.h"
#include "main.h"
#include "pictureloader.h"
#include <QStylePainter>
#include <QWidget>
CardInfoPicture::CardInfoPicture(QWidget *parent) : QWidget(parent), info(nullptr), pixmapDirty(true)
{
setMinimumHeight(100);
}
void CardInfoPicture::setCard(CardInfoPtr card)
{
if (info) {
disconnect(info.data(), nullptr, this, nullptr);
}
info = card;
if (info) {
connect(info.data(), SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap()));
}
updatePixmap();
}
void CardInfoPicture::resizeEvent(QResizeEvent *)
{
updatePixmap();
}
void CardInfoPicture::updatePixmap()
{
pixmapDirty = true;
update();
}
void CardInfoPicture::loadPixmap()
{
if (info)
PictureLoader::getPixmap(resizedPixmap, info, size());
else
PictureLoader::getCardBackPixmap(resizedPixmap, size());
}
void CardInfoPicture::paintEvent(QPaintEvent *)
{
if (width() == 0 || height() == 0)
return;
if (pixmapDirty)
loadPixmap();
QSize scaledSize = resizedPixmap.size().scaled(size(), Qt::KeepAspectRatio);
QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
qreal radius = 0.05 * scaledSize.width();
QStylePainter painter(this);
QPainterPath shape;
shape.addRoundedRect(QRect(topLeft, scaledSize), radius, radius);
painter.setClipPath(shape);
painter.drawItemPixmap(QRect(topLeft, scaledSize), Qt::AlignCenter, resizedPixmap);
}

View File

@@ -1,31 +0,0 @@
#ifndef CARDINFOPICTURE_H
#define CARDINFOPICTURE_H
#include "carddatabase.h"
#include <QWidget>
class AbstractCardItem;
class CardInfoPicture : public QWidget
{
Q_OBJECT
private:
CardInfoPtr info;
QPixmap resizedPixmap;
bool pixmapDirty;
public:
CardInfoPicture(QWidget *parent = nullptr);
protected:
void resizeEvent(QResizeEvent *event);
void paintEvent(QPaintEvent *);
void loadPixmap();
public slots:
void setCard(CardInfoPtr card);
void updatePixmap();
};
#endif

View File

@@ -1,36 +0,0 @@
#ifndef CARDINFOWIDGET_H
#define CARDINFOWIDGET_H
#include "carddatabase.h"
#include <QComboBox>
#include <QFrame>
#include <QStringList>
class CardInfoPicture;
class CardInfoText;
class AbstractCardItem;
class CardInfoWidget : public QFrame
{
Q_OBJECT
private:
qreal aspectRatio;
CardInfoPtr info;
CardInfoPicture *pic;
CardInfoText *text;
public:
explicit CardInfoWidget(const QString &cardName, QWidget *parent = nullptr, Qt::WindowFlags f = {});
public slots:
void setCard(CardInfoPtr card);
void setCard(const QString &cardName);
void setCard(AbstractCardItem *card);
private slots:
void clear();
};
#endif

View File

@@ -1,63 +0,0 @@
#include "cardlist.h"
#include "carddatabase.h"
#include "carditem.h"
#include <algorithm>
CardList::CardList(bool _contentsKnown) : QList<CardItem *>(), contentsKnown(_contentsKnown)
{
}
CardItem *CardList::findCard(const int id, const bool remove, int *position)
{
if (!contentsKnown) {
if (empty())
return 0;
CardItem *temp = at(0);
if (remove)
removeAt(0);
if (position)
*position = id;
return temp;
} else
for (int i = 0; i < size(); i++) {
CardItem *temp = at(i);
if (temp->getId() == id) {
if (remove)
removeAt(i);
if (position)
*position = i;
return temp;
}
}
return 0;
}
class CardList::compareFunctor
{
private:
int flags;
public:
explicit compareFunctor(int _flags) : flags(_flags)
{
}
inline bool operator()(CardItem *a, CardItem *b) const
{
if (flags & SortByType) {
QString t1 = a->getInfo() ? a->getInfo()->getMainCardType() : QString();
QString t2 = b->getInfo() ? b->getInfo()->getMainCardType() : QString();
if ((t1 == t2) && (flags & SortByName))
return a->getName() < b->getName();
return t1 < t2;
} else
return a->getName() < b->getName();
}
};
void CardList::sort(int flags)
{
compareFunctor cf(flags);
std::sort(begin(), end(), cf);
}

View File

@@ -1,31 +0,0 @@
#ifndef CARDLIST_H
#define CARDLIST_H
#include <QList>
class CardItem;
class CardList : public QList<CardItem *>
{
private:
class compareFunctor;
protected:
bool contentsKnown;
public:
enum SortFlags
{
SortByName = 1,
SortByType = 2
};
CardList(bool _contentsKnown);
CardItem *findCard(const int id, const bool remove, int *position = NULL);
bool getContentsKnown() const
{
return contentsKnown;
}
void sort(int flags = SortByName);
};
#endif

View File

@@ -1,5 +1,6 @@
#include "abstractclient.h"
#include "abstract_client.h"
#include "../../server/pending_command.h"
#include "featureset.h"
#include "get_pb_extension.h"
#include "pb/commands.pb.h"
@@ -17,7 +18,6 @@
#include "pb/event_user_left.pb.h"
#include "pb/event_user_message.pb.h"
#include "pb/server_message.pb.h"
#include "pending_command.h"
#include <google/protobuf/descriptor.h>
@@ -52,7 +52,7 @@ AbstractClient::AbstractClient(QObject *parent)
FeatureSet features;
features.initalizeFeatureList(clientFeatures);
connect(this, SIGNAL(sigQueuePendingCommand(PendingCommand *)), this, SLOT(queuePendingCommand(PendingCommand *)));
connect(this, &AbstractClient::sigQueuePendingCommand, this, &AbstractClient::queuePendingCommand);
}
AbstractClient::~AbstractClient()

View File

@@ -48,6 +48,7 @@ class AbstractClient : public QObject
Q_OBJECT
signals:
void statusChanged(ClientStatus _status);
void maxPingTime(int seconds, int maxSeconds);
// Room events
void roomEventReceived(const RoomEvent &event);
@@ -97,8 +98,8 @@ protected:
virtual void sendCommandContainer(const CommandContainer &cont) = 0;
public:
AbstractClient(QObject *parent = nullptr);
~AbstractClient();
explicit AbstractClient(QObject *parent = nullptr);
~AbstractClient() override;
ClientStatus getStatus() const
{

View File

@@ -1,4 +1,4 @@
#include "keysignals.h"
#include "key_signals.h"
#include <QKeyEvent>

View File

@@ -23,7 +23,7 @@ signals:
void onCtrlC();
protected:
virtual bool eventFilter(QObject *, QEvent *event);
bool eventFilter(QObject *, QEvent *event) override;
};
#endif

View File

@@ -1,4 +1,4 @@
#include "gettextwithmax.h"
#include "get_text_with_max.h"
QString getTextWithMax(QWidget *parent,
const QString &title,

View File

@@ -0,0 +1,201 @@
#include "deck_editor_menu.h"
#include "../../../settings/cache_settings.h"
#include "../../../settings/shortcuts_settings.h"
DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEditor)
: QMenu(parent), deckEditor(_deckEditor)
{
aNewDeck = new QAction(QString(), this);
connect(aNewDeck, SIGNAL(triggered()), deckEditor, SLOT(actNewDeck()));
aLoadDeck = new QAction(QString(), this);
connect(aLoadDeck, SIGNAL(triggered()), deckEditor, SLOT(actLoadDeck()));
loadRecentDeckMenu = new QMenu(this);
connect(&SettingsCache::instance().recents(), &RecentsSettings::recentlyOpenedDeckPathsChanged, this,
&DeckEditorMenu::updateRecentlyOpened);
aClearRecents = new QAction(QString(), this);
connect(aClearRecents, &QAction::triggered, this, &DeckEditorMenu::actClearRecents);
updateRecentlyOpened();
aSaveDeck = new QAction(QString(), this);
connect(aSaveDeck, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeck()));
aSaveDeckAs = new QAction(QString(), this);
connect(aSaveDeckAs, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckAs()));
aLoadDeckFromClipboard = new QAction(QString(), this);
connect(aLoadDeckFromClipboard, SIGNAL(triggered()), deckEditor, SLOT(actLoadDeckFromClipboard()));
aEditDeckInClipboard = new QAction(QString(), this);
connect(aEditDeckInClipboard, SIGNAL(triggered()), deckEditor, SLOT(actEditDeckInClipboard()));
aEditDeckInClipboardRaw = new QAction(QString(), this);
connect(aEditDeckInClipboardRaw, SIGNAL(triggered()), deckEditor, SLOT(actEditDeckInClipboardRaw()));
aSaveDeckToClipboard = new QAction(QString(), this);
connect(aSaveDeckToClipboard, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckToClipboard()));
aSaveDeckToClipboardNoSetInfo = new QAction(QString(), this);
connect(aSaveDeckToClipboardNoSetInfo, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckToClipboardNoSetInfo()));
aSaveDeckToClipboardRaw = new QAction(QString(), this);
connect(aSaveDeckToClipboardRaw, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckToClipboardRaw()));
aSaveDeckToClipboardRawNoSetInfo = new QAction(QString(), this);
connect(aSaveDeckToClipboardRawNoSetInfo, SIGNAL(triggered()), deckEditor,
SLOT(actSaveDeckToClipboardRawNoSetInfo()));
aPrintDeck = new QAction(QString(), this);
connect(aPrintDeck, SIGNAL(triggered()), deckEditor, SLOT(actPrintDeck()));
aExportDeckDecklist = new QAction(QString(), this);
connect(aExportDeckDecklist, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklist()));
aExportDeckDecklistXyz = new QAction(QString(), this);
connect(aExportDeckDecklistXyz, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklistXyz()));
aAnalyzeDeckDeckstats = new QAction(QString(), this);
connect(aAnalyzeDeckDeckstats, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckDeckstats()));
aAnalyzeDeckTappedout = new QAction(QString(), this);
connect(aAnalyzeDeckTappedout, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckTappedout()));
analyzeDeckMenu = new QMenu(this);
analyzeDeckMenu->addAction(aExportDeckDecklist);
analyzeDeckMenu->addAction(aExportDeckDecklistXyz);
analyzeDeckMenu->addSeparator();
analyzeDeckMenu->addAction(aAnalyzeDeckDeckstats);
analyzeDeckMenu->addAction(aAnalyzeDeckTappedout);
aClose = new QAction(QString(), this);
connect(aClose, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::closeRequest);
editDeckInClipboardMenu = new QMenu(this);
editDeckInClipboardMenu->addAction(aEditDeckInClipboard);
editDeckInClipboardMenu->addAction(aEditDeckInClipboardRaw);
saveDeckToClipboardMenu = new QMenu(this);
saveDeckToClipboardMenu->addAction(aSaveDeckToClipboard);
saveDeckToClipboardMenu->addAction(aSaveDeckToClipboardNoSetInfo);
saveDeckToClipboardMenu->addAction(aSaveDeckToClipboardRaw);
saveDeckToClipboardMenu->addAction(aSaveDeckToClipboardRawNoSetInfo);
addAction(aNewDeck);
addAction(aLoadDeck);
addMenu(loadRecentDeckMenu);
addAction(aSaveDeck);
addAction(aSaveDeckAs);
addSeparator();
addAction(aLoadDeckFromClipboard);
addMenu(editDeckInClipboardMenu);
addMenu(saveDeckToClipboardMenu);
addSeparator();
addAction(aPrintDeck);
addMenu(analyzeDeckMenu);
addSeparator();
addAction(deckEditor->filterDockWidget->aClearFilterOne);
addAction(deckEditor->filterDockWidget->aClearFilterAll);
addSeparator();
addAction(aClose);
retranslateUi();
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
refreshShortcuts();
}
void DeckEditorMenu::setSaveStatus(bool newStatus)
{
aSaveDeck->setEnabled(newStatus);
aSaveDeckAs->setEnabled(newStatus);
aSaveDeckToClipboard->setEnabled(newStatus);
aSaveDeckToClipboardNoSetInfo->setEnabled(newStatus);
aSaveDeckToClipboardRaw->setEnabled(newStatus);
aSaveDeckToClipboardRawNoSetInfo->setEnabled(newStatus);
saveDeckToClipboardMenu->setEnabled(newStatus);
aPrintDeck->setEnabled(newStatus);
analyzeDeckMenu->setEnabled(newStatus);
}
void DeckEditorMenu::updateRecentlyOpened()
{
loadRecentDeckMenu->clear();
for (const auto &deckPath : SettingsCache::instance().recents().getRecentlyOpenedDeckPaths()) {
QAction *aRecentlyOpenedDeck = new QAction(deckPath, this);
loadRecentDeckMenu->addAction(aRecentlyOpenedDeck);
connect(aRecentlyOpenedDeck, &QAction::triggered, deckEditor,
[=, this] { deckEditor->actOpenRecent(aRecentlyOpenedDeck->text()); });
}
loadRecentDeckMenu->addSeparator();
loadRecentDeckMenu->addAction(aClearRecents);
aClearRecents->setEnabled(SettingsCache::instance().recents().getRecentlyOpenedDeckPaths().length() > 0);
}
void DeckEditorMenu::actClearRecents()
{
SettingsCache::instance().recents().clearRecentlyOpenedDeckPaths();
}
void DeckEditorMenu::retranslateUi()
{
setTitle(tr("&Deck Editor"));
aNewDeck->setText(tr("&New deck"));
aLoadDeck->setText(tr("&Load deck..."));
loadRecentDeckMenu->setTitle(tr("Load recent deck..."));
aClearRecents->setText(tr("Clear"));
aSaveDeck->setText(tr("&Save deck"));
aSaveDeckAs->setText(tr("Save deck &as..."));
aLoadDeckFromClipboard->setText(tr("Load deck from cl&ipboard..."));
editDeckInClipboardMenu->setTitle(tr("Edit deck in clipboard"));
aEditDeckInClipboard->setText(tr("Annotated"));
aEditDeckInClipboardRaw->setText(tr("Not Annotated"));
saveDeckToClipboardMenu->setTitle(tr("Save deck to clipboard"));
aSaveDeckToClipboard->setText(tr("Annotated"));
aSaveDeckToClipboardNoSetInfo->setText(tr("Annotated (No set info)"));
aSaveDeckToClipboardRaw->setText(tr("Not Annotated"));
aSaveDeckToClipboardRawNoSetInfo->setText(tr("Not Annotated (No set info)"));
aPrintDeck->setText(tr("&Print deck..."));
analyzeDeckMenu->setTitle(tr("&Send deck to online service"));
aExportDeckDecklist->setText(tr("Create decklist (decklist.org)"));
aExportDeckDecklistXyz->setText(tr("Create decklist (decklist.xyz)"));
aAnalyzeDeckDeckstats->setText(tr("Analyze deck (deckstats.net)"));
aAnalyzeDeckTappedout->setText(tr("Analyze deck (tappedout.net)"));
aClose->setText(tr("&Close"));
}
void DeckEditorMenu::refreshShortcuts()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aNewDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aNewDeck"));
aLoadDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeck"));
aSaveDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeck"));
aSaveDeckAs->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckAs"));
aLoadDeckFromClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeckFromClipboard"));
aEditDeckInClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboard"));
aEditDeckInClipboardRaw->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboardRaw"));
aPrintDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aPrintDeck"));
aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist"));
aExportDeckDecklistXyz->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklistXyz"));
aAnalyzeDeckDeckstats->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeck"));
aAnalyzeDeckTappedout->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeckTappedout"));
aClose->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aClose"));
aSaveDeckToClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboard"));
aSaveDeckToClipboardNoSetInfo->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboardNoSetInfo"));
aSaveDeckToClipboardRaw->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboardRaw"));
aSaveDeckToClipboardRawNoSetInfo->setShortcuts(
shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboardRawNoSetInfo"));
aClose->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aClose"));
}

View File

@@ -0,0 +1,32 @@
#ifndef DECK_EDITOR_MENU_H
#define DECK_EDITOR_MENU_H
#include "../../tabs/abstract_tab_deck_editor.h"
#include <QMenu>
class AbstractTabDeckEditor;
class DeckEditorMenu : public QMenu
{
Q_OBJECT
public:
explicit DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *deckEditor);
AbstractTabDeckEditor *deckEditor;
QAction *aNewDeck, *aLoadDeck, *aClearRecents, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard,
*aEditDeckInClipboard, *aEditDeckInClipboardRaw, *aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetInfo,
*aSaveDeckToClipboardRaw, *aSaveDeckToClipboardRawNoSetInfo, *aPrintDeck, *aExportDeckDecklist,
*aExportDeckDecklistXyz, *aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose;
QMenu *loadRecentDeckMenu, *analyzeDeckMenu, *editDeckInClipboardMenu, *saveDeckToClipboardMenu;
void setSaveStatus(bool newStatus);
public slots:
void updateRecentlyOpened();
void actClearRecents();
void retranslateUi();
void refreshShortcuts();
};
#endif

View File

@@ -0,0 +1,35 @@
#include "client_update_checker.h"
#include "../../settings/cache_settings.h"
#include "release_channel.h"
ClientUpdateChecker::ClientUpdateChecker(QObject *parent) : QObject(parent)
{
}
void ClientUpdateChecker::check()
{
auto releaseChannel = SettingsCache::instance().getUpdateReleaseChannel();
finishedCheckConnection =
connect(releaseChannel, &ReleaseChannel::finishedCheck, this, &ClientUpdateChecker::actFinishedCheck);
errorConnection = connect(releaseChannel, &ReleaseChannel::error, this, &ClientUpdateChecker::actError);
releaseChannel->checkForUpdates();
}
void ClientUpdateChecker::actFinishedCheck(bool needToUpdate, bool isCompatible, Release *release)
{
disconnect(finishedCheckConnection);
disconnect(errorConnection);
emit finishedCheck(needToUpdate, isCompatible, release);
}
void ClientUpdateChecker::actError(const QString &errorString)
{
disconnect(finishedCheckConnection);
disconnect(errorConnection);
emit error(errorString);
}

View File

@@ -0,0 +1,45 @@
#ifndef CLIENT_UPDATE_CHECKER_H
#define CLIENT_UPDATE_CHECKER_H
#include <QObject>
class Release;
/**
* We use a singleton instance of UpdateChannel, which can cause interference and feedback loops when multiple objects
* connect to it.
*
* This class encapsulates the usage of that UpdateChannel to ensure that the check only happens once per connection and
* the connection is destroyed after it's been used.
*/
class ClientUpdateChecker : public QObject
{
Q_OBJECT
QMetaObject::Connection finishedCheckConnection;
QMetaObject::Connection errorConnection;
void actFinishedCheck(bool needToUpdate, bool isCompatible, Release *release);
void actError(const QString &errorString);
public:
explicit ClientUpdateChecker(QObject *parent = nullptr);
/**
* Actually performs the check, using the currently selected update channel in the settings.
* Any resulting signals will only be sent once.
* This method should only be called ONCE per instance.
*/
void check();
signals:
/**
* Forwarded from UpdateChannel::finishedCheck
*/
void finishedCheck(bool needToUpdate, bool isCompatible, Release *release);
/**
* Forwarded from UpdateChannel::error
*/
void error(const QString &errorString);
};
#endif // CLIENT_UPDATE_CHECKER_H

View File

@@ -1,4 +1,4 @@
#include "releasechannel.h"
#include "release_channel.h"
#include "version_string.h"
@@ -11,6 +11,11 @@
#include <QSysInfo>
#include <QtGlobal>
#if defined(Q_OS_MACOS)
#include <sys/sysctl.h>
#include <sys/types.h>
#endif
#define STABLERELEASE_URL "https://api.github.com/repos/Cockatrice/Cockatrice/releases/latest"
#define STABLEMANUALDOWNLOAD_URL "https://github.com/Cockatrice/Cockatrice/releases/latest"
#define STABLETAG_URL "https://api.github.com/repos/Cockatrice/Cockatrice/git/refs/tags/"
@@ -21,11 +26,8 @@
#define GIT_SHORT_HASH_LEN 7
int ReleaseChannel::sharedIndex = 0;
ReleaseChannel::ReleaseChannel() : netMan(new QNetworkAccessManager(this)), response(nullptr), lastRelease(nullptr)
{
index = sharedIndex++;
}
ReleaseChannel::~ReleaseChannel()
@@ -36,31 +38,42 @@ ReleaseChannel::~ReleaseChannel()
void ReleaseChannel::checkForUpdates()
{
QString releaseChannelUrl = getReleaseChannelUrl();
qDebug() << "Searching for updates on the channel: " << releaseChannelUrl;
qCInfo(ReleaseChannelLog) << "Searching for updates on the channel: " << releaseChannelUrl;
response = netMan->get(QNetworkRequest(releaseChannelUrl));
connect(response, SIGNAL(finished()), this, SLOT(releaseListFinished()));
connect(response, &QNetworkReply::finished, this, &ReleaseChannel::releaseListFinished);
}
// Different release channel checking functions for different operating systems
#if defined(Q_OS_MACOS)
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
{
static QRegularExpression version_regex("macOS-(\\d+)\\.(\\d+)");
#if defined(Q_OS_MACOS)
static QRegularExpression version_regex("macOS(\\d+)");
auto match = version_regex.match(fileName);
if (!match.hasMatch()) {
return false;
}
auto getSystemVersion = [] {
// QSysInfo does not go through translation layers
// We need to use sysctl to reliably detect the underlying architecture
char arch[255];
size_t len = sizeof(arch);
if (sysctlbyname("machdep.cpu.brand_string", arch, &len, nullptr, 0) == 0) {
// Intel mac is only supported on macOS 13 versions
if (QString::fromUtf8(arch).contains("Intel")) {
return 13;
}
}
return QSysInfo::productVersion().split(".")[0].toInt();
};
// older(smaller) releases are compatible with a newer or the same system version
int sys_maj = QSysInfo::productVersion().split(".")[0].toInt();
int sys_min = QSysInfo::productVersion().split(".")[1].toInt();
int sys_maj = getSystemVersion();
int rel_maj = match.captured(1).toInt();
int rel_min = match.captured(2).toInt();
return rel_maj < sys_maj || (rel_maj == sys_maj && rel_min <= sys_min);
}
return rel_maj == sys_maj;
#elif defined(Q_OS_WIN)
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
{
#if Q_PROCESSOR_WORDSIZE == 4
return fileName.contains("32bit");
#elif Q_PROCESSOR_WORDSIZE == 8
@@ -71,16 +84,15 @@ bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
return fileName.contains("Win10");
}
#else
Q_UNUSED(fileName);
return false;
#endif
#else // If the OS doesn't fit one of the above #defines, then it will never match
Q_UNUSED(fileName);
return false;
#endif
}
#else
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &)
{
// If the OS doesn't fit one of the above #defines, then it will never match
return false;
}
#endif
QString StableReleaseChannel::getManualDownloadUrl() const
{
@@ -89,7 +101,7 @@ QString StableReleaseChannel::getManualDownloadUrl() const
QString StableReleaseChannel::getName() const
{
return tr("Stable Releases");
return tr("Default");
}
QString StableReleaseChannel::getReleaseChannelUrl() const
@@ -104,7 +116,7 @@ void StableReleaseChannel::releaseListFinished()
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
reply->deleteLater();
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "No reply received from the release update server.";
qCWarning(ReleaseChannelLog) << "No reply received from the release update server.";
emit error(tr("No reply received from the release update server."));
return;
}
@@ -112,7 +124,7 @@ void StableReleaseChannel::releaseListFinished()
QVariantMap resultMap = jsonResponse.toVariant().toMap();
if (!(resultMap.contains("name") && resultMap.contains("html_url") && resultMap.contains("tag_name") &&
resultMap.contains("published_at"))) {
qWarning() << "Invalid received from the release update server.";
qCWarning(ReleaseChannelLog) << "Invalid received from the release update server:" << resultMap;
emit error(tr("Invalid reply received from the release update server."));
return;
}
@@ -126,39 +138,31 @@ void StableReleaseChannel::releaseListFinished()
if (resultMap.contains("assets")) {
auto rawAssets = resultMap["assets"].toList();
// [(name, url)]
QVector<std::pair<QString, QString>> assets;
std::transform(rawAssets.begin(), rawAssets.end(), std::back_inserter(assets), [](QVariant _asset) {
QVariantMap asset = _asset.toMap();
for (const auto &rawAsset : rawAssets) {
QVariantMap asset = rawAsset.toMap();
QString name = asset["name"].toString();
QString url = asset["browser_download_url"].toString();
return std::make_pair(name, url);
});
auto _releaseAsset = std::find_if(assets.begin(), assets.end(), [](std::pair<QString, QString> nameAndUrl) {
return downloadMatchesCurrentOS(nameAndUrl.first);
});
if (_releaseAsset != assets.end()) {
std::pair<QString, QString> releaseAsset = *_releaseAsset;
auto releaseUrl = releaseAsset.second;
lastRelease->setDownloadUrl(releaseUrl);
if (downloadMatchesCurrentOS(name)) {
lastRelease->setDownloadUrl(url);
break;
}
}
}
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
qDebug() << "Current hash=" << myHash << "update hash=" << shortHash;
qCInfo(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
qDebug() << "Got reply from release server, name=" << lastRelease->getName()
<< "desc=" << lastRelease->getDescriptionUrl() << "date=" << lastRelease->getPublishDate()
<< "url=" << lastRelease->getDownloadUrl();
qCInfo(ReleaseChannelLog) << "Got reply from release server, name=" << lastRelease->getName()
<< "desc=" << lastRelease->getDescriptionUrl() << "date=" << lastRelease->getPublishDate()
<< "url=" << lastRelease->getDownloadUrl();
const QString &tagName = resultMap["tag_name"].toString();
QString url = QString(STABLETAG_URL) + tagName;
qDebug() << "Searching for commit hash corresponding to stable channel tag: " << tagName;
qCInfo(ReleaseChannelLog) << "Searching for commit hash corresponding to stable channel tag: " << tagName;
response = netMan->get(QNetworkRequest(url));
connect(response, SIGNAL(finished()), this, SLOT(tagListFinished()));
connect(response, &QNetworkReply::finished, this, &StableReleaseChannel::tagListFinished);
}
void StableReleaseChannel::tagListFinished()
@@ -168,24 +172,24 @@ void StableReleaseChannel::tagListFinished()
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
reply->deleteLater();
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "No reply received from the tag update server.";
qCWarning(ReleaseChannelLog) << "No reply received from the tag update server.";
emit error(tr("No reply received from the tag update server."));
return;
}
QVariantMap resultMap = jsonResponse.toVariant().toMap();
if (!(resultMap.contains("object") && resultMap["object"].toMap().contains("sha"))) {
qWarning() << "Invalid received from the tag update server.";
qCWarning(ReleaseChannelLog) << "Invalid received from the tag update server.";
emit error(tr("Invalid reply received from the tag update server."));
return;
}
lastRelease->setCommitHash(resultMap["object"].toMap()["sha"].toString());
qDebug() << "Got reply from tag server, commit=" << lastRelease->getCommitHash();
qCInfo(ReleaseChannelLog) << "Got reply from tag server, commit=" << lastRelease->getCommitHash();
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
qDebug() << "Current hash=" << myHash << "update hash=" << shortHash;
qCInfo(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
const bool needToUpdate = (QString::compare(shortHash, myHash, Qt::CaseInsensitive) != 0);
emit finishedCheck(needToUpdate, lastRelease->isCompatibleVersionFound(), lastRelease);
@@ -203,7 +207,7 @@ QString BetaReleaseChannel::getManualDownloadUrl() const
QString BetaReleaseChannel::getName() const
{
return tr("Beta Releases");
return tr("Beta");
}
QString BetaReleaseChannel::getReleaseChannelUrl() const
@@ -228,7 +232,7 @@ void BetaReleaseChannel::releaseListFinished()
QVariantMap resultMap = array.at(0).toObject().toVariantMap();
if (array.empty() || resultMap.empty()) {
qWarning() << "No reply received from the release update server:" << QString(jsonData);
qCWarning(ReleaseChannelLog) << "No reply received from the release update server:" << QString(jsonData);
emit error(tr("No reply received from the release update server."));
return;
}
@@ -237,7 +241,7 @@ void BetaReleaseChannel::releaseListFinished()
if (!resultMap.contains("assets") || !resultMap.contains("author") || !resultMap.contains("tag_name") ||
!resultMap.contains("target_commitish") || !resultMap.contains("assets_url") ||
!resultMap.contains("published_at")) {
qWarning() << "Invalid received from the release update server:" << resultMap;
qCWarning(ReleaseChannelLog) << "Invalid received from the release update server:" << resultMap;
emit error(tr("Invalid reply received from the release update server."));
return;
}
@@ -252,15 +256,15 @@ void BetaReleaseChannel::releaseListFinished()
lastRelease->setName(QString("%1 (%2)").arg(resultMap["tag_name"].toString()).arg(shortHash));
lastRelease->setDescriptionUrl(QString(BETARELEASE_CHANGESURL).arg(VERSION_COMMIT, shortHash));
qDebug() << "Got reply from release server, size=" << resultMap.size() << "name=" << lastRelease->getName()
<< "desc=" << lastRelease->getDescriptionUrl() << "commit=" << lastRelease->getCommitHash()
<< "date=" << lastRelease->getPublishDate();
qCInfo(ReleaseChannelLog) << "Got reply from release server, size=" << resultMap.size()
<< "name=" << lastRelease->getName() << "desc=" << lastRelease->getDescriptionUrl()
<< "commit=" << lastRelease->getCommitHash() << "date=" << lastRelease->getPublishDate();
QString betaBuildDownloadUrl = resultMap["assets_url"].toString();
qDebug() << "Searching for a corresponding file on the beta channel: " << betaBuildDownloadUrl;
qCInfo(ReleaseChannelLog) << "Searching for a corresponding file on the beta channel: " << betaBuildDownloadUrl;
response = netMan->get(QNetworkRequest(betaBuildDownloadUrl));
connect(response, SIGNAL(finished()), this, SLOT(fileListFinished()));
connect(response, &QNetworkReply::finished, this, &BetaReleaseChannel::fileListFinished);
}
void BetaReleaseChannel::fileListFinished()
@@ -270,7 +274,7 @@ void BetaReleaseChannel::fileListFinished()
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
reply->deleteLater();
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "No reply received from the file update server.";
qCWarning(ReleaseChannelLog) << "No reply received from the file update server.";
emit error(tr("No reply received from the file update server."));
return;
}
@@ -278,7 +282,7 @@ void BetaReleaseChannel::fileListFinished()
QVariantList resultList = jsonResponse.toVariant().toList();
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
qDebug() << "Current hash=" << myHash << "update hash=" << shortHash;
qCInfo(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
bool needToUpdate = (QString::compare(shortHash, myHash, Qt::CaseInsensitive) != 0);
bool compatibleVersion = false;
@@ -295,7 +299,7 @@ void BetaReleaseChannel::fileListFinished()
if (downloadMatchesCurrentOS(*url)) {
compatibleVersion = true;
lastRelease->setDownloadUrl(*url);
qDebug() << "Found compatible version url=" << *url;
qCInfo(ReleaseChannelLog) << "Found compatible version url=" << *url;
break;
}
}

View File

@@ -2,11 +2,14 @@
#define RELEASECHANNEL_H
#include <QDate>
#include <QLoggingCategory>
#include <QObject>
#include <QString>
#include <QVariantMap>
#include <utility>
inline Q_LOGGING_CATEGORY(ReleaseChannelLog, "release_channel");
class QNetworkReply;
class QNetworkAccessManager;
@@ -82,9 +85,6 @@ public:
~ReleaseChannel() override;
protected:
// shared by all instances
static int sharedIndex;
int index;
QNetworkAccessManager *netMan;
QNetworkReply *response;
Release *lastRelease;
@@ -94,10 +94,6 @@ protected:
virtual QString getReleaseChannelUrl() const = 0;
public:
int getIndex() const
{
return index;
}
Release *getLastRelease()
{
return lastRelease;

View File

@@ -0,0 +1,193 @@
#include "replay_timeline_widget.h"
#include <QPainter>
#include <QPainterPath>
#include <QPalette>
#include <QTimer>
ReplayTimelineWidget::ReplayTimelineWidget(QWidget *parent)
: QWidget(parent), maxBinValue(1), maxTime(1), timeScaleFactor(1.0), currentVisualTime(0), currentProcessedTime(0),
currentEvent(0)
{
replayTimer = new QTimer(this);
connect(replayTimer, &QTimer::timeout, this, &ReplayTimelineWidget::replayTimerTimeout);
rewindBufferingTimer = new QTimer(this);
rewindBufferingTimer->setSingleShot(true);
connect(rewindBufferingTimer, &QTimer::timeout, this, &ReplayTimelineWidget::processRewind);
}
void ReplayTimelineWidget::setTimeline(const QList<int> &_replayTimeline)
{
replayTimeline = _replayTimeline;
histogram.clear();
int binEndTime = BIN_LENGTH - 1;
int binValue = 0;
for (int i : replayTimeline) {
if (i > binEndTime) {
histogram.append(binValue);
if (binValue > maxBinValue)
maxBinValue = binValue;
while (i > binEndTime + BIN_LENGTH) {
histogram.append(0);
binEndTime += BIN_LENGTH;
}
binValue = 1;
binEndTime += BIN_LENGTH;
} else
++binValue;
}
histogram.append(binValue);
if (!replayTimeline.isEmpty())
maxTime = replayTimeline.last();
update();
}
void ReplayTimelineWidget::paintEvent(QPaintEvent * /* event */)
{
QPainter painter(this);
painter.drawRect(0, 0, width() - 1, height() - 1);
qreal binWidth = (qreal)width() / histogram.size();
QPainterPath path;
path.moveTo(0, height() - 1);
for (int i = 0; i < histogram.size(); ++i)
path.lineTo(qRound(i * binWidth), (height() - 1) * (1.0 - (qreal)histogram[i] / maxBinValue));
path.lineTo(width() - 1, height() - 1);
path.lineTo(0, height() - 1);
painter.fillPath(path, Qt::black);
const QColor barColor = QColor::fromHsv(120, 255, 255, 100);
quint64 w = (quint64)(width() - 1) * (quint64)currentVisualTime / maxTime;
painter.fillRect(0, 0, static_cast<int>(w), height() - 1, barColor);
}
void ReplayTimelineWidget::mousePressEvent(QMouseEvent *event)
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
int newTime = static_cast<int>((qint64)maxTime * (qint64)event->position().x() / width());
#else
int newTime = static_cast<int>((qint64)maxTime * (qint64)event->x() / width());
#endif
// don't buffer rewinds from clicks, since clicks usually don't happen fast enough to require buffering
skipToTime(newTime, false);
}
void ReplayTimelineWidget::skipToTime(int newTime, bool doRewindBuffering)
{
// check boundary conditions
if (newTime < 0) {
newTime = 0;
}
if (newTime > maxTime) {
newTime = maxTime;
}
newTime -= newTime % TIMER_INTERVAL_MS; // Time should always be a multiple of the interval
const bool isBackwardsSkip = newTime < currentProcessedTime;
currentVisualTime = newTime;
if (isBackwardsSkip) {
handleBackwardsSkip(doRewindBuffering);
} else {
processNewEvents(FORWARD_SKIP);
}
update();
}
/// @param doRewindBuffering When true, if multiple backward skips are made in quick succession, only a single rewind
/// is processed at the end. When false, the backwards skip will always cause an immediate rewind
void ReplayTimelineWidget::handleBackwardsSkip(bool doRewindBuffering)
{
if (doRewindBuffering) {
// We use a one-shot timer to implement the rewind buffering.
// The rewind only happens once the timer runs out.
// If another backwards skip happens, the timer will just get reset instead of rewinding.
rewindBufferingTimer->stop();
rewindBufferingTimer->start(SettingsCache::instance().getRewindBufferingMs());
} else {
// otherwise, process the rewind immediately
processRewind();
}
}
void ReplayTimelineWidget::processRewind()
{
// stop any queued-up rewinds
rewindBufferingTimer->stop();
// process the rewind
currentEvent = 0;
emit rewound();
processNewEvents(BACKWARD_SKIP);
}
QSize ReplayTimelineWidget::sizeHint() const
{
return {-1, 50};
}
QSize ReplayTimelineWidget::minimumSizeHint() const
{
return {400, 50};
}
void ReplayTimelineWidget::replayTimerTimeout()
{
currentVisualTime += TIMER_INTERVAL_MS;
processNewEvents(NORMAL_PLAYBACK);
if (!(currentVisualTime % 1000))
update();
}
/// Processes all unprocessed events up to the current time.
void ReplayTimelineWidget::processNewEvents(PlaybackMode playbackMode)
{
currentProcessedTime = currentVisualTime;
while ((currentEvent < replayTimeline.size()) && (replayTimeline[currentEvent] < currentProcessedTime)) {
Player::EventProcessingOptions options;
// backwards skip => always skip reveal windows
// forwards skip => skip reveal windows that don't happen within a big skip of the target
if (playbackMode == BACKWARD_SKIP || currentProcessedTime - replayTimeline[currentEvent] > BIG_SKIP_MS)
options |= Player::EventProcessingOption::SKIP_REVEAL_WINDOW;
// backwards skip => always skip tap animation
if (playbackMode == BACKWARD_SKIP)
options |= Player::EventProcessingOption::SKIP_TAP_ANIMATION;
emit processNextEvent(options);
++currentEvent;
}
if (currentEvent == replayTimeline.size()) {
emit replayFinished();
replayTimer->stop();
}
}
void ReplayTimelineWidget::setTimeScaleFactor(qreal _timeScaleFactor)
{
timeScaleFactor = _timeScaleFactor;
replayTimer->setInterval(static_cast<int>(TIMER_INTERVAL_MS / timeScaleFactor));
}
void ReplayTimelineWidget::startReplay()
{
replayTimer->start(static_cast<int>(TIMER_INTERVAL_MS / timeScaleFactor));
}
void ReplayTimelineWidget::stopReplay()
{
replayTimer->stop();
}
void ReplayTimelineWidget::skipByAmount(int amount)
{
skipToTime(currentVisualTime + amount, amount < 0);
}

View File

@@ -1,6 +1,8 @@
#ifndef REPLAY_TIMELINE_WIDGET
#define REPLAY_TIMELINE_WIDGET
#include "../../game/player/player.h"
#include <QList>
#include <QMouseEvent>
#include <QWidget>
@@ -12,23 +14,44 @@ class ReplayTimelineWidget : public QWidget
{
Q_OBJECT
signals:
void processNextEvent();
void processNextEvent(Player::EventProcessingOptions options);
void replayFinished();
void rewound();
private:
enum PlaybackMode
{
NORMAL_PLAYBACK,
FORWARD_SKIP,
BACKWARD_SKIP
};
static constexpr int TIMER_INTERVAL_MS = 200;
static constexpr int BIN_LENGTH = 5000;
QTimer *replayTimer;
QTimer *rewindBufferingTimer;
QList<int> replayTimeline;
QList<int> histogram;
static const int binLength;
int maxBinValue, maxTime;
qreal timeScaleFactor;
int currentTime;
int currentVisualTime; // time currently displayed by the timeline
int currentProcessedTime; // time that events are currently processed up to. Could differ from visual time due to
// rewind buffering
int currentEvent;
void skipToTime(int newTime, bool doRewindBuffering);
void handleBackwardsSkip(bool doRewindBuffering);
void processRewind();
void processNewEvents(PlaybackMode playbackMode);
private slots:
void replayTimerTimeout();
public:
static constexpr int SMALL_SKIP_MS = 1000;
static constexpr int BIG_SKIP_MS = 10000;
static constexpr qreal FAST_FORWARD_SCALE_FACTOR = 10.0;
explicit ReplayTimelineWidget(QWidget *parent = nullptr);
void setTimeline(const QList<int> &_replayTimeline);
QSize sizeHint() const override;
@@ -41,6 +64,7 @@ public:
public slots:
void startReplay();
void stopReplay();
void skipByAmount(int amount); // use a negative amount to skip backwards
protected:
void paintEvent(QPaintEvent *event) override;

View File

@@ -1,4 +1,4 @@
#include "setsmodel.h"
#include "sets_model.h"
#include <QSortFilterProxyModel>
@@ -195,6 +195,13 @@ void SetsModel::swapRows(int oldRow, int newRow)
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
}
void SetsModel::restoreOriginalOrder()
{
int numRows = rowCount();
sets.defaultSort();
emit dataChanged(index(0, 0), index(numRows - 1, columnCount() - 1));
}
void SetsModel::sort(int column, Qt::SortOrder order)
{
QMultiMap<QString, CardSetPtr> setMap;

View File

@@ -1,7 +1,7 @@
#ifndef SETSMODEL_H
#define SETSMODEL_H
#include "carddatabase.h"
#include "../../game/cards/card_database.h"
#include <QAbstractTableModel>
#include <QMimeData>
@@ -49,44 +49,47 @@ public:
LongNameCol,
ShortNameCol,
SetTypeCol,
ReleaseDateCol
ReleaseDateCol,
PriorityCol
};
enum Role
{
SortRole = Qt::UserRole
};
SetsModel(CardDatabase *_db, QObject *parent = nullptr);
~SetsModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const
explicit SetsModel(CardDatabase *_db, QObject *parent = nullptr);
~SetsModel() override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
Q_UNUSED(parent);
return NUM_COLS;
}
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
Qt::DropActions supportedDropActions() const;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
Qt::DropActions supportedDropActions() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const;
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
QStringList mimeTypes() const;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
bool
dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
QStringList mimeTypes() const override;
void swapRows(int oldRow, int newRow);
void toggleRow(int row, bool enable);
void toggleRow(int row);
void toggleAll(bool);
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
void save(CardDatabase *db);
void restore(CardDatabase *db);
void restoreOriginalOrder();
};
class SetsDisplayModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
SetsDisplayModel(QObject *parent = NULL);
explicit SetsDisplayModel(QObject *parent = nullptr);
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;

View File

@@ -1,9 +1,10 @@
#include "spoilerbackgroundupdater.h"
#include "spoiler_background_updater.h"
#include "carddatabase.h"
#include "main.h"
#include "settingscache.h"
#include "window_main.h"
#include "../../game/cards/card_database.h"
#include "../../game/cards/card_database_manager.h"
#include "../../main.h"
#include "../../settings/cache_settings.h"
#include "../ui/window_main.h"
#include <QApplication>
#include <QCryptographicHash>
@@ -27,7 +28,7 @@ SpoilerBackgroundUpdater::SpoilerBackgroundUpdater(QObject *apParent) : QObject(
// File exists means we're in spoiler season
startSpoilerDownloadProcess(SPOILERS_STATUS_URL, false);
} else {
qDebug() << "Spoilers Disabled";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoilers Disabled";
}
}
@@ -44,10 +45,10 @@ void SpoilerBackgroundUpdater::downloadFromURL(QUrl url, bool saveResults)
if (saveResults) {
// This will write out to the file (used for spoiler.xml)
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSpoilersFile()));
connect(reply, &QNetworkReply::finished, this, &SpoilerBackgroundUpdater::actDownloadFinishedSpoilersFile);
} else {
// This will check the status (used to see if we're in spoiler season or not)
connect(reply, SIGNAL(finished()), this, SLOT(actCheckIfSpoilerSeasonEnabled()));
connect(reply, &QNetworkReply::finished, this, &SpoilerBackgroundUpdater::actCheckIfSpoilerSeasonEnabled);
}
}
@@ -66,7 +67,7 @@ void SpoilerBackgroundUpdater::actDownloadFinishedSpoilersFile()
reply->deleteLater();
emit spoilerCheckerDone();
} else {
qDebug() << "Error downloading spoilers file" << errorCode;
qCWarning(SpoilerBackgroundUpdaterLog) << "Error downloading spoilers file" << errorCode;
emit spoilerCheckerDone();
}
}
@@ -80,11 +81,11 @@ bool SpoilerBackgroundUpdater::deleteSpoilerFile()
// Delete the spoiler.xml file
if (file.exists() && file.remove()) {
qDebug() << "Deleting spoiler.xml";
qCInfo(SpoilerBackgroundUpdaterLog) << "Deleting spoiler.xml";
return true;
}
qDebug() << "Error: Spoiler.xml not found or not deleted";
qCInfo(SpoilerBackgroundUpdaterLog) << "Error: Spoiler.xml not found or not deleted";
return false;
}
@@ -100,24 +101,24 @@ void SpoilerBackgroundUpdater::actCheckIfSpoilerSeasonEnabled()
trayIcon->showMessage(tr("Spoilers season has ended"), tr("Deleting spoiler.xml. Please run Oracle"));
}
qDebug() << "Spoiler Season Offline";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoiler Season Offline";
emit spoilerCheckerDone();
} else if (errorCode == QNetworkReply::NoError) {
qDebug() << "Spoiler Service Online";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoiler Service Online";
startSpoilerDownloadProcess(SPOILERS_URL, true);
} else if (errorCode == QNetworkReply::HostNotFoundError) {
if (trayIcon) {
trayIcon->showMessage(tr("Spoilers download failed"), tr("No internet connection"));
}
qDebug() << "Spoiler download failed due to no internet connection";
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler download failed due to no internet connection";
emit spoilerCheckerDone();
} else {
if (trayIcon) {
trayIcon->showMessage(tr("Spoilers download failed"), tr("Error") + " " + (short)errorCode);
}
qDebug() << "Spoiler download failed with reason" << errorCode;
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler download failed with reason" << errorCode;
emit spoilerCheckerDone();
}
}
@@ -138,19 +139,19 @@ bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data)
trayIcon->showMessage(tr("Spoilers already up to date"), tr("No new spoilers added"));
}
qDebug() << "Spoilers Up to Date";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoilers Up to Date";
return false;
}
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
qDebug() << "Spoiler Service Error: File open (w) failed for" << fileName;
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler Service Error: File open (w) failed for" << fileName;
file.close();
return false;
}
if (file.write(data) == -1) {
qDebug() << "Spoiler Service Error: File write (w) failed for" << fileName;
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler Service Error: File write (w) failed for" << fileName;
file.close();
return false;
}
@@ -158,21 +159,25 @@ bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data)
file.close();
// Data written, so reload the card database
qDebug() << "Spoiler Service Data Written";
const auto reloadOk = QtConcurrent::run([] { db->loadCardDatabases(); });
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoiler Service Data Written";
const auto reloadOk = QtConcurrent::run([] { CardDatabaseManager::getInstance()->loadCardDatabases(); });
// If the user has notifications enabled, let them know
// when the database was last updated
if (trayIcon) {
QList<QByteArray> lines = data.split('\n');
foreach (QByteArray line, lines) {
for (const QByteArray &line : lines) {
if (line.contains("Created At:")) {
QString timeStamp = QString(line).replace("Created At:", "").trimmed();
timeStamp.chop(6); // Remove " (UTC)"
auto utcTime = QLocale().toDateTime(timeStamp, "ddd, MMM dd yyyy, hh:mm:ss");
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
utcTime.setTimeZone(QTimeZone::UTC);
#else
utcTime.setTimeSpec(Qt::UTC);
#endif
QString localTime = utcTime.toLocalTime().toString("MMM d, hh:mm");
@@ -197,12 +202,12 @@ QByteArray SpoilerBackgroundUpdater::getHash(const QString fileName)
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
hash.addData(bytes);
qDebug() << "File Hash =" << hash.result();
qCInfo(SpoilerBackgroundUpdaterLog) << "File Hash =" << hash.result();
file.close();
return hash.result();
} else {
qDebug() << "getHash ReadOnly failed!";
qCWarning(SpoilerBackgroundUpdaterLog) << "getHash ReadOnly failed!";
file.close();
return QByteArray();
}
@@ -216,7 +221,7 @@ QByteArray SpoilerBackgroundUpdater::getHash(QByteArray data)
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
hash.addData(bytes);
qDebug() << "Data Hash =" << hash.result();
qCInfo(SpoilerBackgroundUpdaterLog) << "Data Hash =" << hash.result();
return hash.result();
}

View File

@@ -2,9 +2,12 @@
#define COCKATRICE_SPOILER_DOWNLOADER_H
#include <QByteArray>
#include <QLoggingCategory>
#include <QObject>
#include <QProcess>
inline Q_LOGGING_CATEGORY(SpoilerBackgroundUpdaterLog, "spoiler_background_updater");
class SpoilerBackgroundUpdater : public QObject
{
Q_OBJECT

View File

@@ -1,6 +1,6 @@
#include "soundengine.h"
#include "sound_engine.h"
#include "settingscache.h"
#include "../settings/cache_settings.h"
#include <QDir>
#include <QMediaPlayer>
@@ -12,11 +12,11 @@
#define DEFAULT_THEME_NAME "Default"
#define TEST_SOUND_FILENAME "player_join"
SoundEngine::SoundEngine(QObject *parent) : QObject(parent), player(nullptr)
SoundEngine::SoundEngine(QObject *parent) : QObject(parent), audioOutput(nullptr), player(nullptr)
{
ensureThemeDirectoryExists();
connect(&SettingsCache::instance(), SIGNAL(soundThemeChanged()), this, SLOT(themeChangedSlot()));
connect(&SettingsCache::instance(), SIGNAL(soundEnabledChanged()), this, SLOT(soundEnabledChanged()));
connect(&SettingsCache::instance(), &SettingsCache::soundThemeChanged, this, &SoundEngine::themeChangedSlot);
connect(&SettingsCache::instance(), &SettingsCache::soundEnabledChanged, this, &SoundEngine::soundEnabledChanged);
soundEnabledChanged();
themeChangedSlot();
@@ -28,26 +28,34 @@ SoundEngine::~SoundEngine()
player->deleteLater();
player = nullptr;
}
if (audioOutput) {
audioOutput->deleteLater();
audioOutput = nullptr;
}
}
void SoundEngine::soundEnabledChanged()
{
if (SettingsCache::instance().getSoundEnabled()) {
qDebug() << "SoundEngine: enabling sound with" << audioData.size() << "sounds";
qCInfo(SoundEngineLog) << "SoundEngine: enabling sound with" << audioData.size() << "sounds";
if (!player) {
player = new QMediaPlayer;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
auto qAudioOutput = new QAudioOutput;
player->setAudioOutput(qAudioOutput);
audioOutput = new QAudioOutput(player);
player->setAudioOutput(audioOutput);
#endif
}
} else {
qDebug() << "SoundEngine: disabling sound";
qCInfo(SoundEngineLog) << "SoundEngine: disabling sound";
if (player) {
player->stop();
player->deleteLater();
player = nullptr;
}
if (audioOutput) {
audioOutput->deleteLater();
audioOutput = nullptr;
}
}
}
@@ -82,7 +90,7 @@ void SoundEngine::ensureThemeDirectoryExists()
{
if (SettingsCache::instance().getSoundThemeName().isEmpty() ||
!getAvailableThemes().contains(SettingsCache::instance().getSoundThemeName())) {
qDebug() << "Sounds theme name not set, setting default value";
qCInfo(SoundEngineLog) << "Sounds theme name not set, setting default value";
SettingsCache::instance().setSoundThemeName(DEFAULT_THEME_NAME);
}
}
@@ -123,7 +131,7 @@ QStringMap &SoundEngine::getAvailableThemes()
void SoundEngine::themeChangedSlot()
{
QString themeName = SettingsCache::instance().getSoundThemeName();
qDebug() << "Sound theme changed:" << themeName;
qCInfo(SoundEngineLog) << "Sound theme changed:" << themeName;
QDir dir = getAvailableThemes().value(themeName);

View File

@@ -1,12 +1,15 @@
#ifndef SOUNDENGINE_H
#define SOUNDENGINE_H
#include <QAudioOutput>
#include <QLoggingCategory>
#include <QMap>
#include <QMediaPlayer>
#include <QObject>
#include <QString>
class QAudioOutput;
inline Q_LOGGING_CATEGORY(SoundEngineLog, "sound_engine");
class QBuffer;
typedef QMap<QString, QString> QStringMap;
@@ -23,6 +26,7 @@ public:
private:
QStringMap availableThemes;
QMap<QString, QString> audioData;
QAudioOutput *audioOutput;
QMediaPlayer *player;
protected:

View File

@@ -0,0 +1,569 @@
#include "abstract_tab_deck_editor.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/tapped_out_interface.h"
#include "../../client/ui/widgets/cards/card_info_frame_widget.h"
#include "../../deck/deck_stats_interface.h"
#include "../../dialogs/dlg_load_deck.h"
#include "../../dialogs/dlg_load_deck_from_clipboard.h"
#include "../../game/cards/card_database_manager.h"
#include "../../game/cards/card_database_model.h"
#include "../../server/pending_command.h"
#include "../../settings/cache_settings.h"
#include "../ui/picture_loader/picture_loader.h"
#include "../ui/pixel_map_generator.h"
#include "pb/command_deck_upload.pb.h"
#include "pb/response.pb.h"
#include "tab_supervisor.h"
#include "trice_limits.h"
#include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QCloseEvent>
#include <QDebug>
#include <QDesktopServices>
#include <QDir>
#include <QFileDialog>
#include <QHeaderView>
#include <QLineEdit>
#include <QMenuBar>
#include <QMessageBox>
#include <QPrintPreviewDialog>
#include <QProcessEnvironment>
#include <QPushButton>
#include <QRegularExpression>
#include <QSplitter>
#include <QTextStream>
#include <QTreeView>
#include <QUrl>
AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
{
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
databaseDisplayDockWidget = new DeckEditorDatabaseDisplayWidget(this);
deckDockWidget = new DeckEditorDeckDockWidget(this);
cardInfoDockWidget = new DeckEditorCardInfoDockWidget(this);
filterDockWidget = new DeckEditorFilterDockWidget(this);
printingSelectorDockWidget = new DeckEditorPrintingSelectorDockWidget(this);
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckChanged, this, &AbstractTabDeckEditor::onDeckChanged);
connect(deckDockWidget, &DeckEditorDeckDockWidget::cardChanged, this, &AbstractTabDeckEditor::updateCard);
connect(this, &AbstractTabDeckEditor::decrementCard, deckDockWidget, &DeckEditorDeckDockWidget::actDecrementCard);
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, this,
&AbstractTabDeckEditor::updateCard);
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::addCardToMainDeck, this,
&AbstractTabDeckEditor::actAddCard);
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::addCardToSideboard, this,
&AbstractTabDeckEditor::actAddCardToSideboard);
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::decrementCardFromMainDeck, this,
&AbstractTabDeckEditor::actDecrementCard);
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::decrementCardFromSideboard, this,
&AbstractTabDeckEditor::actDecrementCardFromSideboard);
connect(filterDockWidget, &DeckEditorFilterDockWidget::clearAllDatabaseFilters, databaseDisplayDockWidget,
&DeckEditorDatabaseDisplayWidget::clearAllDatabaseFilters);
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
}
void AbstractTabDeckEditor::updateCard(CardInfoPtr _card)
{
cardInfoDockWidget->updateCard(_card);
printingSelectorDockWidget->printingSelector->setCard(_card, DECK_ZONE_MAIN);
}
void AbstractTabDeckEditor::onDeckChanged()
{
setModified(!isBlankNewDeck());
deckMenu->setSaveStatus(!isBlankNewDeck());
}
void AbstractTabDeckEditor::addCardHelper(const CardInfoPtr info, QString zoneName)
{
if (!info)
return;
if (info->getIsToken())
zoneName = DECK_ZONE_TOKENS;
QModelIndex newCardIndex = deckDockWidget->deckModel->addPreferredPrintingCard(info->getName(), zoneName, false);
// recursiveExpand(newCardIndex);
deckDockWidget->deckView->clearSelection();
deckDockWidget->deckView->setCurrentIndex(newCardIndex);
setModified(true);
databaseDisplayDockWidget->searchEdit->setSelection(0, databaseDisplayDockWidget->searchEdit->text().length());
}
void AbstractTabDeckEditor::actAddCard(CardInfoPtr info)
{
if (QApplication::keyboardModifiers() & Qt::ControlModifier)
actAddCardToSideboard(info);
else
addCardHelper(info, DECK_ZONE_MAIN);
deckMenu->setSaveStatus(true);
}
void AbstractTabDeckEditor::actAddCardToSideboard(CardInfoPtr info)
{
addCardHelper(info, DECK_ZONE_SIDE);
deckMenu->setSaveStatus(true);
}
void AbstractTabDeckEditor::actDecrementCard(CardInfoPtr info)
{
emit decrementCard(info, DECK_ZONE_MAIN);
}
void AbstractTabDeckEditor::actDecrementCardFromSideboard(CardInfoPtr info)
{
emit decrementCard(info, DECK_ZONE_SIDE);
}
void AbstractTabDeckEditor::actSwapCard(CardInfoPtr info, QString zoneName)
{
QString providerId = CardDatabaseManager::getInstance()->getSetInfoForCard(info).getProperty("uuid");
QString collectorNumber = CardDatabaseManager::getInstance()->getSetInfoForCard(info).getProperty("num");
deckDockWidget->swapCard(
deckDockWidget->deckModel->findCard(info->getName(), zoneName, providerId, collectorNumber));
}
/**
* Opens the deck in this tab.
* @param deck The deck. Takes ownership of the object
*/
void AbstractTabDeckEditor::openDeck(DeckLoader *deck)
{
setDeck(deck);
if (!deck->getLastFileName().isEmpty()) {
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(deck->getLastFileName());
}
}
/**
* Sets the currently active deck for this tab
* @param _deck The deck. Takes ownership of the object
*/
void AbstractTabDeckEditor::setDeck(DeckLoader *_deck)
{
deckDockWidget->setDeck(_deck);
PictureLoader::cacheCardPixmaps(
CardDatabaseManager::getInstance()->getCardsByNameAndProviderId(getDeckList()->getCardListWithProviderId()));
setModified(false);
// If they load a deck, make the deck list appear
aDeckDockVisible->setChecked(true);
deckDockWidget->setVisible(aDeckDockVisible->isChecked());
}
DeckLoader *AbstractTabDeckEditor::getDeckList() const
{
return deckDockWidget->getDeckList();
}
void AbstractTabDeckEditor::setModified(bool _modified)
{
modified = _modified;
emit tabTextChanged(this, getTabText());
}
/**
* @brief Returns true if this tab is a blank newly opened tab, as if it was just created with the `New Deck` action.
*/
bool AbstractTabDeckEditor::isBlankNewDeck() const
{
DeckLoader *deck = getDeckList();
return !modified && deck->hasNotBeenLoaded();
}
void AbstractTabDeckEditor::actNewDeck()
{
auto deckOpenLocation = confirmOpen(false);
if (deckOpenLocation == CANCELLED) {
return;
}
if (deckOpenLocation == NEW_TAB) {
emit openDeckEditor(nullptr);
return;
}
cleanDeckAndResetModified();
}
void AbstractTabDeckEditor::cleanDeckAndResetModified()
{
deckMenu->setSaveStatus(false);
deckDockWidget->cleanDeck();
setModified(false);
}
/**
* @brief Displays the save confirmation dialogue that is shown before loading a deck, if required. Takes into
* account the `openDeckInNewTab` settting.
*
* @param openInSameTabIfBlank Open the deck in the same tab instead of a new tab if the current tab is completely
* blank. Only relevant when the `openDeckInNewTab` setting is enabled.
*
* @returns An enum that indicates if and where to load the deck
*/
AbstractTabDeckEditor::DeckOpenLocation AbstractTabDeckEditor::confirmOpen(const bool openInSameTabIfBlank)
{
// handle `openDeckInNewTab` setting
if (SettingsCache::instance().getOpenDeckInNewTab()) {
if (openInSameTabIfBlank && isBlankNewDeck()) {
return SAME_TAB;
} else {
return NEW_TAB;
}
}
// early return if deck is unmodified
if (!modified) {
return SAME_TAB;
}
// do the save confirmation dialogue
tabSupervisor->setCurrentWidget(this);
QMessageBox *msgBox = createSaveConfirmationWindow();
QPushButton *newTabButton = msgBox->addButton(tr("Open in new tab"), QMessageBox::ApplyRole);
int ret = msgBox->exec();
// `exec()` returns an opaque value if a non-standard button was clicked.
// Directly check if newTabButton was clicked before switching over the standard buttons.
if (msgBox->clickedButton() == newTabButton) {
return NEW_TAB;
}
switch (ret) {
case QMessageBox::Save:
return actSaveDeck() ? SAME_TAB : CANCELLED;
case QMessageBox::Discard:
return SAME_TAB;
default:
return CANCELLED;
}
}
/**
* @brief Creates the base save confirmation dialogue box.
*
* @returns A QMessageBox that can be further modified
*/
QMessageBox *AbstractTabDeckEditor::createSaveConfirmationWindow()
{
QMessageBox *msgBox = new QMessageBox(this);
msgBox->setIcon(QMessageBox::Warning);
msgBox->setWindowTitle(tr("Are you sure?"));
msgBox->setText(tr("The decklist has been modified.\nDo you want to save the changes?"));
msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
return msgBox;
}
void AbstractTabDeckEditor::actLoadDeck()
{
auto deckOpenLocation = confirmOpen();
if (deckOpenLocation == CANCELLED) {
return;
}
DlgLoadDeck dialog(this);
if (!dialog.exec())
return;
QString fileName = dialog.selectedFiles().at(0);
openDeckFromFile(fileName, deckOpenLocation);
deckDockWidget->updateBannerCardComboBox();
}
void AbstractTabDeckEditor::actOpenRecent(const QString &fileName)
{
auto deckOpenLocation = confirmOpen();
if (deckOpenLocation == CANCELLED) {
return;
}
openDeckFromFile(fileName, deckOpenLocation);
}
/**
* Actually opens the deck from file
* @param fileName The path of the deck to open
* @param deckOpenLocation Which tab to open the deck
*/
void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation)
{
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
auto *l = new DeckLoader;
if (l->loadFromFile(fileName, fmt, true)) {
if (deckOpenLocation == NEW_TAB) {
emit openDeckEditor(l);
l->deleteLater();
} else {
deckMenu->setSaveStatus(false);
openDeck(l);
}
} else {
l->deleteLater();
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName));
}
deckMenu->setSaveStatus(true);
}
bool AbstractTabDeckEditor::actSaveDeck()
{
DeckLoader *const deck = getDeckList();
if (deck->getLastRemoteDeckId() != -1) {
QString deckString = deck->writeToString_Native();
if (deckString.length() > MAX_FILE_LENGTH) {
QMessageBox::critical(this, tr("Error"), tr("Could not save remote deck"));
return false;
}
Command_DeckUpload cmd;
cmd.set_deck_id(static_cast<google::protobuf::uint32>(deck->getLastRemoteDeckId()));
cmd.set_deck_list(deckString.toStdString());
PendingCommand *pend = AbstractClient::prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(saveDeckRemoteFinished(Response)));
tabSupervisor->getClient()->sendCommand(pend);
return true;
} else if (deck->getLastFileName().isEmpty())
return actSaveDeckAs();
else if (deck->saveToFile(deck->getLastFileName(), deck->getLastFileFormat())) {
setModified(false);
return true;
}
QMessageBox::critical(
this, tr("Error"),
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
return false;
}
bool AbstractTabDeckEditor::actSaveDeckAs()
{
QFileDialog dialog(this, tr("Save deck"));
dialog.setDirectory(SettingsCache::instance().getDeckPath());
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDefaultSuffix("cod");
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
dialog.selectFile(getDeckList()->getName().trimmed());
if (!dialog.exec())
return false;
QString fileName = dialog.selectedFiles().at(0);
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
if (!getDeckList()->saveToFile(fileName, fmt)) {
QMessageBox::critical(
this, tr("Error"),
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
return false;
}
setModified(false);
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
return true;
}
void AbstractTabDeckEditor::saveDeckRemoteFinished(const Response &response)
{
if (response.response_code() != Response::RespOk)
QMessageBox::critical(this, tr("Error"), tr("The deck could not be saved."));
else
setModified(false);
}
void AbstractTabDeckEditor::actLoadDeckFromClipboard()
{
auto deckOpenLocation = confirmOpen();
if (deckOpenLocation == CANCELLED) {
return;
}
DlgLoadDeckFromClipboard dlg(this);
if (!dlg.exec())
return;
if (deckOpenLocation == NEW_TAB) {
emit openDeckEditor(dlg.getDeckList());
} else {
setDeck(dlg.getDeckList());
setModified(true);
}
deckMenu->setSaveStatus(true);
}
void AbstractTabDeckEditor::editDeckInClipboard(bool annotated)
{
DlgEditDeckInClipboard dlg(*getDeckList(), annotated, this);
if (!dlg.exec())
return;
setDeck(dlg.getDeckList());
setModified(true);
deckMenu->setSaveStatus(true);
}
void AbstractTabDeckEditor::actEditDeckInClipboard()
{
editDeckInClipboard(true);
}
void AbstractTabDeckEditor::actEditDeckInClipboardRaw()
{
editDeckInClipboard(false);
}
void AbstractTabDeckEditor::actSaveDeckToClipboard()
{
getDeckList()->saveToClipboard(true, true);
}
void AbstractTabDeckEditor::actSaveDeckToClipboardNoSetInfo()
{
getDeckList()->saveToClipboard(true, false);
}
void AbstractTabDeckEditor::actSaveDeckToClipboardRaw()
{
getDeckList()->saveToClipboard(false, true);
}
void AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetInfo()
{
getDeckList()->saveToClipboard(false, false);
}
void AbstractTabDeckEditor::actPrintDeck()
{
auto *dlg = new QPrintPreviewDialog(this);
connect(dlg, SIGNAL(paintRequested(QPrinter *)), deckDockWidget->deckModel, SLOT(printDeckList(QPrinter *)));
dlg->exec();
}
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
{
// check if deck is not null
if (DeckLoader *const deck = getDeckList()) {
// Get the decklist url string from the deck loader class.
QString decklistUrlString = deck->exportDeckToDecklist(website);
// Check to make sure the string isn't empty.
if (QString::compare(decklistUrlString, "", Qt::CaseInsensitive) == 0) {
// Show an error if the deck is empty, and return.
QMessageBox::critical(this, tr("Error"), tr("There are no cards in your deck to be exported"));
return;
}
// Encode the string recieved from the model to make sure all characters are encoded.
// first we put it into a qurl object
QUrl decklistUrl = QUrl(decklistUrlString);
// we get the correctly encoded url.
decklistUrlString = decklistUrl.toEncoded();
// We open the url in the user's default browser
QDesktopServices::openUrl(decklistUrlString);
} else {
// if there's no deck loader object, return an error
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be exported."));
}
}
/**
* Exports the deck to www.decklist.org (the old website)
*/
void AbstractTabDeckEditor::actExportDeckDecklist()
{
exportToDecklistWebsite(DeckLoader::DecklistOrg);
}
/**
* Exports the deck to www.decklist.xyz (the new website)
*/
void AbstractTabDeckEditor::actExportDeckDecklistXyz()
{
exportToDecklistWebsite(DeckLoader::DecklistXyz);
}
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
{
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),
this); // it deletes itself when done
interface->analyzeDeck(getDeckList());
}
void AbstractTabDeckEditor::actAnalyzeDeckTappedout()
{
auto *interface = new TappedOutInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),
this); // it deletes itself when done
interface->analyzeDeck(getDeckList());
}
void AbstractTabDeckEditor::filterTreeChanged(FilterTree *filterTree)
{
databaseDisplayDockWidget->setFilterTree(filterTree);
}
// Method uses to sync docks state with menu items state
bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QEvent::Close) {
if (o == cardInfoDockWidget) {
aCardInfoDockVisible->setChecked(false);
aCardInfoDockFloating->setEnabled(false);
} else if (o == deckDockWidget) {
aDeckDockVisible->setChecked(false);
aDeckDockFloating->setEnabled(false);
} else if (o == filterDockWidget) {
aFilterDockVisible->setChecked(false);
aFilterDockFloating->setEnabled(false);
} else if (o == printingSelectorDockWidget) {
aPrintingSelectorDockVisible->setChecked(false);
aPrintingSelectorDockFloating->setEnabled(false);
}
}
if (o == this && e->type() == QEvent::Hide) {
LayoutsSettings &layouts = SettingsCache::instance().layouts();
layouts.setDeckEditorLayoutState(saveState());
layouts.setDeckEditorGeometry(saveGeometry());
layouts.setDeckEditorCardSize(cardInfoDockWidget->size());
layouts.setDeckEditorFilterSize(filterDockWidget->size());
layouts.setDeckEditorDeckSize(deckDockWidget->size());
layouts.setDeckEditorPrintingSelectorSize(printingSelectorDockWidget->size());
}
return false;
}
bool AbstractTabDeckEditor::confirmClose()
{
if (modified) {
tabSupervisor->setCurrentWidget(this);
int ret = createSaveConfirmationWindow()->exec();
if (ret == QMessageBox::Save)
return actSaveDeck();
else if (ret == QMessageBox::Cancel)
return false;
}
return true;
}
void AbstractTabDeckEditor::closeRequest(bool forced)
{
if (!forced && !confirmClose()) {
return;
}
emit deckEditorClosing(this);
close();
}

View File

@@ -0,0 +1,155 @@
#ifndef TAB_GENERIC_DECK_EDITOR_H
#define TAB_GENERIC_DECK_EDITOR_H
#include "../../game/cards/card_database.h"
#include "../menus/deck_editor/deck_editor_menu.h"
#include "../ui/widgets/deck_editor/deck_editor_card_info_dock_widget.h"
#include "../ui/widgets/deck_editor/deck_editor_database_display_widget.h"
#include "../ui/widgets/deck_editor/deck_editor_deck_dock_widget.h"
#include "../ui/widgets/deck_editor/deck_editor_filter_dock_widget.h"
#include "../ui/widgets/deck_editor/deck_editor_printing_selector_dock_widget.h"
#include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
#include "tab.h"
class CardDatabaseModel;
class CardDatabaseDisplayModel;
class CardInfoFrameWidget;
class DeckLoader;
class DeckEditorMenu;
class DeckEditorCardInfoDockWidget;
class DeckEditorDatabaseDisplayWidget;
class DeckEditorDeckDockWidget;
class DeckEditorFilterDockWidget;
class DeckEditorPrintingSelectorDockWidget;
class DeckPreviewDeckTagsDisplayWidget;
class Response;
class FilterTreeModel;
class FilterBuilder;
class QTreeView;
class QTextEdit;
class QLabel;
class QComboBox;
class QGroupBox;
class QMessageBox;
class QHBoxLayout;
class QVBoxLayout;
class QPushButton;
class QDockWidget;
class QMenu;
class QAction;
class AbstractTabDeckEditor : public Tab
{
Q_OBJECT
public:
explicit AbstractTabDeckEditor(TabSupervisor *_tabSupervisor);
// UI and Navigation
virtual void createMenus() = 0;
[[nodiscard]] virtual QString getTabText() const override = 0;
bool confirmClose();
virtual void retranslateUi() override = 0;
// Deck Management
void openDeck(DeckLoader *deck);
DeckLoader *getDeckList() const;
void setModified(bool _windowModified);
// UI Elements
DeckEditorMenu *deckMenu;
DeckEditorDatabaseDisplayWidget *databaseDisplayDockWidget;
DeckEditorCardInfoDockWidget *cardInfoDockWidget;
DeckEditorDeckDockWidget *deckDockWidget;
DeckEditorFilterDockWidget *filterDockWidget;
DeckEditorPrintingSelectorDockWidget *printingSelectorDockWidget;
public slots:
void onDeckChanged();
void updateCard(CardInfoPtr _card);
void actAddCard(CardInfoPtr info);
void actAddCardToSideboard(CardInfoPtr info);
void actDecrementCard(CardInfoPtr info);
void actDecrementCardFromSideboard(CardInfoPtr info);
void actOpenRecent(const QString &fileName);
void filterTreeChanged(FilterTree *filterTree);
void closeRequest(bool forced = false) override;
virtual void showPrintingSelector() = 0;
virtual void dockTopLevelChanged(bool topLevel) = 0;
signals:
void openDeckEditor(const DeckLoader *deckLoader);
void deckEditorClosing(AbstractTabDeckEditor *tab);
void decrementCard(CardInfoPtr card, QString zoneName);
protected slots:
// Deck Operations
virtual void actNewDeck();
void cleanDeckAndResetModified();
virtual void actLoadDeck();
bool actSaveDeck();
bool actSaveDeckAs();
virtual void actLoadDeckFromClipboard();
void actEditDeckInClipboard();
void actEditDeckInClipboardRaw();
void actSaveDeckToClipboard();
void actSaveDeckToClipboardNoSetInfo();
void actSaveDeckToClipboardRaw();
void actSaveDeckToClipboardRawNoSetInfo();
void actPrintDeck();
void actExportDeckDecklist();
void actExportDeckDecklistXyz();
void actAnalyzeDeckDeckstats();
void actAnalyzeDeckTappedout();
// Remote Save
void saveDeckRemoteFinished(const Response &r);
// UI Layout Management
virtual void loadLayout() = 0;
virtual void restartLayout() = 0;
virtual void freeDocksSize() = 0;
virtual void refreshShortcuts() = 0;
bool eventFilter(QObject *o, QEvent *e) override;
virtual void dockVisibleTriggered() = 0;
virtual void dockFloatingTriggered() = 0;
private:
virtual void setDeck(DeckLoader *_deck);
void editDeckInClipboard(bool annotated);
void exportToDecklistWebsite(DeckLoader::DecklistWebsite website);
protected:
/**
* @brief Enum for selecting deck open location
*/
enum DeckOpenLocation
{
CANCELLED,
SAME_TAB,
NEW_TAB
};
DeckOpenLocation confirmOpen(bool openInSameTabIfBlank = true);
QMessageBox *createSaveConfirmationWindow();
bool isBlankNewDeck() const;
// Helper functions for card actions
void addCardHelper(CardInfoPtr info, QString zoneName);
void actSwapCard(CardInfoPtr info, QString zoneName);
virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
// UI Menu Elements
QMenu *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu, *printingSelectorDockMenu;
QAction *aResetLayout;
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
bool modified = false;
};
#endif // TAB_GENERIC_DECK_EDITOR_H

View File

@@ -0,0 +1,45 @@
#include "edhrec_commander_api_response.h"
#include <QDebug>
#include <QJsonArray>
void EdhrecCommanderApiResponse::fromJson(const QJsonObject &json)
{
// Parse the collapsed DeckStatistics
deckStats.fromJson(json);
// Parse Archidekt section
QJsonArray archidektJson = json.value("archidekt").toArray();
archidekt.fromJson(archidektJson);
// Parse other fields
similar = json.value("similar").toObject();
header = json.value("header").toString();
panels = json.value("panels").toObject();
description = json.value("description").toString();
QJsonObject containerJson = json.value("container").toObject();
container.fromJson(containerJson);
}
void EdhrecCommanderApiResponse::debugPrint() const
{
qDebug() << "Deck Statistics:";
qDebug() << " Creature:" << deckStats.creature;
qDebug() << " Instant:" << deckStats.instant;
qDebug() << " Sorcery:" << deckStats.sorcery;
qDebug() << " Artifact:" << deckStats.artifact;
qDebug() << " Enchantment:" << deckStats.enchantment;
qDebug() << " Battle:" << deckStats.battle;
qDebug() << " Planeswalker:" << deckStats.planeswalker;
qDebug() << " Land:" << deckStats.land;
qDebug() << " Basic:" << deckStats.basic;
qDebug() << " Nonbasic:" << deckStats.nonbasic;
archidekt.debugPrint();
qDebug() << "Similar:" << similar;
qDebug() << "Header:" << header;
qDebug() << "Panels:" << panels;
qDebug() << "Description:" << description;
container.debugPrint();
}

View File

@@ -0,0 +1,28 @@
#ifndef DECKDATA_H
#define DECKDATA_H
#include "edhrec_commander_api_response_archidekt_links.h"
#include "edhrec_commander_api_response_average_deck_statistics.h"
#include "edhrec_commander_api_response_card_container.h"
#include <QDebug>
#include <QJsonObject>
#include <QString>
// Represents the main structure of the JSON
class EdhrecCommanderApiResponse
{
public:
EdhrecCommanderApiResponseAverageDeckStatistics deckStats;
EdhrecCommanderApiResponseArchidektLinks archidekt;
QJsonObject similar;
QString header;
QJsonObject panels;
QString description;
EdhrecCommanderApiResponseCardContainer container;
void fromJson(const QJsonObject &json);
void debugPrint() const;
};
#endif // DECKDATA_H

View File

@@ -0,0 +1,43 @@
#include "edhrec_commander_api_response_archidekt_links.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
void EdhrecCommanderApiResponseArchidektLink::fromJson(const QJsonObject &json)
{
c = json.value("c").toString();
f = json.value("f").toInt(0);
q = json.value("q").toInt(0);
u = json.value("u").toString();
}
void EdhrecCommanderApiResponseArchidektLink::debugPrint() const
{
qDebug() << " C:" << c;
qDebug() << " F:" << f;
qDebug() << " Q:" << q;
qDebug() << " U:" << u;
}
void EdhrecCommanderApiResponseArchidektLinks::fromJson(const QJsonArray &json)
{
entries.clear();
for (const QJsonValue &value : json) {
if (value.isObject()) {
QJsonObject entryJson = value.toObject();
EdhrecCommanderApiResponseArchidektLink entry;
entry.fromJson(entryJson);
entries.append(entry);
}
}
}
void EdhrecCommanderApiResponseArchidektLinks::debugPrint() const
{
qDebug() << "Archidekt Entries:";
for (const auto &entry : entries) {
entry.debugPrint();
}
}

Some files were not shown because too many files have changed in this diff Show More