Compare commits

...

222 Commits

Author SHA1 Message Date
ebbit1q
401fdcaf7a move changing x coord to after check for token deletion (#4236)
fixes #4235
reverts #4216
2021-01-30 16:44:12 -05:00
ctrlaltca
1bfcca91be add window icons in wayland (#4232)
Co-authored-by: Fabio Bas <fabio.bas@officineinformatiche.net>
2021-01-28 15:21:11 -05:00
ebbit1q
3edb862561 update version number to 2.8.1 (#4229) 2021-01-27 20:49:13 -05:00
ZeldaZach
00c0162da3 Change release name/number for 2.8.0 and make it a forced update 2021-01-26 14:56:29 -05:00
ZeldaZach
6fa5f4f9a5 Translations from Transifex 2021-01-26 14:50:05 -05:00
ebbit1q
db528c6762 Release templates (#4226)
* add creation of release templates to ci and update guide

* touchups to markdown

* correct create release property

* correctly set fetch-depth and release body

* fix replacements, remove arrows

* check if there are no betas

* add extra output

* typo
2021-01-25 19:53:34 -05:00
ebbit1q
0c54cdf6bc set release upload_url correctly during configure (#4225)
correctly set prerelease flag
set prerelease names to their tag instead of full release name
detect version for use in release name during configuration
2021-01-24 16:52:19 -05:00
ebbit1q
b63145c0a1 merge build workflows (#4197)
* merge build workflows

* fix mac version comparisons
2021-01-24 15:20:06 -05:00
Joseph Chamish
1ddc9cc929 Structure change (#4220)
* Structure change

* Remove duplicate folders from previous structure

* Cleanup websocket protocol

* Updating from based off PR

* Fixup - remove wrong files during conflict and get the websocket working

* renaming tsx to ts

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2021-01-20 18:50:18 -05:00
knitknit
a0deb73df6 Fix #2771: Do not change x coordinates of moved card if it will be destroyed when it leaves the table (#4216) 2021-01-02 22:45:11 -05:00
Jeremy Letto
0457e65751 Webatrice P.O.C. (#3854)
* port webclient POC into react shell

* Abstract websocket messaging behind redux store

* refactor architecture

* add rooms store

* introduce application service layer and login form

* display room messages

* implement roomSay

* improve Room view styling

* display room games

* improve gameList update logic

* hide protected games

* improve game update logic

* move mapping to earlier lifecycle hook

* add autoscroll to bottom

* tabs to spaces, refresh guard

* implement server joins/leaves

* show users in room

* add material-ui to build

* refactor, add room joins/leaves to store and render

* begin using Material UI components

* fix spectatorsCount

* remove unused package

* improve Server and Room styling

* fix scroll context

* route on room join

* refactor room path

* add auth guard

* refactor authGuard export

* add missing files

* clear store on disconnect, add logout button to Account view

* fix disconnect handling

* Safari fixes

* organize current todos

* improve login page and server status tracking

* improve login page

* introduce sorting arch, refine reducers, begin viewLogHistory

* audit fix for handlebars

* implement moderator log view

* comply with code style rules

* remove original POC from codebase

* add missing semi

* minor improvements, begin registration functionality

* retry as ws when wss fails

additionally, dont mutate the default options when connecting

* retain user/pass in WebClient.options for login

* take protocol off of options, make it a connect param that defaults to wss

* cleanup server page styling

* match wss logic with desktop client

* add virtual scroll component, add context menu to UserDisplay

* revert VirtualTable on messages

* improve styling for Room view

* add routing to Player view

* increase tooltip delay

* begin implementing Account view

* disable app level contextMenu

* implement buddy/ignore list management

* fix gitignore

Co-authored-by: Jay Letto <jeremy.letto@merrillcorp.com>
Co-authored-by: skwerlman <skwerlman@users.noreply.github.com>
Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2020-12-31 17:08:15 -05:00
saadbruno
d5b36e8b8a Disabled strict mode for MySQL on the docker-compose file (#4214) 2020-12-28 16:43:45 -05:00
ebbit1q
f595a61d50 fix #4198 (#4209) 2020-12-09 02:08:00 -05:00
Joel Bethke
dbf6cd745e cmake: Minor updates (#4204) 2020-12-07 11:50:32 -05:00
ebbit1q
0ce813b826 restore saved previous server (#4206)
fix #3617
2020-12-05 21:36:27 -05:00
tooomm
77be6a120c fix broken image (#4202) 2020-12-01 16:57:27 -05:00
tooomm
37053cc909 Remove AppVeyor config (#4200)
* readability

* update ci badge for windows

* Delete .appveyor.yml
2020-12-01 22:38:50 +01:00
Zach H
34e951298f Address a handful of warnings from #6095 (#4199) 2020-12-01 11:30:22 -05:00
Joel Bethke
8845a23d5d CI: Fix up Windows builds and add GitHub Actions for Windows (#4193)
* ci: Add vcpkg submodule

* cmake: Fix NSIS not detecting platform arch

* cmake: Add QTDIR(64|32)

This change adds a new var for QTDIR(32|64) which makes it easier
to specify a specific directory for Qt, rather than having to edit
the prefix path directly, which can get pretty messy. Functionally,
this shouldn't affect any builds that are already finding Qt as
part of path, and should not affect Linux/macOS.

* cmake: Bump min cmake version

* ci: Add GitHub Actions for Windows
2020-11-30 23:54:50 -05:00
Derek Chiang
38606bdb87 Display a system tray notification when a player joins your game (#4194)
* Display a system tray notification when a player joins your game

* Display game ID in join message
2020-11-29 21:11:35 -05:00
Joel Bethke
56a51c7834 ui: Fix Qt depreaction warnings (#4195) 2020-11-29 02:33:13 -05:00
tooomm
402c09e028 Update CONTRIBUTING and more travis removing (#4179) 2020-11-28 03:14:15 -05:00
ebbit1q
9e702ec358 update link to master builds on appveyor (#4180) 2020-11-28 03:13:42 -05:00
Joel Bethke
c047a8ae3c ui: Add shortcut for "Save deck as..." (#4188)
Fixes: #4174
2020-11-26 22:22:44 +01:00
tooomm
b4740ad395 Update README.md (#4189)
* Update README.md

* don't run on .md-only changes
2020-11-26 13:14:00 -05:00
tooomm
99b0abe7fe GitHub Actions: don't run on .md only changes (#4183) 2020-11-25 21:14:05 -05:00
leiftw
b0239c11ab Fix typo in #L135 to conform with #L138 (#4182) 2020-11-24 14:58:28 -05:00
ebbit1q
46cf50d468 add ubuntu 20.10 Groovy Gorilla (#4178) 2020-11-23 18:09:02 -05:00
Zach H
9f9581c2be Support MTGJSONv5 format in Oracle downloader (#4162)
* Fix #4043, Support MTGJSONv5 format in Oracle downloader

* Auto redirect V4 downloads to V5, as we won't support V4 after this change

* clangify >_>

* Remove null values and account for IDs missing

* fix split cards and double faced cards somewhat

* do not consider double faced cards duplicates

* fix promo double sided cards

* typo

* fix alternative versions of cards with (letter)

* zach says this is more readable

* pre qt 5.10 compatibility

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2020-11-23 16:12:41 -05:00
tooomm
f3cf1f0dde pin badge to master (#4177) 2020-11-23 13:23:47 -05:00
tooomm
2f62671d8a More changes to GitHub Actions (#4175) 2020-11-23 12:27:35 -05:00
tooomm
589fbcdcd5 clearify wording (#4173) 2020-11-23 12:24:49 -05:00
ebbit1q
51b24bb92c refactor getting game age (#4095) 2020-11-22 20:28:56 -05:00
Zach H
6e00db4ef6 Fix racetime condition with token cloning (#4156)
* Fix #2820 by removing (this->setCursor) as this was null by the time we hit this component due to a racetime condition.

* check if card player pointer is valid before setting cursor

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2020-11-22 20:25:23 -05:00
ebbit1q
0d842b5a35 Resurrect 2655 (#4136)
* fix #2640

* clangify

Co-authored-by: Fabio Bas <ctrlaltca@gmail.com>
2020-11-22 20:23:18 -05:00
ebbit1q
8441cb7ba9 refactor pingClockTimeout (#4169)
* refactor pingClockTimeout

try to see if it changes #3954

* use lcoks and unlocks again
2020-11-22 20:21:43 -05:00
ebbit1q
4aaedf64d2 add github actions (#4164) 2020-11-22 20:20:48 -05:00
Zach H
45d838a0b3 Search full subdirectory for custom databases (#4137)
* Fix #2324 by allowing for iteration & symlinks

* Ensure alphabetical sorting
2020-11-22 20:06:25 -05:00
ebbit1q
ca5f1dd434 do some guesswork if cards can't be found (#4131)
modify up the simplifyCardName function to ignore right halves
add guessCard function that prioritises full card names the simple ones
fix imports for misformatted split cards or double faced cards
introduces a small concession: not completely formatted names with a
shared name on the left side will get mixed up, eg "bind" but not "Bind"
this should be fine considering how this would fix a lot more cards
2020-11-22 19:57:51 -05:00
tooomm
d07bf1211a Improve dialogs (#4153) 2020-11-13 16:01:44 -05:00
Zach H
0966a8e90f Fix #566 by allowing for DeckName/Comments to be resized to the max, and even hidden! (#4157) 2020-11-13 15:36:20 -05:00
ebbit1q
68074b0f74 check if node is a dir before deletion (#4165) 2020-11-13 14:55:01 -05:00
ebbit1q
f11f072e0a add missing mysql connector dependencies to docker images (#4160) 2020-11-08 19:35:54 -05:00
tooomm
3064621a7e Add exclude term to search hints (#4038) 2020-11-02 18:44:19 -05:00
tooomm
0405c82cb2 File name cleanup (#4154) 2020-11-01 19:03:08 -05:00
knitknit
8e9d4e3a67 Retain lastDrawList if a card is being moved within hand, e.g. hand reordering only. (#4152) 2020-11-01 15:02:17 -05:00
tooomm
ef78fdf342 Fix resizing for game filter dialog (#4149) 2020-10-29 20:21:01 -04:00
Kaitlin
a49c4865bb Add game filtering for spectator attributes (#4127) 2020-10-27 15:49:02 -04:00
fdipilla
1a94261490 Multiple background images on all zones (#4144) 2020-10-23 15:36:02 -04:00
Zach H
e10446f5b8 Remove annoying spectator log messages (#4138) 2020-10-22 16:46:50 +02:00
rivten
2081639970 fix infinite loop when card file save fails, instead stop the execution just like the other errors in the call (#4143) 2020-10-21 10:31:57 -04:00
ebbit1q
8cbc4c91f6 free qprocess on oracle update fail (#4134)
* free qprocess on oracle update fail

reload the database whenever oracle exits
search for oracle in ../oracle so you can use it from the build dir

* only ask for the db updater once
2020-10-21 10:31:18 -04:00
tooomm
b8cd3af21f CONTRIBUTING: little changes (#4141) 2020-10-14 11:19:37 -04:00
tooomm
1e8464c1d4 README: add discord badge and adjust downloads (#4142) 2020-10-14 11:18:59 -04:00
tooomm
5df069ab19 userlists --> account (#4139) 2020-10-12 17:18:11 -04:00
ebbit1q
752ba7d905 add face down to the string if the card is face down (#4130) 2020-10-06 16:51:20 -04:00
ebbit1q
9cf7621102 rename selected card menu (#4132) 2020-10-06 16:49:29 -04:00
Zach H
9330774632 Add Gitter/Discord info to Contributing (#4126) 2020-10-02 14:53:21 -04:00
ebbit1q
e33f802ae8 update CONTRIBUTING.md (#4125) 2020-10-02 13:54:12 -04:00
ebbit1q
48c6458766 remove nonfunctional mana artifact detection code (#4121)
mana artifacts will use the stack and be placed in the normal tablerow
if you want to put it with your lands you're free to do so, as long as
you promise to not say oh this should not be here three turns after
shatterstorm resolved
2020-10-02 12:14:44 -04:00
ebbit1q
35fe6f624c apply clang format to proto files (#4123)
* add proto files to clangify

* apply clangify to proto files

* remove blocksonsingleline, it didn't actually do anything

also add missing space to the travis warning, emoji are monospace too
2020-10-02 12:14:05 -04:00
ebbit1q
e2251fe06b update sfmt to version 1.5.1 from 1.4.1 (#4124) 2020-10-02 12:13:12 -04:00
ebbit1q
a5511190a3 add missing cardlink for the flip messages in the message log (#4122) 2020-10-02 12:12:13 -04:00
Kaitlin
eba9c097f6 Add dropdown for game age filtering (#4092)
* Part 1 for #3067: Basic combo box (dropdown) filtering mechanism for game age.

* Apply suggestions from draft review

# Conflicts:
#	cockatrice/src/gamesmodel.cpp
#	cockatrice/src/gamesmodel.h

* switch to using QTime

* check for games older than a day

* formatting for casts and more unnecessary cosmetic changes

* ebbit1q fixes

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2020-09-30 23:46:10 -04:00
tooomm
58d024d067 fix update message (#4116) 2020-09-29 22:00:09 -04:00
ebbit1q
be7b172e55 skip misprints marked with † (#4107) 2020-09-26 21:56:45 -04:00
Kaitlin
a8b79fd020 Fix show-buddies-only filter loading, and add handling for creator name filter storage/loading. (#4105) 2020-09-26 21:55:13 -04:00
ebbit1q
14fcb2e5d7 skip duplicate nonpromos (#4097)
* consider cards with frameEffects promos

* skip duplicates entirely

all cards that are not "promo" or something like it will only retain the first copy instead of parsing all of them and keeping the last
2020-09-22 16:09:59 -04:00
ebbit1q
02935be14f fix QByteArray::append(QString) deprecation in qt 5.15.1 (#4102) 2020-09-22 16:09:48 -04:00
Zach H
bec02b4952 Judges can talk in games (#4091) 2020-09-09 13:20:59 -04:00
Kaitlin
79f590c99a Fix #3957: Properly set filters to defaults on initial load and disable "Clear filters" button if filters are set to defaults. (#4088)
* Fix #3957: Properly set filters to defaults on initial load and disable "Clear filters" button if filters are set to defaults

* Reuse resetFilterParameters() in GamesProxyModel constructor, and remove "off" designation for player min/max (as a default of 1/99 is enforced by the UI).
2020-09-09 11:24:54 -04:00
Kaitlin
ade3e81682 Move "Games shown" text to top, to match user count list. (#4089)
Fixes last part of #3068 that isn't already handled by #4088.
2020-09-08 14:34:36 -04:00
ebbit1q
45cbdad5fb bump version to 2.7.6 (#4076)
fixes #4075
2020-08-24 14:04:56 -04:00
Zach H
3536fa8a75 Fix #4072 by changing outdated HTTP to HTTPS calls within the codebase (#4073) 2020-08-23 17:24:26 -04:00
fdipilla
b0c7b9078d Multiple bg images zone (#4005) 2020-08-23 15:55:53 -04:00
ebbit1q
964207d04f make custom sets directory configurable (#4047) 2020-08-23 13:24:30 -04:00
ebbit1q
feee9cc328 fix #4070 (#4071) 2020-08-22 20:30:56 -04:00
olegshtch
4a563a131b Update test card database to v4 (#4064) 2020-08-21 18:18:53 -04:00
ZeldaZach
69f035f017 translation updates 2020-08-16 15:18:21 -04:00
olegshtch
daa89a9fb4 Run tests on WIndows CI (#4056)
* Run tests on Windows CI.

* Add message logger

* Skip tests that cannot be linked.

* Fix test call

* Fix mock link issue on MSVC

* Fix PATH variable to find libraries for tests

* Fail test step on test errors
2020-08-14 12:45:15 -04:00
olegshtch
44297dcd1c Fix release tests (#4063) 2020-08-13 10:18:01 -04:00
tooomm
80f613a77a travis: update macos 10.15 images (#4059) 2020-08-06 10:43:54 -04:00
olegshtch
776aa5c0ff Enable parallel compilation. (#4057) 2020-08-03 01:30:03 -04:00
olegshtch
446f9be24d Fix unresolved symbols when link tests to system libgtest-dev (#4055) 2020-07-30 14:52:44 -04:00
awlangham
5d9d91262b Added horizontal layout and stretch for player icon (#4052) 2020-07-28 01:22:02 -04:00
awlangham
fe63dfa762 Made user information window resizable (#4009) 2020-07-23 18:04:15 -04:00
ebbit1q
a76a3e5db6 Change method of opening directories to be the same for all oses, including linux (#4046)
* add opening directory in file browser to linux

this uses QDesktopServices to open the url "file://[location]"
by default this is
"file://$HOME/.local/share/Cockatrice/Cockatrice/pics/CUSTOM"

any distro that has a file browser should have an accompanying mime type
specifying the file handler for the file:// protocol using the
inode/directory mime type

see https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html

if a user were to have removed their mime database this will not work and
it will fail with nothing but a log message, this would be rare and not
worth checking in my opinion

* make opening directories the same for all oses

* sort headers
2020-07-16 11:22:24 +02:00
Lee Tran
faecfd65fe fix message when moving cards to bottom of library (#4006) 2020-07-09 17:25:25 -04:00
tooomm
0063493066 Remove gitlab config (#4037)
* revert #2345

* remove gitlab yml
2020-07-01 17:36:04 +02:00
tooomm
2a7268c088 move db udpate (#4015) 2020-06-29 10:25:17 +02:00
ebbit1q
7fa1936d0f qt 5.15 compatibility (#4027) 2020-06-19 10:50:09 -04:00
ebbit1q
0f0e0193c1 update fedora 31 to 32 (#4024) 2020-06-09 03:07:34 -04:00
ebbit1q
0337f58088 add extra exceptions to plaintext imports (#4018)
this specifically to support imports from mtg arena that have a set code
and then a collectors number like (ABC) 123 at the end, this pr strips
that from the card name (we don't use it anyway)

fixes #4011
2020-06-02 10:56:01 -04:00
ebbit1q
53c6440cac make sure no //es are added to maintypes (#4017) 2020-06-02 10:55:05 -04:00
tooomm
28f3229a0e remove storm phrasing (#4001) 2020-05-18 15:27:53 -04:00
ZeldaZach
3dff63069e translation updates 2020-05-17 18:25:55 -04:00
kopcion
1eea8e9a37 Refactor messagelogwidget (#3875) 2020-05-17 18:15:30 -04:00
Rocangus
2de863f645 Spell Out Entire Counter Names With First Letter Capitalized (#3997) 2020-05-17 17:24:17 -04:00
tooomm
dc8603596d fix outdated version number (#3999) 2020-05-17 13:39:30 +02:00
fdipilla
fd0620445c Different backgrounds per player (#3990) 2020-05-14 20:31:12 -04:00
ebbit1q
04274d2497 add ubuntu 20.04 to travis (#3989) 2020-05-13 13:42:08 -04:00
Mikael Palmujoki
c69e77f330 Docker-Compose support for Windows (#3974)
* Add docker-compose document that works out of the box for Windows, and a storage location for the mysql-database.

* Documented Windows support in Readme file
2020-05-08 15:22:39 -04:00
Kaitlin
1988e4558f Change filter hint text to "Games shown: X / Y" and fix user-game segfault (#3973) 2020-05-08 15:15:54 -04:00
Zach H
9246c190fa Enhance Shortcut Menu (#3987) 2020-05-08 15:10:36 -04:00
ctrlaltca
d30691559a Some improvements to Servatice network code (#3969)
* Some improvements to Servatice network code

1. fix crash on fuzzy connection (tcp server only)
2. ensure websockets are parent()ed to avoid leaking them
3. quick catch disconnect()ed sockets instead of waiting for a socket error to happen
4. supporto mulltiple connection pools on the websocket server; they are still bound to the same thread due to a qt5 limitation.
2020-04-24 16:26:59 -04:00
Olxinos
46fe0cd725 prevent checkboxes' labels from being clipped in settings (#3968)
Merged, thank you
2020-04-24 18:33:26 +02:00
ebbit1q
45d62b6880 skip all duplicate promos instead of just stars (#3965) 2020-04-23 11:24:39 -04:00
Olxinos
db85ec48c7 Minor fixes to some std::sort calls (#3967) 2020-04-23 11:23:59 -04:00
ctrlaltca
1976c4caed macOS: test a simple way to bypass apptranslocation (#3944) 2020-04-08 17:34:57 -04:00
Kaitlin
2c3eab9b0c Fix #3068: Add hint text about game list filters (#3946)
Kaitlin Huben <kaitlin.huben+gitlab@gmail.com>
2020-04-07 17:55:36 -04:00
ctrlaltca
27b7ebe208 Oracle / card xml improvements (#3934)
* fix #1610

* fix #2679; partially fix #3647

* Fix tests

* Remove debug code
2020-03-30 21:56:03 +02:00
Zach H
a135ad064a Handle Release Channels better as we host more packages now (#3922) 2020-03-26 13:41:38 -04:00
ebbit1q
e8d5715f7a More OS support (#3915) 2020-03-20 15:32:12 -04:00
Zach H
9cec0852bb Remove force update appveyor (#3920)
According to https://help.appveyor.com/discussions/questions/16192-build-tag-annotation-overwritten, we don't need force_update to push the files up. This will preserve name/description of the release
2020-03-20 14:04:17 -04:00
ctrlaltca
ca618c6cc1 Travis: skip cleanup before deploy (#3919) 2020-03-20 12:23:49 -04:00
ctrlaltca
c5e0b08800 Cmake: get release name from github page instead of using APIs (#3916)
APIs are limited
2020-03-19 15:59:48 -04:00
ZeldaZach
568a4973fa make sh executable 2020-03-19 11:52:09 -04:00
ctrlaltca
5508699e92 Fix openssl name for windows x64 (#3914) 2020-03-19 10:09:29 -04:00
ZeldaZach
71dd6b8a30 Fix missing QDate
Signed-off-by: ZeldaZach <zahalpern+github@gmail.com>
2020-03-18 17:57:40 -04:00
ebbit1q
18a07274d4 clangify everything with the new header sorting (#3908) 2020-03-18 17:36:02 -04:00
ctrlaltca
1eb766b9d8 Fix dynamic loading of openssl libraries on windows (#3912) 2020-03-18 17:22:49 -04:00
ZeldaZach
e84409c0cf Translation Updates 2020-03-16 22:01:57 -04:00
Phillip Wheatley
91dc8b3b08 Add configuration option to send desktop notification on buddy presence (#3886) 2020-03-16 21:49:11 -04:00
Xenos6666
63b4f9b2f0 Add keyboard shorcuts to focus and unfocus chat (#3898)
* Added keyboard shorcuts to focus and unfocus chat

* Fixed format

* Changed the Esc behavior to work on any QLineEdit in the main Window and ignore shortcut conflicts

* Fixed a conflict with shortcuts

* Configurable unfocus shortcut and format fixes

* minor style fix
2020-03-16 21:48:05 -04:00
Phillip Wheatley
7285f24a29 Docker-compose setup for Servatrice (#3887)
* Docker compose for servatrice

* Update README.md

* Clean up docker-compose specific configuration
2020-03-16 21:40:58 -04:00
ebbit1q
17efe8c003 add pauper to the list of checked formats in search (#3901)
* add pauper to the list of checked formats without a short form

l:p remains reserved for pioneer

* throw out weird hardcoded formats

this will at least still work whenever a format gets added
the shorthands are still kept
2020-03-16 20:56:30 -04:00
ebbit1q
1815094249 Keep stars but only sometimes, add scheme cards back (#3904)
* ignore stars and promos but only sometimes

this will correct #3706 and #3715 being a bit overzealous in removing
cards and thus fix scheme cards being removed in entirety
fix #3845
note that this causes a lot more cards to be added that are in promo
sets, if these promo sets should prove to be problematic they should be
disabled somehow as having them as an option is still nice.

* remove debug lines
2020-03-16 20:42:27 -04:00
ebbit1q
a80c756dcb update deprecated methods in qt5.14 and protobuf 3.4 (#3906) 2020-03-16 20:41:41 -04:00
tooomm
361833e023 clarify language setting (#3897) 2020-02-19 10:54:55 -05:00
ctrlaltca
632e44b0b7 Fix missing languages in oracle dropdown (#3896) 2020-02-18 22:33:41 +01:00
skwerlman
8dd1e39ea9 support mtgo .dek files (#3889)
* support mtgo .dek files

they use plain text internally so we just need to reveal them in the load dialog

* formatting
2020-02-04 08:11:24 -05:00
Phillip Wheatley
0f18fa9546 Hide games created/hosted by people on your Ignore List (#3883)
* Implement filter for games created by ignored users.
2020-01-13 10:13:36 -05:00
ebbit1q
7bfefee073 add deck hash copying functions (#3882) 2020-01-13 10:11:19 -05:00
skwerlman
0ff7472ce5 fix password length checks (#3884)
unit testing when
2020-01-13 09:54:55 -05:00
Zach H
8fb0baa449 Trim tokens as this is our most common issue (#3870)
Signed-off-by: ZeldaZach <zahalpern+github@gmail.com>
2019-11-23 14:18:28 -05:00
skwerlman
57c02dcd5a GitHub: Switch to new issue template system (#3862) 2019-11-22 23:54:28 -05:00
tooomm
b072b540a2 Travis: more appealing thank you message (#3858) 2019-11-22 23:53:47 -05:00
kopcion
cd431594e2 Issue 3015 - store timestamp when password is reset (#3863)
* Added few unsigned to ints in order to get rid of warnings.
Added column to users table, for when password is changed(issue#3015).
Moved password length check to separate method, to make it cleaner.
* Added migration file and changed schema version to 27 due to servatrice.sql schema modification.
* Make password length configurable.
2019-11-22 23:52:45 -05:00
tooomm
e4c98e2ab8 Travis: update config for dpl v2 (#3853) 2019-11-05 17:39:00 -05:00
tooomm
32b557b862 readme: fix toc link (#3859)
* fix toc link

* adjust order
2019-11-03 23:15:08 -05:00
Zach H
e690b45f27 Create FUNDING.yml 2019-11-02 23:52:14 -04:00
tooomm
eadcdc6f7c link to new AllPrintings file (#3851) 2019-11-02 23:51:10 -04:00
ebbit1q
b187fb52e0 add pioneer (#3856) 2019-11-02 23:48:17 -04:00
tooomm
7e89933552 bump version number (#3857) 2019-11-02 23:47:55 -04:00
ZeldaZach
096a472ed0 translations 2019-10-21 19:09:28 -04:00
tooomm
365b0a31ed Travis: add Mojave deploy target and release a zipped .dmg (#3819)
* add osx mojave build+deploy

* add job names, change variables

* add zipping to packaging step

* see #3814

* update to high sierra

* update homebrew

* xcode 11.1

* [skip ci] add link to config explorer
2019-10-21 19:06:40 -04:00
skwerlman
e8fd2ce2aa add support for adventures to oracle (#3836)
* add support for adventures to oracle

this causes cockatrice to correctly fetch the front of the card for the adventure portion rather than sending lots of bad requests to scryfall

* treat adventures more like split cards

* dont hardcode `maintype: creature`
2019-10-09 01:05:30 -04:00
ebbit1q
a3fc9b6ee5 add move top card to stack keybind (#3827) 2019-10-09 00:10:23 -04:00
ebbit1q
9eebc590c1 [WIP] add shortcuts for readying and sideboarding in the lobby (#3832)
* add shortcuts for readying and sideboarding in the lobby

* clangify
2019-10-08 23:59:48 -04:00
ebbit1q
f840dcbd66 Increase macos version, drop sierra support (#3837)
800b0f4b2f homebrew no longer provides a bottle for protobuf, which is so big we can't do without a precompiled version. This means we can no longer support sierra 10.12 and have to use high sierra 10.13, this does not seems like a very painful grade however as there are no differences in hardware requirements between the two and any user on sierra can upgrade to high sierra if they wanted to.
2019-10-08 23:55:47 -04:00
ebbit1q
8879fc2e39 fix compiling on gcc 9 (#3830) 2019-10-02 15:48:49 -04:00
ebbit1q
cd29e2f252 add disable tearoffmenu option (#3826) 2019-10-02 14:58:22 -04:00
ctrlaltca
bcf505c98b Oracle: fix crash on no card type; fix #3815 (#3816) 2019-10-02 14:54:51 -04:00
tooomm
933f3e1392 update os name (#3814) 2019-10-02 14:54:10 -04:00
Ashley Davis
ba0462b24f Update Dockerfile to include missing lib, not build dbconv, and use ENTRYPOINT (#3808) 2019-09-09 17:06:28 +02:00
ctrlaltca
7e8a63cd62 Settings: default to current chosen directory while opening file dialogs (#3810) 2019-09-09 09:23:38 +02:00
tooomm
03e109ef12 wait > sleep (#3806) 2019-09-05 15:44:14 +02:00
ebbit1q
257f2eb34c warning message is way too scary (#3805)
People keep complaining they can't compile on ubuntu 16.04 because of this warning message, while it just disables 2 "prettyness" warnings and only in the automatically generated code by protobuf which should never be a problem anyway!
original pr: #3432
2019-09-05 15:43:51 +02:00
Zach H
53728598fe translation updates (#3804) 2019-08-31 21:36:13 -04:00
ctrlaltca
3b98eb77f5 Close all player-associated zoneviews when he quits; fix #3799 (#3800) 2019-08-27 20:07:33 -04:00
ctrlaltca
b6df5a4ac3 Deal with recent Qt methods deprecation (#3801)
* Deal with recent Qt methods deprecation

 * Use std::sort, std::less instead of qSort/qLess
 * Use QFontMetrics::horizontalAdvance instead of ::width
 * Use qApp->primaryScreen() instead of QDesktopWidget
 * use lambas instead of QSignalMapper
 * Use QTreeWidgetItem::setForeground instead of ::setTextColor
 * Use QDir::setPath instead of operator=(QString)
 * Use QList::swapItemsAt instead of ::swap

* fix error
2019-08-27 20:06:54 -04:00
ctrlaltca
f54165025e Add a new command to reverse turn order (#3802) 2019-08-27 20:04:27 -04:00
ctrlaltca
013137c418 Fix #3783 (#3785) 2019-07-17 10:05:00 -04:00
ebbit1q
faf02100a5 add 4BB to nonenglish sets (#3786) 2019-07-17 10:04:19 -04:00
tooomm
a8b34d51a5 travis: separate lint build (#3778)
* Create travis-lint.sh

* separate lint

* Update travis-lint.sh

* Update travis-lint.sh

* use default image

* call lint externally

* add xenial again for tests

* Update .travis.yml

* fix path

* move test to docker build

* remove --format argument test / passed

* add test label

* use bash command

* source > execute
2019-07-13 15:39:51 -04:00
Rob Blanckaert
2ef3e6fc93 Enable tear-off on menus. (#3772) 2019-07-11 22:53:43 -04:00
ebbit1q
a3a1e20074 replace old mulligan with new behavior (#3773) 2019-07-11 22:53:09 -04:00
tooomm
ce54aa6813 remove fedora package support (#3752) 2019-07-11 16:05:42 -04:00
ebbit1q
5139039402 add homebrew cache to cache (#3776)
* add homebrew cache to cache

* use same image

* ruuun travis, ruunn

* remove extra space

* do these dashes do this?

* trigger ci

* these dashes confuse me, consistency is like woosh
2019-07-11 09:21:35 -04:00
ctrlaltca
f4adf79ad9 Message log: remove all workarounds; fix #3553 (#3760)
* Remove workarounds in messagelog
2019-07-07 22:27:50 -04:00
ebbit1q
f10f9ada3a properly capitalize set types like Duel Deck and From the Vault (#3770)
* properly capitalize set types like Duel Deck and From the Vault

* add more tiny words

* update macos for travis (slower build times)
2019-06-30 12:08:07 -04:00
ctrlaltca
965a6cdde7 fix #3755 (#3756) 2019-06-12 14:50:26 +02:00
tooomm
62c0825874 fix grammar (#3754) 2019-06-09 19:01:32 +02:00
tooomm
4e918f0f5d move brackets out of link tags (#3753) 2019-06-09 19:00:53 +02:00
tooomm
3e3154a58c version bump to 2.7.2 (#3751) 2019-06-09 19:00:04 +02:00
Zach H
22e2e442f5 updated translations for 2.7.1 (#3750) 2019-06-08 12:38:59 -04:00
ctrlaltca
c0c4a6df50 Fix card database load after update (#3748) 2019-06-08 14:48:34 +02:00
ctrlaltca
36ba9c2d94 fix #2786 (#3747) 2019-06-08 10:15:33 +02:00
ctrlaltca
1288795de9 fix #3735 (#3746) 2019-06-08 10:14:58 +02:00
Zach H
0380de9571 add trans strings for upstream (#3745) 2019-06-04 17:41:58 -04:00
ebbit1q
6ac3852995 grammar fixes (#3727) 2019-06-04 17:33:36 -04:00
ctrlaltca
1d8fb79e11 Misc startup improvement (#3740)
* Misc startup improvement

* fix paths

* clangiftw

* reworked save sets dialog

* Unified load and save steps for tokens and spoilers; added "finished" page

* linting1

* linting2

* wording

* undo layout change

* wording

* fix spoiler path again

* simplify phrase

* lint

* lint fix

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>
2019-06-02 21:47:37 -04:00
tooomm
e084bd18a9 fix aftermath (#3742) 2019-06-02 12:05:54 +02:00
ctrlaltca
7c3cc527f6 fix windows style (#3739) 2019-06-01 16:08:44 +02:00
ctrlaltca
218aec07f8 Split buttons in the deck editor (#3709) 2019-05-31 11:54:32 -04:00
ctrlaltca
ada13f6578 Card Database converter (#3694)
* Database converter

* Fix win compilation and NSIS installer

* Maybe fix windows again

* Re-fix windows
2019-05-31 11:48:30 -04:00
Rob Blanckaert
8682367b52 View hand window (#3731)
* Roar

* Add View Hand menu to player

* Add shortcut

* reorder right click menu
2019-05-31 16:53:24 +02:00
tooomm
a80f3b77da use Qt 5.12 LTS (#3732) 2019-05-30 12:02:10 +02:00
tooomm
fd8bf66acd style (#3728) 2019-05-27 21:17:57 +02:00
ctrlaltca
115ed78059 Update Translations (#3717)
* Extract new strings from translations

* fetch new translations
2019-05-10 23:13:34 +02:00
ctrlaltca
00ca69fced Add v4 xsd (#3710) 2019-05-09 09:38:52 +02:00
ctrlaltca
6c21855f98 Token dialog fixes (#3711)
* Token dialog fixes

* clangify

* edit custom tokens

* Fix in-game token dialog
2019-05-09 09:37:27 +02:00
ebbit1q
3830c85ce6 skip more cards (#3715)
closes #3713
2019-05-09 09:37:04 +02:00
ctrlaltca
0dc4cc7e03 propose to save deck before loading a new one; fix #3699 (#3707) 2019-05-05 22:38:53 +02:00
ctrlaltca
8f5bfd1f87 Oracle: skip cards with a star in the collectors' number (#3706)
* Oracle: skip cards with a star in the collectors' number

* clangify
2019-05-05 22:38:31 +02:00
ctrlaltca
95d6efcdbf Dont create dummy card infos for unkown cards (#3708) 2019-05-05 22:37:48 +02:00
skwerlman
63cf0ae764 Fail cmake if protoc doesn't exist (#3705)
fix #3704
2019-05-04 23:33:38 -04:00
tooomm
f1e79707e8 work around confusing new default badge label (#3701) 2019-05-01 17:29:15 -04:00
ebbit1q
9073cb53a8 add !sflang! property for card image urls (#3670)
update translations
add translation for the sflang property to supported languages
2019-04-18 13:01:50 -04:00
skwerlman
d018070891 Fix cipt check for shock lands (#3678)
* Fix #3410

The oracle text for shock lands has changed such that they no longer get `cipt`. This fixes that.

* fix whitespace

* use shorter check
2019-04-09 13:12:15 -04:00
tooomm
837924b819 reword (#3682) 2019-04-06 23:12:21 -04:00
tooomm
00cfb1347a Update ISSUE_TEMPLATE.md (#3679) 2019-04-04 14:52:48 -04:00
ctrlaltca
0ce2e61db9 Fix filters (#3676) 2019-04-02 23:02:34 -04:00
ebbit1q
1854e3440b add ci: filter for color identity to help page (#3673) 2019-03-27 22:57:12 -04:00
ebbit1q
a0260eb0b2 add italian renaissance to nonenglish sets (#3672) 2019-03-27 22:56:52 -04:00
ebbit1q
c874f201c3 add a bunch of parents to dialogs (#3658)
* add a bunch of parents to dialogs

works on #3651

* use game as parent instead

* add more parents

* fix create token dialog modality

* add parent to game information window

* replace a bunch of nullptrs with the magic of sed

* add parent to tip of the day and counters

* reorder game ptr

* set parent for life counter

* clangify
2019-03-26 14:54:47 -04:00
tooomm
7072f24103 update link (#3665)
repo got moved
2019-03-22 16:11:36 -04:00
ebbit1q
eb4914d36f include a list of priorities for maincardtypes in oracle (#3663)
fix #3662
2019-03-16 15:00:34 -04:00
James Le Cuirot
6d27631764 Add USE_CCACHE option to CMake so that ccache can be forcibly disabled (#3661) 2019-03-14 16:19:55 -04:00
Rob Blanckaert
a522255baf - Chnage some hard-coded colors to take into account their background. (#3654)
- Change some SVGs from black to white if their background is too dark.
2019-03-13 16:11:30 -07:00
ebbit1q
7eb2e36740 workaround for foreign card arts getting priority by default (#3652)
fixes #3623
2019-03-12 10:12:31 +01:00
ctrlaltca
2d8f01b2e9 Show current counter value on "set counter" dialog (#3650)
* fix point 10 of issue #655

* clanfigyism
2019-03-11 00:33:19 +01:00
ctrlaltca
6f95556632 Fix related cards menu in deck editor (#3649) 2019-03-10 23:15:24 +01:00
ctrlaltca
0326f0d4c9 Permit use of up/down keys to increment/decrement counter value; Fix #3618 (#3646)
* Fix #3618

* clanfigy me softly

* fix unused var and params

* Frce the dialog being modal; ensure self deletion

* More qt-like behavior

* Restore dialogSemaphore logic
2019-03-10 22:22:19 +01:00
ctrlaltca
389f7fdc25 Shortcuts preference pane (#3641)
* Shortcuts preference pane

* Honor and glory to the hypnoclangifier

* clanfigy: exclude deleted files from being checked

* keep the olf translation context to be able to reuse old translations

* Fix gcc; extract translations

* Moved generic buttons after the groupbox

* Update current item on "clear/reset all"

* Sequenceedit: make buttons larger and translatable, add text

* Event filter

* Don't filter arrow keys; added placeholder text

* group counters
2019-03-10 21:49:33 +01:00
ebbit1q
11b2942d09 try to use fabs instead of abs to see if flatpack cares (#3638) 2019-03-10 18:49:18 +01:00
ctrlaltca
52cc725de4 Fix crash on card relation to inexistent card; fix #3637 (#3640)
* Fix crash on card relation to inexistent card; fix #3637

But that whole loop is a logic mess

* Check if related cards exists before creating the menu entry

* honor and glory to the hypnoclanfigier
2019-03-10 18:47:24 +01:00
Rob Blanckaert
a304d4235d Fix #3614 (#3633) 2019-03-07 22:48:03 -05:00
tooomm
4d7024e066 version bump to 2.7.1 (#3635) 2019-03-07 22:47:41 -05:00
Rob Blanckaert
4ce928eb41 Allow more characters in bare searches (#3632) 2019-03-07 12:21:30 +01:00
Rob Blanckaert
b172172be1 Fix #3587 (#3634) 2019-03-07 12:21:08 +01:00
ctrlaltca
5fd86954d6 fix #3621 (#3628) 2019-03-06 19:18:19 -05:00
597 changed files with 88131 additions and 62310 deletions

View File

@@ -1,107 +0,0 @@
version: build {build}
# Skipping commits affecting specific files (GitHub only).
# More details here: https://www.appveyor.com/docs/appveyor-yml and https://www.appveyor.com/docs/how-to/filtering-commits
skip_commits:
files:
- .ci/travis-*
- .github/
- .tx/
- webclient/
- .clang-format
- .*ignore
- .codacy.yml
- .gitlab-ci.yml
- .travis.yml
- '**/*.md'
- Dockerfile
- LICENSE
skip_branch_with_pr: true
clone_depth: 15
image: Visual Studio 2017
cache:
- c:\Tools\vcpkg\installed
environment:
matrix:
- target_arch: win64
qt_ver: 5.9\msvc2017_64
cmake_generator: Visual Studio 15 2017 Win64
cmake_toolset: v141,host=x64
vcpkg_arch: x64
- target_arch: win32
qt_ver: 5.9\msvc2015 # Qt doesn't provide a msvc2017_32
cmake_generator: Visual Studio 15 2017
cmake_toolset: v141
vcpkg_arch: x86
install:
- vcpkg remove --outdated --recurse
- vcpkg install openssl protobuf liblzma zlib --triplet %vcpkg_arch%-windows
services:
- mysql
build_script:
- ps: |
New-Item -ItemType directory -Path $env:APPVEYOR_BUILD_FOLDER\build
Set-Location -Path $env:APPVEYOR_BUILD_FOLDER\build
$vcpkgbindir = "C:\Tools\vcpkg\installed\$env:vcpkg_arch-windows\bin"
$mysqldll = "c:\Program Files\MySQL\MySQL Server 5.7\lib\libmysql.dll"
cmake --version
cmake .. -G "$env:cmake_generator" -T "$env:cmake_toolset" "-DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake" "-DCMAKE_PREFIX_PATH=c:/Qt/$env:qt_ver;$vcpkgbindir" "-DWITH_SERVER=1" "-DMYSQLCLIENT_LIBRARIES=$mysqldll"
- msbuild PACKAGE.vcxproj /p:Configuration=Release
- ps: |
$exe = dir -name *.exe
$new_name = $exe.Replace(".exe", "-${env:target_arch}.exe")
Push-AppveyorArtifact $exe -FileName $new_name
$cmake_name = $exe.Replace(".exe", "-${env:target_arch}.cmake.txt")
Push-AppveyorArtifact CMakeCache.txt -FileName $cmake_name
$json = New-Object PSObject
(New-Object PSObject | Add-Member -PassThru NoteProperty bin $new_name | Add-Member -PassThru NoteProperty cmake $cmake_name | Add-Member -PassThru NoteProperty commit $env:APPVEYOR_REPO_COMMIT) | ConvertTo-JSON | Out-File -FilePath "latest-$env:target_arch" -Encoding ASCII
Push-AppveyorArtifact "latest-$env:target_arch"
$version = $matches['content']
test: off
# Builds for pull requests skip the deployment step altogether
deploy:
# Deploy configuration for "beta" releases
- provider: GitHub
auth_token:
secure: z8Xh1lSCYtvs0SUfhOK6AijCFk0Rgf5jAxu7QvBByR42NG1SxFHPOmyrOllkfy1u
tag: "$(APPVEYOR_REPO_TAG_NAME)"
release: "Cockatrice $(APPVEYOR_REPO_TAG_NAME)"
description: "Beta release of Cockatrice"
artifact: /.*\.exe/
force_update: true
draft: false
prerelease: true
on:
APPVEYOR_REPO_TAG: true
APPVEYOR_REPO_TAG_NAME: /([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}-beta(\.([2-9]|[1-9][0-9]))?$/ # regex to match semver naming convention for beta pre-releases
# Deploy configuration for "stable" releases
- provider: GitHub
auth_token:
secure: z8Xh1lSCYtvs0SUfhOK6AijCFk0Rgf5jAxu7QvBByR42NG1SxFHPOmyrOllkfy1u
tag: "$(APPVEYOR_REPO_TAG_NAME)"
release: "Cockatrice $(APPVEYOR_REPO_TAG_NAME)"
artifact: /.*\.exe/
force_update: true
draft: false
prerelease: false
on:
APPVEYOR_REPO_TAG: true
APPVEYOR_REPO_TAG_NAME: /([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}$/ # regex to match semver naming convention for stable full releases
# Announcements of build image updates: https://www.appveyor.com/updates/
# Official validator for ".appveyor.yml" config file: https://ci.appveyor.com/tools/validate-yaml
# AppVeyor config documentation: https://www.appveyor.com/docs/build-configuration/

15
.ci/ArchLinux/Dockerfile Normal file
View File

@@ -0,0 +1,15 @@
from archlinux:latest
RUN pacman --sync --refresh --sysupgrade --needed --noconfirm \
base-devel \
ccache \
cmake \
git \
mariadb-libs \
protobuf \
qt5-base \
qt5-multimedia \
qt5-svg \
qt5-tools \
qt5-websockets \
&& pacman --sync --clean --clean --noconfirm

View File

@@ -0,0 +1,24 @@
FROM debian:buster
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 \
qtbase5-dev \
qtmultimedia5-dev \
qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -1,4 +1,4 @@
FROM fedora:29
FROM fedora:33
RUN dnf install -y \
@development-tools \
@@ -7,13 +7,15 @@ RUN dnf install -y \
desktop-file-utils \
file \
gcc-c++ \
git \
hicolor-icon-theme \
libappstream-glib \
mariadb-devel \
protobuf-devel \
qt5-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel-5.11.1-2.fc29 \
qt5-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
rpm-build \
sqlite-devel \
wget \
zlib-devel \
xz-devel \
zlib-devel \
&& dnf clean all

View File

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

View File

@@ -0,0 +1,25 @@
FROM ubuntu:focal
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive 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 \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -0,0 +1,25 @@
FROM ubuntu:groovy
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive 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 \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

142
.ci/compile.sh Executable file
View File

@@ -0,0 +1,142 @@
#!/bin/bash
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
# Read arguments
while [[ "$@" ]]; do
case "$1" in
'--')
shift
;;
'--format')
CHECK_FORMAT=1
shift
;;
'--install')
MAKE_INSTALL=1
shift
;;
'--package')
MAKE_PACKAGE=1
shift
if [[ $# != 0 && $1 != -* ]]; then
PACKAGE_TYPE="$1"
shift
fi
;;
'--suffix')
shift
if [[ $# == 0 ]]; then
echo "::error file=$0::--suffix expects an argument"
exit 1
fi
PACKAGE_SUFFIX="$1"
shift
;;
'--server')
MAKE_SERVER=1
shift
;;
'--test')
MAKE_TEST=1
shift
;;
'--debug')
BUILDTYPE="Debug"
shift
;;
'--release')
BUILDTYPE="Release"
shift
;;
*)
if [[ $1 == -* ]]; then
echo "::error file=$0::unrecognized option: $1"
exit 3
fi
BUILDTYPE="$1"
shift
;;
esac
done
# Check formatting using clang-format
if [[ $CHECK_FORMAT ]]; then
echo "::group::Run linter"
source ./.ci/lint.sh
echo "::endgroup::"
fi
set -e
# Setup
./servatrice/check_schema_version.sh
mkdir -p build
cd build
if [[ ! $CMAKE_BUILD_PARALLEL_LEVEL ]]; then
CMAKE_BUILD_PARALLEL_LEVEL=2 # default machines have 2 cores
fi
# Add cmake flags
if [[ $MAKE_SERVER ]]; then
flags+=" -DWITH_SERVER=1"
fi
if [[ $MAKE_TEST ]]; then
flags+=" -DTEST=1"
fi
if [[ $BUILDTYPE ]]; then
flags+=" -DCMAKE_BUILD_TYPE=$BUILDTYPE"
fi
if [[ $PACKAGE_TYPE ]]; then
flags+=" -DCPACK_GENERATOR=$PACKAGE_TYPE"
fi
if [[ $(uname) == "Darwin" ]]; then
# prepend ccache compiler binaries to path
PATH="/usr/local/opt/ccache/libexec:$PATH"
# Add qt install location when using homebrew
flags+=" -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5/"
fi
# Compile
echo "::group::Show ccache stats"
ccache --show-stats
echo "::endgroup::"
echo "::group::Configure cmake"
cmake --version
cmake .. $flags
echo "::endgroup::"
echo "::group::Build project"
cmake --build .
echo "::endgroup::"
echo "::group::Show ccache stats again"
ccache --show-stats
echo "::endgroup::"
if [[ $MAKE_TEST ]]; then
echo "::group::Run tests"
cmake --build . --target test
echo "::endgroup::"
fi
if [[ $MAKE_INSTALL ]]; then
echo "::group::Install"
cmake --build . --target install
echo "::endgroup::"
fi
if [[ $MAKE_PACKAGE ]]; then
echo "::group::Create package"
cmake --build . --target package
echo "::endgroup::"
if [[ $PACKAGE_SUFFIX ]]; then
echo "::group::Update package name"
../.ci/name_build.sh "$PACKAGE_SUFFIX"
echo "::endgroup::"
fi
fi

146
.ci/docker.sh Normal file
View File

@@ -0,0 +1,146 @@
#!/bin/bash
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
# Creates or loads docker images to use in compilation, creates RUN function to start compilation on the docker image.
# --get loads the image from a previously saved image cache, will build if no image is found
# --build builds the image from the Dockerfile in .ci/$NAME
# --save stores the image, if an image was loaded it will not be stored
# requires: docker
# uses env: NAME CACHE BUILD GET SAVE (correspond to args: <name> --set-cache <cache> --build --get --save)
# sets env: RUN CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT
# exitcode: 1 for failure, 2 for missing dockerfile, 3 for invalid arguments
export BUILD_SCRIPT=".ci/compile.sh"
project_name="cockatrice"
save_extension=".tar.gz"
image_cache="image"
ccache_cache=".ccache"
# Read arguments
while [[ "$@" ]]; do
case "$1" in
'--build')
BUILD=1
shift
;;
'--get')
GET=1
shift
;;
'--save')
SAVE=1
shift
;;
'--set-cache')
CACHE=$2
if ! [[ -d $CACHE ]]; then
echo "could not find cache path: $CACHE" >&2
exit 3
fi
shift 2
;;
*)
if [[ $1 == -* ]]; then
echo "unrecognized option: $1"
return 3
fi
NAME="$1"
shift
;;
esac
done
# Setup
if ! [[ $NAME ]]; then
echo "no build name given" >&2
return 3
fi
export IMAGE_NAME="${project_name,,}_${NAME,,}" # lower case
docker_dir=".ci/$NAME"
if ! [[ -r $docker_dir/Dockerfile ]]; then
echo "could not find Dockerfile in $docker_dir" >&2
return 2 # even if the image is cached, we do not want to run if there is no way to build this image
fi
if ! [[ $CACHE ]]; then
echo "cache dir is not set!" >&2
else
if ! [[ -d $CACHE ]]; then
echo "could not find cache dir: $CACHE" >&2
mkdir -p $CACHE
unset GET # the dir is empty
fi
if [[ $GET || $SAVE ]]; then
img_dir="$CACHE/$image_cache"
img_save="$img_dir/$IMAGE_NAME$save_extension"
if ! [[ -d $img_dir ]]; then
echo "could not find image dir: $img_dir" >&2
mkdir -p "$img_dir"
fi
fi
export CCACHE_DIR="$CACHE/$ccache_cache"
if ! [[ -d $CCACHE_DIR ]]; then
echo "could not find ccache dir: $CCACHE_DIR" >&2
mkdir -p "$CCACHE_DIR"
fi
fi
# Get the docker image from previously stored save
if [[ $GET ]]; then
if [[ $img_save ]] && docker load --input "$img_save"; then
echo "loaded image"
docker images
unset BUILD # do not overwrite the loaded image with build
unset SAVE # do not overwrite the stored image with the same image
if [[ $(find "$CCACHE_DIR" -type f -print -quit) ]]; then # check contents of ccache
echo "setting ccache to readonly"
export RUN_ARGS="$RUN_ARGS -e CCACHE_READONLY=1 -e CCACHE_NOSTATS=1" # do not overwrite ccache
else
echo "ccache is empty: $(find "$CCACHE_DIR")" >&2
fi
else
echo "could not load cached image, building instead" >&2
BUILD=1
fi
fi
# Build the docker image from dockerfile
if [[ $BUILD ]]; then
if docker build --tag "$IMAGE_NAME" "$docker_dir"; then
echo "built image"
docker images
else
echo "could not build image $IMAGE_NAME" >&2
return 1
fi
fi
# Save docker image to cache (compressed)
if [[ $SAVE ]]; then
if [[ $img_save ]] && docker save --output "$img_save" "$IMAGE_NAME"; then
echo "saved image to: $img_save"
else
echo "could not save image $IMAGE_NAME" >&2
fi
fi
# Set compile function, runs the compile script on the image, passes arguments to the script
function RUN ()
{
echo "running image:"
if docker images | grep "$IMAGE_NAME"; then
args="--mount type=bind,source=$PWD,target=/src -w=/src"
if [[ $CCACHE_DIR ]]; then
args+=" --mount type=bind,source=$CCACHE_DIR,target=/.ccache -e CCACHE_DIR=/.ccache"
fi
docker run $args $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS $@
return $?
else
echo "could not find docker image: $IMAGE_NAME" >&2
return 3
fi
}

69
.ci/lint.sh Executable file
View File

@@ -0,0 +1,69 @@
#!/bin/bash
# fetch master branch
git fetch origin master
# unshallow if needed
echo "Finding merge base"
if ! git merge-base origin/master HEAD; then
echo "Could not find merge base, unshallowing repo"
git fetch --unshallow
fi
# Check formatting using clangify
echo "Checking your code using clang-format..."
diff="$(./clangify.sh --diff --cf-version --branch origin/master)"
err=$?
case $err in
1)
cat <<EOM
***********************************************************
*** ***
*** Your code does not comply with our style guide. ***
*** ***
*** Please correct it or run the "clangify.sh" script. ***
*** Then commit and push those changes to this branch. ***
*** Check our CONTRIBUTING.md file for more details. ***
*** ***
*** Thank you ❤️ ***
*** ***
***********************************************************
Used clang-format version:
${diff%%
*}
The following changes should be made:
${diff#*
}
Exiting...
EOM
exit 2
;;
0)
cat <<EOM
***********************************************************
*** ***
*** Your code complies with our style guide! ***
*** ***
*** Awesome 👍 ***
*** ***
***********************************************************
Exiting...
EOM
exit 0
;;
*)
echo ""
echo "Something went wrong in our formatting checks: clangify returned $err" >&2
echo ""
;;
esac

50
.ci/name_build.sh Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
# used by the ci to rename build artifacts
# renames the file to [original name][SUFFIX].[original extension]
# where SUFFIX is either available in the environment or as the first arg
# if MAKE_ZIP is set instead a zip is made
# expected to be run in the build directory
builddir="."
findrx="Cockatrice-*.*"
if [[ $1 ]]; then
SUFFIX="$1"
fi
# check env
if [[ ! $SUFFIX ]]; then
echo "::error file=$0::SUFFIX is missing"
exit 2
fi
set -e
# find file
found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)"
path="${found%/*}" # remove all after last /
file="${found##*/}" # remove all before last /
if [[ ! $file ]]; then
echo "::error file=$0::could not find package"
exit 1
fi
if ! cd "$path"; then
echo "::error file=$0::could not get file path"
exit 1
fi
# set filename
name="${file%.*}" # remove all after last .
new_name="$name$SUFFIX."
if [[ $MAKE_ZIP ]]; then
filename="${new_name}zip"
echo "creating zip '$filename' from '$file'"
zip "$filename" "$file"
else
extension="${file##*.}" # remove all before last .
filename="$new_name$extension"
echo "renaming '$file' to '$filename'"
mv "$file" "$filename"
fi
ls -l "$PWD/$filename"
echo "::set-output name=path::$PWD/$filename"
echo "::set-output name=name::$filename"

103
.ci/prep_release.sh Executable file
View File

@@ -0,0 +1,103 @@
#!/bin/bash
# sets the properties of ci releases
# this doesn't have to be 100% foolproof
# the releases are first made as drafts and will be vetted by a human
# it just has to provide a template
# this requires the repo to be unshallowed
template_path=".ci/release_template.md"
body_path="/tmp/release.md"
beta_regex='beta'
name_regex='set\(GIT_TAG_RELEASENAME "([[:print:]]+)")'
whitespace='^\s*$'
if [[ $1 ]]; then
TAG="$1"
fi
# check env
if [[ ! $TAG ]]; then
echo "::error file=$0::TAG is missing"
exit 2
fi
# create title
if [[ $TAG =~ $beta_regex ]]; then
echo "::set-output name=is_beta::yes"
title="$TAG"
echo "creating beta release '$title'"
elif [[ ! $(cat CMakeLists.txt) =~ $name_regex ]]; then
echo "::error file=$0::could not find releasename in CMakeLists.txt"
exit 1
else
echo "::set-output name=is_beta::no"
name="${BASH_REMATCH[1]}"
version="${TAG##*-}"
title="Cockatrice $version: $name"
no_beta=1
echo "::set-output name=friendly_name::$name"
echo "creating full release '$title'"
fi
echo "::set-output name=title::$title"
# add release notes template
if [[ $no_beta ]]; then
body="$(cat "$template_path")"
if [[ ! $body ]]; then
echo "::warning file=$0::could not find release template"
fi
body="${body//--REPLACE-WITH-RELEASE-TITLE--/$title}"
else
body="Included commits over previous version:
--REPLACE-WITH-GENERATED-LIST--"
fi
# add git log to release notes
all_tags="
$(git tag)" # tags are ordered alphabetically
before="${all_tags%%
$TAG*}" # strip line with current tag an all lines after it
# note the extra newlines are needed to always have a last line
if [[ $all_tags == $before ]]; then
echo "::warning file=$0::could not find current tag"
else
while
previous="${before##*
}" # get the last line
# skip this tag if this is a full release and it's a beta or if empty
[[ $no_beta && $previous =~ $beta_regex || ! $previous ]]
do
beta_list+=" $previous" # add to list of skipped betas
next_before="${before%
*}" # strip the last line
if [[ $next_before == $before ]]; then
unset previous
break
fi
before="$next_before"
done
if [[ $previous ]]; then
if generated_list="$(git log "$previous..$TAG" --pretty="- %s")"; then
count="$(git rev-list --count "$previous..$TAG")"
echo "adding list of commits to release notes:"
echo "'$previous' to '$TAG' ($count commits)"
# --> is the markdown comment escape sequence, emojis are way better
generated_list="${generated_list//-->/→}"
body="${body//--REPLACE-WITH-GENERATED-LIST--/$generated_list}"
if [[ $beta_list =~ $whitespace ]]; then
beta_list="-n there are no betas to delete!"
else
echo "the following betas should be deleted after publishing:"
echo "$beta_list"
fi
body="${body//--REPLACE-WITH-BETA-LIST--/$beta_list}"
else
echo "::warning file=$0::failed to produce git log"
fi
else
echo "::warning file=$0::could not find previous tag"
fi
fi
# write to file
echo "::set-output name=body_path::$body_path"
echo "$body" >"$body_path"

71
.ci/release_template.md Normal file
View File

@@ -0,0 +1,71 @@
<!-- this template comes from .ci/release_template.md -->
<!-- Don't forget to delete the previous betas after publishing this!
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 -->
<pre>
<b>Pre-compiled binaries we serve:</b>
- <kbd>Windows 7/8/10 (32-bit)</kbd></i>
- <kbd>Windows 7/8/10 (64-bit)</kbd></i>
- <kbd>macOS 10.14</kbd> ("Mojave")</i>
- <kbd>macOS 10.15</kbd> ("Catalina")</i>
- <kbd>macOS 11.0</kbd> ("Big Sur")</i>
- <kbd>Ubuntu 18.04</kbd> ("Bionic Beaver")</i>
- <kbd>Ubuntu 20.04</kbd> ("Focal Fossa")</i>
- <kbd>Ubuntu 20.10</kbd> ("Groovy Gorilla")</i>
- <kbd>Debian 10</kbd> ("Buster")</i>
- <kbd>Fedora 33</kbd></i>
<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>
</pre>
## General Notes
<!-- --REPLACE-WITH-RELEASE-TITLE-- should be placed here by the ci -->
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.
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))
For any information relating to Cockatrice, 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.
## Upgrading Cockatrice
- 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>)
## Changelog
<!--
This list is generated and should be moved to their repective header and
possibly edited a little.
Move pr numbers of fixups into their main pr to keep the list coherent.
Remove empty headers after.
Use these label badges for highlighting important and key changes:
<kbd>New!</kbd>
<kbd>Fixed!</kbd> or <kbd>Resolved!</kbd>
--REPLACE-WITH-GENERATED-LIST--
-->
### User Interface
### Under the Hood
### Oracle
### Servatrice
### Webatrice
## Translations
- **Thanks for over 300 people contributing to 20+ different languages up to now!**
- Without the help of the community we couldn't offer that great language support... keep up the good work!
- It's actually very easy to join and help for yourself - find out more here:
- [Help us Translate Cockatrice into your native language!](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ)
## 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.
<!-- 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

@@ -1,149 +0,0 @@
#!/bin/bash
# This script is to be used in .travis.yaml from the project root directory, do not use it from somewhere else.
# Read arguments
while [[ "$@" ]]; do
case "$1" in
'--format')
CHECK_FORMAT=1
shift
;;
'--install')
MAKE_INSTALL=1
shift
;;
'--package')
MAKE_PACKAGE=1
shift
if [[ $# != 0 && $1 != -* ]]; then
PACKAGE_NAME="$1"
shift
if [[ $# != 0 && $1 != -* ]]; then
PACKAGE_TYPE="$1"
shift
fi
fi
;;
'--server')
MAKE_SERVER=1
shift
;;
'--test')
MAKE_TEST=1
shift
;;
'--debug')
BUILDTYPE="Debug"
shift
;;
'--release')
BUILDTYPE="Release"
shift
;;
*)
if [[ $1 == -* ]]; then
echo "unrecognized option: $1"
exit 3
fi
BUILDTYPE="$1"
shift
;;
esac
done
# Check formatting using clang-format
if [[ $CHECK_FORMAT ]]; then
echo "Checking your code using clang-format..."
diff="$(./clangify.sh --diff --cf-version)"
err=$?
case $err in
1)
cat <<EOM
***********************************************************
*** ***
*** Your code does not comply with our styleguide. ***
*** ***
*** Please correct it or run the "clangify.sh" script. ***
*** Then commit and push those changes to this branch. ***
*** Check our CONTRIBUTING.md file for more details. ***
*** ***
*** Thank you ♥ ***
*** ***
***********************************************************
Used clang-format version:
${diff%%
*}
The following changes should be made:
${diff#*
}
Exiting...
EOM
exit 2
;;
0)
echo "Thank you for complying with our code standards."
;;
*)
echo "Something went wrong in our formatting checks: clangify returned $err" >&2
;;
esac
fi
set -e
# Setup
./servatrice/check_schema_version.sh
mkdir -p build
cd build
# Add cmake flags
if [[ $MAKE_SERVER ]]; then
flags+=" -DWITH_SERVER=1"
fi
if [[ $MAKE_TEST ]]; then
flags+=" -DTEST=1"
BUILDTYPE="Debug" # test requires buildtype Debug
fi
if [[ $BUILDTYPE ]]; then
flags+=" -DCMAKE_BUILD_TYPE=$BUILDTYPE"
fi
if [[ $PACKAGE_TYPE ]]; then
flags+=" -DCPACK_GENERATOR=$PACKAGE_TYPE"
fi
# Add qt install location when using brew
if [[ $(uname) == "Darwin" ]]; then
PATH="/usr/local/opt/ccache/bin:$PATH"
flags+=" -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5/"
fi
# Compile
cmake --version
cmake .. $flags
make -j2
if [[ $MAKE_TEST ]]; then
make test
fi
if [[ $MAKE_INSTALL ]]; then
make install
fi
if [[ $MAKE_PACKAGE ]]; then
make package
if [[ $PACKAGE_NAME ]]; then
found=$(find . -maxdepth 1 -type f -name "Cockatrice-*.*" -print -quit)
path=${found%/*}
file=${found##*/}
if [[ ! $file ]]; then
echo "could not find package" >&2
exit 1
fi
mv "$path/$file" "$path/${file%.*}-$PACKAGE_NAME.${file##*.}"
fi
fi

View File

@@ -22,4 +22,10 @@ AllowShortFunctionsOnASingleLine: None
BinPackParameters: false
AllowAllParametersOfDeclarationOnNextLine: false
IndentCaseLabels: true
PointerAlignment: Right
PointerAlignment: Right
SortIncludes: true
IncludeBlocks: Regroup
---
Language: Proto
AllowShortFunctionsOnASingleLine: None
SpacesInContainerLiterals: false

View File

@@ -1,7 +1,6 @@
.git/
build/
.github/
.travis/
.tx/
cockatrice/
doc/

View File

@@ -1,4 +1,6 @@
&nbsp; [Introduction](#contributing-to-cockatrice) | [Code Style Guide](#code-style-guide) | [Translations](#translations) | [Release Management](#release-management)
&nbsp; [Introduction](#contributing-to-cockatrice) | [Code Style Guide](
#code-style-guide) | [Translations](#translations) | [Release Management](
#release-management)
----
@@ -7,50 +9,89 @@
# 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.
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.
# Recommended Setups #
For those developers who like the 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.
For those developers who like the 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.
Developers who like Windows development tend to find [Visual Studio](https://www.visualstudio.com/) the best tool for the job.
Developers who like Windows development tend to find [Visual Studio](
https://www.visualstudio.com/) the best tool for the job.
If you have any questions on IDEs, feel free to chat with us on [Gitter](https://gitter.im/Cockatrice/Cockatrice) and we would love to help answer your questions!
[![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.
# Code Style Guide #
### Formatting and continuous integration (ci) ###
### Formatting and continuous integration (CI) ###
We currently use Travis CI to check your code for formatting issues, if your pull request was rejected because of this it would show a message in the logs. Click on "Details" next to the failed Travis CI build and then click on the failed build (most likely the fastest one) to see the log.
We use a separate job on the CI to check your code for formatting issues. If
your pull request failed the test, you can check the output on the checks tab.
It's the first job called "linter", you can click the "Run clangify" step to
see the output of the test.
The message will look somewhat similar to this:
The message will look like this:
```
************************************************************
*** Your code does not meet our formatting guidelines. ***
*** Please correct it then commit and push your changes. ***
*** See our CONTRIBUTING.md file for more information. ***
************************************************************
***********************************************************
*** ***
*** Your code does not comply with our style guide. ***
*** ***
*** Please correct it or run the "clangify.sh" script. ***
*** Then commit and push those changes to this branch. ***
*** Check our CONTRIBUTING.md file for more details. ***
*** ***
*** Thank you ❤️ ***
*** ***
***********************************************************
```
The CONTRIBUTING.md file mentioned is this file. Please read [this section](#Formatting) for full information on our formatting guidelines.
The CONTRIBUTING.md file mentioned in that message is the file you are
currently reading. Please see [this section](#formatting) below for full
information on our formatting guidelines.
### Compatibility ###
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>. You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free to help convert it over!
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>.
You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free
to help convert it over!
For consistency, we use Qt data structures where possible. For example, `QString` over
`std::string` and `QList` over `std::vector`.
For consistency, we use Qt data structures where possible. For example,
`QString` over `std::string` and `QList` over `std::vector`.
Do not use old C style casts in new code, instead use a [`static_cast<>`](
https://en.cppreference.com/w/cpp/language/static_cast)
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 included in the project and is used to format your code.
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
included in the project and is used to format your code.
We've also included a bash script, `clangify.sh`, that will use clang-format to format all files in one go. Use `./clangify.sh --help` to show a full help page.
We've also included a bash script, `clangify.sh`, that will use clang-format to
format all files in your pr in one go. Use `./clangify.sh --help` to show a
full help page.
To run clang-format on a single source file simply use the command `clang-format -i <filename>` to format it in place. (some systems install clang-format with a specific version number appended, `find /usr/bin -name clang-format*` should find it for you)
To run clang-format on a single source file simply use the command
`clang-format -i <filename>` to format it in place. (Some systems install
clang-format with a specific version number appended,
`find /usr/bin -name clang-format*` should find it for you)
See [the clang-format documentation](https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
See [the clang-format documentation](
https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
#### Header files ####
@@ -62,7 +103,8 @@ Use header guards in the form of `FILE_NAME_H`.
Simple functions, such as getters, may be written inline in the header file,
but other functions should be written in the source file.
Group library includes after project includes, and in alphabetic order. Like this:
Group project includes first, followed by library includes. All in alphabetic order.
Like this:
```c++
// Good
#include "card.h"
@@ -88,9 +130,15 @@ Group library includes after project includes, and in alphabetic order. Like thi
Use `UpperCamelCase` for classes, structs, enums, etc. and `lowerCamelCase` for
function and variable names.
Member variables aren't decorated in any way. Don't prefix or suffix with
Don't use [Hungarian Notation](
https://en.wikipedia.org/wiki/Hungarian_notation).
Member variables aren't decorated in any way. Don't prefix or suffix them with
underscores, etc.
Use a separate line for each declaration, don't use a single line like this
`int one = 1, two = 2` and instead split them into two lines.
For arguments to constructors which have the same names as member variables,
prefix those arguments with underscores:
```c++
@@ -115,7 +163,8 @@ If you find any usage of the old keywords, we encourage you to fix it.
#### Braces ####
Braces should go on their own line except for control statements, the use of braces around single line statements is preferred.
Braces should go on their own line except for control statements, the use of
braces around single line statements is preferred.
See the following example:
```c++
int main()
@@ -136,17 +185,25 @@ int main()
#### Indentation and Spacing ####
Always indent using 4 spaces, do not use tabs. Opening and closing braces should be on the same indentation layer, member access specifiers in classes or structs should not be indented.
Always indent using 4 spaces, do not use tabs. Opening and closing braces
should be on the same indentation layer, member access specifiers in classes or
structs should not be indented.
All operators and braces should be separated by spaces, do not add a space next to the inside of a brace.
All operators and braces should be separated by spaces, do not add a space next
to the inside of a brace.
If multiple lines of code that follow eachother have single line comments behind them, place all of them on the same indentation level. This indentation level should be equal to the longest line of code for each of these comments, without added spacing.
If multiple lines of code that follow eachother have single line comments
behind them, place all of them on the same indentation level. This indentation
level should be equal to the longest line of code for each of these comments,
without added spacing.
#### Lines ####
Do not have trailing whitespace in your lines. Most IDEs check for this nowadays and clean it up for you.
Do not leave trailing whitespace on any line. Most IDEs check for this
nowadays and clean it up for you.
Lines should be 120 characters or less. Please break up lines that are too long into smaller parts, for example at spaces or after opening a brace.
Lines should be 120 characters or less. Please break up lines that are too long
into smaller parts, for example at spaces or after opening a brace.
### Memory Management ###
@@ -182,44 +239,93 @@ as `QScopedPointer`, or, less preferably, `QSharedPointer`.
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
Everytime the schema gets modified, some other steps are due:
1. Increment the value of `cockatrice_schema_version` in `servatrice.sql`;
2. Increment the value of `DATABASE_SCHEMA_VERSION` in `servatrice_database_interface.h` accordingly;
3. Create a new migration file inside the `servatrice/migrations` directory named after the new schema version.
4. Run the `servatrice/check_schema_version.sh` script to ensure everything is fine.
2. Increment the value of `DATABASE_SCHEMA_VERSION` in
`servatrice_database_interface.h` accordingly;
3. Create a new migration file inside the `servatrice/migrations` directory
named after the new schema version.
4. Run the `servatrice/check_schema_version.sh` script to ensure everything is
fine.
The migration file should include the sql statements needed to migrate the database schema and data from the previous to the new version, and an additional statement that updates `cockatrice_schema_version` to the correct value.
The migration file should include the sql statements needed to migrate the
database schema and data from the previous to the new version, and an
additional statement that updates `cockatrice_schema_version` to the correct
value.
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.
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 ###
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 files defines the way data contained in each message is serialized using Google's [protocol buffer](https://developers.google.com/protocol-buffers/).
Any change to the `proto` file should be taken with caution and tested intensively before being merged, becaus a change to the protocol could make new clients incompatible to the old server and vice versa.
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
files define the way data contained in each message is serialized using
Google's [protocol buffers](https://developers.google.com/protocol-buffers/).
Any change to the `proto` files should be taken with caution and tested
intensively before being merged, because a change to the protocol could make
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)
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
separate branch of your fork on GitHub and open a [pull request](
https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/creating-an-issue-or-pull-request
).
Your code will then be automatically compiled by GitHub actions for Linux and
macOS, and by Appveyor for Windows. Additionally GitHub will perform a [Linting
check](#formatting-and-continuous-integration-ci). If any issues come up you
can check their status at the bottom of the pull request page, click on details
to go to the CI website and see the different build logs.
If your pull request passes our tests and has no merge conflicts, it will be
reviewed by our team members. You can then address any requested changes. When
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:
1. Developer adds a `tr("foo")` string in the code;
2. Every few days, a maintainer updates the `*_en.ts files` with the new strings;
3. Transifex picks up the new files from github every 24 hours;
3. Transifex picks up the new files from GitHub every 24 hours;
4. Translators translate the new untranslated strings on Transifex;
5. Before a release, a maintainer fetches the updated translations from Transifex.
### Using Translations (for developers) ###
All the user-interface strings inside Cockatrice's source code must be written in english.
Translations to other languages are managed using [Transifex](https://www.transifex.com/projects/p/cockatrice/).
All the 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/).
Adding a new string to translate 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 this label in a way that the string "My name is:" can be translated:
Adding a new string to translate 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
`"My name is:"` can be translated:
```c++
nameLabel.setText(tr("My name is:"));
```
If you're about to propose a change that adds or modifies any translatable string in the code, you don't need to take care of adding the new strings to the translation files.
Every few days, or when a lot of new strings have been added, someone from the development team will take care of extracting all the new strings and adding them to the english translation files and making them available to translators on Transifex.
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);
```
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
string in the code, you don't need to take care of adding the new strings to
the translation files.
Every few days, or when a lot of new strings have been added, someone from the
development team will take care of extracting all the new strings and adding
them to the english translation files and making them available to translators
on Transifex.
### Maintaining Translations (for maintainers) ###
@@ -253,8 +359,9 @@ cmake .. -DUPDATE_TRANSLATIONS=OFF
```
Now you are ready to propose your change.
Once your change gets merged, Transifex will pick up the modified files automatically (checked every 24 hours)
and update the interface where translators will be able to translate the new strings.
Once your change gets merged, Transifex will pick up the modified files
automatically (checked every 24 hours) and update the interface where
translators will be able to translate the new strings.
### Releasing Translations (for maintainers) ###
@@ -272,51 +379,85 @@ 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/).
Please have a look at the specific [FAQ for translators](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
As a translator you can help translate the new strings on [Transifex](
https://www.transifex.com/projects/p/cockatrice/).
Please have a look at the specific [FAQ for translators](
https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
# Release Management #
### Publishing A New Beta Release ###
### Publishing A New Release ###
Travis and AppVeyor have been configured to upload files to GitHub Releases whenever a <kbd>tag</kbd> is pushed.<br>
Usually, tags are created through publishing a (pre-)release, but there's a way around that.
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.
To trigger Travis and AppVeyor, simply do the following:
To create a tag, simply do the following:
```bash
cd $COCKATRICE_REPO
git checkout master
git remote update -p
git pull
git tag $TAG_NAME
git push upstream $TAG_NAME
git push $UPSTREAM $TAG_NAME
```
You should define the variables as such:
```
upstream - git@github.com:Cockatrice/Cockatrice.git
$COCKATRICE_REPO - /Location/of/repository/cockatrice.git
`$TAG_NAME` should be:
`$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!
```
This will cause a tagged release to be established on the GitHub repository, which will then lead to the upload of binaries. If you use this method, the tags (releases) that you create will be marked as a "Pre-release". The `/latest` URL will not be impacted (for stable release downloads) so that's good.
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.
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
points to the latest stable release and not pre-releases/betas.
If you accidentally push a tag incorrectly (the tag is outdated, you didn't pull in the latest branch accidentally, you named the tag wrong, etc.) you can revoke the tag by doing the following:
If you accidentally push a tag incorrectly (the tag is outdated, you didn't
pull in the latest branch accidentally, you named the tag wrong, etc.) you can
revoke the tag by doing the following:
```bash
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.
**NOTE:** Unfortunately, due to the method of how Travis and AppVeyor work, to publish a stable release you will need to make a copy of the release notes locally and then paste them into the GitHub GUI once the binaries have been uploaded by them. These CI services will automatically overwrite the name of the release (to "Cockatrice $TAG_NAME"), the status of the release (to "Pre-release"), and the release body (to "Beta build of Cockatrice").
**NOTE 2:** In the first lines of https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt there's an hardcoded version number used when compiling custom (not tagged) versions. While on tagged versions these numbers are overridden by the version numbers coming from the tag title, it's good practice to keep them aligned with the real ones.
In the first lines of [CMakeLists.txt](
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
there's an hardcoded version number and pretty name used when compiling from
master or custom (not tagged) versions.
While on tagged versions these numbers are overridden by the version numbers
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, update the version number in CMakeLists.txt to "next release version";
* tag the release following the previously described syntax in order to get it built by CI;
* wait for CI to upload the binaries, double check if everything is in order
* after the release is complete, update the version number again to "next targeted beta version", typically increasing `PROJECT_VERSION_PATCH` by one.
* 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](
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.
**NOTE 3:** When releasing a new stable version, all the previous beta versions should be deleted. This is needed for Cockatrice to update users of the "beta" release channel to the latest version like other users.
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.
This can be done the same way as revoking tags, mentioned above.

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [ZeldaZach]
patreon: mtgjson
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ["paypal.me/zachhalpern"]

View File

@@ -1,14 +0,0 @@
<b>System Information:</b>
<!-- Go to "Help → View Debug Log" and copy all lines above the separation here! -->
<!-- If you can't install Cockatrice to access that information, make
sure to include your OS and the app version from the setup file here -->
__________________________________________________________________________________________
<!-- Explain your issue/request/suggestion in detail here! -->
<!-- This repository is ONLY about development of the Cockatrice app.
If you have any problems with a server (e.g. registering, connecting, ban...)
you have to contact that server's owner/admin.
Check this list of public servers with webpage links and contact details:
https://github.com/Cockatrice/Cockatrice/wiki/Public-Servers -->

17
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,17 @@
---
name: "🐛 Bug Report"
about: Report an issue encountered while using Cockatrice
title: ''
labels: 'Bug'
assignees: ''
---
<b>System Information:</b>
<!-- Go to "Help → View Debug Log" and copy all lines above the separation here! -->
<!-- If you can't install Cockatrice to access that information, make
sure to include your OS and the app version from the setup file here -->
_______________________________________________________________________________________
<!-- Explain your issue in detail here! -->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Discord Community (Get help with server issues, e.g. Login)
url: https://discord.gg/3Z9yzmA
about: Need help with using the client? Want to find some games? Try the Discord server!

View File

@@ -0,0 +1,23 @@
---
name: "💡 Feature Request"
about: Request a new feature
title: ''
labels: 'Feature Request'
assignees: ''
---
<!--
Please search the issue tracker for similar issues before posting!
If your request is related to another request (but not the same!) list it here
-->
**Similar Requests**
<!-- Describe your feature idea here in detail -->
**Description of New Feature**
<!-- If your feature requires some context, provide it here -->
**Additional Context**

412
.github/workflows/ci-builds.yml vendored Normal file
View File

@@ -0,0 +1,412 @@
name: Build
on:
push:
branches:
- master
paths-ignore:
- '**.md'
tags:
- '*'
pull_request:
branches:
- master
paths-ignore:
- '**.md'
jobs:
configure:
name: Configure
runs-on: ubuntu-latest
outputs:
tag: ${{steps.configure.outputs.tag}}
sha: ${{steps.configure.outputs.sha}}
upload_url: ${{steps.create_release.outputs.upload_url}}
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.6.0
with:
access_token: ${{github.token}} # needs other token https://github.com/styfle/cancel-workflow-action/issues/7
- name: Configure
id: configure
shell: bash
run: |
tag_regex='^refs/tags/'
if [[ $GITHUB_EVENT_NAME == pull-request ]]; then # pull request
sha="${{github.event.pull_request.head.sha}}"
elif [[ $GITHUB_REF =~ $tag_regex ]]; then # release
sha="$GITHUB_SHA"
tag="${GITHUB_REF/refs\/tags\//}"
echo "::set-output name=tag::$tag"
else # push to branch
sha="$GITHUB_SHA"
fi
echo "::set-output name=sha::$sha"
- name: Checkout
if: steps.configure.outputs.tag != null
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Prepare release paramaters
id: prepare
if: steps.configure.outputs.tag != null
shell: bash
env:
TAG: ${{steps.configure.outputs.tag}}
run: .ci/prep_release.sh
- name: Create release
if: steps.configure.outputs.tag != null
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{github.token}}
with:
tag_name: ${{github.ref}}
release_name: ${{steps.prepare.outputs.title}}
body_path: ${{steps.prepare.outputs.body_path}}
draft: true
prerelease: ${{steps.prepare.outputs.is_beta == 'yes'}}
build-linux:
strategy:
fail-fast: false
matrix:
distro: # these names correspond to the files in .ci/$distro
- UbuntuGroovy
- UbuntuFocal
- UbuntuBionic
- ArchLinux
- DebianBuster
- Fedora33
include:
- distro: UbuntuGroovy
package: DEB
- distro: UbuntuFocal
package: DEB
test: skip # UbuntuFocal has a broken qt for debug builds
- distro: UbuntuBionic
package: DEB
- distro: ArchLinux
package: skip # we are packaged in arch already
allow-failure: yes
- distro: DebianBuster
package: DEB
- distro: Fedora33
package: RPM
test: skip # Fedora is our slowest build
name: ${{matrix.distro}}
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?
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Get cache timestamp
id: cache_timestamp
shell: bash
run: echo "::set-output name=timestamp::$(date -u '+%Y%m%d%H%M%S')"
- name: Restore cache
uses: actions/cache@v2
env:
timestamp: ${{steps.cache_timestamp.outputs.timestamp}}
with:
path: ${{env.CACHE}}
key: docker-${{matrix.distro}}-cache-${{env.timestamp}}
restore-keys: |
docker-${{matrix.distro}}-cache-
- name: Build ${{matrix.distro}} Docker image
shell: bash
run: source .ci/docker.sh --build
- name: Build debug and test
if: matrix.test != 'skip'
shell: bash
run: |
source .ci/docker.sh
RUN --server --debug --test
- name: Build release package
id: package
if: matrix.package != 'skip'
shell: bash
env:
suffix: '-${{matrix.distro}}'
type: '${{matrix.package}}'
run: |
source .ci/docker.sh
RUN --server --release --package "$type" --suffix "$suffix"
- name: Upload artifact
if: matrix.package != 'skip'
uses: actions/upload-artifact@v2
with:
name: ${{matrix.distro}}-package
path: ./build/${{steps.package.outputs.name}}
if-no-files-found: error
- name: Upload to release
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ./build/${{steps.package.outputs.name}}
asset_name: ${{steps.package.outputs.name}}
asset_content_type: application/octet-stream
build-macos:
strategy:
fail-fast: false
matrix:
target:
- Debug
- 10.11_El_Capitan
- 10.14_Mojave
- 10.15_Catalina
- 11.0_Big_Sur
include:
- target: Debug # tests only
os: macos-latest
xcode: 11.7
type: Debug
do_tests: 0 # tests do not work yet on mac
make_package: false
- target: 10.11_El_Capitan
os: macos-10.13 # runs on HighSierra
allow-failure: yes # we don't know if it'll be added
xcode: 8.2.1 # should be compatible with macos 10.11.5
type: Release
do_tests: 0
make_package: true
- target: 10.14_Mojave
os: macos-10.15 # runs on Catalina
xcode: 10.3 # should be compatible with macos 10.14.3
type: Release
do_tests: 0
make_package: true
- target: 10.15_Catalina
os: macos-10.15
xcode: 11.7
type: Release
do_tests: 0
make_package: true
- target: 11.0_Big_Sur
os: macos-11.0
xcode: 12.2
type: Release
do_tests: 0
make_package: true
name: macOS ${{matrix.target}}
needs: configure
runs-on: ${{matrix.os}}
continue-on-error: ${{matrix.allow-failure == 'yes'}}
env:
CCACHE_DIR: ~/.ccache
DEVELOPER_DIR:
/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install dependencies using homebrew
shell: bash
# cmake cannot find the mysql connector
# neither of these works: mariadb-connector-c mysql-connector-c++
run: brew install ccache protobuf
- name: Install QT using homebrew
id: brew_install_qt
continue-on-error: true
shell: bash
run: brew install qt --force-bottle
- name: Install QT using actions
if: steps.brew_install_qt.outcome != 'success'
uses: jurplel/install-qt-action@v2
- name: Get ccache timestamp
id: ccache_timestamp
shell: bash
run: echo "::set-output name=timestamp::$(date -u '+%Y%m%d%H%M%S')"
- name: Restore ccache cache
uses: actions/cache@v2
env:
timestamp: ${{steps.ccache_timestamp.outputs.timestamp}}
with:
path: ${{env.CCACHE_DIR}}
key: ${{runner.os}}-xcode-${{matrix.xcode}}-ccache-${{env.timestamp}}
restore-keys: |
${{runner.os}}-xcode-${{matrix.xcode}}-ccache-
- name: Build on Xcode ${{matrix.xcode}}
shell: bash
run: .ci/compile.sh ${{matrix.type}} --server
- name: Test
if: matrix.do_tests == 1
shell: bash
working-directory: build
run: cmake --build . --target test
- name: Package for ${{matrix.target}}
id: package
if: matrix.make_package
shell: bash
working-directory: build
run: |
cmake --build . --target package
../.ci/name_build.sh "-macOS-${{matrix.target}}"
- name: Upload artifact
if: matrix.make_package
uses: actions/upload-artifact@v2
with:
name: macOS-${{matrix.target}}-xcode-${{matrix.xcode}}-dmg
path: ${{steps.package.outputs.path}}
if-no-files-found: error
- name: Upload to release
if: matrix.make_package && needs.configure.outputs.tag != null
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ${{steps.package.outputs.path}}
asset_name: ${{steps.package.outputs.name}}
asset_content_type: application/octet-stream
windows-build:
strategy:
fail-fast: false
matrix:
arch:
- 64
- 32
include:
- arch: 64
triplet: x64
cmake: x64
append: _64
- arch: 32
triplet: x86
cmake: Win32
name: Windows ${{matrix.arch}}
needs: configure
runs-on: windows-latest
env:
QT_VERSION: '5.12.9'
QT_ARCH: msvc2017${{matrix.append}}
CMAKE_GENERATOR: 'Visual Studio 16 2019'
steps:
- name: Add msbuild to PATH
id: add-msbuild
uses: microsoft/setup-msbuild@v1.0.2
- name: Checkout
uses: actions/checkout@v2
with:
submodules: recursive
- name: Restore Qt ${{env.QT_VERSION}} ${{matrix.arch}}-bit from cache
id: cache-qt
uses: actions/cache@v2
with:
key: ${{runner.os}}-QtCache-${{env.QT_VERSION}}-${{matrix.arch}}
path: ${{runner.workspace}}/Qt
- name: Install ${{matrix.arch}}-bit Qt
uses: jurplel/install-qt-action@v2
with:
cached: ${{steps.cache-qt.outputs.cache-hit}}
version: ${{env.QT_VERSION}}
arch: win${{matrix.arch}}_${{env.QT_ARCH}}
- name: Restore or setup vcpkg
uses: lukka/run-vcpkg@v6
with:
vcpkgArguments: '@${{github.workspace}}/vcpkg.txt'
vcpkgDirectory: ${{github.workspace}}/vcpkg
appendedCacheKey: ${{hashFiles('**/vcpkg.txt')}}
vcpkgTriplet: ${{matrix.triplet}}-windows
- name: Configure Cockatrice ${{matrix.arch}}-bit
shell: bash
run: |
mkdir -p build
cd build
export QTDIR="${{runner.workspace}}/Qt/$QT_VERSION/$QT_ARCH"
cmake .. -G "${{env.CMAKE_GENERATOR}}" -A "${{matrix.cmake}}" -DCMAKE_BUILD_TYPE="Release" -DWITH_SERVER=1 -DTEST=1
- name: Build Cockatrice ${{matrix.arch}}-bit
id: package
shell: bash
working-directory: build
run: |
cmake --build . --target package --config Release
../.ci/name_build.sh "-win${{matrix.arch}}"
- name: Run tests
shell: bash
working-directory: build
run: ctest -T Test -C Release
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: Windows-${{matrix.arch}}bit-installer
path: ./build/${{steps.package.outputs.name}}
if-no-files-found: error
- name: Upload to release
if: needs.configure.outputs.tag != null
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ./build/${{steps.package.outputs.name}}
asset_name: ${{steps.package.outputs.name}}
asset_content_type: application/octet-stream

26
.github/workflows/clangify.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Clangify
on:
pull_request:
branches:
- master
jobs:
linter:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 20 # should be enough to find merge base
- name: Install clang-format
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends clang-format
- name: Run clangify
shell: bash
run: ./.ci/lint.sh

View File

@@ -1,139 +0,0 @@
---
stages:
- build
.artifacts: &artifacts
artifacts:
paths:
- build/
.cache: &cache
cache:
key: "$CI_BUILD_NAME"
paths:
- cache/
.branches: &branches
only:
- master
.tags: &tags
tags:
- linux
- docker
#================================ DEBIAN-BASED ================================
.build_rc_package_deb: &build_rc_package_deb
stage: build
script:
- mkdir -p build
- cd build
- cmake .. -DWITH_SERVER=1 -DCMAKE_BUILD_TYPE=Release -DCPACK_GENERATOR=DEB
- make package -j2
.build_debug_package_deb: &build_debug_package_deb
stage: build
script:
- mkdir -p build
- cd build
- cmake .. -DWITH_SERVER=1 -DCMAKE_BUILD_TYPE=Debug -DCPACK_GENERATOR=DEB
- make package -j2
.deb-artifacts: &artifacts_deb
artifacts:
paths:
- build/*.deb
- build/CMakeFiles/*.log
when: always
#----------------------------------- UBUNTU -----------------------------------
.requirements_16xx: &install_requirements_16xx
before_script:
- apt-get -o dir::cache::archives="cache" update -qq
- apt-get -o dir::cache::archives="cache" install -y build-essential g++ cmake git
- apt-get -o dir::cache::archives="cache" install -y libprotobuf-dev protobuf-compiler
- apt-get -o dir::cache::archives="cache" install -y qt5-default qttools5-dev qttools5-dev-tools
- apt-get -o dir::cache::archives="cache" install -y qtmultimedia5-dev libqt5multimedia5-plugins
- apt-get -o dir::cache::archives="cache" install -y libqt5svg5-dev libqt5sql5-mysql
- apt-get -o dir::cache::archives="cache" install -y libqt5websockets5-dev
.requirements_17xx: &install_requirements_17xx
before_script:
- apt-get -o dir::cache::archives="cache" update -qq
- apt-get -o dir::cache::archives="cache" install -y build-essential g++ cmake git
- apt-get -o dir::cache::archives="cache" install -y libprotobuf-dev protobuf-compiler
- apt-get -o dir::cache::archives="cache" install -y qt5-default qttools5-dev qttools5-dev-tools
- apt-get -o dir::cache::archives="cache" install -y qtmultimedia5-dev libqt5multimedia5-plugins
- apt-get -o dir::cache::archives="cache" install -y libqt5svg5-dev libqt5sql5-mysql
- apt-get -o dir::cache::archives="cache" install -y libqt5websockets5-dev
.build_1604: &1604
image: ubuntu:16.04
<<: *tags
<<: *branches
<<: *install_requirements_16xx
<<: *artifacts_deb
<<: *cache
.build_1710: &1710
image: ubuntu:17.10
<<: *tags
<<: *branches
<<: *install_requirements_17xx
<<: *artifacts_deb
<<: *cache
build_rc_1604:
<<: *1604
<<: *build_rc_package_deb
when: always
build_debug_1604:
<<: *1604
<<: *build_debug_package_deb
when: always
build_rc_1710:
<<: *1710
<<: *build_rc_package_deb
when: always
build_debug_1710:
<<: *1710
<<: *build_debug_package_deb
when: always
allow_failure: true
#----------------------------------- DEBIAN -----------------------------------
.requirements_stretch: &install_requirements_stretch
before_script:
- apt-get -o dir::cache::archives="cache" update -qq
- apt-get -o dir::cache::archives="cache" install -y build-essential g++ cmake git
- apt-get -o dir::cache::archives="cache" install -y qt5-default qtbase5-dev-tools
- apt-get -o dir::cache::archives="cache" install -y qttools5-dev-tools qtmultimedia5-dev
- apt-get -o dir::cache::archives="cache" install -y libqt5svg5-dev libqt5websockets5-dev
- apt-get -o dir::cache::archives="cache" install -y libprotobuf-dev protobuf-compiler
.build_stretch: &stretch
image: debian:stretch
<<: *tags
<<: *branches
<<: *install_requirements_stretch
<<: *artifacts_deb
<<: *cache
build_rc_stretch:
<<: *stretch
<<: *build_rc_package_deb
when: always
build_debug_stretch:
<<: *stretch
<<: *build_debug_package_deb
when: always
allow_failure: true

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "vcpkg"]
path = vcpkg
url = https://github.com/microsoft/vcpkg.git

View File

@@ -1,166 +0,0 @@
language: cpp
compiler: gcc
git:
depth: 15
matrix:
include:
#Ubuntu Xenial (Debug only)
- name: Ubuntu Xenial (Debug)
if: tag IS NOT present
os: linux
dist: xenial
group: stable
cache: ccache
addons:
apt:
packages:
- libprotobuf-dev
- protobuf-compiler
- liblzma-dev
- qt5-default
- qttools5-dev
- qttools5-dev-tools
- qtmultimedia5-dev
- libqt5multimedia5-plugins
- libqt5svg5-dev
- libqt5sql5-mysql
- libqt5websockets5-dev
script: bash ./.ci/travis-compile.sh --format --server --test --debug
#Ubuntu Bionic (on docker)
- name: Ubuntu Bionic (Debug)
if: tag IS NOT present
services: docker
env: NAME=UbuntuBionic
cache:
directories:
- $HOME/$NAME/
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
"cockatrice_${NAME,,}"
bash .ci/travis-compile.sh --server --debug
- name: Ubuntu Bionic (Release)
if: (branch = master AND NOT type = pull_request) OR tag IS present
services: docker
env: NAME=UbuntuBionic
cache:
directories:
- $HOME/$NAME/
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
"cockatrice_${NAME,,}"
bash .ci/travis-compile.sh --server --package "$NAME" --release
#Fedora 29 (on docker)
- name: Fedora 29 (Debug)
if: tag IS NOT present
services: docker
env: NAME=Fedora29
cache:
directories:
- $HOME/$NAME/
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
"cockatrice_${NAME,,}"
bash .ci/travis-compile.sh --server --debug
- name: Fedora 29 (Release)
if: (branch = master AND NOT type = pull_request) OR tag IS present
services: docker
env: NAME=Fedora29
cache:
directories:
- $HOME/$NAME/
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
"cockatrice_${NAME,,}"
bash .ci/travis-compile.sh --server --package "$NAME" "RPM" --release
#macOS
- name: macOS (Debug)
if: tag IS NOT present
os: osx
osx_image: xcode10.1
cache: ccache
addons:
homebrew:
packages:
- ccache
- protobuf
- qt
- xz
script: bash ./.ci/travis-compile.sh --server --install --debug
- name: macOS (Release)
if: (branch = master AND NOT type = pull_request) OR tag IS present
os: osx
osx_image: xcode9.2
cache: ccache
addons:
homebrew:
packages:
- ccache
- protobuf
- qt
- xz
update: true
script: bash ./.ci/travis-compile.sh --server --package "$TRAVIS_OS_NAME" --release
# Builds for pull requests skip the deployment step altogether
deploy:
# Deploy configuration for "beta" releases
- provider: releases
api_key:
secure: mLMF41q7xgOR1sjczsilEy7HQis2PkZCzhfOGbn/8FoOQnmmPOZjrsdhn06ZSl3SFsbfCLuClDYXAbFscQmdgjcGN5AmHV+JYfW650QEuQa/f4/lQFsVRtEqUA1O3FQ0OuRxdpCfJubZBdFVH8SbZ93GLC5zXJbkWQNq+xCX1fU=
skip_cleanup: true
name: "Cockatrice $TRAVIS_TAG"
body: "Beta release of Cockatrice"
file_glob: true
file: "build/Cockatrice-*"
overwrite: true
draft: false
prerelease: true
on:
tags: true
repo: Cockatrice/Cockatrice
condition: $TRAVIS_TAG =~ ([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}-beta(\.([2-9]|[1-9][0-9]))?$ # regex to match semver naming convention for beta pre-releases
# Deploy configuration for "stable" releases
- provider: releases
api_key:
secure: mLMF41q7xgOR1sjczsilEy7HQis2PkZCzhfOGbn/8FoOQnmmPOZjrsdhn06ZSl3SFsbfCLuClDYXAbFscQmdgjcGN5AmHV+JYfW650QEuQa/f4/lQFsVRtEqUA1O3FQ0OuRxdpCfJubZBdFVH8SbZ93GLC5zXJbkWQNq+xCX1fU=
skip_cleanup: true
file_glob: true
file: "build/Cockatrice-*"
overwrite: true
draft: false
prerelease: false
on:
tags: true
repo: Cockatrice/Cockatrice
condition: $TRAVIS_TAG =~ ([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}$ # regex to match semver naming convention for stable full releases
notifications:
email: false
webhooks:
urls:
- https://webhooks.gitter.im/e/d94969c3b01b22cbdcb7
on_success: change
on_failure: change
on_start: never
on_cancel: change
on_error: change
# Announcements of build image updates: https://docs.travis-ci.com/user/build-environment-updates/
# For precise versions of preinstalled tools on the VM, check “Build system information” in the build log!
# Official validator for ".travis.yml" config file: https://yaml.travis-ci.org
# Travis CI config documentation: https://docs.travis-ci.com/user/customizing-the-build

View File

@@ -6,15 +6,7 @@
# like the installation path, compilation flags etc..
# Cmake 3.1 is required to enable C++11 support correctly
cmake_minimum_required(VERSION 3.1)
if(POLICY CMP0064)
cmake_policy(SET CMP0064 NEW)
endif()
if(POLICY CMP0071)
cmake_policy(SET CMP0071 NEW)
endif()
cmake_minimum_required(VERSION 3.10)
# Default to "Release" build type
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
@@ -25,16 +17,36 @@ ELSE()
ENDIF()
# Early detect ccache
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
# Support Unix Makefiles and Ninja
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
MESSAGE(STATUS "Found CCache ${CCACHE_PROGRAM}")
OPTION(USE_CCACHE "Cache the build results with ccache" ON)
if(USE_CCACHE)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
# Support Unix Makefiles and Ninja
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
MESSAGE(STATUS "Found CCache ${CCACHE_PROGRAM}")
endif()
endif()
if(WIN32)
# Use vcpkg toolchain on Windows
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake
CACHE STRING "Vcpkg toolchain file")
# Qt path set by user or env var
if (QTDIR OR DEFINED ENV{QTDIR} OR DEFINED ENV{QTDIR32} OR DEFINED ENV{QTDIR64})
else()
set(QTDIR "" CACHE PATH "Path to Qt (e.g. C:/Qt/5.7/msvc2015_64)")
message(WARNING "QTDIR variable is missing. Please set this variable to specify path to Qt (e.g. C:/Qt/5.7/msvc2015_64)")
endif()
endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
PROJECT("Cockatrice" VERSION 2.7.0)
PROJECT("Cockatrice" VERSION 2.8.1)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)
set(GIT_TAG_RELEASENAME "Prismatic Bridge")
endif()
# Use c++11 for all targets
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ ISO Standard")
@@ -46,7 +58,6 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
# Search path for cmake modules
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# Retrieve git version hash
include(getversion)
# Create a header and a cpp file containing the version hash
@@ -89,7 +100,7 @@ if(UNIX)
endif()
endif()
elseif(WIN32)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/release)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/rundir/${CMAKE_BUILD_TYPE})
endif()
# Treat warnings as errors (Debug builds only)
@@ -97,10 +108,8 @@ option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON)
# Define proper compilation flags
IF(MSVC)
# Visual Studio:
# Maximum optimization
# Disable warning C4251
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251")
# Visual Studio: Maximum optimization, disable warning C4251
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 ")
# Generate complete debugging information
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
@@ -133,9 +142,24 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
ADD_DEFINITIONS("-DSFMT_MEXP=19937")
ENDIF()
FIND_PACKAGE(Threads REQUIRED)
# Find Qt5
OPTION(UPDATE_TRANSLATIONS "Update translations on compile" OFF)
MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_lib_suffix 64)
else()
set(_lib_suffix 32)
endif()
if(DEFINED QTDIR${_lib_suffix})
list(APPEND CMAKE_PREFIX_PATH "${QTDIR${_lib_suffix}}")
elseif(DEFINED QTDIR)
list(APPEND CMAKE_PREFIX_PATH "${QTDIR}")
elseif(DEFINED ENV{QTDIR${_lib_suffix}})
list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR${_lib_suffix}}")
elseif(DEFINED ENV{QTDIR})
list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR}")
endif()
FIND_PACKAGE(Qt5Core 5.5.0 REQUIRED)
@@ -156,10 +180,19 @@ ELSE()
MESSAGE(FATAL_ERROR "No Qt5 found!")
ENDIF()
# Check for translation updates
OPTION(UPDATE_TRANSLATIONS "Update translations on compile" OFF)
MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}")
set(CMAKE_AUTOMOC TRUE)
# Find other needed libraries
FIND_PACKAGE(Protobuf REQUIRED)
IF(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
MESSAGE(FATAL_ERROR "No protoc command found!")
ELSE()
MESSAGE(STATUS "Protoc version ${Protobuf_VERSION} found!")
ENDIF()
#Find OpenSSL
IF(WIN32)
@@ -207,7 +240,7 @@ if(UNIX)
endif()
elseif(WIN32)
set(CPACK_GENERATOR NSIS ${CPACK_GENERATOR})
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "(x64)")
set(TRICE_IS_64_BIT 1)
else()
set(TRICE_IS_64_BIT 0)
@@ -249,6 +282,13 @@ if(WITH_ORACLE)
SET(CPACK_INSTALL_CMAKE_PROJECTS "Oracle;Oracle;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
# Compile dbconverter (default on)
option(WITH_DBCONVERTER "build dbconverter" ON)
if(WITH_DBCONVERTER)
add_subdirectory(dbconverter)
SET(CPACK_INSTALL_CMAKE_PROJECTS "Dbconverter;Dbconverter;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
# Compile tests (default off)
option(TEST "build tests" OFF)
if(TEST)

View File

@@ -7,6 +7,7 @@ RUN apt-get update && apt-get install -y\
git\
libprotobuf-dev\
libqt5sql5-mysql\
libmysqlclient-dev\
libqt5websockets5-dev\
protobuf-compiler\
qt5-default\
@@ -18,7 +19,7 @@ COPY . /home/servatrice/code/
WORKDIR /home/servatrice/code
WORKDIR build
RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 &&\
RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=0 &&\
make &&\
make install
@@ -26,4 +27,5 @@ WORKDIR /home/servatrice
EXPOSE 4747
CMD [ "servatrice", "--log-to-console" ]
ENTRYPOINT [ "servatrice", "--log-to-console" ]

View File

@@ -5,10 +5,10 @@
<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>
<a href="#build---">Build</a> <b>|</b>
<a href="#run">Run</a> <b>|</b>
<a href="#license-">License</a>
</p>
@@ -29,21 +29,22 @@ Cockatrice is an open-source, multiplatform program for playing tabletop card ga
# Download [![Cockatrice Eternal Download Count](https://img.shields.io/github/downloads/cockatrice/cockatrice/total.svg)](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)
Downloads are available for full releases and the current beta version in development.<br>
Full releases are checkpoints featuring major feature or UI enhancements - we recommend to use those. There is no strict schedule for new full releases.
Downloads are available for full releases and the current beta version in development. There is no strict release schedule for either of them.
The beta release contains the most recently added features and bugfixes, but can be unstable. They are released as we feel need.
- Latest `stable` release: [![Download from GitHub Releases](https://img.shields.io/github/release/cockatrice/cockatrice.svg)](https://github.com/cockatrice/cockatrice/releases/latest) [![DL Count on Latest Release](https://img.shields.io/github/downloads/cockatrice/cockatrice/latest/total.svg?label=downloads)](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)<br>
- Stable versions are checkpoints featuring major feature and UI enhancements.
- **Recommended for most users!**
- Latest `stable` release (**recommended**): [![Download from GitHub Releases](https://img.shields.io/github/release/cockatrice/cockatrice.svg)](https://github.com/cockatrice/cockatrice/releases/latest) [![DL Count on Latest Release](https://img.shields.io/github/downloads/cockatrice/cockatrice/latest/total.svg)](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)<br>
- Latest `beta` release: [![Download from GitHub Pre-Releases](https://img.shields.io/github/release/cockatrice/cockatrice/all.svg)](https://github.com/cockatrice/cockatrice/releases) [![DL Count on Latest Pre-Release](https://img.shields.io/github/downloads-pre/cockatrice/cockatrice/latest/total.svg)](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)
- Beta versions may be unstable and contain bugs.
- Latest `beta` release: [![Download from GitHub Pre-Releases](https://img.shields.io/github/release/cockatrice/cockatrice/all.svg)](https://github.com/cockatrice/cockatrice/releases) [![DL Count on Latest Pre-Release](https://img.shields.io/github/downloads-pre/cockatrice/cockatrice/latest/total.svg?label=downloads)](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)
- Beta versions include the most recently added features and bugfixes, but can be unstable.
- To be a Cockatrice Beta Tester, use this version. Find more information [here](https://github.com/Cockatrice/Cockatrice/wiki/Release-Channels)!
# Get Involved [![Gitter Chat](https://img.shields.io/gitter/room/Cockatrice/Cockatrice.svg)](https://gitter.im/Cockatrice/Cockatrice)
# Get Involved [![Discord](https://img.shields.io/discord/314987288398659595?label=Discord&logo=discord&logoColor=white)](https://discord.gg/3Z9yzmA) [![Gitter Chat](https://img.shields.io/gitter/room/Cockatrice/Cockatrice)](https://gitter.im/Cockatrice/Cockatrice)
[Chat](https://gitter.im/Cockatrice/Cockatrice) with the Cockatrice developers on Gitter. Come here to talk about the application, features, or just to hang out. For support regarding specific servers, please contact that server's admin or forum for support rather than asking here.<br>
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>
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).
We maintain two tags for contributors to find issues to work on:
@@ -67,7 +68,7 @@ Cockatrice uses the [Google Developer Documentation Style Guide](https://develop
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
# Translations [![Cockatrice on Transiflex](https://tx-assets.scdn5.secure.raxcdn.com/static/charts/images/tx-logo-micro.c5603f91c780.png)](https://www.transifex.com/projects/p/cockatrice/)
# Translations [![Transifex Project](https://img.shields.io/badge/translate-on%20transifex-brightgreen)](https://www.transifex.com/projects/p/cockatrice/)
Cockatrice uses Transifex for translations. You can help us bring Cockatrice and Oracle to your language or just edit single wordings right from within your browser by visiting our [Transifex project page](https://www.transifex.com/projects/p/cockatrice/).<br>
@@ -78,18 +79,18 @@ Cockatrice uses Transifex for translations. You can help us bring Cockatrice and
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about contributing!<br>
# Build [![Travis Build Status - master](https://travis-ci.org/Cockatrice/Cockatrice.svg?branch=master)](https://travis-ci.org/Cockatrice/Cockatrice) [![Appveyor Build Status - master](https://ci.appveyor.com/api/projects/status/oauxf5a0sj689rcg/branch/master?svg=true)](https://ci.appveyor.com/project/ZeldaZach/cockatrice/branch/master) <!-- link to zachs appveyor not correct yet -->
# Build [![Linux builds - master](https://github.com/Cockatrice/Cockatrice/workflows/Build%20on%20Linux%20(Docker)/badge.svg?branch=master)](https://github.com/Cockatrice/Cockatrice/actions?query=workflow%3A%22Build+on+Linux+%28Docker%29%22+branch%3Amaster) [![macOS builds - master](https://github.com/Cockatrice/Cockatrice/workflows/Build%20on%20macOS/badge.svg?branch=master)](https://github.com/Cockatrice/Cockatrice/actions?query=workflow%3A%22Build+on+macOS%22+branch%3Amaster) [![Windows builds - master](https://github.com/Cockatrice/Cockatrice/workflows/Build%20on%20Windows/badge.svg?branch=master)](https://github.com/Cockatrice/Cockatrice/actions?query=workflow%3A%22Build+on+Windows%22+branch%3Amaster)
**Detailed compiling instructions are on the Cockatrice wiki under [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)**
**Detailed compiling instructions can be found on the Cockatrice wiki under [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)**
Dependencies: *(for minimum requirements search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
- [Qt](https://www.qt.io/developers/)
- [protobuf](https://github.com/google/protobuf)
- [protobuf](https://github.com/protocolbuffers/protobuf)
- [CMake](https://www.cmake.org/)
Oracle can optionally use zlib and xz to load compressed files:
- [zlib](https://www.zlib.net/)
- [xz](https://tukaani.org/xz/)
- [zlib](https://www.zlib.net/)
To compile:
@@ -141,6 +142,26 @@ 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).
**Docker compose**
There is also a docker-compose file available which will configure and run both a MySQL server and Servatrice. The docker-compose setup scripts can be found in the `servatrice/docker` folder and vary only slightly from the default sql and server .ini files. The setup scripts can either be modified in place, or docker-compose can mount alternative files into the images, as you prefer.
To run Servatrice via docker-compose, first install docker-compose following the [install instructions](https://docs.docker.com/compose/install/). Once installed, run the following from the root of the repository:
```bash
docker-compose build # Build the Servatrice image using the same Dockerfile as above.
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: 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.
**Docker compose in Windows**
A out of box working docker-compose file has been added to help setup in Windows.
Docker in Windows requires additional steps in form of using Docker Desktop to allow resource sharing from the drive the volumes are mapped from, as well as potential workarounds needed to get file sharing working in Windows. This [StackOverflow discussion sheds some light on it](https://stackoverflow.com/questions/42203488/settings-to-windows-firewall-to-allow-docker-for-windows-to-share-drive)
# License [![GPLv2 License](https://img.shields.io/github/license/Cockatrice/Cockatrice.svg)](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE)
Cockatrice is free software, licensed under the [GPLv2](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE).

View File

@@ -18,7 +18,7 @@ exclude=("servatrice/src/smtp" \
"oracle/src/zip" \
"oracle/src/lzma" \
"oracle/src/qt-json")
exts=("cpp" "h")
exts=("cpp" "h" "proto")
cf_cmd="clang-format"
branch="origin/master"
@@ -162,7 +162,7 @@ if [[ $branch ]]; then
for ex in ${exts[@]}; do
reg+=(${include[@]/%/.*\\.$ex\$})
done
names=$(git diff --name-only $base | grep ${reg[@]/#/-e ^})
names=$(git diff --diff-filter=d --name-only $base | grep ${reg[@]/#/-e ^})
else
names=$(find ${include[@]} -type f -false ${exts[@]/#/-o -name *\\.})
fi

View File

@@ -52,9 +52,15 @@ set(_OPENSSL_ROOT_HINTS_AND_PATHS
# For OpenSSL < 1.1, they are named libeay32 and ssleay32 and even if the dll is 64bit, it's still suffixed as *32.dll
# For OpenSSL >= 1.1, they are named libcrypto and libssl with no suffix
FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libeay32.dll libcrypto.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES ssleay32.dll libssl.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
# target win64
FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1-x64.dll libcrypto.dll libeay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1-x64.dll libssl.dll ssleay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
else( CMAKE_SIZEOF_VOID_P EQUAL 8 )
# target win32
FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1.dll libcrypto.dll libeay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1.dll libssl.dll ssleay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
IF(WIN32SSLRUNTIME_LIBEAY AND WIN32SSLRUNTIME_SSLEAY)
SET(WIN32SSLRUNTIME_LIBRARIES "${WIN32SSLRUNTIME_LIBEAY}" "${WIN32SSLRUNTIME_SSLEAY}")

View File

@@ -213,6 +213,7 @@ ${AndIf} ${FileExists} "$INSTDIR\portable.dat"
Delete "$INSTDIR\uninstall.exe"
Delete "$INSTDIR\cockatrice.exe"
Delete "$INSTDIR\oracle.exe"
Delete "$INSTDIR\dbconverter.exe"
Delete "$INSTDIR\servatrice.exe"
Delete "$INSTDIR\Qt*.dll"
Delete "$INSTDIR\libmysql.dll"
@@ -250,7 +251,7 @@ ${If} $PortableMode = 0
IfFileExists "$INSTDIR\vcredist_x86.exe" VcRedist86Exists PastVcRedist86Check
VcRedist86Exists:
ExecWait '"$INSTDIR\vcredist_x86.exe" /passive /norestart'
DetailPrint "Sleep to ensure unlock of vc_redist file after installation..."
DetailPrint "Wait to ensure unlock of vc_redist file after installation..."
Sleep 3000
Delete "$INSTDIR\vcredist_x86.exe"
PastVcRedist86Check:

View File

@@ -38,25 +38,6 @@ function(get_commit_date)
set(GIT_COMMIT_DATE "${GIT_COM_DATE}" PARENT_SCOPE)
endfunction()
function(clean_release_name name)
# "name": "Cockatrice: Thopter Pie Network, Revision 2"
# Remove all double quotes
STRING(REPLACE "\"" "" name "${name}")
# Remove json prefix "name: "
STRING(REPLACE " name: " "" name "${name}")
# Remove "cockatrice" name
STRING(REPLACE "Cockatrice" "" name "${name}")
# Remove all unwanted chars
STRING(REGEX REPLACE "[^A-Za-z0-9_ ]" "" name "${name}")
# Strip (trim) whitespaces
STRING(STRIP "${name}" name)
# Replace all spaces with underscores
STRING(REPLACE " " "_" name "${name}")
set(GIT_TAG_RELEASENAME "${name}" PARENT_SCOPE)
endfunction()
function(get_tag_name commit)
if(${commit} STREQUAL "unknown")
return()
@@ -165,23 +146,8 @@ function(get_tag_name commit)
set(PROJECT_VERSION_LABEL ${GIT_TAG_LABEL} PARENT_SCOPE)
elseif(${GIT_TAG_TYPE} STREQUAL "Release")
set(PROJECT_VERSION_LABEL "" PARENT_SCOPE)
# get version name from github
set(GIT_TAG_TEMP_FILE "${PROJECT_BINARY_DIR}/tag_informations.txt")
set(GIT_TAG_TEMP_URL "https://api.github.com/repos/Cockatrice/Cockatrice/releases/tags/${GIT_TAG}")
message(STATUS "Fetching tag informations from ${GIT_TAG_TEMP_URL}")
file(REMOVE "${GIT_TAG_TEMP_FILE}")
file(DOWNLOAD "${GIT_TAG_TEMP_URL}" "${GIT_TAG_TEMP_FILE}" STATUS status LOG log INACTIVITY_TIMEOUT 30 TIMEOUT 300 SHOW_PROGRESS)
list(GET status 0 err)
list(GET status 1 msg)
if(err)
message(WARNING "Download failed with error ${msg}: ${log}")
return()
endif()
file(STRINGS "${GIT_TAG_TEMP_FILE}" GIT_TAG_RAW_RELEASENAME REGEX "\"name\": \"" LIMIT_COUNT 1)
clean_release_name("${GIT_TAG_RAW_RELEASENAME}")
set(PROJECT_VERSION_RELEASENAME "${GIT_TAG_RELEASENAME}" PARENT_SCOPE)
# set release name from env var
set(PROJECT_VERSION_RELEASENAME "${GIT_TAG_RELEASENAME}" PARENT_SCOPE)
endif()
endfunction()
@@ -190,9 +156,9 @@ endfunction()
# fallback defaults
set(GIT_COMMIT_ID "unknown")
set(GIT_COMMIT_DATE "unknown")
set(GIT_COMMIT_DATE_FRIENDLY "unknown")
set(PROJECT_VERSION_LABEL "custom(unknown)")
set(GIT_COMMIT_DATE "")
set(GIT_COMMIT_DATE_FRIENDLY "")
set(PROJECT_VERSION_LABEL "")
set(PROJECT_VERSION_RELEASENAME "")
find_package(Git)

View File

@@ -18,6 +18,7 @@ SET(cockatrice_SOURCES
src/dlg_forgotpasswordrequest.cpp
src/dlg_forgotpasswordreset.cpp
src/dlg_forgotpasswordchallenge.cpp
src/dlg_manage_sets.cpp
src/dlg_register.cpp
src/dlg_tip_of_the_day.cpp
src/tip_of_the_day.cpp
@@ -62,7 +63,6 @@ SET(cockatrice_SOURCES
src/carddragitem.cpp
src/carddatabasemodel.cpp
src/setsmodel.cpp
src/window_sets.cpp
src/abstractgraphicsitem.cpp
src/abstractcarddragitem.cpp
src/dlg_settings.cpp
@@ -79,14 +79,13 @@ SET(cockatrice_SOURCES
src/tab_replays.cpp
src/tab_supervisor.cpp
src/tab_admin.cpp
src/tab_userlists.cpp
src/tab_account.cpp
src/tab_deck_editor.cpp
src/tab_logs.cpp
src/replay_timeline_widget.cpp
src/deckstats_interface.cpp
src/tappedout_interface.cpp
src/chatview/chatview.cpp
src/chatview/userlistProxy.h
src/userlist.cpp
src/userinfobox.cpp
src/user_context_menu.cpp
@@ -105,7 +104,6 @@ SET(cockatrice_SOURCES
src/pictureloader.cpp
src/shortcutssettings.cpp
src/sequenceEdit/sequenceedit.cpp
src/sequenceEdit/shortcutstab.cpp
src/lineeditcompleter.cpp
src/settings/settingsmanager.cpp
src/settings/carddatabasesettings.cpp
@@ -124,6 +122,9 @@ SET(cockatrice_SOURCES
src/carddbparser/cockatricexml3.cpp
src/carddbparser/cockatricexml4.cpp
src/filter_string.cpp
src/phase.cpp
src/customlineedit.cpp
src/translatecountername.cpp
${VERSION_STRING_CPP}
)
@@ -261,7 +262,7 @@ if(WIN32)
# qt5 plugins: audio, iconengines, imageformats, platforms, printsupport
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(audio|iconengines|imageformats|platforms|printsupport)/.*[^d]\\.dll")
FILES_MATCHING REGEX "(audio|iconengines|imageformats|platforms|printsupport|styles)/.*[^d]\\.dll")
install(CODE "
file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths]

View File

@@ -28,6 +28,7 @@ The search bar recognizes a set of special commands similar to some other card d
<dd>[c=wubrg](#c%3Dwubrg) <small>(Cards that are all five colors)</small></dd>
-->
<dd>[c:c](#c:c) <small>(Any colorless card)</small></dd>
<dd>[ci:w](#ci:w) <small>(Any card that has white in it's color identity)</small></dd>
<dt><u>Pow</u>er, <u>Tou</u>ghness, <u>C</u>onverted <u>M</u>ana <u>C</u>ost:</dt>
<dd>[tou:1](#tou:1) <small>(Any card with a toughness of 1)</small></dd>
@@ -48,7 +49,7 @@ The search bar recognizes a set of special commands similar to some other card d
<dd>[e:lea,leb](#e:lea,leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
<dd><a href="#e:lea,leb -(e:lea e:leb)">e:lea,leb -(e:lea e:leb)</a> <small>(Cards that appear in Alpha or Beta but not in both editions)</small></dd>
<dt>Inverse:</dt>
<dt>Negate:</dt>
<dd>[c:wu -c:m](#c:wu -c:m) <small>(Any card that is white or blue, but not multicolored)</small></dd>
<dt>Branching:</dt>

View File

@@ -1,5 +1,7 @@
#include "abstractcarddragitem.h"
#include "carddatabase.h"
#include <QCursor>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
@@ -39,7 +41,6 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
AbstractCardDragItem::~AbstractCardDragItem()
{
qDebug("CardDragItem destructor");
for (int i = 0; i < childDrags.size(); i++)
delete childDrags[i];
}

View File

@@ -22,7 +22,7 @@ AbstractCardItem::AbstractCardItem(const QString &_name, Player *_owner, int _id
setFlag(ItemIsSelectable);
setCacheMode(DeviceCoordinateCache);
connect(settingsCache, SIGNAL(displayCardNamesChanged()), this, SLOT(callUpdate()));
connect(&SettingsCache::instance(), SIGNAL(displayCardNamesChanged()), this, SLOT(callUpdate()));
cardInfoUpdated();
}
@@ -46,13 +46,15 @@ void AbstractCardItem::cardInfoUpdated()
{
info = db->getCard(name);
if (!info) {
if (!info && !name.isEmpty()) {
QVariantHash properties = QVariantHash();
info = CardInfo::newInstance(name, "", true, QVariantHash(), QList<CardRelation *>(), QList<CardRelation *>(),
CardInfoPerSetMap(), false, -1, false);
}
connect(info.data(), SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated()));
if (info.data()) {
connect(info.data(), SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated()));
}
cacheBgColor();
update();
@@ -72,7 +74,7 @@ QSizeF AbstractCardItem::getTranslatedSize(QPainter *painter) const
void AbstractCardItem::transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle)
{
const int MAX_FONT_SIZE = settingsCache->getMaxFontSize();
const int MAX_FONT_SIZE = SettingsCache::instance().getMaxFontSize();
const int fontSize = std::max(9, MAX_FONT_SIZE);
QRectF totalBoundingRect = painter->combinedTransform().mapRect(boundingRect());
@@ -131,7 +133,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
else
painter->drawRect(QRectF(1, 1, CARD_WIDTH - 2, CARD_HEIGHT - 1.5));
if (translatedPixmap.isNull() || settingsCache->getDisplayCardNames() || facedown) {
if (translatedPixmap.isNull() || SettingsCache::instance().getDisplayCardNames() || facedown) {
painter->save();
transformPainter(painter, translatedSize, angle);
painter->setPen(Qt::white);
@@ -201,7 +203,7 @@ void AbstractCardItem::setHovered(bool _hovered)
processHoverEvent();
isHovered = _hovered;
setZValue(_hovered ? 2000000004 : realZValue);
setScale(_hovered && settingsCache->getScaleCards() ? 1.1 : 1);
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
setTransformOriginPoint(_hovered ? CARD_WIDTH / 2 : 0, _hovered ? CARD_HEIGHT / 2 : 0);
update();
}
@@ -254,7 +256,7 @@ void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
return;
tapped = _tapped;
if (settingsCache->getTapAnimation() && canAnimate)
if (SettingsCache::instance().getTapAnimation() && canAnimate)
static_cast<GameScene *>(scene())->registerAnimationItem(this);
else {
tapAngle = tapped ? 90 : 0;
@@ -285,14 +287,14 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
}
if (event->button() == Qt::LeftButton)
setCursor(Qt::ClosedHandCursor);
else if (event->button() == Qt::MidButton)
else if (event->button() == Qt::MiddleButton)
emit showCardInfoPopup(event->screenPos(), name);
event->accept();
}
void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::MidButton)
if (event->button() == Qt::MiddleButton)
emit deleteCardInfoPopup(name);
// This function ensures the parent function doesn't mess around with our selection.
@@ -311,4 +313,4 @@ QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change,
return value;
} else
return QGraphicsItem::itemChange(change, value);
}
}

View File

@@ -49,7 +49,10 @@ public:
{
return Type;
}
AbstractCardItem(const QString &_name = QString(), Player *_owner = 0, int _id = -1, QGraphicsItem *parent = 0);
AbstractCardItem(const QString &_name = QString(),
Player *_owner = nullptr,
int _id = -1,
QGraphicsItem *parent = nullptr);
~AbstractCardItem();
QRectF boundingRect() const;
QSizeF getTranslatedSize(QPainter *painter) const;

View File

@@ -19,6 +19,7 @@
#include "pb/event_user_message.pb.h"
#include "pb/server_message.pb.h"
#include "pending_command.h"
#include <google/protobuf/descriptor.h>
AbstractClient::AbstractClient(QObject *parent) : QObject(parent), nextCmdId(0), status(StatusDisconnected)

View File

@@ -3,6 +3,7 @@
#include "pb/response.pb.h"
#include "pb/serverinfo_user.pb.h"
#include <QMutex>
#include <QObject>
#include <QVariant>
@@ -95,7 +96,7 @@ protected:
virtual void sendCommandContainer(const CommandContainer &cont) = 0;
public:
AbstractClient(QObject *parent = 0);
AbstractClient(QObject *parent = nullptr);
~AbstractClient();
ClientStatus getStatus() const

View File

@@ -1,15 +1,20 @@
#include "abstractcounter.h"
#include "expression.h"
#include "pb/command_inc_counter.pb.h"
#include "pb/command_set_counter.pb.h"
#include "player.h"
#include "settingscache.h"
#include "translatecountername.h"
#include <QAction>
#include <QApplication>
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsSceneMouseEvent>
#include <QKeyEvent>
#include <QMenu>
#include <QPainter>
#include <QString>
AbstractCounter::AbstractCounter(Player *_player,
int _id,
@@ -17,22 +22,24 @@ AbstractCounter::AbstractCounter(Player *_player,
bool _shownInCounterArea,
int _value,
bool _useNameForShortcut,
QGraphicsItem *parent)
QGraphicsItem *parent,
QWidget *_game)
: QGraphicsItem(parent), player(_player), id(_id), name(_name), value(_value),
useNameForShortcut(_useNameForShortcut), hovered(false), aDec(nullptr), aInc(nullptr), dialogSemaphore(false),
deleteAfterDialog(false), shownInCounterArea(_shownInCounterArea)
deleteAfterDialog(false), shownInCounterArea(_shownInCounterArea), game(_game)
{
setAcceptHoverEvents(true);
shortcutActive = false;
if (player->getLocalOrJudge()) {
menu = new QMenu(name);
QString displayName = TranslateCounterName::getDisplayName(_name);
menu = new TearOffMenu(displayName);
aSet = new QAction(this);
connect(aSet, SIGNAL(triggered()), this, SLOT(setCounter()));
menu->addAction(aSet);
menu->addSeparator();
for (int i = 10; i >= -10; --i)
for (int i = 10; i >= -10; --i) {
if (i == 0) {
menu->addSeparator();
} else {
@@ -45,10 +52,12 @@ AbstractCounter::AbstractCounter(Player *_player,
connect(aIncrement, SIGNAL(triggered()), this, SLOT(incrementCounter()));
menu->addAction(aIncrement);
}
} else
}
} else {
menu = nullptr;
}
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
refreshShortcuts();
retranslateUi();
}
@@ -78,16 +87,17 @@ void AbstractCounter::setShortcutsActive()
if (!player->getLocal()) {
return;
}
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
if (name == "life") {
shortcutActive = true;
aSet->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aSet"));
aDec->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aDec"));
aInc->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aInc"));
aSet->setShortcuts(shortcuts.getShortcut("Player/aSet"));
aDec->setShortcuts(shortcuts.getShortcut("Player/aDec"));
aInc->setShortcuts(shortcuts.getShortcut("Player/aInc"));
} else if (useNameForShortcut) {
shortcutActive = true;
aSet->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aSetCounter_" + name));
aDec->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aDecCounter_" + name));
aInc->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aIncCounter_" + name));
aSet->setShortcuts(shortcuts.getShortcut("Player/aSetCounter_" + name));
aDec->setShortcuts(shortcuts.getShortcut("Player/aDecCounter_" + name));
aInc->setShortcuts(shortcuts.getShortcut("Player/aIncCounter_" + name));
}
}
@@ -103,8 +113,9 @@ void AbstractCounter::setShortcutsInactive()
void AbstractCounter::refreshShortcuts()
{
if (shortcutActive)
if (shortcutActive) {
setShortcutsActive();
}
}
void AbstractCounter::setValue(int _value)
@@ -116,7 +127,7 @@ void AbstractCounter::setValue(int _value)
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (isUnderMouse() && player->getLocalOrJudge()) {
if (event->button() == Qt::MidButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
if (event->button() == Qt::MiddleButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
if (menu)
menu->exec(event->screenPos());
event->accept();
@@ -160,24 +171,60 @@ void AbstractCounter::incrementCounter()
void AbstractCounter::setCounter()
{
bool ok;
dialogSemaphore = true;
QString expression = QInputDialog::getText(nullptr, tr("Set counter"), tr("New value for counter '%1':").arg(name),
QLineEdit::Normal, QString::number(value), &ok);
Expression exp(value);
int newValue = static_cast<int>(exp.parse(expression));
AbstractCounterDialog dialog(name, QString::number(value), game);
const int ok = dialog.exec();
if (deleteAfterDialog) {
deleteLater();
return;
}
dialogSemaphore = false;
if (!ok)
return;
Expression exp(value);
int newValue = static_cast<int>(exp.parse(dialog.textValue()));
Command_SetCounter cmd;
cmd.set_counter_id(id);
cmd.set_value(newValue);
player->sendGameCommand(cmd);
}
AbstractCounterDialog::AbstractCounterDialog(const QString &name, const QString &value, QWidget *parent)
: QInputDialog(parent)
{
setWindowTitle(tr("Set counter"));
setLabelText(tr("New value for counter '%1':").arg(name));
setTextValue(value);
qApp->installEventFilter(this);
}
bool AbstractCounterDialog::eventFilter(QObject *obj, QEvent *event)
{
Q_UNUSED(obj);
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch (keyEvent->key()) {
case Qt::Key_Up:
changeValue(+1);
return true;
case Qt::Key_Down:
changeValue(-1);
return true;
}
}
return false;
}
void AbstractCounterDialog::changeValue(int diff)
{
bool ok;
int curValue = textValue().toInt(&ok);
if (!ok)
return;
curValue += diff;
setTextValue(QString::number(curValue));
}

View File

@@ -1,11 +1,16 @@
#ifndef COUNTER_H
#define COUNTER_H
#include "tearoffmenu.h"
#include <QGraphicsItem>
#include <QInputDialog>
class Player;
class QMenu;
class QAction;
class QKeyEvent;
class QMenu;
class QString;
class AbstractCounter : public QObject, public QGraphicsItem
{
@@ -25,10 +30,11 @@ protected:
private:
QAction *aSet, *aDec, *aInc;
QMenu *menu;
TearOffMenu *menu;
bool dialogSemaphore, deleteAfterDialog;
bool shownInCounterArea;
bool shortcutActive;
QWidget *game;
private slots:
void refreshShortcuts();
@@ -42,7 +48,8 @@ public:
bool _shownInCounterArea,
int _value,
bool _useNameForShortcut = false,
QGraphicsItem *parent = nullptr);
QGraphicsItem *parent = nullptr,
QWidget *game = nullptr);
~AbstractCounter() override;
void retranslateUi();
@@ -74,4 +81,15 @@ public:
}
};
class AbstractCounterDialog : public QInputDialog
{
Q_OBJECT
public:
AbstractCounterDialog(const QString &name, const QString &value, QWidget *parent = nullptr);
protected:
bool eventFilter(QObject *obj, QEvent *event);
void changeValue(int diff);
};
#endif

View File

@@ -1,4 +1,5 @@
#include "abstractgraphicsitem.h"
#include <QPainter>
void AbstractGraphicsItem::paintNumberEllipse(int number,
@@ -16,7 +17,12 @@ void AbstractGraphicsItem::paintNumberEllipse(int number,
font.setWeight(QFont::Bold);
QFontMetrics fm(font);
double w = fm.width(numStr) * 1.3;
double w = 1.3 *
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
fm.horizontalAdvance(numStr);
#else
fm.width(numStr);
#endif
double h = fm.height() * 1.3;
if (w < h)
w = h;

View File

@@ -21,7 +21,7 @@ protected:
void paintNumberEllipse(int number, int radius, const QColor &color, int position, int count, QPainter *painter);
public:
AbstractGraphicsItem(QGraphicsItem *parent = 0) : QObject(), QGraphicsItem(parent)
AbstractGraphicsItem(QGraphicsItem *parent = nullptr) : QObject(), QGraphicsItem(parent)
{
}
};

View File

@@ -1,22 +1,22 @@
#define _USE_MATH_DEFINES
#include <cmath>
#include "arrowitem.h"
#include "carddatabase.h"
#include "carditem.h"
#include "cardzone.h"
#include "player.h"
#include "playertarget.h"
#include "settingscache.h"
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include "color.h"
#include "pb/command_attach_card.pb.h"
#include "pb/command_create_arrow.pb.h"
#include "pb/command_delete_arrow.pb.h"
#include "player.h"
#include "playertarget.h"
#include "settingscache.h"
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <cmath>
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), color(_color),
@@ -240,12 +240,12 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (startZone->getName().compare("hand") == 0) {
startCard->playCard(false);
CardInfoPtr ci = startCard->getInfo();
if (ci && (((!settingsCache->getPlayToStack() && ci->getTableRow() == 3) ||
((settingsCache->getPlayToStack() && ci->getTableRow() != 0) &&
if (ci && (((!SettingsCache::instance().getPlayToStack() && ci->getTableRow() == 3) ||
((SettingsCache::instance().getPlayToStack() && ci->getTableRow() != 0) &&
startCard->getZone()->getName().toStdString() != "stack"))))
cmd.set_start_zone("stack");
else
cmd.set_start_zone(settingsCache->getPlayToStack() ? "stack" : "table");
cmd.set_start_zone(SettingsCache::instance().getPlayToStack() ? "stack" : "table");
}
player->sendGameCommand(cmd);
}

View File

@@ -1,4 +1,5 @@
#include "arrowtarget.h"
#include "arrowitem.h"
#include "player.h"

View File

@@ -2,6 +2,7 @@
#define ARROWTARGET_H
#include "abstractgraphicsitem.h"
#include <QList>
class Player;
@@ -18,7 +19,7 @@ private:
QList<ArrowItem *> arrowsFrom, arrowsTo;
public:
ArrowTarget(Player *_owner, QGraphicsItem *parent = 0);
ArrowTarget(Player *_owner, QGraphicsItem *parent = nullptr);
~ArrowTarget();
Player *getOwner() const

View File

@@ -1,4 +1,5 @@
#include "carddatabase.h"
#include "carddbparser/cockatricexml3.h"
#include "carddbparser/cockatricexml4.h"
#include "game_specific_terms.h"
@@ -9,8 +10,11 @@
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QMessageBox>
#include <QRegularExpression>
#include <algorithm>
#include <utility>
const char *CardDatabase::TOKENS_SETNAME = "TK";
@@ -66,27 +70,27 @@ QString CardSet::getCorrectedShortName() const
void CardSet::loadSetOptions()
{
sortKey = settingsCache->cardDatabase().getSortKey(shortName);
enabled = settingsCache->cardDatabase().isEnabled(shortName);
isknown = settingsCache->cardDatabase().isKnown(shortName);
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->cardDatabase().setSortKey(shortName, _sortKey);
SettingsCache::instance().cardDatabase().setSortKey(shortName, _sortKey);
}
void CardSet::setEnabled(bool _enabled)
{
enabled = _enabled;
settingsCache->cardDatabase().setEnabled(shortName, _enabled);
SettingsCache::instance().cardDatabase().setEnabled(shortName, _enabled);
}
void CardSet::setIsKnown(bool _isknown)
{
isknown = _isknown;
settingsCache->cardDatabase().setIsKnown(shortName, _isknown);
SettingsCache::instance().cardDatabase().setIsKnown(shortName, _isknown);
}
class SetList::KeyCompareFunctor
@@ -105,7 +109,7 @@ public:
void SetList::sortByKey()
{
qSort(begin(), end(), KeyCompareFunctor());
std::sort(begin(), end(), KeyCompareFunctor());
}
int SetList::getEnabledSetsNum()
@@ -289,22 +293,23 @@ void CardInfo::refreshCachedSetNames()
QString CardInfo::simplifyName(const QString &name)
{
QString simpleName(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");
simpleName.replace("Æ", "AE");
// Replace Jötun Grunt with Jotun Grunt.
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
// Replace dashes with spaces so that we can say "garruk the veil cursed"
// instead of the unintuitive "garruk the veilcursed".
simpleName = simpleName.replace("-", " ");
simpleName.remove(QRegExp("[^a-zA-Z0-9 ]"));
simpleName = simpleName.toLower();
// remove all non alphanumeric characters from the name
simpleName.remove(nonAlnum);
return simpleName;
}
@@ -327,15 +332,15 @@ CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoa
qRegisterMetaType<CardInfoPtr>("CardSetPtr");
// add new parsers here
availableParsers << new CockatriceXml3Parser;
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, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabases()));
connect(&SettingsCache::instance(), SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabases()));
}
CardDatabase::~CardDatabase()
@@ -435,6 +440,19 @@ 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)) {
@@ -513,15 +531,25 @@ LoadStatus CardDatabase::loadCardDatabases()
clear(); // remove old db
loadStatus = loadCardDatabase(settingsCache->getCardDatabasePath()); // load main card database
loadCardDatabase(settingsCache->getTokenDatabasePath()); // load tokens database
loadCardDatabase(settingsCache->getSpoilerCardDatabasePath()); // load spoilers database
loadStatus = loadCardDatabase(SettingsCache::instance().getCardDatabasePath()); // load main card database
loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database
loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database
// load custom card databases
QDir dir(settingsCache->getCustomCardDatabasePath());
for (const QString &fileName :
dir.entryList(QStringList("*.xml"), QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase)) {
loadCardDatabase(dir.absoluteFilePath(fileName));
// 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
@@ -572,7 +600,7 @@ QStringList CardDatabase::getAllMainCardTypes() const
while (cardIterator.hasNext()) {
types.insert(cardIterator.next().value()->getMainCardType());
}
return types.toList();
return types.values();
}
void CardDatabase::checkUnknownSets()
@@ -623,7 +651,8 @@ void CardDatabase::notifyEnabledSetsChanged()
bool CardDatabase::saveCustomTokensToFile()
{
QString fileName = settingsCache->getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml";
QString fileName =
SettingsCache::instance().getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml";
SetNameMap tmpSets;
CardSetPtr customTokensSet = getSet(CardDatabase::TOKENS_SETNAME);
@@ -698,4 +727,4 @@ const QString CardInfo::getPowTough() const
void CardInfo::setPowTough(const QString &value)
{
setProperty(Mtg::PowTough, value);
}
}

View File

@@ -409,6 +409,7 @@ public:
void removeCard(CardInfoPtr card);
CardInfoPtr getCard(const QString &cardName) const;
QList<CardInfoPtr> getCards(const QStringList &cardNames) const;
CardInfoPtr guessCard(const QString &cardName) const;
/*
* Get a card by its simple name. The name will be simplified in this
@@ -437,7 +438,7 @@ public slots:
LoadStatus loadCardDatabases();
void addCard(CardInfoPtr card);
void addSet(CardSetPtr set);
private slots:
protected slots:
LoadStatus loadCardDatabase(const QString &path);
signals:
void cardDatabaseLoadingFailed();

View File

@@ -1,5 +1,7 @@
#include "carddatabasemodel.h"
#include "filtertree.h"
#include <QMap>
#define CARDDBMODEL_COLUMNS 6
@@ -349,6 +351,7 @@ const QString CardDatabaseDisplayModel::sanitizeCardName(const QString &dirtyNam
}
return QString::fromStdWString(toReturn);
}
TokenDisplayModel::TokenDisplayModel(QObject *parent) : CardDatabaseDisplayModel(parent)
{
}
@@ -364,3 +367,19 @@ int TokenDisplayModel::rowCount(const QModelIndex &parent) const
// always load all tokens at start
return QSortFilterProxyModel::rowCount(parent);
}
TokenEditModel::TokenEditModel(QObject *parent) : CardDatabaseDisplayModel(parent)
{
}
bool TokenEditModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const
{
CardInfoPtr info = static_cast<CardDatabaseModel *>(sourceModel())->getCard(sourceRow);
return info->getIsToken() && info->getSets().contains(CardDatabase::TOKENS_SETNAME) && rowMatchesCardName(info);
}
int TokenEditModel::rowCount(const QModelIndex &parent) const
{
// always load all tokens at start
return QSortFilterProxyModel::rowCount(parent);
}

View File

@@ -3,6 +3,7 @@
#include "carddatabase.h"
#include "filter_string.h"
#include <QAbstractListModel>
#include <QList>
#include <QSet>
@@ -140,4 +141,15 @@ protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
};
class TokenEditModel : public CardDatabaseDisplayModel
{
Q_OBJECT
public:
explicit TokenEditModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
};
#endif

View File

@@ -1,10 +1,12 @@
#ifndef CARDDATABASE_PARSER_H
#define CARDDATABASE_PARSER_H
#include "../carddatabase.h"
#include <QIODevice>
#include <QString>
#include "../carddatabase.h"
#define COCKATRICE_XML_XSI_NAMESPACE "http://www.w3.org/2001/XMLSchema-instance"
class ICardDatabaseParser : public QObject
{
@@ -13,7 +15,11 @@ public:
virtual bool getCanParseFile(const QString &name, QIODevice &device) = 0;
virtual void parseFile(QIODevice &device) = 0;
virtual bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) = 0;
virtual bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",
const QString &sourceVersion = "unknown") = 0;
static void clearSetlist();
protected:

View File

@@ -1,11 +1,15 @@
#include "cockatricexml3.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QXmlStreamReader>
#include <version_string.h>
#define COCKATRICE_XML3_TAGNAME "cockatrice_carddatabase"
#define COCKATRICE_XML3_TAGVER 3
#define COCKATRICE_XML3_SCHEMALOCATION \
"https://raw.githubusercontent.com/Cockatrice/Cockatrice/master/doc/carddatabase_v3/cards.xsd"
bool CockatriceXml3Parser::getCanParseFile(const QString &fileName, QIODevice &device)
{
@@ -403,7 +407,11 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
return xml;
}
bool CockatriceXml3Parser::saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName)
bool CockatriceXml3Parser::saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl,
const QString &sourceVersion)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
@@ -416,6 +424,15 @@ bool CockatriceXml3Parser::saveToFile(SetNameMap sets, CardNameMap cards, const
xml.writeStartDocument();
xml.writeStartElement(COCKATRICE_XML3_TAGNAME);
xml.writeAttribute("version", QString::number(COCKATRICE_XML3_TAGVER));
xml.writeAttribute("xmlns:xsi", COCKATRICE_XML_XSI_NAMESPACE);
xml.writeAttribute("xsi:schemaLocation", COCKATRICE_XML3_SCHEMALOCATION);
xml.writeStartElement("info");
xml.writeTextElement("author", QCoreApplication::applicationName() + QString(" %1").arg(VERSION_STRING));
xml.writeTextElement("createdAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
xml.writeTextElement("sourceUrl", sourceUrl);
xml.writeTextElement("sourceVersion", sourceVersion);
xml.writeEndElement();
if (sets.count() > 0) {
xml.writeStartElement("sets");

View File

@@ -1,10 +1,10 @@
#ifndef COCKATRICE_XML3_H
#define COCKATRICE_XML3_H
#include <QXmlStreamReader>
#include "carddatabaseparser.h"
#include <QXmlStreamReader>
class CockatriceXml3Parser : public ICardDatabaseParser
{
Q_OBJECT
@@ -14,7 +14,11 @@ public:
~CockatriceXml3Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override;
bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",
const QString &sourceVersion = "unknown") override;
private:
void loadCardsFromXml(QXmlStreamReader &xml);

View File

@@ -1,11 +1,15 @@
#include "cockatricexml4.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QXmlStreamReader>
#include <version_string.h>
#define COCKATRICE_XML4_TAGNAME "cockatrice_carddatabase"
#define COCKATRICE_XML4_TAGVER 4
#define COCKATRICE_XML4_SCHEMALOCATION \
"https://raw.githubusercontent.com/Cockatrice/Cockatrice/master/doc/carddatabase_v4/cards.xsd"
bool CockatriceXml4Parser::getCanParseFile(const QString &fileName, QIODevice &device)
{
@@ -329,7 +333,11 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
return xml;
}
bool CockatriceXml4Parser::saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName)
bool CockatriceXml4Parser::saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl,
const QString &sourceVersion)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
@@ -342,6 +350,15 @@ bool CockatriceXml4Parser::saveToFile(SetNameMap sets, CardNameMap cards, const
xml.writeStartDocument();
xml.writeStartElement(COCKATRICE_XML4_TAGNAME);
xml.writeAttribute("version", QString::number(COCKATRICE_XML4_TAGVER));
xml.writeAttribute("xmlns:xsi", COCKATRICE_XML_XSI_NAMESPACE);
xml.writeAttribute("xsi:schemaLocation", COCKATRICE_XML4_SCHEMALOCATION);
xml.writeStartElement("info");
xml.writeTextElement("author", QCoreApplication::applicationName() + QString(" %1").arg(VERSION_STRING));
xml.writeTextElement("createdAt", QDateTime::currentDateTimeUtc().toString(Qt::ISODate));
xml.writeTextElement("sourceUrl", sourceUrl);
xml.writeTextElement("sourceVersion", sourceVersion);
xml.writeEndElement();
if (sets.count() > 0) {
xml.writeStartElement("sets");

View File

@@ -1,10 +1,10 @@
#ifndef COCKATRICE_XML4_H
#define COCKATRICE_XML4_H
#include <QXmlStreamReader>
#include "carddatabaseparser.h"
#include <QXmlStreamReader>
class CockatriceXml4Parser : public ICardDatabaseParser
{
Q_OBJECT
@@ -14,7 +14,11 @@ public:
~CockatriceXml4Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override;
bool saveToFile(SetNameMap sets,
CardNameMap cards,
const QString &fileName,
const QString &sourceUrl = "unknown",
const QString &sourceVersion = "unknown") override;
private:
QVariantHash loadCardPropertiesFromXml(QXmlStreamReader &xml);

View File

@@ -1,9 +1,11 @@
#include "carddragitem.h"
#include "carditem.h"
#include "cardzone.h"
#include "gamescene.h"
#include "tablezone.h"
#include "zoneviewzone.h"
#include <QCursor>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>

View File

@@ -1,5 +1,3 @@
#include <utility>
#include "cardframe.h"
#include "cardinfopicture.h"
@@ -10,6 +8,7 @@
#include <QSplitter>
#include <QVBoxLayout>
#include <utility>
CardFrame::CardFrame(const QString &cardName, QWidget *parent) : QTabWidget(parent), info(nullptr), cardTextOnly(false)
{
@@ -56,7 +55,7 @@ CardFrame::CardFrame(const QString &cardName, QWidget *parent) : QTabWidget(pare
tab3Layout->addWidget(splitter);
tab3->setLayout(tab3Layout);
setViewMode(settingsCache->getCardInfoViewMode());
setViewMode(SettingsCache::instance().getCardInfoViewMode());
setCard(db->getCard(cardName));
}
@@ -87,7 +86,7 @@ void CardFrame::setViewMode(int mode)
break;
}
settingsCache->setCardInfoViewMode(mode);
SettingsCache::instance().setCardInfoViewMode(mode);
}
void CardFrame::setCard(CardInfoPtr card)
@@ -108,7 +107,7 @@ void CardFrame::setCard(CardInfoPtr card)
void CardFrame::setCard(const QString &cardName)
{
setCard(db->getCardBySimpleName(cardName));
setCard(db->guessCard(cardName));
}
void CardFrame::setCard(AbstractCardItem *card)

View File

@@ -1,10 +1,10 @@
#ifndef CARDFRAME_H
#define CARDFRAME_H
#include <QTabWidget>
#include "carddatabase.h"
#include <QTabWidget>
class AbstractCardItem;
class CardInfoPicture;
class CardInfoText;

View File

@@ -1,13 +1,13 @@
#include "cardinfopicture.h"
#include <QPainter>
#include <QStyle>
#include <QWidget>
#include "carditem.h"
#include "main.h"
#include "pictureloader.h"
#include <QPainter>
#include <QStyle>
#include <QWidget>
CardInfoPicture::CardInfoPicture(QWidget *parent) : QWidget(parent), info(nullptr), pixmapDirty(true)
{
setMinimumHeight(100);

View File

@@ -1,10 +1,10 @@
#ifndef CARDINFOPICTURE_H
#define CARDINFOPICTURE_H
#include <QWidget>
#include "carddatabase.h"
#include <QWidget>
class AbstractCardItem;
class CardInfoPicture : public QWidget
@@ -17,7 +17,7 @@ private:
bool pixmapDirty;
public:
CardInfoPicture(QWidget *parent = 0);
CardInfoPicture(QWidget *parent = nullptr);
protected:
void resizeEvent(QResizeEvent *event);

View File

@@ -1,4 +1,5 @@
#include "cardinfotext.h"
#include "carditem.h"
#include "game_specific_terms.h"
#include "main.h"
@@ -47,9 +48,8 @@ void CardInfoText::setCard(CardInfoPtr card)
QString("<tr><td>%1</td><td></td><td>%2</td></tr>").arg(keyText, card->getProperty(key).toHtmlEscaped());
}
auto relatedCards = card->getRelatedCards();
auto reverserelatedCards2Me = card->getReverseRelatedCards2Me();
if (!relatedCards.empty() || !reverserelatedCards2Me.empty()) {
auto relatedCards = card->getAllRelatedCards();
if (!relatedCards.empty()) {
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>").arg(tr("Related cards:"));
for (auto *relatedCard : relatedCards) {
@@ -57,11 +57,6 @@ void CardInfoText::setCard(CardInfoPtr card)
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
}
for (auto *i : reverserelatedCards2Me) {
QString tmp = i->getName().toHtmlEscaped();
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
}
text += "</td></tr>";
}

View File

@@ -1,9 +1,9 @@
#ifndef CARDINFOTEXT_H
#define CARDINFOTEXT_H
#include <QFrame>
#include "carddatabase.h"
#include <QFrame>
class QLabel;
class QTextEdit;

View File

@@ -1,11 +1,17 @@
#include <utility>
#include "cardinfowidget.h"
#include "cardinfopicture.h"
#include "cardinfotext.h"
#include "cardinfowidget.h"
#include "carditem.h"
#include "main.h"
#include <QApplication>
#include <utility>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
#include <QScreen>
#else
#include <QDesktopWidget>
#endif
#include <QVBoxLayout>
CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::WindowFlags flags)
@@ -27,8 +33,13 @@ CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::Win
setLayout(layout);
setFrameStyle(QFrame::Panel | QFrame::Raised);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
int pixmapHeight = qApp->primaryScreen()->geometry().height() / 3;
#else
QDesktopWidget desktopWidget;
int pixmapHeight = desktopWidget.screenGeometry().height() / 3;
#endif
int pixmapWidth = static_cast<int>(pixmapHeight / aspectRatio);
pic->setFixedWidth(pixmapWidth);
pic->setFixedHeight(pixmapHeight);
@@ -54,9 +65,10 @@ void CardInfoWidget::setCard(CardInfoPtr card)
void CardInfoWidget::setCard(const QString &cardName)
{
setCard(db->getCardBySimpleName(cardName));
if (!info)
setCard(db->guessCard(cardName));
if (info == nullptr) {
text->setInvalidCardName(cardName);
}
}
void CardInfoWidget::setCard(AbstractCardItem *card)

View File

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

View File

@@ -1,4 +1,5 @@
#include "carditem.h"
#include "arrowitem.h"
#include "carddatabase.h"
#include "carddragitem.h"
@@ -11,6 +12,7 @@
#include "tab_game.h"
#include "tablezone.h"
#include "zoneviewzone.h"
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QMenu>
@@ -46,22 +48,22 @@ CardItem::~CardItem()
void CardItem::prepareDelete()
{
if (owner) {
if (owner != nullptr) {
if (owner->getCardMenu() == cardMenu) {
owner->setCardMenu(0);
owner->getGame()->setActiveCard(0);
owner->setCardMenu(nullptr);
owner->getGame()->setActiveCard(nullptr);
}
owner = 0;
owner = nullptr;
}
while (!attachedCards.isEmpty()) {
attachedCards.first()->setZone(0); // so that it won't try to call reorganizeCards()
attachedCards.first()->setAttachedTo(0);
attachedCards.first()->setZone(nullptr); // so that it won't try to call reorganizeCards()
attachedCards.first()->setAttachedTo(nullptr);
}
if (attachedTo) {
if (attachedTo != nullptr) {
attachedTo->removeAttachedCard(this);
attachedTo = 0;
attachedTo = nullptr;
}
}
@@ -263,9 +265,10 @@ CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPoin
void CardItem::deleteDragItem()
{
if (dragItem)
if (dragItem) {
dragItem->deleteLater();
dragItem = NULL;
}
dragItem = nullptr;
}
void CardItem::drawArrow(const QColor &arrowColor)
@@ -360,15 +363,15 @@ void CardItem::playCard(bool faceDown)
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::RightButton) {
if (cardMenu && !cardMenu->isEmpty() && owner) {
if (cardMenu && !cardMenu->isEmpty() && owner != nullptr) {
owner->updateCardMenu(this);
cardMenu->exec(event->screenPos());
}
} else if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) &&
(!settingsCache->getDoubleClickToPlay())) {
(!SettingsCache::instance().getDoubleClickToPlay())) {
bool hideCard = false;
if (zone && zone->getIsView()) {
ZoneViewZone *view = static_cast<ZoneViewZone *>(zone);
auto *view = static_cast<ZoneViewZone *>(zone);
if (view->getRevealZone() && !view->getWriteableRevealZone())
hideCard = true;
}
@@ -379,13 +382,15 @@ void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
}
}
setCursor(Qt::OpenHandCursor);
if (owner != nullptr){ // cards without owner will be deleted
setCursor(Qt::OpenHandCursor);
}
AbstractCardItem::mouseReleaseEvent(event);
}
void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->modifiers() != Qt::AltModifier) && (settingsCache->getDoubleClickToPlay()) &&
if ((event->modifiers() != Qt::AltModifier) && (SettingsCache::instance().getDoubleClickToPlay()) &&
(event->buttons() == Qt::LeftButton)) {
if (revealedCard)
zone->removeCard(this);

View File

@@ -52,7 +52,7 @@ public:
const QString &_name = QString(),
int _cardid = -1,
bool revealedCard = false,
QGraphicsItem *parent = 0);
QGraphicsItem *parent = nullptr);
~CardItem();
void retranslateUi();
CardZone *getZone() const

View File

@@ -1,7 +1,10 @@
#include "cardlist.h"
#include "carddatabase.h"
#include "carditem.h"
#include <algorithm>
CardList::CardList(bool _contentsKnown) : QList<CardItem *>(), contentsKnown(_contentsKnown)
{
}
@@ -56,5 +59,5 @@ public:
void CardList::sort(int flags)
{
compareFunctor cf(flags);
qSort(begin(), end(), cf);
std::sort(begin(), end(), cf);
}

View File

@@ -1,9 +1,11 @@
#include "cardzone.h"
#include "carditem.h"
#include "pb/command_move_card.pb.h"
#include "pb/serverinfo_user.pb.h"
#include "player.h"
#include "zoneviewzone.h"
#include <QAction>
#include <QDebug>
#include <QGraphicsSceneMouseEvent>

View File

@@ -4,6 +4,7 @@
#include "abstractgraphicsitem.h"
#include "cardlist.h"
#include "translation.h"
#include <QString>
class Player;
@@ -52,7 +53,7 @@ public:
bool _hasCardAttr,
bool _isShufflable,
bool _contentsKnown,
QGraphicsItem *parent = 0,
QGraphicsItem *parent = nullptr,
bool _isView = false);
~CardZone();
void retranslateUi();

View File

@@ -1,10 +1,12 @@
#include "chatview.h"
#include "../pixmapgenerator.h"
#include "../settingscache.h"
#include "../soundengine.h"
#include "../tab_userlists.h"
#include "../tab_account.h"
#include "../user_context_menu.h"
#include "user_level.h"
#include <QApplication>
#include <QDateTime>
#include <QDesktopServices>
@@ -29,11 +31,13 @@ ChatView::ChatView(const TabSupervisor *_tabSupervisor,
)");
serverMessageColor = QColor(0xFF, 0x73, 0x83);
otherUserColor = otherUserColor.lighter(150);
linkColor = QColor(71, 158, 252);
} else {
document()->setDefaultStyleSheet(R"(
a { text-decoration: none; color: blue; }
.blue { color: blue }
)");
linkColor = palette().link().color();
}
userContextMenu = new UserContextMenu(tabSupervisor, this, game);
@@ -45,7 +49,7 @@ ChatView::ChatView(const TabSupervisor *_tabSupervisor,
mentionFormat.setFontWeight(QFont::Bold);
mentionFormatOtherUser.setFontWeight(QFont::Bold);
mentionFormatOtherUser.setForeground(palette().link());
mentionFormatOtherUser.setForeground(linkColor);
mentionFormatOtherUser.setAnchor(true);
viewport()->setCursor(Qt::IBeamCursor);
@@ -111,7 +115,7 @@ void ChatView::appendCardTag(QTextCursor &cursor, const QString &cardName)
{
QTextCharFormat oldFormat = cursor.charFormat();
QTextCharFormat anchorFormat = oldFormat;
anchorFormat.setForeground(palette().link());
anchorFormat.setForeground(linkColor);
anchorFormat.setAnchor(true);
anchorFormat.setAnchorHref("card://" + cardName);
anchorFormat.setFontItalic(true);
@@ -124,14 +128,14 @@ void ChatView::appendCardTag(QTextCursor &cursor, const QString &cardName)
void ChatView::appendUrlTag(QTextCursor &cursor, QString url)
{
if (!url.contains("://"))
url.prepend("http://");
url.prepend("https://");
QTextCharFormat oldFormat = cursor.charFormat();
QTextCharFormat anchorFormat = oldFormat;
anchorFormat.setForeground(palette().link());
anchorFormat.setForeground(linkColor);
anchorFormat.setAnchor(true);
anchorFormat.setAnchorHref(url);
anchorFormat.setUnderlineColor(palette().link().color());
anchorFormat.setUnderlineColor(linkColor);
anchorFormat.setFontUnderline(true);
cursor.setCharFormat(anchorFormat);
@@ -214,8 +218,12 @@ void ChatView::appendMessage(QString message,
}
cursor.setCharFormat(defaultFormat);
bool mentionEnabled = settingsCache->getChatMention();
highlightedWords = settingsCache->getHighlightWords().split(' ', QString::SkipEmptyParts);
bool mentionEnabled = SettingsCache::instance().getChatMention();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
highlightedWords = SettingsCache::instance().getHighlightWords().split(' ', Qt::SkipEmptyParts);
#else
highlightedWords = SettingsCache::instance().getHighlightWords().split(' ', QString::SkipEmptyParts);
#endif
// parse the message
while (message.size()) {
@@ -313,8 +321,8 @@ void ChatView::checkMention(QTextCursor &cursor, QString &message, QString &send
// You have received a valid mention!!
soundEngine->playSound("chat_mention");
mentionFormat.setBackground(QBrush(getCustomMentionColor()));
mentionFormat.setForeground(settingsCache->getChatMentionForeground() ? QBrush(Qt::white)
: QBrush(Qt::black));
mentionFormat.setForeground(SettingsCache::instance().getChatMentionForeground() ? QBrush(Qt::white)
: QBrush(Qt::black));
cursor.insertText(mention, mentionFormat);
message = message.mid(mention.size());
showSystemPopup(sender);
@@ -335,8 +343,8 @@ void ChatView::checkMention(QTextCursor &cursor, QString &message, QString &send
// Moderator Sending Global Message
soundEngine->playSound("all_mention");
mentionFormat.setBackground(QBrush(getCustomMentionColor()));
mentionFormat.setForeground(settingsCache->getChatMentionForeground() ? QBrush(Qt::white)
: QBrush(Qt::black));
mentionFormat.setForeground(SettingsCache::instance().getChatMentionForeground() ? QBrush(Qt::white)
: QBrush(Qt::black));
cursor.insertText("@" + fullMentionUpToSpaceOrEnd, mentionFormat);
message = message.mid(fullMentionUpToSpaceOrEnd.size() + 1);
showSystemPopup(sender);
@@ -383,8 +391,8 @@ void ChatView::checkWord(QTextCursor &cursor, QString &message)
if (fullWordUpToSpaceOrEnd.compare(word, Qt::CaseInsensitive) == 0) {
// You have received a valid mention of custom word!!
highlightFormat.setBackground(QBrush(getCustomHighlightColor()));
highlightFormat.setForeground(settingsCache->getChatHighlightForeground() ? QBrush(Qt::white)
: QBrush(Qt::black));
highlightFormat.setForeground(SettingsCache::instance().getChatHighlightForeground() ? QBrush(Qt::white)
: QBrush(Qt::black));
cursor.insertText(fullWordUpToSpaceOrEnd, highlightFormat);
cursor.insertText(rest, defaultFormat);
QApplication::alert(this);
@@ -440,7 +448,7 @@ void ChatView::actMessageClicked()
void ChatView::showSystemPopup(QString &sender)
{
QApplication::alert(this);
if (settingsCache->getShowMentionPopup()) {
if (SettingsCache::instance().getShowMentionPopup()) {
QString ref = sender.left(sender.length() - 2);
emit showMentionPopup(ref);
}
@@ -449,14 +457,14 @@ void ChatView::showSystemPopup(QString &sender)
QColor ChatView::getCustomMentionColor()
{
QColor customColor;
customColor.setNamedColor("#" + settingsCache->getChatMentionColor());
customColor.setNamedColor("#" + SettingsCache::instance().getChatMentionColor());
return customColor.isValid() ? customColor : DEFAULT_MENTION_COLOR;
}
QColor ChatView::getCustomHighlightColor()
{
QColor customColor;
customColor.setNamedColor("#" + settingsCache->getChatHighlightColor());
customColor.setNamedColor("#" + SettingsCache::instance().getChatHighlightColor());
return customColor.isValid() ? customColor : DEFAULT_MENTION_COLOR;
}
@@ -521,12 +529,12 @@ void ChatView::mousePressEvent(QMouseEvent *event)
{
switch (hoveredItemType) {
case HoveredCard: {
if ((event->button() == Qt::MidButton) || (event->button() == Qt::LeftButton))
if ((event->button() == Qt::MiddleButton) || (event->button() == Qt::LeftButton))
emit showCardInfoPopup(event->globalPos(), hoveredContent);
break;
}
case HoveredUser: {
if (event->button() != Qt::MidButton) {
if (event->button() != Qt::MiddleButton) {
const int delimiterIndex = hoveredContent.indexOf("_");
const QString userName = hoveredContent.mid(delimiterIndex + 1);
switch (event->button()) {
@@ -556,7 +564,7 @@ void ChatView::mousePressEvent(QMouseEvent *event)
void ChatView::mouseReleaseEvent(QMouseEvent *event)
{
if ((event->button() == Qt::MidButton) || (event->button() == Qt::LeftButton))
if ((event->button() == Qt::MiddleButton) || (event->button() == Qt::LeftButton))
emit deleteCardInfoPopup(QString("_"));
QTextBrowser::mouseReleaseEvent(event);

View File

@@ -6,6 +6,7 @@
#include "room_message_type.h"
#include "user_level.h"
#include "userlistProxy.h"
#include <QAction>
#include <QColor>
#include <QTextBrowser>
@@ -62,6 +63,7 @@ private:
QColor otherUserColor = QColor(0, 65, 255); // dark blue
QColor serverMessageColor = QColor(0x85, 0x15, 0x15);
QColor linkColor;
private slots:
void openLink(const QUrl &link);
@@ -72,14 +74,14 @@ public:
const UserlistProxy *_userlistProxy,
TabGame *_game,
bool _showTimestamps,
QWidget *parent = 0);
QWidget *parent = nullptr);
void retranslateUi();
void appendHtml(const QString &html);
void virtual appendHtmlServerMessage(const QString &html,
bool optionalIsBold = false,
QString optionalFontColor = QString());
void appendMessage(QString message,
RoomMessageTypeFlags messageType = 0,
RoomMessageTypeFlags messageType = {},
QString sender = QString(),
UserLevelFlags userLevel = UserLevelFlags(),
QString UserPrivLevel = "NONE",

View File

@@ -1,6 +1,8 @@
#include "counter_general.h"
#include "abstractgraphicsitem.h"
#include "pixmapgenerator.h"
#include <QPainter>
GeneralCounter::GeneralCounter(Player *_player,
@@ -10,8 +12,10 @@ GeneralCounter::GeneralCounter(Player *_player,
int _radius,
int _value,
bool useNameForShortcut,
QGraphicsItem *parent)
: AbstractCounter(_player, _id, _name, true, _value, useNameForShortcut, parent), color(_color), radius(_radius)
QGraphicsItem *parent,
QWidget *game)
: AbstractCounter(_player, _id, _name, true, _value, useNameForShortcut, parent, game), color(_color),
radius(_radius)
{
setCacheMode(DeviceCoordinateCache);
}

View File

@@ -18,7 +18,8 @@ public:
int _radius,
int _value,
bool useNameForShortcut = false,
QGraphicsItem *parent = 0);
QGraphicsItem *parent = nullptr,
QWidget *game = nullptr);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};

View File

@@ -0,0 +1,72 @@
#include "customlineedit.h"
#include "settingscache.h"
#include "shortcutssettings.h"
#include <QKeyEvent>
#include <QLineEdit>
#include <QObject>
#include <QWidget>
LineEditUnfocusable::LineEditUnfocusable(QWidget *parent) : QLineEdit(parent)
{
installEventFilter(this);
}
LineEditUnfocusable::LineEditUnfocusable(const QString &contents, QWidget *parent) : QLineEdit(contents, parent)
{
installEventFilter(this);
}
bool LineEditUnfocusable::isUnfocusShortcut(QKeyEvent *event)
{
QString modifier;
QString keyNoMod;
if (event->modifiers() & Qt::ShiftModifier)
modifier += "Shift+";
if (event->modifiers() & Qt::ControlModifier)
modifier += "Ctrl+";
if (event->modifiers() & Qt::AltModifier)
modifier += "Alt+";
if (event->modifiers() & Qt::MetaModifier)
modifier += "Meta+";
keyNoMod = QKeySequence(event->key()).toString();
QKeySequence key(modifier + keyNoMod);
QList<QKeySequence> unfocusShortcut = SettingsCache::instance().shortcuts().getShortcut("Textbox/unfocusTextBox");
for (QList<QKeySequence>::iterator i = unfocusShortcut.begin(); i != unfocusShortcut.end(); ++i) {
if (key.matches(*i) == QKeySequence::ExactMatch)
return true;
}
return false;
}
void LineEditUnfocusable::keyPressEvent(QKeyEvent *event)
{
if (isUnfocusShortcut(event)) {
clearFocus();
return;
}
QLineEdit::keyPressEvent(event);
}
bool LineEditUnfocusable::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::ShortcutOverride) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (isUnfocusShortcut(keyEvent)) {
event->accept();
return true;
}
}
return QLineEdit::eventFilter(watched, event);
}

View File

@@ -0,0 +1,27 @@
#ifndef CUSTOMLINEEDIT_H
#define CUSTOMLINEEDIT_H
#include <QLineEdit>
class QKeyEvent;
class QWidget;
class QString;
// Should be used when the there is a risk of conflict between line editor
// shortcuts and other shortcuts
class LineEditUnfocusable : public QLineEdit
{
public:
LineEditUnfocusable(QWidget *parent = nullptr);
LineEditUnfocusable(const QString &contents, QWidget *parent = nullptr);
private:
bool isUnfocusShortcut(QKeyEvent *key);
protected:
void keyPressEvent(QKeyEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
};
#endif

View File

@@ -1,13 +1,16 @@
#include "deck_loader.h"
#include "carddatabase.h"
#include "decklist.h"
#include "main.h"
#include <QDebug>
#include <QFile>
#include <QStringList>
const QStringList DeckLoader::fileNameFilters =
QStringList() << QObject::tr("Common deck formats (*.cod *.dec *.txt *.mwDeck)") << QObject::tr("All files (*.*)");
const QStringList DeckLoader::fileNameFilters = QStringList()
<< QObject::tr("Common deck formats (*.cod *.dec *.dek *.txt *.mwDeck)")
<< QObject::tr("All files (*.*)");
DeckLoader::DeckLoader() : DeckList(), lastFileName(QString()), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
{
@@ -288,11 +291,11 @@ QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneNam
QString DeckLoader::getCompleteCardName(const QString cardName) const
{
if (db) {
CardInfoPtr temp = db->getCardBySimpleName(cardName);
CardInfoPtr temp = db->guessCard(cardName);
if (temp) {
return temp->getName();
}
}
return cardName;
}
}

View File

@@ -1,8 +1,10 @@
#include "decklistmodel.h"
#include "carddatabase.h"
#include "deck_loader.h"
#include "main.h"
#include "settingscache.h"
#include <QBrush>
#include <QFile>
#include <QFont>
@@ -193,7 +195,7 @@ QModelIndex DeckListModel::parent(const QModelIndex &ind) const
Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) {
return nullptr;
return Qt::NoItemFlags;
}
Qt::ItemFlags result = Qt::ItemIsEnabled;
@@ -515,4 +517,4 @@ void DeckListModel::printDeckList(QPrinter *printer)
}
doc.print(printer);
}
}

View File

@@ -2,6 +2,7 @@
#define DECKLISTMODEL_H
#include "decklist.h"
#include <QAbstractItemModel>
#include <QList>

View File

@@ -1,5 +1,7 @@
#include "deckstats_interface.h"
#include "decklist.h"
#include <QDesktopServices>
#include <QMessageBox>
#include <QNetworkAccessManager>
@@ -50,7 +52,7 @@ void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
urlQuery.addQueryItem("decktitle", deck->getName());
params.setQuery(urlQuery);
data->append(params.query(QUrl::EncodeReserved));
data->append(params.query(QUrl::EncodeReserved).toUtf8());
}
void DeckStatsInterface::analyzeDeck(DeckList *deck)

View File

@@ -3,6 +3,7 @@
#include "carddatabase.h"
#include "decklist.h"
#include <QObject>
class QByteArray;
@@ -30,7 +31,7 @@ private slots:
void getAnalyzeRequestData(DeckList *deck, QByteArray *data);
public:
DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = 0);
DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
void analyzeDeck(DeckList *deck);
};

View File

@@ -1,12 +1,15 @@
#include "deckview.h"
#include "carddatabase.h"
#include "decklist.h"
#include "main.h"
#include "settingscache.h"
#include "thememanager.h"
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QMouseEvent>
#include <algorithm>
#include <math.h>
DeckViewCardDragItem::DeckViewCardDragItem(DeckViewCard *_item,
@@ -283,7 +286,7 @@ void DeckViewCardContainer::rearrangeItems(const QList<QPair<int, int>> &rowsAnd
QList<QString> cardTypeList = cardsByType.uniqueKeys();
QList<DeckViewCard *> row = cardsByType.values(cardTypeList[i]);
qSort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName);
std::sort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName);
for (int j = 0; j < row.size(); ++j) {
DeckViewCard *card = row[j];
card->setPos(x + (j % tempCols) * CARD_WIDTH, yUntilNow + (j / tempCols) * CARD_HEIGHT);

View File

@@ -2,14 +2,14 @@
#define DECKVIEW_H
#include "abstractcarddragitem.h"
#include "pb/move_card_to_zone.pb.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QMap>
#include <QMultiMap>
#include <QPixmap>
#include "pb/move_card_to_zone.pb.h"
class DeckList;
class InnerDecklistNode;
class CardInfo;
@@ -24,7 +24,9 @@ private:
DeckViewCardDragItem *dragItem;
public:
DeckViewCard(const QString &_name = QString(), const QString &_originZone = QString(), QGraphicsItem *parent = 0);
DeckViewCard(const QString &_name = QString(),
const QString &_originZone = QString(),
QGraphicsItem *parent = nullptr);
~DeckViewCard();
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
const QString &getOriginZone() const
@@ -110,7 +112,7 @@ private:
void rebuildTree();
public:
DeckViewScene(QObject *parent = 0);
DeckViewScene(QObject *parent = nullptr);
~DeckViewScene();
void setLocked(bool _locked)
{
@@ -147,7 +149,7 @@ signals:
void sideboardPlanChanged();
public:
DeckView(QWidget *parent = 0);
DeckView(QWidget *parent = nullptr);
void setDeck(const DeckList &_deck);
void setLocked(bool _locked)
{

View File

@@ -1,6 +1,8 @@
#include "dlg_connect.h"
#include "settingscache.h"
#include "userconnection_information.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDebug>
@@ -61,11 +63,11 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
autoConnectCheckBox = new QCheckBox(tr("A&uto connect"));
autoConnectCheckBox->setToolTip(tr("Automatically connect to the most recent login when Cockatrice opens"));
if (settingsCache->servers().getSavePassword()) {
autoConnectCheckBox->setChecked(static_cast<bool>(settingsCache->servers().getAutoConnect()));
if (SettingsCache::instance().servers().getSavePassword()) {
autoConnectCheckBox->setChecked(static_cast<bool>(SettingsCache::instance().servers().getAutoConnect()));
autoConnectCheckBox->setEnabled(true);
} else {
settingsCache->servers().setAutoConnect(0);
SettingsCache::instance().servers().setAutoConnect(0);
autoConnectCheckBox->setChecked(false);
autoConnectCheckBox->setEnabled(false);
}
@@ -190,13 +192,14 @@ void DlgConnect::rebuildComboBoxList(int failure)
UserConnection_Information uci;
savedHostList = uci.getServerInfo();
bool autoConnectEnabled = static_cast<bool>(settingsCache->servers().getAutoConnect());
QString autoConnectSaveName = settingsCache->servers().getSaveName();
bool autoConnectEnabled = static_cast<bool>(SettingsCache::instance().servers().getAutoConnect());
QString previousHostName = SettingsCache::instance().servers().getPrevioushostName();
QString autoConnectSaveName = SettingsCache::instance().servers().getSaveName();
int index = 0;
for (const auto &pair : savedHostList) {
auto tmp = pair.second;
const auto &tmp = pair.second;
QString saveName = tmp.getSaveName();
if (saveName.size()) {
previousHosts->addItem(saveName);
@@ -205,7 +208,7 @@ void DlgConnect::rebuildComboBoxList(int failure)
if (saveName.compare(autoConnectSaveName) == 0) {
previousHosts->setCurrentIndex(index);
}
} else if (saveName.compare("Rooster Ranges") == 0) {
} else if (saveName.compare(previousHostName) == 0) {
previousHosts->setCurrentIndex(index);
}
@@ -295,23 +298,24 @@ void DlgConnect::passwordSaved(int state)
void DlgConnect::actOk()
{
ServersSettings &servers = SettingsCache::instance().servers();
if (newHostButton->isChecked()) {
if (saveEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Connection Warning"), tr("You need to name your new connection profile."));
return;
}
settingsCache->servers().addNewServer(saveEdit->text().trimmed(), hostEdit->text().trimmed(),
portEdit->text().trimmed(), playernameEdit->text().trimmed(),
passwordEdit->text(), savePasswordCheckBox->isChecked());
servers.addNewServer(saveEdit->text().trimmed(), hostEdit->text().trimmed(), portEdit->text().trimmed(),
playernameEdit->text().trimmed(), passwordEdit->text(), savePasswordCheckBox->isChecked());
} else {
settingsCache->servers().updateExistingServer(saveEdit->text().trimmed(), hostEdit->text().trimmed(),
portEdit->text().trimmed(), playernameEdit->text().trimmed(),
passwordEdit->text(), savePasswordCheckBox->isChecked());
servers.updateExistingServer(saveEdit->text().trimmed(), hostEdit->text().trimmed(), portEdit->text().trimmed(),
playernameEdit->text().trimmed(), passwordEdit->text(),
savePasswordCheckBox->isChecked());
}
settingsCache->servers().setPrevioushostName(saveEdit->text());
settingsCache->servers().setAutoConnect(autoConnectCheckBox->isChecked());
servers.setPrevioushostName(saveEdit->text());
servers.setAutoConnect(autoConnectCheckBox->isChecked());
if (playernameEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Connect Warning"), tr("The player name can't be empty."));
@@ -345,4 +349,4 @@ void DlgConnect::actForgotPassword()
{
emit sigStartForgotPasswordRequest();
reject();
}
}

View File

@@ -3,6 +3,7 @@
#include "handle_public_servers.h"
#include "userconnection_information.h"
#include <QDialog>
#include <QLineEdit>

View File

@@ -1,3 +1,11 @@
#include "dlg_create_token.h"
#include "carddatabasemodel.h"
#include "cardinfopicture.h"
#include "decklist.h"
#include "main.h"
#include "settingscache.h"
#include <QCheckBox>
#include <QCloseEvent>
#include <QComboBox>
@@ -12,13 +20,6 @@
#include <QTreeView>
#include <QVBoxLayout>
#include "carddatabasemodel.h"
#include "cardinfopicture.h"
#include "decklist.h"
#include "dlg_create_token.h"
#include "main.h"
#include "settingscache.h"
DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent)
: QDialog(parent), predefinedTokens(_predefinedTokens)
{
@@ -76,7 +77,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
chooseTokenFromDeckRadioButton = new QRadioButton(tr("Show tokens from this &deck"));
connect(chooseTokenFromDeckRadioButton, SIGNAL(toggled(bool)), this, SLOT(actChooseTokenFromDeck(bool)));
QByteArray deckHeaderState = settingsCache->layouts().getDeckEditorDbHeaderState();
QByteArray deckHeaderState = SettingsCache::instance().layouts().getDeckEditorDbHeaderState();
chooseTokenView = new QTreeView;
chooseTokenView->setModel(cardDatabaseDisplayModel);
chooseTokenView->setUniformRowHeights(true);
@@ -103,7 +104,11 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
chooseTokenFromDeckRadioButton->setDisabled(true); // No tokens in deck = no need for option
} else {
chooseTokenFromDeckRadioButton->setChecked(true);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
#else
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>::fromList(predefinedTokens));
#endif
}
QVBoxLayout *tokenChooseLayout = new QVBoxLayout;
@@ -132,13 +137,13 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
setWindowTitle(tr("Create token"));
resize(600, 500);
restoreGeometry(settingsCache->getTokenDialogGeometry());
restoreGeometry(SettingsCache::instance().getTokenDialogGeometry());
}
void DlgCreateToken::closeEvent(QCloseEvent *event)
{
event->accept();
settingsCache->setTokenDialogGeometry(saveGeometry());
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
}
void DlgCreateToken::tokenSelectionChanged(const QModelIndex &current, const QModelIndex & /*previous*/)
@@ -156,7 +161,7 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex &current, const QMo
const QChar cardColor = cardInfo->getColorChar();
colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString));
ptEdit->setText(cardInfo->getPowTough());
if (settingsCache->getAnnotateTokens())
if (SettingsCache::instance().getAnnotateTokens())
annotationEdit->setText(cardInfo->getText());
} else {
nameEdit->setText("");
@@ -182,25 +187,31 @@ void DlgCreateToken::updateSearch(const QString &search)
void DlgCreateToken::actChooseTokenFromAll(bool checked)
{
if (checked)
if (checked) {
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>());
}
}
void DlgCreateToken::actChooseTokenFromDeck(bool checked)
{
if (checked)
if (checked) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
#else
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>::fromList(predefinedTokens));
#endif
}
}
void DlgCreateToken::actOk()
{
settingsCache->setTokenDialogGeometry(saveGeometry());
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
accept();
}
void DlgCreateToken::actReject()
{
settingsCache->setTokenDialogGeometry(saveGeometry());
SettingsCache::instance().setTokenDialogGeometry(saveGeometry());
reject();
}
@@ -227,4 +238,4 @@ QString DlgCreateToken::getAnnotation() const
bool DlgCreateToken::getDestroy() const
{
return destroyCheckBox->isChecked();
}
}

View File

@@ -21,7 +21,7 @@ class DlgCreateToken : public QDialog
{
Q_OBJECT
public:
DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent = 0);
DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent = nullptr);
QString getName() const;
QString getColor() const;
QString getPT() const;

View File

@@ -1,6 +1,10 @@
#include "dlg_creategame.h"
#include "pb/serverinfo_game.pb.h"
#include "pending_command.h"
#include "settingscache.h"
#include "tab_room.h"
#include <QApplication>
#include <QCheckBox>
#include <QDialogButtonBox>
@@ -15,9 +19,6 @@
#include <QSpinBox>
#include <QWizard>
#include "pb/serverinfo_game.pb.h"
#include "pending_command.h"
void DlgCreateGame::sharedCtor()
{
rememberGameSettings = new QCheckBox(tr("Re&member settings"));
@@ -48,7 +49,7 @@ void DlgCreateGame::sharedCtor()
QRadioButton *gameTypeRadioButton = new QRadioButton(gameTypeIterator.value(), this);
gameTypeLayout->addWidget(gameTypeRadioButton);
gameTypeCheckBoxes.insert(gameTypeIterator.key(), gameTypeRadioButton);
bool isChecked = settingsCache->getGameTypes().contains(gameTypeIterator.value() + ", ");
bool isChecked = SettingsCache::instance().getGameTypes().contains(gameTypeIterator.value() + ", ");
gameTypeCheckBoxes[gameTypeIterator.key()]->setChecked(isChecked);
}
QGroupBox *gameTypeGroupBox = new QGroupBox(tr("Game type"));
@@ -94,7 +95,7 @@ void DlgCreateGame::sharedCtor()
grid->addWidget(generalGroupBox, 0, 0);
grid->addWidget(joinRestrictionsGroupBox, 0, 1);
grid->addWidget(gameTypeGroupBox, 1, 0);
grid->addWidget(spectatorsGroupBox, 1, 1);
grid->addWidget(spectatorsGroupBox, 1, 1, Qt::AlignTop);
grid->addWidget(rememberGameSettings, 2, 0);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
@@ -114,20 +115,20 @@ DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameType
{
sharedCtor();
rememberGameSettings->setChecked(settingsCache->getRememberGameSettings());
descriptionEdit->setText(settingsCache->getGameDescription());
maxPlayersEdit->setValue(settingsCache->getMaxPlayers());
rememberGameSettings->setChecked(SettingsCache::instance().getRememberGameSettings());
descriptionEdit->setText(SettingsCache::instance().getGameDescription());
maxPlayersEdit->setValue(SettingsCache::instance().getMaxPlayers());
if (room && room->getUserInfo()->user_level() & ServerInfo_User::IsRegistered) {
onlyBuddiesCheckBox->setChecked(settingsCache->getOnlyBuddies());
onlyRegisteredCheckBox->setChecked(settingsCache->getOnlyRegistered());
onlyBuddiesCheckBox->setChecked(SettingsCache::instance().getOnlyBuddies());
onlyRegisteredCheckBox->setChecked(SettingsCache::instance().getOnlyRegistered());
} else {
onlyBuddiesCheckBox->setEnabled(false);
onlyRegisteredCheckBox->setEnabled(false);
}
spectatorsAllowedCheckBox->setChecked(settingsCache->getSpectatorsAllowed());
spectatorsNeedPasswordCheckBox->setChecked(settingsCache->getSpectatorsNeedPassword());
spectatorsCanTalkCheckBox->setChecked(settingsCache->getSpectatorsCanTalk());
spectatorsSeeEverythingCheckBox->setChecked(settingsCache->getSpectatorsCanSeeEverything());
spectatorsAllowedCheckBox->setChecked(SettingsCache::instance().getSpectatorsAllowed());
spectatorsNeedPasswordCheckBox->setChecked(SettingsCache::instance().getSpectatorsNeedPassword());
spectatorsCanTalkCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanTalk());
spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything());
if (!rememberGameSettings->isChecked()) {
actReset();
@@ -236,17 +237,17 @@ void DlgCreateGame::actOK()
}
}
settingsCache->setRememberGameSettings(rememberGameSettings->isChecked());
SettingsCache::instance().setRememberGameSettings(rememberGameSettings->isChecked());
if (rememberGameSettings->isChecked()) {
settingsCache->setGameDescription(descriptionEdit->text());
settingsCache->setMaxPlayers(maxPlayersEdit->value());
settingsCache->setOnlyBuddies(onlyBuddiesCheckBox->isChecked());
settingsCache->setOnlyRegistered(onlyRegisteredCheckBox->isChecked());
settingsCache->setSpectatorsAllowed(spectatorsAllowedCheckBox->isChecked());
settingsCache->setSpectatorsNeedPassword(spectatorsNeedPasswordCheckBox->isChecked());
settingsCache->setSpectatorsCanTalk(spectatorsCanTalkCheckBox->isChecked());
settingsCache->setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked());
settingsCache->setGameTypes(gameTypes);
SettingsCache::instance().setGameDescription(descriptionEdit->text());
SettingsCache::instance().setMaxPlayers(maxPlayersEdit->value());
SettingsCache::instance().setOnlyBuddies(onlyBuddiesCheckBox->isChecked());
SettingsCache::instance().setOnlyRegistered(onlyRegisteredCheckBox->isChecked());
SettingsCache::instance().setSpectatorsAllowed(spectatorsAllowedCheckBox->isChecked());
SettingsCache::instance().setSpectatorsNeedPassword(spectatorsNeedPasswordCheckBox->isChecked());
SettingsCache::instance().setSpectatorsCanTalk(spectatorsCanTalkCheckBox->isChecked());
SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked());
SettingsCache::instance().setGameTypes(gameTypes);
}
PendingCommand *pend = room->prepareRoomCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(checkResponse(Response)));

View File

@@ -20,8 +20,8 @@ class DlgCreateGame : public QDialog
{
Q_OBJECT
public:
DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameTypes, QWidget *parent = 0);
DlgCreateGame(const ServerInfo_Game &game, const QMap<int, QString> &_gameTypes, QWidget *parent = 0);
DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameTypes, QWidget *parent = nullptr);
DlgCreateGame(const ServerInfo_Game &game, const QMap<int, QString> &_gameTypes, QWidget *parent = nullptr);
private slots:
void actOK();
void actReset();

View File

@@ -1,3 +1,5 @@
#include "dlg_edit_avatar.h"
#include <QBuffer>
#include <QDebug>
#include <QDialogButtonBox>
@@ -8,9 +10,7 @@
#include <QPushButton>
#include <QVBoxLayout>
#include "dlg_edit_avatar.h"
DlgEditAvatar::DlgEditAvatar(QWidget *parent) : QDialog(parent)
DlgEditAvatar::DlgEditAvatar(QWidget *parent) : QDialog(parent), image()
{
imageLabel = new QLabel(tr("No image chosen."));
imageLabel->setFixedSize(400, 200);
@@ -55,7 +55,6 @@ void DlgEditAvatar::actBrowse()
return;
}
QImage image;
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
imgReader.setFileName(fileName);
@@ -69,13 +68,9 @@ void DlgEditAvatar::actBrowse()
QByteArray DlgEditAvatar::getImage()
{
const QPixmap *pix = imageLabel->pixmap();
if (!pix || pix->isNull())
return QByteArray();
QImage image = pix->toImage();
if (image.isNull())
if (image.isNull()) {
return QByteArray();
}
QByteArray ba;
QBuffer buffer(&ba);

View File

@@ -13,13 +13,14 @@ class DlgEditAvatar : public QDialog
{
Q_OBJECT
public:
DlgEditAvatar(QWidget *parent = 0);
DlgEditAvatar(QWidget *parent = nullptr);
QByteArray getImage();
private slots:
void actOk();
void actBrowse();
private:
QImage image;
QLabel *textLabel, *imageLabel;
QPushButton *browseButton;
};

View File

@@ -1,20 +1,21 @@
#include "dlg_edit_password.h"
#include "settingscache.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include "dlg_edit_password.h"
#include "settingscache.h"
DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
{
oldPasswordLabel = new QLabel(tr("Old password:"));
oldPasswordEdit = new QLineEdit();
if (settingsCache->servers().getSavePassword())
oldPasswordEdit->setText(settingsCache->servers().getPassword());
if (SettingsCache::instance().servers().getSavePassword())
oldPasswordEdit->setText(SettingsCache::instance().servers().getPassword());
oldPasswordLabel->setBuddy(oldPasswordEdit);
oldPasswordEdit->setEchoMode(QLineEdit::Password);
@@ -59,6 +60,6 @@ void DlgEditPassword::actOk()
}
// always save the password so it will be picked up by the connect dialog
settingsCache->servers().setPassword(newPasswordEdit->text());
SettingsCache::instance().servers().setPassword(newPasswordEdit->text());
accept();
}

View File

@@ -13,7 +13,7 @@ class DlgEditPassword : public QDialog
{
Q_OBJECT
public:
DlgEditPassword(QWidget *parent = 0);
DlgEditPassword(QWidget *parent = nullptr);
QString getOldPassword() const
{
return oldPasswordEdit->text();

View File

@@ -1,7 +1,9 @@
#include "dlg_edit_tokens.h"
#include "carddatabase.h"
#include "carddatabasemodel.h"
#include "main.h"
#include <QAction>
#include <QComboBox>
#include <QDialogButtonBox>
@@ -61,7 +63,7 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nul
databaseModel = new CardDatabaseModel(db, false, this);
databaseModel->setObjectName("databaseModel");
cardDatabaseDisplayModel = new TokenDisplayModel(this);
cardDatabaseDisplayModel = new TokenEditModel(this);
cardDatabaseDisplayModel->setSourceModel(databaseModel);
cardDatabaseDisplayModel->setIsToken(CardDatabaseDisplayModel::ShowTrue);
@@ -110,7 +112,7 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nul
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Edit tokens"));
setWindowTitle(tr("Edit custom tokens"));
}
void DlgEditTokens::tokenSelectionChanged(const QModelIndex &current, const QModelIndex & /* previous */)
@@ -123,7 +125,7 @@ void DlgEditTokens::tokenSelectionChanged(const QModelIndex &current, const QMod
currentCard.clear();
}
if (!currentCard) {
if (currentCard) {
nameEdit->setText(currentCard->getName());
const QChar cardColor = currentCard->getColorChar();
colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString));
@@ -154,9 +156,12 @@ void DlgEditTokens::actAddToken()
}
} while (askAgain);
CardInfoPtr card = CardInfo::newInstance(name, "", true);
QString setName = CardDatabase::TOKENS_SETNAME;
CardInfoPerSetMap sets;
sets.insert(setName, CardInfoPerSet(databaseModel->getDatabase()->getSet(setName)));
CardInfoPtr card = CardInfo::newInstance(name, "", true, QVariantHash(), QList<CardRelation *>(),
QList<CardRelation *>(), sets, false, -1, false);
card->setCardType("Token");
card->addToSet(databaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME));
databaseModel->getDatabase()->addCard(card);
}

View File

@@ -2,11 +2,12 @@
#define DLG_EDIT_TOKENS_H
#include "carddatabase.h"
#include <QDialog>
class QModelIndex;
class CardDatabaseModel;
class TokenDisplayModel;
class TokenEditModel;
class QLabel;
class QComboBox;
class QLineEdit;
@@ -27,7 +28,7 @@ private slots:
private:
CardInfoPtr currentCard;
CardDatabaseModel *databaseModel;
TokenDisplayModel *cardDatabaseDisplayModel;
TokenEditModel *cardDatabaseDisplayModel;
QStringList predefinedTokens;
QLabel *nameLabel, *colorLabel, *ptLabel, *annotationLabel;
QComboBox *colorEdit;

View File

@@ -1,12 +1,13 @@
#include "dlg_edit_user.h"
#include "settingscache.h"
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include "dlg_edit_user.h"
#include "settingscache.h"
DlgEditUser::DlgEditUser(QWidget *parent, QString email, QString country, QString realName) : QDialog(parent)
{
emailLabel = new QLabel(tr("Email:"));
@@ -20,7 +21,7 @@ DlgEditUser::DlgEditUser(QWidget *parent, QString email, QString country, QStrin
countryEdit->insertItem(0, tr("Undefined"));
countryEdit->setCurrentIndex(0);
QStringList countries = settingsCache->getCountries();
QStringList countries = SettingsCache::instance().getCountries();
int i = 1;
foreach (QString c, countries) {
countryEdit->addItem(QPixmap("theme:countries/" + c.toLower()), c);

View File

@@ -13,7 +13,7 @@ class DlgEditUser : public QDialog
{
Q_OBJECT
public:
DlgEditUser(QWidget *parent = 0,
DlgEditUser(QWidget *parent = nullptr,
QString email = QString(),
QString country = QString(),
QString realName = QString());

View File

@@ -1,5 +1,7 @@
#include "dlg_filter_games.h"
#include <QCheckBox>
#include <QComboBox>
#include <QCryptographicHash>
#include <QDialogButtonBox>
#include <QGridLayout>
@@ -14,40 +16,62 @@
DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
const GamesProxyModel *_gamesProxyModel,
QWidget *parent)
: QDialog(parent), allGameTypes(_allGameTypes), gamesProxyModel(_gamesProxyModel)
: QDialog(parent), allGameTypes(_allGameTypes), gamesProxyModel(_gamesProxyModel),
gameAgeMap({{QTime(), tr("no limit")},
{QTime(0, 5), tr("5 minutes")},
{QTime(0, 10), tr("10 minutes")},
{QTime(0, 30), tr("30 minutes")},
{QTime(1, 0), tr("1 hour")},
{QTime(2, 0), tr("2 hours")}})
{
showBuddiesOnlyGames = new QCheckBox(tr("Show '&buddies only' games"));
showBuddiesOnlyGames->setChecked(gamesProxyModel->getShowBuddiesOnlyGames());
unavailableGamesVisibleCheckBox = new QCheckBox(tr("Show &unavailable games"));
unavailableGamesVisibleCheckBox->setChecked(gamesProxyModel->getUnavailableGamesVisible());
showFullGames = new QCheckBox(tr("Show &full games"));
showFullGames->setChecked(gamesProxyModel->getShowFullGames());
showGamesThatStarted = new QCheckBox(tr("Show games &that have started"));
showGamesThatStarted->setChecked(gamesProxyModel->getShowGamesThatStarted());
showPasswordProtectedGames = new QCheckBox(tr("Show &password protected games"));
showPasswordProtectedGames->setChecked(gamesProxyModel->getShowPasswordProtectedGames());
hideIgnoredUserGames = new QCheckBox(tr("Hide '&ignored user' games"));
hideIgnoredUserGames->setChecked(gamesProxyModel->getHideIgnoredUserGames());
maxGameAgeComboBox = new QComboBox();
maxGameAgeComboBox->setEditable(false);
maxGameAgeComboBox->addItems(gameAgeMap.values());
QTime gameAge = gamesProxyModel->getMaxGameAge();
maxGameAgeComboBox->setCurrentIndex(gameAgeMap.keys().indexOf(gameAge)); // index is -1 if unknown
auto *maxGameAgeLabel = new QLabel(tr("&Newer than:"));
maxGameAgeLabel->setBuddy(maxGameAgeComboBox);
gameNameFilterEdit = new QLineEdit;
gameNameFilterEdit->setText(gamesProxyModel->getGameNameFilter());
QLabel *gameNameFilterLabel = new QLabel(tr("Game &description:"));
auto *gameNameFilterLabel = new QLabel(tr("Game &description:"));
gameNameFilterLabel->setBuddy(gameNameFilterEdit);
creatorNameFilterEdit = new QLineEdit;
creatorNameFilterEdit->setText(gamesProxyModel->getCreatorNameFilter());
QLabel *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
auto *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
creatorNameFilterLabel->setBuddy(creatorNameFilterEdit);
QGridLayout *generalGrid = new QGridLayout;
auto *generalGrid = new QGridLayout;
generalGrid->addWidget(gameNameFilterLabel, 0, 0);
generalGrid->addWidget(gameNameFilterEdit, 0, 1);
generalGrid->addWidget(creatorNameFilterLabel, 1, 0);
generalGrid->addWidget(creatorNameFilterEdit, 1, 1);
generalGrid->addWidget(maxGameAgeLabel, 2, 0);
generalGrid->addWidget(maxGameAgeComboBox, 2, 1);
generalGroupBox = new QGroupBox(tr("General"));
generalGroupBox->setLayout(generalGrid);
QVBoxLayout *gameTypeFilterLayout = new QVBoxLayout;
auto *gameTypeFilterLayout = new QVBoxLayout;
QMapIterator<int, QString> gameTypesIterator(allGameTypes);
while (gameTypesIterator.hasNext()) {
gameTypesIterator.next();
QCheckBox *temp = new QCheckBox(gameTypesIterator.value());
auto *temp = new QCheckBox(gameTypesIterator.value());
temp->setChecked(gamesProxyModel->getGameTypeFilter().contains(gameTypesIterator.key()));
gameTypeFilterCheckBoxes.insert(gameTypesIterator.key(), temp);
@@ -58,65 +82,95 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
gameTypeFilterGroupBox = new QGroupBox(tr("&Game types"));
gameTypeFilterGroupBox->setLayout(gameTypeFilterLayout);
} else
gameTypeFilterGroupBox = 0;
gameTypeFilterGroupBox = nullptr;
QLabel *maxPlayersFilterMinLabel = new QLabel(tr("at &least:"));
auto *maxPlayersFilterMinLabel = new QLabel(tr("at &least:"));
maxPlayersFilterMinSpinBox = new QSpinBox;
maxPlayersFilterMinSpinBox->setMinimum(1);
maxPlayersFilterMinSpinBox->setMaximum(99);
maxPlayersFilterMinSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMin());
maxPlayersFilterMinLabel->setBuddy(maxPlayersFilterMinSpinBox);
QLabel *maxPlayersFilterMaxLabel = new QLabel(tr("at &most:"));
auto *maxPlayersFilterMaxLabel = new QLabel(tr("at &most:"));
maxPlayersFilterMaxSpinBox = new QSpinBox;
maxPlayersFilterMaxSpinBox->setMinimum(1);
maxPlayersFilterMaxSpinBox->setMaximum(99);
maxPlayersFilterMaxSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMax());
maxPlayersFilterMaxLabel->setBuddy(maxPlayersFilterMaxSpinBox);
QGridLayout *maxPlayersFilterLayout = new QGridLayout;
auto *maxPlayersFilterLayout = new QGridLayout;
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinLabel, 0, 0);
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinSpinBox, 0, 1);
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxLabel, 1, 0);
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxSpinBox, 1, 1);
QGroupBox *maxPlayersGroupBox = new QGroupBox(tr("Maximum player count"));
auto *maxPlayersGroupBox = new QGroupBox(tr("Maximum player count"));
maxPlayersGroupBox->setLayout(maxPlayersFilterLayout);
QGridLayout *restrictionsLayout = new QGridLayout;
restrictionsLayout->addWidget(unavailableGamesVisibleCheckBox, 0, 0);
restrictionsLayout->addWidget(showPasswordProtectedGames, 1, 0);
restrictionsLayout->addWidget(showBuddiesOnlyGames, 2, 0);
auto *restrictionsLayout = new QGridLayout;
restrictionsLayout->addWidget(showFullGames, 0, 0);
restrictionsLayout->addWidget(showGamesThatStarted, 1, 0);
restrictionsLayout->addWidget(showPasswordProtectedGames, 2, 0);
restrictionsLayout->addWidget(showBuddiesOnlyGames, 3, 0);
restrictionsLayout->addWidget(hideIgnoredUserGames, 4, 0);
QGroupBox *restrictionsGroupBox = new QGroupBox(tr("Restrictions"));
auto *restrictionsGroupBox = new QGroupBox(tr("Restrictions"));
restrictionsGroupBox->setLayout(restrictionsLayout);
QGridLayout *leftGrid = new QGridLayout;
showOnlyIfSpectatorsCanWatch = new QCheckBox(tr("Show games only if &spectators can watch"));
showOnlyIfSpectatorsCanWatch->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanWatch());
connect(showOnlyIfSpectatorsCanWatch, SIGNAL(toggled(bool)), this, SLOT(toggleSpectatorCheckboxEnabledness(bool)));
showSpectatorPasswordProtected = new QCheckBox(tr("Show spectator password p&rotected games"));
showSpectatorPasswordProtected->setChecked(gamesProxyModel->getShowSpectatorPasswordProtected());
showOnlyIfSpectatorsCanChat = new QCheckBox(tr("Show only if spectators can ch&at"));
showOnlyIfSpectatorsCanChat->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanChat());
showOnlyIfSpectatorsCanSeeHands = new QCheckBox(tr("Show only if spectators can see &hands"));
showOnlyIfSpectatorsCanSeeHands->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanSeeHands());
toggleSpectatorCheckboxEnabledness(getShowOnlyIfSpectatorsCanWatch());
auto *spectatorsLayout = new QGridLayout;
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanWatch, 0, 0);
spectatorsLayout->addWidget(showSpectatorPasswordProtected, 1, 0);
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanChat, 2, 0);
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanSeeHands, 3, 0);
auto *spectatorsGroupBox = new QGroupBox(tr("Spectators"));
spectatorsGroupBox->setLayout(spectatorsLayout);
auto *leftGrid = new QGridLayout;
leftGrid->addWidget(generalGroupBox, 0, 0, 1, 2);
leftGrid->addWidget(maxPlayersGroupBox, 2, 0, 1, 2);
leftGrid->addWidget(restrictionsGroupBox, 3, 0, 1, 2);
QVBoxLayout *leftColumn = new QVBoxLayout;
auto *leftColumn = new QVBoxLayout;
leftColumn->addLayout(leftGrid);
leftColumn->addStretch();
QVBoxLayout *rightColumn = new QVBoxLayout;
rightColumn->addWidget(gameTypeFilterGroupBox);
auto *rightGrid = new QGridLayout;
rightGrid->addWidget(gameTypeFilterGroupBox, 0, 0, 1, 1);
rightGrid->addWidget(spectatorsGroupBox, 1, 0, 1, 1);
QHBoxLayout *hbox = new QHBoxLayout;
auto *rightColumn = new QVBoxLayout;
rightColumn->addLayout(rightGrid);
rightColumn->addStretch();
auto *hbox = new QHBoxLayout;
hbox->addLayout(leftColumn);
hbox->addLayout(rightColumn);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
QVBoxLayout *mainLayout = new QVBoxLayout;
auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(hbox);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Filter games"));
setFixedHeight(sizeHint().height());
}
void DlgFilterGames::actOk()
@@ -124,14 +178,21 @@ void DlgFilterGames::actOk()
accept();
}
bool DlgFilterGames::getUnavailableGamesVisible() const
void DlgFilterGames::toggleSpectatorCheckboxEnabledness(bool spectatorsEnabled)
{
return unavailableGamesVisibleCheckBox->isChecked();
showSpectatorPasswordProtected->setDisabled(!spectatorsEnabled);
showOnlyIfSpectatorsCanChat->setDisabled(!spectatorsEnabled);
showOnlyIfSpectatorsCanSeeHands->setDisabled(!spectatorsEnabled);
}
void DlgFilterGames::setUnavailableGamesVisible(bool _unavailableGamesVisible)
bool DlgFilterGames::getShowFullGames() const
{
unavailableGamesVisibleCheckBox->setChecked(_unavailableGamesVisible);
return showFullGames->isChecked();
}
bool DlgFilterGames::getShowGamesThatStarted() const
{
return showGamesThatStarted->isChecked();
}
bool DlgFilterGames::getShowBuddiesOnlyGames() const
@@ -154,6 +215,16 @@ void DlgFilterGames::setShowPasswordProtectedGames(bool _passwordProtectedGamesH
showPasswordProtectedGames->setChecked(_passwordProtectedGamesHidden);
}
bool DlgFilterGames::getHideIgnoredUserGames() const
{
return hideIgnoredUserGames->isChecked();
}
void DlgFilterGames::setHideIgnoredUserGames(bool _hideIgnoredUserGames)
{
hideIgnoredUserGames->setChecked(_hideIgnoredUserGames);
}
QString DlgFilterGames::getGameNameFilter() const
{
return gameNameFilterEdit->text();
@@ -205,9 +276,38 @@ int DlgFilterGames::getMaxPlayersFilterMax() const
return maxPlayersFilterMaxSpinBox->value();
}
const QTime &DlgFilterGames::getMaxGameAge() const
{
int index = maxGameAgeComboBox->currentIndex();
if (index < 0 || index >= gameAgeMap.size()) { // index is out of bounds
return gamesProxyModel->getMaxGameAge(); // leave the setting unchanged
}
return gameAgeMap.keys().at(index);
}
void DlgFilterGames::setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax)
{
maxPlayersFilterMinSpinBox->setValue(_maxPlayersFilterMin);
maxPlayersFilterMaxSpinBox->setValue(_maxPlayersFilterMax == -1 ? maxPlayersFilterMaxSpinBox->maximum()
: _maxPlayersFilterMax);
}
bool DlgFilterGames::getShowOnlyIfSpectatorsCanWatch() const
{
return showOnlyIfSpectatorsCanWatch->isChecked();
}
bool DlgFilterGames::getShowSpectatorPasswordProtected() const
{
return showSpectatorPasswordProtected->isEnabled() && showSpectatorPasswordProtected->isChecked();
}
bool DlgFilterGames::getShowOnlyIfSpectatorsCanChat() const
{
return showOnlyIfSpectatorsCanChat->isEnabled() && showOnlyIfSpectatorsCanChat->isChecked();
}
bool DlgFilterGames::getShowOnlyIfSpectatorsCanSeeHands() const
{
return showOnlyIfSpectatorsCanSeeHands->isEnabled() && showOnlyIfSpectatorsCanSeeHands->isChecked();
}

View File

@@ -2,12 +2,16 @@
#define DLG_FILTER_GAMES_H
#include "gamesmodel.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDialog>
#include <QMap>
#include <QSet>
#include <QTime>
class QCheckBox;
class QComboBox;
class QGroupBox;
class QLineEdit;
class QSpinBox;
@@ -18,31 +22,42 @@ class DlgFilterGames : public QDialog
private:
QGroupBox *generalGroupBox;
QCheckBox *showBuddiesOnlyGames;
QCheckBox *unavailableGamesVisibleCheckBox;
QCheckBox *showFullGames;
QCheckBox *showGamesThatStarted;
QCheckBox *showPasswordProtectedGames;
QCheckBox *hideIgnoredUserGames;
QLineEdit *gameNameFilterEdit;
QLineEdit *creatorNameFilterEdit;
QMap<int, QCheckBox *> gameTypeFilterCheckBoxes;
QSpinBox *maxPlayersFilterMinSpinBox;
QSpinBox *maxPlayersFilterMaxSpinBox;
QComboBox *maxGameAgeComboBox;
QCheckBox *showOnlyIfSpectatorsCanWatch;
QCheckBox *showSpectatorPasswordProtected;
QCheckBox *showOnlyIfSpectatorsCanChat;
QCheckBox *showOnlyIfSpectatorsCanSeeHands;
const QMap<int, QString> &allGameTypes;
const GamesProxyModel *gamesProxyModel;
private slots:
void actOk();
void toggleSpectatorCheckboxEnabledness(bool spectatorsEnabled);
public:
DlgFilterGames(const QMap<int, QString> &_allGameTypes,
const GamesProxyModel *_gamesProxyModel,
QWidget *parent = 0);
QWidget *parent = nullptr);
bool getUnavailableGamesVisible() const;
void setUnavailableGamesVisible(bool _unavailableGamesVisible);
bool getShowFullGames() const;
bool getShowGamesThatStarted() const;
bool getShowPasswordProtectedGames() const;
void setShowPasswordProtectedGames(bool _passwordProtectedGamesHidden);
bool getShowBuddiesOnlyGames() const;
void setShowBuddiesOnlyGames(bool _showBuddiesOnlyGames);
bool getHideIgnoredUserGames() const;
void setHideIgnoredUserGames(bool _hideIgnoredUserGames);
QString getGameNameFilter() const;
void setGameNameFilter(const QString &_gameNameFilter);
QString getCreatorNameFilter() const;
@@ -52,6 +67,12 @@ public:
int getMaxPlayersFilterMin() const;
int getMaxPlayersFilterMax() const;
void setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax);
const QTime &getMaxGameAge() const;
const QMap<QTime, QString> gameAgeMap;
bool getShowOnlyIfSpectatorsCanWatch() const;
bool getShowSpectatorPasswordProtected() const;
bool getShowOnlyIfSpectatorsCanChat() const;
bool getShowOnlyIfSpectatorsCanSeeHands() const;
};
#endif

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