Compare commits
308 commits
2026-01-05
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b17d879da8 | ||
|
|
6be9cec6e2 | ||
|
|
6d0a423dcf | ||
|
|
f72c82d0f9 | ||
|
|
da4ba222c0 | ||
|
|
cbfd286908 | ||
|
|
487bb84b6f | ||
|
|
9e03f82616 | ||
|
|
e674a39b87 | ||
|
|
1efc382c05 | ||
|
|
dc152e89f7 | ||
|
|
20cdcdb382 | ||
|
|
23da49ee5b | ||
|
|
c14a008080 | ||
|
|
0da2ac4087 | ||
|
|
29cc622ce3 | ||
|
|
86256602ff | ||
|
|
f37c418865 | ||
|
|
46d3b820db | ||
|
|
e0cbb7f06c | ||
|
|
f52dc6dda8 | ||
|
|
3fa377a11c | ||
|
|
c5372a9e92 | ||
|
|
6de55e9096 | ||
|
|
43c3bf5966 | ||
|
|
c4f4cece01 | ||
|
|
0d7047a728 | ||
|
|
7f30728f87 | ||
|
|
1d5d3f2d38 | ||
|
|
b3c89167c5 | ||
|
|
90ab663212 | ||
|
|
98c00c55ed | ||
|
|
d2164c3f08 | ||
|
|
8004d4f2d4 | ||
|
|
8751f0605d | ||
|
|
09d817770e | ||
|
|
81a2712b92 | ||
|
|
8dca14933c | ||
|
|
74102aa1ec | ||
|
|
a9003be30f | ||
|
|
6faa0d54e3 | ||
|
|
33e0f8699b | ||
|
|
03d54265fe | ||
|
|
491d1c9187 | ||
|
|
bddf9bd818 | ||
|
|
0549892092 | ||
|
|
10b9a65f17 | ||
|
|
5219cffa6b | ||
|
|
71790d8e10 | ||
|
|
fe31a49f86 | ||
|
|
55c84ca860 | ||
|
|
40b947c1e7 | ||
|
|
40cef0e436 | ||
|
|
9f1c225b7a | ||
|
|
af2f888293 | ||
|
|
7a5b2e9f0e | ||
|
|
021a9f8383 | ||
|
|
cba9ce2b2b | ||
|
|
bb1a5b33a1 | ||
|
|
6ac340026f | ||
|
|
059eeebe89 | ||
|
|
117ea543c5 | ||
|
|
989a5be23b | ||
|
|
f8ce5c2e39 | ||
|
|
20cd7ce73d | ||
|
|
aadee34238 | ||
|
|
7153f7d4c1 | ||
|
|
762e742be0 | ||
|
|
67f6ab66f0 | ||
|
|
7507103bb2 | ||
|
|
fe12f4cbb9 | ||
|
|
d18f3bce47 | ||
|
|
b66743c83c | ||
|
|
1a62f82aee | ||
|
|
5735a44a9a | ||
|
|
dbaf5f2e05 | ||
|
|
9c53dad4b8 | ||
|
|
7814204fe2 | ||
|
|
cdb171f201 | ||
|
|
48e21aad38 | ||
|
|
f223ff387e | ||
|
|
8845a75627 | ||
|
|
caf2bb9ded | ||
|
|
985936a917 | ||
|
|
2c51054e77 | ||
|
|
f7eeaeddcb | ||
|
|
6cace2a8e6 | ||
|
|
6b5f341e10 | ||
|
|
63143f9416 | ||
|
|
efe52b5412 | ||
|
|
0e014c0e5c | ||
|
|
511ccae738 | ||
|
|
0672603755 | ||
|
|
f5f326f65b | ||
|
|
c5702cc8b6 | ||
|
|
4f2f942121 | ||
|
|
a4c2b1411f | ||
|
|
43bee2316e | ||
|
|
19dbb17fb9 | ||
|
|
7c9fbe2be0 | ||
|
|
d30690236a | ||
|
|
ac2e995f15 | ||
|
|
dac611f0f1 | ||
|
|
45ab2602c6 | ||
|
|
5101cc3d74 | ||
|
|
9ac9a0c73a | ||
|
|
314a577807 | ||
|
|
c5ace60f26 | ||
|
|
8953ae3c67 | ||
|
|
b1fe4c85d3 | ||
|
|
a20f3c0fb4 | ||
|
|
9226bc9ddd | ||
|
|
501c4b96d4 | ||
|
|
6ab947418c | ||
|
|
6765831b92 | ||
|
|
98c4e829f8 | ||
|
|
ccb9901b28 | ||
|
|
58a8c7d3df | ||
|
|
655a8e52a1 | ||
|
|
db235ecae8 | ||
|
|
682ac4ed0c | ||
|
|
77978c7178 | ||
|
|
e918856fa4 | ||
|
|
87c4216e80 | ||
|
|
832f70496a | ||
|
|
f97864b72b | ||
|
|
338c56678a | ||
|
|
8cc65b8967 | ||
|
|
2e10b2f5d5 | ||
|
|
92fe406c22 | ||
|
|
d677e2bb70 | ||
|
|
e977f123ce | ||
|
|
f56b672307 | ||
|
|
29c1d7f3e4 | ||
|
|
36aba81b1b | ||
|
|
f9fb03b26b | ||
|
|
d2732ac742 | ||
|
|
9aa5702e14 | ||
|
|
2d412bfe52 | ||
|
|
ac06fb9d1c | ||
|
|
d7b31f2f9d | ||
|
|
635fae101d | ||
|
|
335022c4aa | ||
|
|
dbed6890da | ||
|
|
3ec9ae9772 | ||
|
|
a46ab5cd68 | ||
|
|
690a00aa6c | ||
|
|
ba786a0289 | ||
|
|
9dfac77ba2 | ||
|
|
f3370a4f52 | ||
|
|
7caa88bc58 | ||
|
|
34a5b8b9ce | ||
|
|
d8e3807ec5 | ||
|
|
42bd8164a0 | ||
|
|
abf6e72ad1 | ||
|
|
74cce5ccb2 | ||
|
|
dd053c76df | ||
|
|
5ef428b9d0 | ||
|
|
94ea574c76 | ||
|
|
70b41c2095 | ||
|
|
aa85a39d6a | ||
|
|
51c684251f | ||
|
|
fa2934373c | ||
|
|
414567f8b6 | ||
|
|
bc219191db | ||
|
|
652c8464a7 | ||
|
|
067fe9b534 | ||
|
|
38c85e6db1 | ||
|
|
c5cd7d8700 | ||
|
|
fc453c68a7 | ||
|
|
69c046cca4 | ||
|
|
dd8164611b | ||
|
|
b4a5c863d7 | ||
|
|
4a3d79d00b | ||
|
|
96f436b65e | ||
|
|
cf01dc770b | ||
|
|
ce652de272 | ||
|
|
9bb399606c | ||
|
|
8180d2e3b0 | ||
|
|
33d5721490 | ||
|
|
2b2a6db081 | ||
|
|
aa4592dc9e | ||
|
|
20ad9af989 | ||
|
|
9e2276a59f | ||
|
|
42cec10457 | ||
|
|
95d7e027fc | ||
|
|
8268311fab | ||
|
|
413b4b637b | ||
|
|
e79bbc67b9 | ||
|
|
15a1d5440b | ||
|
|
fd293444c5 | ||
|
|
852429f248 | ||
|
|
4606fcdbd5 | ||
|
|
c375cdbb1a | ||
|
|
f15b70e4ae | ||
|
|
2f10634ca2 | ||
|
|
dead993639 | ||
|
|
bd5cbb89d4 | ||
|
|
14f1925edc | ||
|
|
e39bbd2b31 | ||
|
|
04f06206b7 | ||
|
|
1bcea27a44 | ||
|
|
e7a3ad86eb | ||
|
|
b36ab66583 | ||
|
|
566c876bdc | ||
|
|
43acac5f5d | ||
|
|
846ecb7e8d | ||
|
|
2fba5dcd20 | ||
|
|
2828854d32 | ||
|
|
9794893b63 | ||
|
|
e57ee8e9c9 | ||
|
|
f978407a19 | ||
|
|
59ce70afc5 | ||
|
|
208ccc3a1a | ||
|
|
6f8f9f016a | ||
|
|
7ad2481e3d | ||
|
|
12c667afd7 | ||
|
|
2cb16c9fd0 | ||
|
|
9f00c6f955 | ||
|
|
a90997353b | ||
|
|
c6dc7eee64 | ||
|
|
0f2899b5c7 | ||
|
|
71cf3fabbf | ||
|
|
f0da3cff40 | ||
|
|
485e4d56aa | ||
|
|
99424e460b | ||
|
|
006abf79b1 | ||
|
|
5c3c3bfdba | ||
|
|
189f3a7bbc | ||
|
|
6ab558dd58 | ||
|
|
a7bb5254a3 | ||
|
|
ef87b54b43 | ||
|
|
88d0ebb12d | ||
|
|
bdb42bbbbd | ||
|
|
ac7ff3a0e9 | ||
|
|
1eb6027443 | ||
|
|
edc8691731 | ||
|
|
804a60f1ea | ||
|
|
a80a0531a6 | ||
|
|
24bc713ba8 | ||
|
|
4884640070 | ||
|
|
8d7535c039 | ||
|
|
32aa60bb14 | ||
|
|
3ada27eae1 | ||
|
|
a096a0e3bb | ||
|
|
d410078673 | ||
|
|
bf5891a910 | ||
|
|
c7249dfbd9 | ||
|
|
1b29e0bfa8 | ||
|
|
5cc5767c87 | ||
|
|
165c4ddd2a | ||
|
|
7b64970e97 | ||
|
|
5309dd17be | ||
|
|
364470b3c8 | ||
|
|
915da79cad | ||
|
|
630c71f123 | ||
|
|
0b4e7be596 | ||
|
|
303bd8b607 | ||
|
|
c02cf5e89e | ||
|
|
92f02fa4ee | ||
|
|
49e6cf95c4 | ||
|
|
8a126263a9 | ||
|
|
afdb385770 | ||
|
|
5b8897231d | ||
|
|
ffc55aff10 | ||
|
|
2b372c14e4 | ||
|
|
12b5525a2d | ||
|
|
3c48d92663 | ||
|
|
948ec9e042 | ||
|
|
5a274fdbed | ||
|
|
bfeb3a7ca9 | ||
|
|
d363ec5154 | ||
|
|
999733fc0f | ||
|
|
8d274c1924 | ||
|
|
2e1a0bec93 | ||
|
|
39ddaa0c35 | ||
|
|
d9b9c79112 | ||
|
|
485d5a8b48 | ||
|
|
f7e71a0868 | ||
|
|
af2995ba96 | ||
|
|
f7ffcc58fe | ||
|
|
792f077071 | ||
|
|
9c07c7a963 | ||
|
|
d579c82cb9 | ||
|
|
c7c7bf550a | ||
|
|
84483c56d7 | ||
|
|
1b71519ec6 | ||
|
|
154b9ace92 | ||
|
|
93f0715d02 | ||
|
|
57e6c91689 | ||
|
|
6213ccff48 | ||
|
|
c075deeb2d | ||
|
|
29f60c4a67 | ||
|
|
c553e15036 | ||
|
|
a4eef648bc | ||
|
|
47720ff286 | ||
|
|
289b139be9 | ||
|
|
21d60ec3f1 | ||
|
|
ed1115f4c0 | ||
|
|
cc5e2ab10a | ||
|
|
b19312be70 | ||
|
|
a0d1359860 | ||
|
|
52547bbfe8 | ||
|
|
9ab398f08d | ||
|
|
0deaa9d9b4 | ||
|
|
7c7755b61d | ||
|
|
6340c4a6b7 | ||
|
|
0a2fdb05ad |
|
|
@ -1,26 +0,0 @@
|
||||||
FROM debian:11
|
|
||||||
|
|
||||||
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 \
|
|
||||||
ninja-build \
|
|
||||||
protobuf-compiler \
|
|
||||||
qt5-image-formats-plugins \
|
|
||||||
qtmultimedia5-dev \
|
|
||||||
qttools5-dev \
|
|
||||||
qttools5-dev-tools \
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM fedora:42
|
FROM fedora:44
|
||||||
|
|
||||||
RUN dnf install -y \
|
RUN dnf install -y \
|
||||||
ccache \
|
ccache \
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM debian:11
|
FROM debian:12
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
|
@ -11,11 +11,11 @@ RUN apt-get update && \
|
||||||
git \
|
git \
|
||||||
libmariadb-dev-compat \
|
libmariadb-dev-compat \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt5sql5-mysql \
|
libqt6sql6-mysql \
|
||||||
libqt5websockets5-dev \
|
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qttools5-dev \
|
qt6-tools-dev \
|
||||||
qttools5-dev-tools \
|
qt6-tools-dev-tools \
|
||||||
|
qt6-websockets-dev \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
FROM ubuntu:22.04
|
FROM ubuntu:26.04
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
build-essential \
|
build-essential \
|
||||||
|
ca-certificates \
|
||||||
ccache \
|
ccache \
|
||||||
clang-format \
|
clang-format \
|
||||||
cmake \
|
cmake \
|
||||||
|
|
@ -15,14 +16,14 @@ RUN apt-get update && \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt6multimedia6 \
|
||||||
libqt6sql6-mysql \
|
libqt6sql6-mysql \
|
||||||
libqt6svg6-dev \
|
|
||||||
libqt6websockets6-dev \
|
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt6-image-formats-plugins \
|
||||||
qt6-l10n-tools \
|
qt6-l10n-tools \
|
||||||
qt6-multimedia-dev \
|
qt6-multimedia-dev \
|
||||||
|
qt6-svg-dev \
|
||||||
qt6-tools-dev \
|
qt6-tools-dev \
|
||||||
qt6-tools-dev-tools \
|
qt6-tools-dev-tools \
|
||||||
|
qt6-websockets-dev \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
@ -10,9 +10,11 @@
|
||||||
# --test runs tests
|
# --test runs tests
|
||||||
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
|
||||||
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
# --ccache [<size>] uses ccache and shows stats, optionally provide size
|
||||||
|
# --evict-ccache <age> runs ccache eviction based on given age after build
|
||||||
# --dir <dir> sets the name of the build dir, default is "build"
|
# --dir <dir> sets the name of the build dir, default is "build"
|
||||||
|
# --cmake-generator <generator> sets CMAKE_GENERATOR as used by cmake
|
||||||
# --target-macos-version <version> sets the min os version - only used for macOS builds
|
# --target-macos-version <version> sets the min os version - only used for macOS builds
|
||||||
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION
|
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE CCACHE_EVICTION_AGE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION
|
||||||
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir>)
|
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir>)
|
||||||
# exitcode: 1 for failure, 3 for invalid arguments
|
# exitcode: 1 for failure, 3 for invalid arguments
|
||||||
|
|
||||||
|
|
@ -71,6 +73,15 @@ while [[ $# != 0 ]]; do
|
||||||
shift
|
shift
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
'--evict-ccache')
|
||||||
|
shift
|
||||||
|
if [[ $# == 0 ]]; then
|
||||||
|
echo "::error file=$0::--evict-ccache expects an argument"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
CCACHE_EVICTION_AGE=$1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
'--vcpkg')
|
'--vcpkg')
|
||||||
USE_VCPKG=1
|
USE_VCPKG=1
|
||||||
shift
|
shift
|
||||||
|
|
@ -84,6 +95,15 @@ while [[ $# != 0 ]]; do
|
||||||
BUILD_DIR="$1"
|
BUILD_DIR="$1"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
'--cmake-generator')
|
||||||
|
shift
|
||||||
|
if [[ $# == 0 ]]; then
|
||||||
|
echo "::error file=$0::--cmake-generator expects an argument"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
export CMAKE_GENERATOR=$1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
'--target-macos-version')
|
'--target-macos-version')
|
||||||
shift
|
shift
|
||||||
if [[ $# == 0 ]]; then
|
if [[ $# == 0 ]]; then
|
||||||
|
|
@ -183,7 +203,11 @@ if [[ $RUNNER_OS == macOS ]]; then
|
||||||
arch="x64"
|
arch="x64"
|
||||||
fi
|
fi
|
||||||
mkdir -p "$triplets_dir"
|
mkdir -p "$triplets_dir"
|
||||||
cp "../vcpkg/triplets/$arch-osx.cmake" "$triplet_file"
|
triplet_source="../vcpkg/triplets/$arch-osx.cmake"
|
||||||
|
if [[ ! -f "$triplet_source" ]]; then
|
||||||
|
triplet_source="../vcpkg/triplets/community/$arch-osx.cmake"
|
||||||
|
fi
|
||||||
|
cp "$triplet_source" "$triplet_file"
|
||||||
echo "set(VCPKG_CMAKE_SYSTEM_VERSION $TARGET_MACOS_VERSION)" >>"$triplet_file"
|
echo "set(VCPKG_CMAKE_SYSTEM_VERSION $TARGET_MACOS_VERSION)" >>"$triplet_file"
|
||||||
echo "set(VCPKG_OSX_DEPLOYMENT_TARGET $TARGET_MACOS_VERSION)" >>"$triplet_file"
|
echo "set(VCPKG_OSX_DEPLOYMENT_TARGET $TARGET_MACOS_VERSION)" >>"$triplet_file"
|
||||||
flags+=("-DVCPKG_OVERLAY_TRIPLETS=$triplets_dir")
|
flags+=("-DVCPKG_OVERLAY_TRIPLETS=$triplets_dir")
|
||||||
|
|
@ -251,9 +275,16 @@ cmake --build . "${buildflags[@]}"
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
|
|
||||||
if [[ $USE_CCACHE ]]; then
|
if [[ $USE_CCACHE ]]; then
|
||||||
|
if [[ $CCACHE_EVICTION_AGE ]]; then
|
||||||
|
echo "::group::evict ccache files older than $CCACHE_EVICTION_AGE"
|
||||||
|
ccache --evict-older-than "$CCACHE_EVICTION_AGE"
|
||||||
|
echo "::endgroup::"
|
||||||
|
fi
|
||||||
echo "::group::Show ccache stats again"
|
echo "::group::Show ccache stats again"
|
||||||
ccachestatsverbose
|
ccachestatsverbose
|
||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
|
elif [[ $CCACHE_EVICTION_AGE ]]; then
|
||||||
|
echo "::error file=$0::ccache eviction is enabled while ccache is disabled!"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $RUNNER_OS == macOS ]]; then
|
if [[ $RUNNER_OS == macOS ]]; then
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,28 @@
|
||||||
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
|
# 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.
|
# Creates or loads docker images to use in compilation, creates RUN function to start compilation on the docker image.
|
||||||
# <arg> sets the name of the docker image, these correspond to directories in .ci
|
#
|
||||||
|
# usage: source <script> <name> [--get] [--build] [--save] [--interactive] [--set-cache <location>]
|
||||||
|
# <name> sets the name of the docker image, these correspond to directories in .ci
|
||||||
# --get loads the image from a previously saved image cache, will build if no image is found
|
# --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
|
# --build builds the image from the Dockerfile in .ci/$NAME
|
||||||
# --save stores the image, if an image was loaded it will not be stored
|
# --save stores the image, if an image was loaded it will not be stored
|
||||||
# --interactive immediately starts the image interactively for debugging
|
# --interactive immediately starts the image interactively for debugging
|
||||||
# --set-cache <location> sets the location to cache the image or for ccache
|
# --set-cache <location> sets the location to cache the image or for ccache
|
||||||
|
#
|
||||||
# requires: docker
|
# requires: docker
|
||||||
# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE
|
# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE
|
||||||
# (correspond to args: <name> --set-cache <cache> --build --get --save --interactive)
|
# (correspond to args: <name> --set-cache <cache> --build --get --save --interactive)
|
||||||
# sets env: RUN CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT
|
# 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
|
# exitcode: 1 for failure, 2 for missing dockerfile, 3 for invalid arguments
|
||||||
|
#
|
||||||
|
# exported RUN function will run the BUILD_SCRIPT inside of the docker container.
|
||||||
|
# note that the docker container will not inherit any environment variables!
|
||||||
|
#
|
||||||
|
# usage: RUN [arguments for build script]
|
||||||
|
# roughly equivalent to `docker run $IMAGE_NAME bash $BUILD_SCRIPT $@`
|
||||||
|
# uses env: CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT
|
||||||
|
# exitcode: 3 for invalid arguments, returns the returncode of docker run
|
||||||
export BUILD_SCRIPT=".ci/compile.sh"
|
export BUILD_SCRIPT=".ci/compile.sh"
|
||||||
|
|
||||||
project_name="cockatrice"
|
project_name="cockatrice"
|
||||||
|
|
@ -41,12 +52,17 @@ while [[ $# != 0 ]]; do
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
'--set-cache')
|
'--set-cache')
|
||||||
CACHE=$2
|
shift
|
||||||
|
if [[ $# == 0 ]]; then
|
||||||
|
echo "--set-cache expects an argument" >&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
CACHE=$1
|
||||||
|
shift
|
||||||
if ! [[ -d $CACHE ]]; then
|
if ! [[ -d $CACHE ]]; then
|
||||||
echo "could not find cache path: $CACHE" >&2
|
echo "could not find cache path: $CACHE" >&2
|
||||||
return 3
|
return 3
|
||||||
fi
|
fi
|
||||||
shift 2
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [[ ${1:0:1} == - ]]; then
|
if [[ ${1:0:1} == - ]]; then
|
||||||
|
|
@ -149,10 +165,11 @@ function RUN ()
|
||||||
args+=(--mount "type=bind,source=$CCACHE_DIR,target=/.ccache")
|
args+=(--mount "type=bind,source=$CCACHE_DIR,target=/.ccache")
|
||||||
args+=(--env "CCACHE_DIR=/.ccache")
|
args+=(--env "CCACHE_DIR=/.ccache")
|
||||||
fi
|
fi
|
||||||
if [[ -n "$CMAKE_GENERATOR" ]]; then
|
if [[ $GITHUB_OUTPUT ]]; then
|
||||||
args+=(--env "CMAKE_GENERATOR=$CMAKE_GENERATOR")
|
args+=(--mount "type=bind,source=$GITHUB_OUTPUT,target=/gh_output")
|
||||||
|
args+=(--env "GITHUB_OUTPUT=/gh_output")
|
||||||
fi
|
fi
|
||||||
# shellcheck disable=2086
|
# shellcheck disable=2086
|
||||||
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
|
||||||
return $?
|
return $?
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,9 @@ fi
|
||||||
# Check formatting using format.sh
|
# Check formatting using format.sh
|
||||||
echo "Checking your code using format.sh..."
|
echo "Checking your code using format.sh..."
|
||||||
|
|
||||||
diff="$(./format.sh --diff --cmake --shell --print-version --branch origin/master)"
|
./format.sh --color-diff --cmake --shell --print-version --branch origin/master
|
||||||
err=$?
|
err=$?
|
||||||
|
|
||||||
sep="
|
|
||||||
----------
|
|
||||||
"
|
|
||||||
used_version="${diff%%"$sep"*}"
|
|
||||||
diff="${diff#*"$sep"}"
|
|
||||||
changes_to_make="${diff%%"$sep"*}"
|
|
||||||
files_to_edit="${diff#*"$sep"}"
|
|
||||||
|
|
||||||
case $err in
|
case $err in
|
||||||
1)
|
1)
|
||||||
cat <<EOM
|
cat <<EOM
|
||||||
|
|
@ -36,19 +28,10 @@ case $err in
|
||||||
*** Then commit and push those changes to this branch. ***
|
*** Then commit and push those changes to this branch. ***
|
||||||
*** Check our CONTRIBUTING.md file for more details. ***
|
*** Check our CONTRIBUTING.md file for more details. ***
|
||||||
*** ***
|
*** ***
|
||||||
*** Thank you ❤️ ***
|
*** Thank you ❤️ ***
|
||||||
*** ***
|
*** ***
|
||||||
***********************************************************
|
***********************************************************
|
||||||
|
|
||||||
Used version:
|
|
||||||
$used_version
|
|
||||||
|
|
||||||
Affected files:
|
|
||||||
$files_to_edit
|
|
||||||
|
|
||||||
The following changes should be made:
|
|
||||||
$changes_to_make
|
|
||||||
|
|
||||||
Exiting...
|
Exiting...
|
||||||
EOM
|
EOM
|
||||||
exit 2
|
exit 2
|
||||||
|
|
@ -65,9 +48,6 @@ EOM
|
||||||
*** ***
|
*** ***
|
||||||
***********************************************************
|
***********************************************************
|
||||||
|
|
||||||
Used version:
|
|
||||||
$used_version
|
|
||||||
|
|
||||||
Exiting...
|
Exiting...
|
||||||
EOM
|
EOM
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
# used by the ci to rename build artifacts
|
# used by the ci to rename build artifacts
|
||||||
# renames the file to [original name][SUFFIX].[original extension]
|
# renames the file to [original name][SUFFIX].[original extension]
|
||||||
# where SUFFIX is either available in the environment or as the first arg
|
# 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 unless BUILD_DIR is set
|
# expected to be run in the build directory unless BUILD_DIR is set
|
||||||
# adds output to GITHUB_OUTPUT
|
# adds output to GITHUB_OUTPUT
|
||||||
builddir="${BUILD_DIR:=.}"
|
builddir="${BUILD_DIR:=.}"
|
||||||
|
|
@ -22,8 +21,8 @@ set -e
|
||||||
|
|
||||||
# find file
|
# find file
|
||||||
found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)"
|
found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)"
|
||||||
path="${found%/*}" # remove all after last /
|
path="${found%/*}" # remove all including first "/" from right side
|
||||||
file="${found##*/}" # remove all before last /
|
file="${found##*/}" # remove all including last "/" from left side
|
||||||
if [[ ! $file ]]; then
|
if [[ ! $file ]]; then
|
||||||
echo "::error file=$0::could not find package"
|
echo "::error file=$0::could not find package"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
@ -35,21 +34,16 @@ if ! cd "$path"; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# set filename
|
# set filename
|
||||||
name="${file%.*}" # remove all after last .
|
name="${file%.*}" # remove all including first "." from right side
|
||||||
new_name="$name$SUFFIX."
|
new_name="$name$SUFFIX"
|
||||||
if [[ $MAKE_ZIP ]]; then
|
extension="${file##*.}" # remove all including last "." from left side
|
||||||
filename="${new_name}zip"
|
filename="$new_name.$extension"
|
||||||
echo "creating zip '$filename' from '$file'"
|
echo "renaming '$file' to '$filename'"
|
||||||
zip "$filename" "$file"
|
mv "$file" "$filename"
|
||||||
else
|
|
||||||
extension="${file##*.}" # remove all before last .
|
|
||||||
filename="$new_name$extension"
|
|
||||||
echo "renaming '$file' to '$filename'"
|
|
||||||
mv "$file" "$filename"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$oldpwd"
|
cd "$oldpwd"
|
||||||
relative_path="$path/$filename"
|
relative_path="$path/$filename"
|
||||||
ls -l "$relative_path"
|
ls -l "$relative_path"
|
||||||
echo "path=$relative_path" >>"$GITHUB_OUTPUT"
|
echo "path=$relative_path" >>"$GITHUB_OUTPUT"
|
||||||
echo "name=$filename" >>"$GITHUB_OUTPUT"
|
echo "name=$new_name" >>"$GITHUB_OUTPUT"
|
||||||
|
echo "fullname=$filename" >>"$GITHUB_OUTPUT"
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,8 @@ else
|
||||||
echo "'$previous' to '$TAG' ($count commits)"
|
echo "'$previous' to '$TAG' ($count commits)"
|
||||||
# --> is the markdown comment escape sequence, emojis are way better
|
# --> is the markdown comment escape sequence, emojis are way better
|
||||||
generated_list="${generated_list//-->/→}"
|
generated_list="${generated_list//-->/→}"
|
||||||
|
# Escape & to preserve it from commit message into markdown output
|
||||||
|
generated_list="${generated_list//&/\\&}"
|
||||||
body="${body//--REPLACE-WITH-GENERATED-LIST--/$generated_list}"
|
body="${body//--REPLACE-WITH-GENERATED-LIST--/$generated_list}"
|
||||||
body="${body//--REPLACE-WITH-COMMIT-COUNT--/$count}"
|
body="${body//--REPLACE-WITH-COMMIT-COUNT--/$count}"
|
||||||
body="${body//--REPLACE-WITH-PREVIOUS-RELEASE-TAG--/$previous}"
|
body="${body//--REPLACE-WITH-PREVIOUS-RELEASE-TAG--/$previous}"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ Available pre-compiled binaries for installation:
|
||||||
|
|
||||||
<b>Windows</b>
|
<b>Windows</b>
|
||||||
• <kbd>Windows 10+</kbd>
|
• <kbd>Windows 10+</kbd>
|
||||||
• <kbd>Windows 7+</kbd>
|
|
||||||
|
|
||||||
<b>macOS</b>
|
<b>macOS</b>
|
||||||
• <kbd>macOS 15+</kbd> <sub><i>Sequoia</i></sub> <sub>Apple M</sub>
|
• <kbd>macOS 15+</kbd> <sub><i>Sequoia</i></sub> <sub>Apple M</sub>
|
||||||
|
|
@ -18,16 +17,17 @@ Available pre-compiled binaries for installation:
|
||||||
• <kbd>macOS 13+</kbd> <sub><i>Ventura</i></sub> <sub>Intel</sub>
|
• <kbd>macOS 13+</kbd> <sub><i>Ventura</i></sub> <sub>Intel</sub>
|
||||||
|
|
||||||
<b>Linux</b>
|
<b>Linux</b>
|
||||||
|
• <kbd>Ubuntu 26.04 LTS</kbd> <sub><i>Resolute Racoon</i></sub>
|
||||||
• <kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
|
• <kbd>Ubuntu 24.04 LTS</kbd> <sub><i>Noble Numbat</i></sub>
|
||||||
• <kbd>Ubuntu 22.04 LTS</kbd> <sub><i>Jammy Jellyfish</i></sub>
|
|
||||||
• <kbd>Debian 13</kbd> <sub><i>Trixie</i></sub>
|
• <kbd>Debian 13</kbd> <sub><i>Trixie</i></sub>
|
||||||
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
|
• <kbd>Debian 12</kbd> <sub><i>Bookworm</i></sub>
|
||||||
• <kbd>Debian 11</kbd> <sub><i>Bullseye</i></sub>
|
• <kbd>Fedora 44</kbd>
|
||||||
• <kbd>Fedora 43</kbd>
|
• <kbd>Fedora 43</kbd>
|
||||||
• <kbd>Fedora 42</kbd>
|
|
||||||
|
|
||||||
<sub>We are also packaged in <kbd>Arch Linux</kbd>'s <a href="https://archlinux.org/packages/extra/x86_64/cockatrice">official extra repository</a>, courtesy of @FFY00.</sub>
|
<sub>We are also packaged in <kbd>Arch Linux</kbd>'s <a href="https://archlinux.org/packages/extra/x86_64/cockatrice">official extra repository</a>, courtesy of @FFY00.</sub>
|
||||||
<sub>General Linux support is available via a <kbd>flatpak</kbd> package at <a href="https://flathub.org/apps/io.github.Cockatrice.cockatrice">Flathub</a>!</sub>
|
<sub>General Linux support is available via a <kbd>flatpak</kbd> package at <a href="https://flathub.org/apps/io.github.Cockatrice.cockatrice">Flathub</a>!</sub>
|
||||||
|
|
||||||
|
<sub>We provide a <kbd>Docker</kbd> image for "Servatrice" in <a href="https://github.com/Cockatrice/Cockatrice/pkgs/container/servatrice">GHCR</a>. You can docker pull it or use our Docker Compose files!</sub>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -83,7 +83,6 @@ Remove empty headers when done.
|
||||||
### Under the Hood
|
### Under the Hood
|
||||||
### Oracle
|
### Oracle
|
||||||
### Servatrice
|
### Servatrice
|
||||||
### Webatrice
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,16 @@ if ! hash aqt; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Resolve latest patch
|
# Resolve latest patch
|
||||||
if ! qt_resolved=$(aqt list-qt mac desktop --spec "$qt_spec" --latest-version); then
|
if [[ $RUNNER_OS == macOS ]]; then
|
||||||
|
if ! qt_resolved=$(aqt list-qt mac desktop --spec "$qt_spec" --latest-version); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
elif [[ $RUNNER_OS == Windows ]]; then
|
||||||
|
if ! qt_resolved=$(aqt list-qt windows desktop --spec "$qt_spec" --latest-version); then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "aqt command for $RUNNER_OS not defined."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ AccessModifierOffset: -4
|
||||||
ColumnLimit: 120
|
ColumnLimit: 120
|
||||||
---
|
---
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
BreakBeforeBraces: Custom
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
BinPackParameters: false
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterClass: true
|
AfterClass: true
|
||||||
AfterControlStatement: false
|
AfterControlStatement: false
|
||||||
|
|
@ -18,16 +20,14 @@ BraceWrapping:
|
||||||
SplitEmptyFunction: true
|
SplitEmptyFunction: true
|
||||||
SplitEmptyRecord: true
|
SplitEmptyRecord: true
|
||||||
SplitEmptyNamespace: true
|
SplitEmptyNamespace: true
|
||||||
AllowShortFunctionsOnASingleLine: None
|
BreakBeforeBraces: Custom
|
||||||
BinPackParameters: false
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
|
||||||
IndentCaseLabels: true
|
|
||||||
PointerAlignment: Right
|
|
||||||
SortIncludes: true
|
|
||||||
IncludeBlocks: Regroup
|
IncludeBlocks: Regroup
|
||||||
|
IndentCaseLabels: true
|
||||||
|
InsertBraces: true
|
||||||
|
PointerAlignment: Right
|
||||||
|
RemoveSemicolon: true
|
||||||
|
SortIncludes: true
|
||||||
StatementAttributeLikeMacros: [emit]
|
StatementAttributeLikeMacros: [emit]
|
||||||
# requires clang-format 16
|
|
||||||
# RemoveSemicolon: true
|
|
||||||
---
|
---
|
||||||
Language: Proto
|
Language: Proto
|
||||||
AllowShortFunctionsOnASingleLine: None
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|
|
||||||
16
.github/CONTRIBUTING.md
vendored
|
|
@ -209,6 +209,16 @@ nowadays and clean it up for you.
|
||||||
Lines should be 120 characters or less. Please break up lines that are too long
|
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.
|
into smaller parts, for example at spaces or after opening a brace.
|
||||||
|
|
||||||
|
### Documentation Comments ###
|
||||||
|
|
||||||
|
Use [Doxygen](https://www.doxygen.nl/) for code documentation:
|
||||||
|
|
||||||
|
- **Doc blocks**: Use `/** @brief Description */` (Javadoc-style), not `///`
|
||||||
|
- **Member comments**: Use trailing `///<` for inline member documentation
|
||||||
|
- **TODOs**: Use `//! \todo Description` (Qt-style), Doxygen collects them into a Todo List
|
||||||
|
(uses [Qt-style comments](https://www.doxygen.nl/manual/docblocks.html) with
|
||||||
|
Doxygen's [\todo command](https://www.doxygen.nl/manual/commands.html#cmdtodo))
|
||||||
|
|
||||||
### Memory Management ###
|
### Memory Management ###
|
||||||
|
|
||||||
New code should be written using references over pointers and stack allocation
|
New code should be written using references over pointers and stack allocation
|
||||||
|
|
@ -461,7 +471,11 @@ revoke the tag by doing the following:
|
||||||
git push --delete upstream $TAG_NAME
|
git push --delete upstream $TAG_NAME
|
||||||
git tag -d $TAG_NAME
|
git tag -d $TAG_NAME
|
||||||
```
|
```
|
||||||
You can also do this on GitHub, you'll also want to delete the false release.
|
You can also do this on GitHub.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> If you want to push a new release to replace it immediately with the same
|
||||||
|
> name you have to delete the automatically created release first!
|
||||||
|
|
||||||
In the first lines of [CMakeLists.txt](
|
In the first lines of [CMakeLists.txt](
|
||||||
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
||||||
|
|
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,9 +1,12 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 💬 Discord Community (Get help with server issues, e.g. Login)
|
- name: 💬 Discord Community (Get help with server issues, e.g. Login)
|
||||||
url: https://discord.gg/3Z9yzmA
|
url: https://discord.com/invite/3Z9yzmA
|
||||||
about: Need help with using the client? Want to find some games? Try the Discord server!
|
about: Need help with using the client? Want to find some games? Try the Discord server!
|
||||||
- name: 🌐 Translations (Help improve the localization of the app)
|
- name: 🌐 Translations (Help improve the localization of the app)
|
||||||
url: https://explore.transifex.com/cockatrice/cockatrice/
|
url: https://explore.transifex.com/cockatrice/cockatrice/
|
||||||
# it is not possible to add a link to the wiki to this description
|
# it is not possible to add a link to the wiki to this description
|
||||||
about: For more information and guidance check our Translation FAQ on our wiki!
|
about: For more information and guidance check our Translation FAQ on our wiki!
|
||||||
|
- name: 📖 Code Documentation
|
||||||
|
url: https://cockatrice.github.io/docs/
|
||||||
|
about: Helpful source focusing on developers, but there are also references for users!
|
||||||
|
|
|
||||||
34
.github/dependabot.yml
vendored
|
|
@ -2,19 +2,21 @@
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
# # Enable version updates for git submodules
|
# Enable version updates for git submodules
|
||||||
# Not yet possible to bump only on tags or releases, see:
|
# If SemVer is used, updates will happen to new releases only (not HEAD)
|
||||||
# https://github.com/dependabot/dependabot-core/issues/1639
|
# https://github.com/dependabot/dependabot-core/issues/1639
|
||||||
# https://github.com/dependabot/dependabot-core/issues/2192
|
# https://github.com/dependabot/dependabot-core/issues/2192
|
||||||
# Alternative: Action that updates submodule and can be manually run on demand (workflow_dispatch)
|
- package-ecosystem: "gitsubmodule"
|
||||||
# - package-ecosystem: "gitsubmodule"
|
# Look for `.gitmodules` in the `root` directory
|
||||||
# # Look for `.gitmodules` in the `root` directory
|
directory: "/"
|
||||||
# directory: "/"
|
ignore:
|
||||||
# # Check for updates once a month
|
# Ignore updates for vcpkg (Bump to latest tag not working (no SemVer used)
|
||||||
# schedule:
|
- dependency-name: "vcpkg"
|
||||||
# interval: "monthly"
|
# Check for updates once a month
|
||||||
# # Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
|
schedule:
|
||||||
# open-pull-requests-limit: 1
|
interval: "monthly"
|
||||||
|
# Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
|
||||||
|
open-pull-requests-limit: 2
|
||||||
|
|
||||||
# # Enable version updates for Docker
|
# # Enable version updates for Docker
|
||||||
# Not yet possible to bump from one LTS version to the next and skip others, see:
|
# Not yet possible to bump from one LTS version to the next and skip others, see:
|
||||||
|
|
@ -37,13 +39,3 @@ updates:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
# Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
|
# Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
|
||||||
open-pull-requests-limit: 2
|
open-pull-requests-limit: 2
|
||||||
|
|
||||||
# # Enable version updates for npm
|
|
||||||
# - package-ecosystem: "npm"
|
|
||||||
# # Look for `package.json` and `lock` files in the `webclient` subdirectory
|
|
||||||
# directory: "/webclient"
|
|
||||||
# # Check the npm registry for updates once a week
|
|
||||||
# schedule:
|
|
||||||
# interval: "weekly"
|
|
||||||
# # Limit the amout of open PR's (default = 5, disabled = 0, security updates are not impacted)
|
|
||||||
# open-pull-requests-limit: 5
|
|
||||||
|
|
|
||||||
466
.github/workflows/desktop-build.yml
vendored
|
|
@ -1,10 +1,10 @@
|
||||||
name: Build Desktop
|
name: Build Desktop
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
actions: write # needed to delete entries in GHA cache (update ccache)
|
||||||
|
attestations: write # needed to persist the attestation.
|
||||||
contents: write
|
contents: write
|
||||||
id-token: write
|
id-token: write # needed for signing certificate in attestation
|
||||||
attestations: write
|
|
||||||
actions: write # needed for ccache action to be able to delete gha caches
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -14,14 +14,12 @@ on:
|
||||||
- '*/**' # matches all files not in root
|
- '*/**' # matches all files not in root
|
||||||
- '!**.md'
|
- '!**.md'
|
||||||
- '!.github/**'
|
- '!.github/**'
|
||||||
- '!.husky/**'
|
|
||||||
- '!.tx/**'
|
- '!.tx/**'
|
||||||
- '!doc/**'
|
- '!doc/**'
|
||||||
- '!webclient/**'
|
|
||||||
- '.github/workflows/desktop-build.yml'
|
- '.github/workflows/desktop-build.yml'
|
||||||
- 'CMakeLists.txt'
|
- 'CMakeLists.txt'
|
||||||
- 'vcpkg.json'
|
- 'vcpkg.json'
|
||||||
- 'vcpkg'
|
- 'vcpkg' # needed to match submodule bumps (gitlink)
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
@ -29,30 +27,28 @@ on:
|
||||||
- '*/**' # matches all files not in root
|
- '*/**' # matches all files not in root
|
||||||
- '!**.md'
|
- '!**.md'
|
||||||
- '!.github/**'
|
- '!.github/**'
|
||||||
- '!.husky/**'
|
|
||||||
- '!.tx/**'
|
- '!.tx/**'
|
||||||
- '!doc/**'
|
- '!doc/**'
|
||||||
- '!webclient/**'
|
|
||||||
- '.github/workflows/desktop-build.yml'
|
- '.github/workflows/desktop-build.yml'
|
||||||
- 'CMakeLists.txt'
|
- 'CMakeLists.txt'
|
||||||
- 'vcpkg.json'
|
- 'vcpkg.json'
|
||||||
- 'vcpkg'
|
- 'vcpkg' # needed to match submodule bumps (gitlink)
|
||||||
|
|
||||||
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on master)
|
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on release)
|
||||||
concurrency:
|
concurrency:
|
||||||
group: "${{ github.workflow }} @ ${{ github.ref_name }}"
|
group: "${{ github.workflow }} @ ${{ github.ref_name }}"
|
||||||
cancel-in-progress: ${{ github.ref_name != 'master' }}
|
cancel-in-progress: ${{ github.ref_type != 'tag' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
configure:
|
configure:
|
||||||
name: Configure
|
name: Configure
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
outputs:
|
outputs:
|
||||||
tag: ${{steps.configure.outputs.tag}}
|
tag: ${{ steps.configure.outputs.tag }}
|
||||||
sha: ${{steps.configure.outputs.sha}}
|
sha: ${{ steps.configure.outputs.sha }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Configure
|
- name: "Configure"
|
||||||
id: configure
|
id: configure
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -68,181 +64,200 @@ jobs:
|
||||||
fi
|
fi
|
||||||
echo "sha=$sha" >>"$GITHUB_OUTPUT"
|
echo "sha=$sha" >>"$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Checkout
|
- name: "Checkout"
|
||||||
if: steps.configure.outputs.tag != null
|
if: steps.configure.outputs.tag != null
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0 # fetch all history for all branches and tags
|
||||||
|
|
||||||
- name: Prepare release parameters
|
- name: "Prepare release parameters"
|
||||||
id: prepare
|
id: prepare
|
||||||
if: steps.configure.outputs.tag != null
|
if: steps.configure.outputs.tag != null
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
TAG: ${{steps.configure.outputs.tag}}
|
TAG: ${{ steps.configure.outputs.tag }}
|
||||||
run: .ci/prep_release.sh
|
run: .ci/prep_release.sh
|
||||||
|
|
||||||
- name: Create release
|
- name: "Create release"
|
||||||
if: steps.configure.outputs.tag != null
|
if: steps.configure.outputs.tag != null
|
||||||
id: create_release
|
id: create_release
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{ github.token }}
|
||||||
tag_name: ${{steps.configure.outputs.tag}}
|
tag_name: ${{ steps.configure.outputs.tag }}
|
||||||
target: ${{steps.configure.outputs.sha}}
|
target: ${{ steps.configure.outputs.sha }}
|
||||||
release_name: ${{steps.prepare.outputs.title}}
|
release_name: ${{ steps.prepare.outputs.title }}
|
||||||
body_path: ${{steps.prepare.outputs.body_path}}
|
body_path: ${{ steps.prepare.outputs.body_path }}
|
||||||
prerelease: ${{steps.prepare.outputs.is_beta}}
|
prerelease: ${{ steps.prepare.outputs.is_beta }}
|
||||||
run: |
|
run: |
|
||||||
if [[ $prerelease == yes ]]; then
|
args=()
|
||||||
args="--prerelease"
|
[[ $prerelease == yes ]] && args+=(--prerelease)
|
||||||
fi
|
|
||||||
gh release create "$tag_name" --draft --verify-tag $args \
|
gh release create "$tag_name" --verify-tag --draft "${args[@]}" \
|
||||||
--target "$target" --title "$release_name" \
|
--target "$target" \
|
||||||
--notes-file "$body_path"
|
--title "$release_name" \
|
||||||
|
--notes-file "$body_path"
|
||||||
|
|
||||||
build-linux:
|
build-linux:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
# These names correspond to the files in ".ci/$distro$version"
|
# The files in ".ci/$distro$version" correspond to the values given here
|
||||||
include:
|
include:
|
||||||
- distro: Arch
|
- distro: Arch
|
||||||
package: skip # We are packaged in Arch already
|
|
||||||
allow-failure: yes
|
allow-failure: yes
|
||||||
|
package: skip # We are packaged in Arch already
|
||||||
- distro: Debian
|
|
||||||
version: 11
|
|
||||||
package: DEB
|
|
||||||
|
|
||||||
- distro: Servatrice_Debian
|
- distro: Servatrice_Debian
|
||||||
version: 11
|
version: 12
|
||||||
|
|
||||||
package: DEB
|
package: DEB
|
||||||
test: skip
|
|
||||||
server_only: yes
|
server_only: yes
|
||||||
|
test: skip
|
||||||
|
|
||||||
- distro: Debian
|
- distro: Debian
|
||||||
version: 12
|
version: 12
|
||||||
|
|
||||||
package: DEB
|
package: DEB
|
||||||
test: skip # Running tests on all distros is superfluous
|
test: skip # Running tests on all distros is superfluous
|
||||||
|
|
||||||
- distro: Debian
|
- distro: Debian
|
||||||
version: 13
|
version: 13
|
||||||
|
|
||||||
package: DEB
|
package: DEB
|
||||||
|
|
||||||
- distro: Fedora
|
- distro: Fedora
|
||||||
version: 42
|
version: 43
|
||||||
|
|
||||||
package: RPM
|
package: RPM
|
||||||
test: skip # Running tests on all distros is superfluous
|
test: skip # Running tests on all distros is superfluous
|
||||||
|
|
||||||
- distro: Fedora
|
- distro: Fedora
|
||||||
version: 43
|
version: 44
|
||||||
|
|
||||||
package: RPM
|
package: RPM
|
||||||
|
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
version: 22.04
|
version: 24.04
|
||||||
|
|
||||||
package: DEB
|
package: DEB
|
||||||
|
test: skip # Running tests on all distros is superfluous
|
||||||
|
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
version: 24.04
|
version: 26.04
|
||||||
|
|
||||||
package: DEB
|
package: DEB
|
||||||
|
|
||||||
name: ${{matrix.distro}} ${{matrix.version}}
|
name: ${{ matrix.distro }} ${{ matrix.version }}
|
||||||
needs: configure
|
needs: configure
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
continue-on-error: ${{ matrix.allow-failure == 'yes' }}
|
||||||
|
timeout-minutes: 70
|
||||||
env:
|
env:
|
||||||
NAME: ${{matrix.distro}}${{matrix.version}}
|
CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }} # directory for caching docker image and ccache
|
||||||
CACHE: ${{github.workspace}}/.cache/${{matrix.distro}}${{matrix.version}} # directory for caching docker image and ccache
|
CCACHE_EVICTION_AGE: 7d
|
||||||
# Cache size over the entire repo is 10Gi:
|
CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
||||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
|
||||||
CCACHE_SIZE: 500M
|
|
||||||
CMAKE_GENERATOR: 'Ninja'
|
CMAKE_GENERATOR: 'Ninja'
|
||||||
|
NAME: ${{ matrix.distro }}${{ matrix.version }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: "Checkout"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Restore compiler cache (ccache)
|
- name: "Restore compiler cache (ccache)"
|
||||||
id: ccache_restore
|
id: ccache_restore
|
||||||
uses: actions/cache/restore@v5
|
uses: actions/cache/restore@v5
|
||||||
env:
|
env:
|
||||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
with:
|
with:
|
||||||
path: ${{env.CACHE}}
|
key: ccache-${{ matrix.distro }}${{ matrix.version }}-${{ env.BRANCH_NAME }}
|
||||||
key: ccache-${{matrix.distro}}${{matrix.version}}-${{env.BRANCH_NAME}}
|
path: ${{ env.CACHE }}
|
||||||
restore-keys: ccache-${{matrix.distro}}${{matrix.version}}-
|
restore-keys: ccache-${{ matrix.distro }}${{ matrix.version }}-
|
||||||
|
|
||||||
- name: Build ${{matrix.distro}} ${{matrix.version}} Docker image
|
- name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image"
|
||||||
shell: bash
|
shell: bash
|
||||||
run: source .ci/docker.sh --build
|
run: source .ci/docker.sh --build
|
||||||
|
|
||||||
- name: Build debug and test
|
- name: "Build debug and test"
|
||||||
if: matrix.test != 'skip'
|
if: matrix.test != 'skip'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
|
||||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
|
||||||
run: |
|
run: |
|
||||||
source .ci/docker.sh
|
source .ci/docker.sh
|
||||||
RUN --server --debug --test --ccache "$CCACHE_SIZE"
|
RUN --server --debug --test --ccache "$CCACHE_SIZE" \
|
||||||
|
--cmake-generator "$CMAKE_GENERATOR"
|
||||||
|
|
||||||
- name: Build release package
|
- name: "Build release package"
|
||||||
id: build
|
id: build
|
||||||
if: matrix.package != 'skip'
|
if: matrix.package != 'skip'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
BUILD_DIR: build
|
SUFFIX: '-${{ matrix.distro }}${{ matrix.version }}'
|
||||||
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
|
package: '${{ matrix.package }}'
|
||||||
package: '${{matrix.package}}'
|
server_only: '${{ matrix.server_only }}'
|
||||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
|
||||||
NO_CLIENT: ${{matrix.server_only == 'yes' && '--no-client' || '' }}
|
|
||||||
run: |
|
run: |
|
||||||
source .ci/docker.sh
|
source .ci/docker.sh
|
||||||
RUN --server --release --package "$package" --dir "$BUILD_DIR" \
|
args=()
|
||||||
--ccache "$CCACHE_SIZE" $NO_CLIENT
|
[[ $server_only == yes ]] && args+=(--no-client)
|
||||||
.ci/name_build.sh
|
[[ $GITHUB_REF == "refs/heads/master" ]] && args+=(--evict-ccache "$CCACHE_EVICTION_AGE")
|
||||||
|
args+=(--ccache "$CCACHE_SIZE")
|
||||||
|
args+=(--cmake-generator "$CMAKE_GENERATOR")
|
||||||
|
args+=(--suffix "$SUFFIX")
|
||||||
|
|
||||||
|
RUN --server --release --package "$package" "${args[@]}"
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
|
||||||
|
- name: "Delete remote compiler cache (ccache)"
|
||||||
|
if: github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
if gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}; then
|
||||||
|
echo "Cache deleted successfully"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: "Save updated compiler cache (ccache)"
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: actions/cache/save@v5
|
uses: actions/cache/save@v5
|
||||||
with:
|
with:
|
||||||
path: ${{env.CACHE}}
|
|
||||||
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
path: ${{ env.CACHE }}
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: "Upload artifact"
|
||||||
id: upload_artifact
|
id: upload_artifact
|
||||||
if: matrix.package != 'skip'
|
if: matrix.package != 'skip'
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: ${{matrix.distro}}${{matrix.version}}-package
|
archive: false
|
||||||
path: ${{steps.build.outputs.path}}
|
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
path: ${{ steps.build.outputs.path }}
|
||||||
|
|
||||||
- name: Upload to release
|
- name: "Upload to release"
|
||||||
id: upload_release
|
id: upload_release
|
||||||
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
|
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
asset_name: ${{ steps.build.outputs.fullname }}
|
||||||
tag_name: ${{needs.configure.outputs.tag}}
|
asset_path: ${{ steps.build.outputs.path }}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
GH_TOKEN: ${{ github.token }}
|
||||||
asset_name: ${{steps.build.outputs.name}}
|
tag_name: ${{ needs.configure.outputs.tag }}
|
||||||
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
||||||
|
|
||||||
- name: Attest binary provenance
|
- name: "Attest binary provenance"
|
||||||
id: attestation
|
id: attestation
|
||||||
if: steps.upload_release.outcome == 'success'
|
if: steps.upload_release.outcome == 'success'
|
||||||
uses: actions/attest-build-provenance@v3
|
uses: actions/attest@v4
|
||||||
with:
|
with:
|
||||||
subject-name: ${{steps.build.outputs.name}}
|
show-summary: false
|
||||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
subject-path: ${{ steps.build.outputs.path }}
|
||||||
|
|
||||||
- name: Verify binary attestation
|
- name: "Verify binary attestation"
|
||||||
if: steps.attestation.outcome == 'success'
|
if: steps.attestation.outcome == 'success'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
run: gh attestation verify "${{ steps.build.outputs.path }}" --repo Cockatrice/Cockatrice
|
||||||
|
|
||||||
build-vcpkg:
|
build-vcpkg:
|
||||||
strategy:
|
strategy:
|
||||||
|
|
@ -252,214 +267,220 @@ jobs:
|
||||||
- os: macOS
|
- os: macOS
|
||||||
target: 13
|
target: 13
|
||||||
runner: macos-15-intel
|
runner: macos-15-intel
|
||||||
soc: Intel
|
|
||||||
xcode: "16.4"
|
ccache_eviction_age: 7d
|
||||||
type: Release
|
cmake_generator: Ninja
|
||||||
override_target: 13
|
|
||||||
make_package: 1
|
make_package: 1
|
||||||
|
override_target: 13
|
||||||
package_suffix: "-macOS13_Intel"
|
package_suffix: "-macOS13_Intel"
|
||||||
artifact_name: macOS13_Intel-package
|
qt_version: 6.11.0
|
||||||
qt_version: 6.6.*
|
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cmake_generator: Ninja
|
soc: Intel
|
||||||
|
type: Release
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
xcode: "16.4"
|
||||||
|
|
||||||
- os: macOS
|
- os: macOS
|
||||||
target: 14
|
target: 14
|
||||||
runner: macos-14
|
runner: macos-14
|
||||||
soc: Apple
|
|
||||||
xcode: "15.4"
|
ccache_eviction_age: 7d
|
||||||
type: Release
|
cmake_generator: Ninja
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS14"
|
package_suffix: "-macOS14"
|
||||||
artifact_name: macOS14-package
|
qt_version: 6.11.0
|
||||||
qt_version: 6.6.*
|
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cmake_generator: Ninja
|
soc: Apple
|
||||||
|
type: Release
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
xcode: "15.4"
|
||||||
|
|
||||||
- os: macOS
|
- os: macOS
|
||||||
target: 15
|
target: 15
|
||||||
runner: macos-15
|
runner: macos-15
|
||||||
soc: Apple
|
|
||||||
xcode: "16.4"
|
ccache_eviction_age: 7d
|
||||||
type: Release
|
cmake_generator: Ninja
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS15"
|
package_suffix: "-macOS15"
|
||||||
artifact_name: macOS15-package
|
qt_version: 6.11.0
|
||||||
qt_version: 6.6.*
|
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cmake_generator: Ninja
|
soc: Apple
|
||||||
|
type: Release
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
xcode: "16.4"
|
||||||
|
|
||||||
- os: macOS
|
- os: macOS
|
||||||
target: 15
|
target: 15
|
||||||
runner: macos-15
|
runner: macos-15
|
||||||
soc: Apple
|
|
||||||
xcode: "16.4"
|
ccache_eviction_age: 7d
|
||||||
type: Debug
|
cmake_generator: Ninja
|
||||||
qt_version: 6.6.*
|
qt_version: 6.11.0
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cmake_generator: Ninja
|
soc: Apple
|
||||||
|
type: Debug
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
xcode: "16.4"
|
||||||
- os: Windows
|
|
||||||
target: 7
|
|
||||||
runner: windows-2022
|
|
||||||
type: Release
|
|
||||||
make_package: 1
|
|
||||||
package_suffix: "-Win7"
|
|
||||||
artifact_name: Windows7-installer
|
|
||||||
qt_version: 5.15.*
|
|
||||||
qt_arch: win64_msvc2019_64
|
|
||||||
cmake_generator: "Visual Studio 17 2022"
|
|
||||||
cmake_generator_platform: x64
|
|
||||||
|
|
||||||
- os: Windows
|
- os: Windows
|
||||||
target: 10
|
target: 10
|
||||||
runner: windows-2022
|
runner: windows-2025
|
||||||
type: Release
|
|
||||||
make_package: 1
|
|
||||||
package_suffix: "-Win10"
|
|
||||||
artifact_name: Windows10-installer
|
|
||||||
qt_version: 6.6.*
|
|
||||||
qt_arch: win64_msvc2019_64
|
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
|
||||||
cmake_generator: "Visual Studio 17 2022"
|
cmake_generator: "Visual Studio 17 2022"
|
||||||
cmake_generator_platform: x64
|
cmake_generator_platform: x64
|
||||||
|
make_package: 1
|
||||||
|
package_suffix: "-Win10"
|
||||||
|
qt_version: 6.11.0
|
||||||
|
qt_arch: win64_msvc2022_64
|
||||||
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
|
type: Release
|
||||||
|
|
||||||
name: ${{matrix.os}} ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
name: ${{ matrix.os }} ${{ matrix.target }}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
||||||
needs: configure
|
needs: configure
|
||||||
runs-on: ${{matrix.runner}}
|
runs-on: ${{ matrix.runner }}
|
||||||
|
timeout-minutes: 100
|
||||||
env:
|
env:
|
||||||
CCACHE_DIR: ${{github.workspace}}/.cache/
|
CCACHE_DIR: ${{ github.workspace }}/.cache/
|
||||||
# Cache size over the entire repo is 10Gi:
|
CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
||||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
|
||||||
CCACHE_SIZE: 500M
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: "Checkout"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: Add msbuild to PATH
|
- name: "[Windows] Add msbuild to PATH"
|
||||||
if: matrix.os == 'Windows'
|
if: matrix.os == 'Windows'
|
||||||
id: add-msbuild
|
id: add-msbuild
|
||||||
uses: microsoft/setup-msbuild@v2
|
uses: microsoft/setup-msbuild@v3
|
||||||
with:
|
with:
|
||||||
msbuild-architecture: x64
|
msbuild-architecture: x64
|
||||||
|
|
||||||
- name: Setup ccache
|
- name: "[macOS] Setup ccache"
|
||||||
if: matrix.use_ccache == 1 && matrix.os == 'macOS'
|
if: matrix.os == 'macOS' && matrix.use_ccache == 1
|
||||||
run: brew install ccache
|
run: brew install ccache
|
||||||
|
|
||||||
- name: Restore compiler cache (ccache)
|
- name: "[macOS] Restore compiler cache (ccache)"
|
||||||
if: matrix.use_ccache == 1
|
if: matrix.os == 'macOS' && matrix.use_ccache == 1
|
||||||
id: ccache_restore
|
id: ccache_restore
|
||||||
uses: actions/cache/restore@v5
|
uses: actions/cache/restore@v5
|
||||||
env:
|
env:
|
||||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
with:
|
with:
|
||||||
path: ${{env.CCACHE_DIR}}
|
key: ccache-${{ matrix.runner }}-${{ matrix.soc }}-${{ matrix.type }}-${{ env.BRANCH_NAME }}
|
||||||
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
path: ${{ env.CCACHE_DIR }}
|
||||||
restore-keys: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-
|
restore-keys: ccache-${{ matrix.runner }}-${{ matrix.soc }}-${{ matrix.type }}-
|
||||||
|
|
||||||
- name: Install aqtinstall
|
- name: "Install aqtinstall"
|
||||||
if: matrix.os == 'macOS'
|
|
||||||
run: pipx install aqtinstall
|
run: pipx install aqtinstall
|
||||||
|
|
||||||
# Checking if there's a newer, uncached version of Qt available to install via aqtinstall
|
# Resolve given wildcard versions (e.g. Qt 6.6.*) to latest version via aqtinstall to avoid stale caches on new releases
|
||||||
- name: Resolve latest Qt patch version
|
- name: "Resolve latest Qt patch version"
|
||||||
if: matrix.os == 'macOS'
|
|
||||||
id: resolve_qt_version
|
id: resolve_qt_version
|
||||||
shell: bash
|
shell: bash
|
||||||
# Ouputs the version of Qt to install via aqtinstall
|
run: .ci/resolve_latest_aqt_qt_version.sh "${{ matrix.qt_version }}"
|
||||||
run: .ci/resolve_latest_aqt_qt_version.sh "${{matrix.qt_version}}"
|
|
||||||
|
|
||||||
- name: Restore thin Qt ${{ steps.resolve_qt_version.outputs.version }} libraries (${{ matrix.soc }} macOS)
|
- name: "[macOS] Restore thin Qt ${{ steps.resolve_qt_version.outputs.version }} libraries"
|
||||||
if: matrix.os == 'macOS'
|
if: matrix.os == 'macOS'
|
||||||
id: restore_qt
|
id: restore_qt
|
||||||
uses: actions/cache/restore@v5
|
uses: actions/cache/restore@v5
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/Qt
|
|
||||||
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
|
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
|
||||||
|
path: ${{ github.workspace }}/Qt
|
||||||
|
|
||||||
# Using jurplel/install-qt-action to install Qt without using brew
|
# Using jurplel/install-qt-action to install Qt without using brew
|
||||||
# qt build using vcpkg either just fails or takes too long to build
|
# Qt build using vcpkg either just fails or takes too long to build
|
||||||
- name: Install fat Qt ${{ steps.resolve_qt_version.outputs.version }} (${{ matrix.soc }} macOS)
|
- name: "[macOS] Install fat Qt ${{ steps.resolve_qt_version.outputs.version }}"
|
||||||
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
|
arch: ${{ matrix.qt_arch }}
|
||||||
cache: false
|
cache: false
|
||||||
|
dir: ${{ github.workspace }}
|
||||||
|
modules: ${{ matrix.qt_modules }}
|
||||||
version: ${{ steps.resolve_qt_version.outputs.version }}
|
version: ${{ steps.resolve_qt_version.outputs.version }}
|
||||||
arch: ${{matrix.qt_arch}}
|
|
||||||
modules: ${{matrix.qt_modules}}
|
|
||||||
dir: ${{github.workspace}}
|
|
||||||
|
|
||||||
- name: Thin Qt libraries (${{ matrix.soc }} macOS)
|
- name: "[macOS] Create thin Qt libraries"
|
||||||
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
||||||
run: .ci/thin_macos_qtlib.sh
|
run: .ci/thin_macos_qtlib.sh
|
||||||
|
|
||||||
- name: Cache thin Qt libraries (${{ matrix.soc }} macOS)
|
- name: "[macOS] Cache thin Qt libraries"
|
||||||
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache/save@v5
|
uses: actions/cache/save@v5
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/Qt
|
|
||||||
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
|
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
|
||||||
|
path: ${{ github.workspace }}/Qt
|
||||||
|
|
||||||
- name: Install Qt ${{matrix.qt_version}} (Windows)
|
- name: "[Windows] Install Qt ${{ matrix.qt_version }}"
|
||||||
if: matrix.os == 'Windows'
|
if: matrix.os == 'Windows'
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: ${{matrix.qt_version}}
|
# Qt 6.11.0 only works with aqtinstall directly from git until aqtinstall 3.4 is released
|
||||||
arch: ${{matrix.qt_arch}}
|
aqtsource: git+https://github.com/miurahr/aqtinstall.git
|
||||||
modules: ${{matrix.qt_modules}}
|
arch: ${{ matrix.qt_arch }}
|
||||||
cache: true
|
cache: true
|
||||||
|
modules: ${{ matrix.qt_modules }}
|
||||||
|
version: ${{ steps.resolve_qt_version.outputs.version }}
|
||||||
|
|
||||||
- name: Setup vcpkg cache
|
- name: "[Windows] Install NSIS"
|
||||||
|
if: matrix.os == 'Windows'
|
||||||
|
shell: bash
|
||||||
|
run: choco install nsis
|
||||||
|
|
||||||
|
- name: "Setup vcpkg cache"
|
||||||
id: vcpkg-cache
|
id: vcpkg-cache
|
||||||
uses: TAServers/vcpkg-cache@v3
|
uses: TAServers/vcpkg-cache@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
# uses environment variables, see compile.sh for more details
|
# Uses environment variables, see compile.sh for more details
|
||||||
- name: Build Cockatrice
|
- name: "Build Cockatrice"
|
||||||
id: build
|
id: build
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
BUILDTYPE: '${{matrix.type}}'
|
BUILDTYPE: '${{ matrix.type }}'
|
||||||
MAKE_PACKAGE: '${{matrix.make_package}}'
|
CCACHE_EVICTION_AGE: ${{ matrix.ccache_eviction_age }}
|
||||||
PACKAGE_SUFFIX: '${{matrix.package_suffix}}'
|
CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
|
||||||
CMAKE_GENERATOR: ${{matrix.cmake_generator}}
|
CMAKE_GENERATOR_PLATFORM: ${{ matrix.cmake_generator_platform }}
|
||||||
CMAKE_GENERATOR_PLATFORM: ${{matrix.cmake_generator_platform}}
|
DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer'
|
||||||
USE_CCACHE: ${{matrix.use_ccache}}
|
|
||||||
VCPKG_DISABLE_METRICS: 1
|
|
||||||
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
|
|
||||||
# macOS-specific environment variables, will be ignored on Windows
|
|
||||||
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
|
||||||
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
|
||||||
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||||
|
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
|
||||||
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||||
DEVELOPER_DIR: '/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer'
|
MAKE_PACKAGE: '${{ matrix.make_package }}'
|
||||||
|
PACKAGE_SUFFIX: '${{ matrix.package_suffix }}'
|
||||||
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
||||||
|
USE_CCACHE: ${{ matrix.use_ccache }}
|
||||||
|
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
|
||||||
|
VCPKG_DISABLE_METRICS: 1
|
||||||
run: .ci/compile.sh --server --test --vcpkg
|
run: .ci/compile.sh --server --test --vcpkg
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
|
||||||
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
|
- name: "[macOS] Delete remote compiler cache (ccache)"
|
||||||
uses: actions/cache/save@v5
|
if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
|
||||||
|
continue-on-error: true
|
||||||
env:
|
env:
|
||||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
with:
|
run: |
|
||||||
path: ${{env.CCACHE_DIR}}
|
if gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}; then
|
||||||
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
echo "Cache deleted successfully"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Sign app bundle
|
- name: "[macOS] Save updated compiler cache (ccache)"
|
||||||
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master'
|
||||||
|
uses: actions/cache/save@v5
|
||||||
|
with:
|
||||||
|
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
path: ${{ env.CCACHE_DIR }}
|
||||||
|
|
||||||
|
- name: "[macOS] Sign app bundle"
|
||||||
|
if: matrix.os == 'macOS' && matrix.make_package && needs.configure.outputs.tag != null
|
||||||
|
id: sign_macos
|
||||||
env:
|
env:
|
||||||
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
|
||||||
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
|
||||||
|
|
@ -467,15 +488,15 @@ jobs:
|
||||||
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
|
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
|
||||||
then
|
then
|
||||||
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
|
||||||
/usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose ${{steps.build.outputs.path}}
|
/usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose "${{ steps.build.outputs.path }}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Notarize app bundle
|
- name: "[macOS] Notarize app bundle"
|
||||||
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
if: matrix.os == 'macOS' && steps.sign_macos.outcome == 'success'
|
||||||
env:
|
env:
|
||||||
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
|
||||||
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
|
||||||
MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
|
MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
|
||||||
|
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
||||||
run: |
|
run: |
|
||||||
if [[ -n "$MACOS_NOTARIZATION_APPLE_ID" ]]
|
if [[ -n "$MACOS_NOTARIZATION_APPLE_ID" ]]
|
||||||
then
|
then
|
||||||
|
|
@ -487,7 +508,7 @@ jobs:
|
||||||
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
|
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
|
||||||
# notarization service
|
# notarization service
|
||||||
echo "Creating temp notarization archive"
|
echo "Creating temp notarization archive"
|
||||||
ditto -c -k --keepParent ${{steps.build.outputs.path}} "notarization.zip"
|
ditto -c -k --keepParent "${{ steps.build.outputs.path }}" "notarization.zip"
|
||||||
|
|
||||||
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
|
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
|
||||||
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
|
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
|
||||||
|
|
@ -499,50 +520,51 @@ jobs:
|
||||||
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
|
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
|
||||||
# validated by macOS even when an internet connection is not available.
|
# validated by macOS even when an internet connection is not available.
|
||||||
echo "Attach staple"
|
echo "Attach staple"
|
||||||
xcrun stapler staple ${{steps.build.outputs.path}}
|
xcrun stapler staple "${{ steps.build.outputs.path }}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: "Upload artifact"
|
||||||
id: upload_artifact
|
|
||||||
if: matrix.make_package
|
if: matrix.make_package
|
||||||
uses: actions/upload-artifact@v6
|
id: upload_artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: ${{matrix.artifact_name}}
|
archive: false
|
||||||
path: ${{steps.build.outputs.path}}
|
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
path: ${{ steps.build.outputs.path }}
|
||||||
|
|
||||||
- name: Upload pdb database
|
- name: "[Windows] Upload PDBs (Program Databases)"
|
||||||
if: matrix.os == 'Windows'
|
if: matrix.os == 'Windows' && github.ref_type != 'tag'
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: Windows${{matrix.target}}-debug-pdbs
|
if-no-files-found: error
|
||||||
|
name: ${{ steps.build.outputs.name }}-PDBs
|
||||||
path: |
|
path: |
|
||||||
build/cockatrice/Release/*.pdb
|
build/cockatrice/Release/*.pdb
|
||||||
|
build/oracle/Release/*.pdb
|
||||||
build/servatrice/Release/*.pdb
|
build/servatrice/Release/*.pdb
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: Upload to release
|
- name: "Upload to release"
|
||||||
|
if: needs.configure.outputs.tag != null && matrix.make_package == '1'
|
||||||
id: upload_release
|
id: upload_release
|
||||||
if: needs.configure.outputs.tag != null
|
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
asset_name: ${{ steps.build.outputs.fullname }}
|
||||||
tag_name: ${{needs.configure.outputs.tag}}
|
asset_path: ${{ steps.build.outputs.path }}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
GH_TOKEN: ${{ github.token }}
|
||||||
asset_name: ${{steps.build.outputs.name}}
|
tag_name: ${{ needs.configure.outputs.tag }}
|
||||||
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
run: gh release upload "$tag_name" "$asset_path#$asset_name"
|
||||||
|
|
||||||
- name: Attest binary provenance
|
- name: "Attest binary provenance"
|
||||||
id: attestation
|
|
||||||
if: steps.upload_release.outcome == 'success'
|
if: steps.upload_release.outcome == 'success'
|
||||||
uses: actions/attest-build-provenance@v3
|
id: attestation
|
||||||
|
uses: actions/attest@v4
|
||||||
with:
|
with:
|
||||||
subject-name: ${{steps.build.outputs.name}}
|
show-summary: false
|
||||||
subject-digest: sha256:${{ steps.upload_artifact.outputs.artifact-digest }}
|
subject-path: ${{ steps.build.outputs.path }}
|
||||||
|
|
||||||
- name: Verify binary attestation
|
- name: "Verify binary attestation"
|
||||||
if: steps.attestation.outcome == 'success'
|
if: steps.attestation.outcome == 'success'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{github.token}}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: gh attestation verify ${{steps.build.outputs.path}} -R Cockatrice/Cockatrice
|
run: gh attestation verify "${{ steps.build.outputs.path }}" --repo Cockatrice/Cockatrice
|
||||||
|
|
|
||||||
19
.github/workflows/desktop-lint.yml
vendored
|
|
@ -1,17 +1,15 @@
|
||||||
name: Code Style (C++)
|
name: Code Style (C++)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# push trigger not needed for linting, we do not allow direct pushes to master
|
# Push trigger not needed for linting, we do not allow direct pushes to master
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '*/**' # matches all files not in root
|
- '*/**' # matches all files not in root
|
||||||
- '!**.md'
|
- '!**.md'
|
||||||
- '!.ci/**'
|
- '!.ci/**'
|
||||||
- '!.github/**'
|
- '!.github/**'
|
||||||
- '!.husky/**'
|
|
||||||
- '!.tx/**'
|
- '!.tx/**'
|
||||||
- '!doc/**'
|
- '!doc/**'
|
||||||
- '!webclient/**'
|
|
||||||
- '.ci/lint_cpp.sh'
|
- '.ci/lint_cpp.sh'
|
||||||
- '.github/workflows/desktop-lint.yml'
|
- '.github/workflows/desktop-lint.yml'
|
||||||
- '.clang-format'
|
- '.clang-format'
|
||||||
|
|
@ -20,20 +18,23 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
format:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: "Checkout"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 20 # should be enough to find merge base
|
fetch-depth: 20 # should be enough to find merge base
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: "Install dependencies"
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends clang-format cmake-format shellcheck
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
clang-format \
|
||||||
|
cmake-format \
|
||||||
|
shellcheck
|
||||||
|
|
||||||
- name: Check code formatting
|
- name: "Check code formatting"
|
||||||
shell: bash
|
shell: bash
|
||||||
run: ./.ci/lint_cpp.sh
|
run: ./.ci/lint_cpp.sh
|
||||||
|
|
|
||||||
63
.github/workflows/docker-release.yml
vendored
|
|
@ -1,9 +1,11 @@
|
||||||
name: Build Docker Image
|
name: Build Docker Image
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
|
||||||
- '*Release*'
|
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
@ -12,55 +14,64 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/docker-release.yml'
|
- '.github/workflows/docker-release.yml'
|
||||||
- 'Dockerfile'
|
- 'Dockerfile'
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- released # publishing of stable releases
|
||||||
|
|
||||||
|
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on release)
|
||||||
|
concurrency:
|
||||||
|
group: "${{ github.workflow }} @ ${{ github.ref_name }}"
|
||||||
|
cancel-in-progress: ${{ github.event_name != 'release' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
name: amd64 & arm64
|
name: amd64 & arm64
|
||||||
|
if: ${{ github.repository_owner == 'Cockatrice' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: "Checkout"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Docker metadata
|
- name: "Docker metadata"
|
||||||
id: metadata
|
id: metadata
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
|
env:
|
||||||
|
DOCKER_METADATA_ANNOTATIONS_LEVELS: index # needed for GHCR
|
||||||
with:
|
with:
|
||||||
|
annotations: |
|
||||||
|
org.opencontainers.image.title=Servatrice
|
||||||
|
org.opencontainers.image.url=https://cockatrice.github.io/
|
||||||
|
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
|
||||||
images: |
|
images: |
|
||||||
ghcr.io/cockatrice/servatrice
|
ghcr.io/cockatrice/servatrice
|
||||||
labels: |
|
labels: |
|
||||||
org.opencontainers.image.title=Servatrice
|
org.opencontainers.image.title=Servatrice
|
||||||
org.opencontainers.image.url=https://cockatrice.github.io/
|
org.opencontainers.image.url=https://cockatrice.github.io/
|
||||||
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
|
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
|
||||||
annotations: |
|
|
||||||
org.opencontainers.image.title=Servatrice
|
|
||||||
org.opencontainers.image.url=https://cockatrice.github.io/
|
|
||||||
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: "Set up QEMU"
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker buildx
|
- name: "Set up Docker buildx"
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: "Login to GitHub Container Registry"
|
||||||
if: github.ref_type == 'tag'
|
if: contains(github.event.release.tag_name, 'Release') && github.event.release.target_commitish == 'master'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
|
password: ${{ github.token }}
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ github.token }}
|
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: "Build and push Docker image"
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
|
annotations: ${{ steps.metadata.outputs.annotations }}
|
||||||
|
cache-from: type=gha,scope=servatrice
|
||||||
|
cache-to: type=gha,mode=max,scope=servatrice
|
||||||
context: .
|
context: .
|
||||||
|
labels: ${{ steps.metadata.outputs.labels }}
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: ${{ github.ref_type == 'tag' }}
|
push: ${{ github.ref_type == 'tag' }}
|
||||||
tags: ${{ steps.metadata.outputs.tags }}
|
tags: ${{ steps.metadata.outputs.tags }}
|
||||||
labels: ${{ steps.metadata.outputs.labels }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
|
|
|
||||||
30
.github/workflows/documentation-build.yml
vendored
|
|
@ -1,18 +1,18 @@
|
||||||
name: Generate Docs
|
name: Generate Docs
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- '*' # Only re-generate docs when a new tagged version is pushed
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- 'doc/doxygen/**'
|
- 'doc/doxygen/**'
|
||||||
- '.github/workflows/documentation-build.yml'
|
- '.github/workflows/documentation-build.yml'
|
||||||
- 'Doxyfile'
|
- 'Doxyfile'
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- published # publishing of stable releases and pre-releases
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
COCKATRICE_REF: ${{ github.ref_name }} # Tag name if the commit is tagged, otherwise branch name
|
COCKATRICE_REF: ${{ github.ref_name }} # tag name if the commit is tagged, otherwise branch name
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docs:
|
docs:
|
||||||
|
|
@ -20,20 +20,22 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: "Checkout code"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
- name: Install Graphviz
|
- name: "Install Graphviz"
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install -y graphviz
|
sudo apt-get install -y graphviz
|
||||||
dot -V
|
dot -V
|
||||||
|
|
||||||
- name: Install Doxygen
|
- name: "Install Doxygen"
|
||||||
uses: ssciwr/doxygen-install@v1
|
uses: ssciwr/doxygen-install@v2
|
||||||
with:
|
with:
|
||||||
version: "1.14.0"
|
version: "1.16.1"
|
||||||
|
|
||||||
- name: Update Doxygen Configuration
|
- name: "Update Doxygen Configuration"
|
||||||
run: |
|
run: |
|
||||||
git diff Doxyfile
|
git diff Doxyfile
|
||||||
doxygen -u Doxyfile
|
doxygen -u Doxyfile
|
||||||
|
|
@ -46,16 +48,16 @@ jobs:
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Generate Documentation
|
- name: "Generate Documentation"
|
||||||
if: always()
|
if: always()
|
||||||
run: doxygen Doxyfile
|
run: doxygen Doxyfile
|
||||||
|
|
||||||
- name: Deploy to cockatrice.github.io
|
- name: "Deploy to cockatrice.github.io"
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
|
||||||
uses: peaceiris/actions-gh-pages@v4
|
uses: peaceiris/actions-gh-pages@v4
|
||||||
with:
|
with:
|
||||||
deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
|
deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
|
||||||
|
destination_dir: docs # docs will be available at https://cockatrice.github.io/docs/
|
||||||
external_repository: Cockatrice/cockatrice.github.io
|
external_repository: Cockatrice/cockatrice.github.io
|
||||||
publish_branch: master
|
publish_branch: master
|
||||||
publish_dir: ./docs/html
|
publish_dir: ./docs/html
|
||||||
destination_dir: docs # Docs will live under https://cockatrice.github.io/docs/
|
|
||||||
|
|
|
||||||
38
.github/workflows/translations-pull.yml
vendored
|
|
@ -1,14 +1,14 @@
|
||||||
name: Update Translations
|
name: Update Translations
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# runs in the middle of each month starting a quarter (UTC) = two weeks after new strings are built
|
|
||||||
- cron: '0 0 15 1,4,7,10 *'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.tx/**'
|
- '.tx/**'
|
||||||
- '.github/workflows/translations-pull.yml'
|
- '.github/workflows/translations-pull.yml'
|
||||||
|
schedule:
|
||||||
|
# Runs in the middle of each month starting a quarter (UTC) = two weeks after new strings are built
|
||||||
|
- cron: '0 0 15 1,4,7,10 *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
translations:
|
translations:
|
||||||
|
|
@ -16,21 +16,21 @@ jobs:
|
||||||
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
|
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
|
||||||
|
|
||||||
name: Pull languages
|
name: Pull languages
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: "Checkout repo"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Pull translated strings from Transifex
|
- name: "Pull translated strings from Transifex"
|
||||||
uses: transifex/cli-action@v2
|
uses: transifex/cli-action@v2
|
||||||
with:
|
with:
|
||||||
# used config file: https://github.com/Cockatrice/Cockatrice/blob/master/.tx/config
|
# Used config file: https://github.com/Cockatrice/Cockatrice/blob/master/.tx/config
|
||||||
# https://github.com/transifex/cli#pulling-files-from-transifex
|
# Docs: https://github.com/transifex/cli#pulling-files-from-transifex
|
||||||
token: ${{ secrets.TX_TOKEN }}
|
|
||||||
args: pull --force --all
|
args: pull --force --all
|
||||||
|
token: ${{ secrets.TX_TOKEN }}
|
||||||
|
|
||||||
- name: Create pull request
|
- name: "Create pull request"
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
id: create_pr
|
id: create_pr
|
||||||
uses: peter-evans/create-pull-request@v8
|
uses: peter-evans/create-pull-request@v8
|
||||||
|
|
@ -38,13 +38,7 @@ jobs:
|
||||||
add-paths: |
|
add-paths: |
|
||||||
cockatrice/translations/*.ts
|
cockatrice/translations/*.ts
|
||||||
oracle/translations/*.ts
|
oracle/translations/*.ts
|
||||||
webclient/public/locales/*/translation.json
|
author: github-actions <github-actions@github.com> # owner of the commit
|
||||||
commit-message: Update translation files
|
|
||||||
# author is the owner of the commit
|
|
||||||
author: github-actions <github-actions@github.com>
|
|
||||||
branch: ci-update_translations
|
|
||||||
delete-branch: true
|
|
||||||
title: 'Update translations'
|
|
||||||
body: |
|
body: |
|
||||||
Pulled all translated strings from [Transifex][1].
|
Pulled all translated strings from [Transifex][1].
|
||||||
|
|
||||||
|
|
@ -54,12 +48,16 @@ jobs:
|
||||||
|
|
||||||
[1]: https://explore.transifex.com/cockatrice/cockatrice/
|
[1]: https://explore.transifex.com/cockatrice/cockatrice/
|
||||||
[2]: https://github.com/Cockatrice/Cockatrice/actions/workflows/translations-pull.yml?query=branch%3Amaster
|
[2]: https://github.com/Cockatrice/Cockatrice/actions/workflows/translations-pull.yml?query=branch%3Amaster
|
||||||
|
branch: ci-update_translations
|
||||||
|
commit-message: Update translation files
|
||||||
|
delete-branch: true
|
||||||
|
draft: false
|
||||||
labels: |
|
labels: |
|
||||||
CI
|
CI
|
||||||
Translation
|
Translation
|
||||||
draft: false
|
title: 'Update translations'
|
||||||
|
|
||||||
- name: PR Status
|
- name: "PR Status"
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
|
|
|
||||||
41
.github/workflows/translations-push.yml
vendored
|
|
@ -1,14 +1,14 @@
|
||||||
name: Update Translation Source
|
name: Update Translation Source
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# runs at the start of each quarter (UTC)
|
|
||||||
- cron: '0 0 1 1,4,7,10 *'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.ci/update_translation_source_strings.sh'
|
- '.ci/update_translation_source_strings.sh'
|
||||||
- '.github/workflows/translations-push.yml'
|
- '.github/workflows/translations-push.yml'
|
||||||
|
schedule:
|
||||||
|
# Runs at the start of each quarter (UTC)
|
||||||
|
- cron: '0 0 1 1,4,7,10 *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
translations:
|
translations:
|
||||||
|
|
@ -16,19 +16,19 @@ jobs:
|
||||||
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
|
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
|
||||||
|
|
||||||
name: Push strings
|
name: Push strings
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: "Checkout repo"
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install lupdate
|
- name: "Install lupdate"
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y --no-install-recommends qttools5-dev-tools
|
sudo apt-get install -y --no-install-recommends qttools5-dev-tools
|
||||||
|
|
||||||
- name: Update Cockatrice translation source
|
- name: "Update Cockatrice translation source"
|
||||||
id: cockatrice
|
id: cockatrice
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -36,17 +36,17 @@ jobs:
|
||||||
export DIRS="cockatrice/src $(find . -maxdepth 1 -type d -name 'libcockatrice_*')"
|
export DIRS="cockatrice/src $(find . -maxdepth 1 -type d -name 'libcockatrice_*')"
|
||||||
FILE="$FILE" DIRS="$DIRS" .ci/update_translation_source_strings.sh
|
FILE="$FILE" DIRS="$DIRS" .ci/update_translation_source_strings.sh
|
||||||
|
|
||||||
- name: Update Oracle translation source
|
- name: "Update Oracle translation source"
|
||||||
id: oracle
|
id: oracle
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
FILE: 'oracle/oracle_en@source.ts'
|
|
||||||
DIRS: 'oracle/src'
|
DIRS: 'oracle/src'
|
||||||
|
FILE: 'oracle/oracle_en@source.ts'
|
||||||
run: .ci/update_translation_source_strings.sh
|
run: .ci/update_translation_source_strings.sh
|
||||||
|
|
||||||
- name: Render template
|
- name: "Render template"
|
||||||
id: template
|
id: template
|
||||||
uses: chuhlomin/render-template@v1
|
uses: chuhlomin/render-template/binary@v1
|
||||||
with:
|
with:
|
||||||
template: .ci/update_translation_source_strings_template.md
|
template: .ci/update_translation_source_strings_template.md
|
||||||
vars: |
|
vars: |
|
||||||
|
|
@ -54,7 +54,7 @@ jobs:
|
||||||
oracle_output: ${{ steps.oracle.outputs.output }}
|
oracle_output: ${{ steps.oracle.outputs.output }}
|
||||||
commit: ${{ github.sha }}
|
commit: ${{ github.sha }}
|
||||||
|
|
||||||
- name: Create pull request
|
- name: "Create pull request"
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
id: create_pr
|
id: create_pr
|
||||||
uses: peter-evans/create-pull-request@v8
|
uses: peter-evans/create-pull-request@v8
|
||||||
|
|
@ -62,19 +62,18 @@ jobs:
|
||||||
add-paths: |
|
add-paths: |
|
||||||
cockatrice/cockatrice_en@source.ts
|
cockatrice/cockatrice_en@source.ts
|
||||||
oracle/oracle_en@source.ts
|
oracle/oracle_en@source.ts
|
||||||
commit-message: Update translation source strings
|
author: github-actions <github-actions@github.com> # owner of the commit
|
||||||
# author is the owner of the commit
|
|
||||||
author: github-actions <github-actions@github.com>
|
|
||||||
branch: ci-update_translation_source
|
|
||||||
delete-branch: true
|
|
||||||
title: 'Update source strings'
|
|
||||||
body: ${{ steps.template.outputs.result }}
|
body: ${{ steps.template.outputs.result }}
|
||||||
|
branch: ci-update_translation_source
|
||||||
|
commit-message: Update translation source strings
|
||||||
|
delete-branch: true
|
||||||
|
draft: false
|
||||||
labels: |
|
labels: |
|
||||||
CI
|
CI
|
||||||
Translation
|
Translation
|
||||||
draft: false
|
title: 'Update source strings'
|
||||||
|
|
||||||
- name: PR Status
|
- name: "PR Status"
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
|
|
|
||||||
54
.github/workflows/web-build.yml
vendored
|
|
@ -1,54 +0,0 @@
|
||||||
name: Build Web
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- '.husky/**'
|
|
||||||
- 'webclient/**'
|
|
||||||
- '!**.md'
|
|
||||||
- '.github/workflows/web-build.yml'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- '.husky/**'
|
|
||||||
- 'webclient/**'
|
|
||||||
- '!**.md'
|
|
||||||
- '.github/workflows/web-build.yml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-web:
|
|
||||||
name: React (Node ${{matrix.node_version}})
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: webclient
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
node_version:
|
|
||||||
- 16
|
|
||||||
- lts/*
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: ${{matrix.node_version}}
|
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: 'webclient/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm clean-install
|
|
||||||
|
|
||||||
- name: Build app
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: Test app
|
|
||||||
run: npm run test
|
|
||||||
33
.github/workflows/web-lint.yml
vendored
|
|
@ -1,33 +0,0 @@
|
||||||
name: Code Style (TypeScript)
|
|
||||||
|
|
||||||
on:
|
|
||||||
# push trigger not needed for linting, we do not allow direct pushes to master
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'webclient/**'
|
|
||||||
- '!**.md'
|
|
||||||
- '.github/workflows/web-lint.yml'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ESLint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: webclient
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
cache: 'npm'
|
|
||||||
cache-dependency-path: 'webclient/package-lock.json'
|
|
||||||
|
|
||||||
- name: Install ESLint
|
|
||||||
run: npm clean-install --ignore-scripts
|
|
||||||
|
|
||||||
- name: Run ESLint
|
|
||||||
run: npm run lint
|
|
||||||
3
.gitmodules
vendored
|
|
@ -1,3 +1,6 @@
|
||||||
[submodule "vcpkg"]
|
[submodule "vcpkg"]
|
||||||
path = vcpkg
|
path = vcpkg
|
||||||
url = https://github.com/microsoft/vcpkg.git
|
url = https://github.com/microsoft/vcpkg.git
|
||||||
|
[submodule "doxygen-awesome-css"]
|
||||||
|
path = doc/doxygen/theme
|
||||||
|
url = https://github.com/jothepro/doxygen-awesome-css.git
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
cd webclient
|
|
||||||
npm run translate
|
|
||||||
|
|
||||||
git add src/i18n-default.json
|
|
||||||
|
|
@ -16,11 +16,3 @@ source_file = oracle/oracle_en@source.ts
|
||||||
file_filter = oracle/translations/oracle_<lang>.ts
|
file_filter = oracle/translations/oracle_<lang>.ts
|
||||||
type = QT
|
type = QT
|
||||||
minimum_perc = 10
|
minimum_perc = 10
|
||||||
|
|
||||||
[o:cockatrice:p:cockatrice:r:webclient-src-i18n-default-json--master]
|
|
||||||
resource_name = Webclient
|
|
||||||
source_lang = en
|
|
||||||
source_file = webclient/src/i18n-default.json
|
|
||||||
file_filter = webclient/public/locales/<lang>/translation.json
|
|
||||||
type = KEYVALUEJSON
|
|
||||||
minimum_perc = 10
|
|
||||||
|
|
|
||||||
|
|
@ -74,11 +74,11 @@ endif()
|
||||||
|
|
||||||
# A project name is needed for CPack
|
# A project name is needed for CPack
|
||||||
# Version can be overriden by git tags, see cmake/getversion.cmake
|
# Version can be overriden by git tags, see cmake/getversion.cmake
|
||||||
project("Cockatrice" VERSION 2.11.0)
|
project("Cockatrice" VERSION 3.1.0)
|
||||||
|
|
||||||
# Set release name if not provided via env/cmake var
|
# Set release name if not provided via env/cmake var
|
||||||
if(NOT DEFINED GIT_TAG_RELEASENAME)
|
if(NOT DEFINED GIT_TAG_RELEASENAME)
|
||||||
set(GIT_TAG_RELEASENAME "Omenpath")
|
set(GIT_TAG_RELEASENAME "Graduation Day")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Use c++20 for all targets
|
# Use c++20 for all targets
|
||||||
|
|
@ -174,6 +174,7 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
-Wno-error=delete-non-virtual-dtor
|
-Wno-error=delete-non-virtual-dtor
|
||||||
-Wno-error=sign-compare
|
-Wno-error=sign-compare
|
||||||
-Wno-error=missing-declarations
|
-Wno-error=missing-declarations
|
||||||
|
-Wno-error=sfinae-incomplete # GCC 16+: Qt MOC + protobuf forward decls trigger this
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach(FLAG ${ADDITIONAL_DEBUG_FLAGS})
|
foreach(FLAG ${ADDITIONAL_DEBUG_FLAGS})
|
||||||
|
|
@ -254,7 +255,9 @@ endif()
|
||||||
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zach@cockatrice.us>")
|
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zach@cockatrice.us>")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}")
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}")
|
||||||
set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team")
|
set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
|
set(CPACK_PACKAGE_DESCRIPTION
|
||||||
|
"Cockatrice is an open-source, multiplatform application for playing tabletop card games over a network. The program's server design prevents users from manipulating the game for unfair advantage. The client also provides a single-player mode, which allows users to brew while offline."
|
||||||
|
)
|
||||||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
||||||
|
|
@ -328,7 +331,12 @@ include(CPack)
|
||||||
|
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_interfaces ${CMAKE_BINARY_DIR}/libcockatrice_interfaces)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_interfaces ${CMAKE_BINARY_DIR}/libcockatrice_interfaces)
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_protocol ${CMAKE_BINARY_DIR}/libcockatrice_protocol)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_protocol ${CMAKE_BINARY_DIR}/libcockatrice_protocol)
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_network ${CMAKE_BINARY_DIR}/libcockatrice_network)
|
if(WITH_CLIENT
|
||||||
|
OR WITH_SERVER
|
||||||
|
OR WITH_ORACLE
|
||||||
|
)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_network ${CMAKE_BINARY_DIR}/libcockatrice_network)
|
||||||
|
endif()
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_deck_list ${CMAKE_BINARY_DIR}/libcockatrice_deck_list)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_deck_list ${CMAKE_BINARY_DIR}/libcockatrice_deck_list)
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_rng ${CMAKE_BINARY_DIR}/libcockatrice_rng)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_rng ${CMAKE_BINARY_DIR}/libcockatrice_rng)
|
||||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_card ${CMAKE_BINARY_DIR}/libcockatrice_card)
|
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_card ${CMAKE_BINARY_DIR}/libcockatrice_card)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# -------- Build Stage --------
|
# -------- Build Stage --------
|
||||||
FROM ubuntu:24.04 AS build
|
FROM ubuntu:26.04 AS build
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ RUN mkdir build && cd build && \
|
||||||
|
|
||||||
|
|
||||||
# -------- Runtime Stage (clean) --------
|
# -------- Runtime Stage (clean) --------
|
||||||
FROM ubuntu:24.04
|
FROM ubuntu:26.04
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
libprotobuf32t64 \
|
libprotobuf32t64 \
|
||||||
|
|
|
||||||
111
Doxyfile
|
|
@ -1,4 +1,4 @@
|
||||||
# Doxyfile 1.14.0
|
# Doxyfile 1.16.1
|
||||||
|
|
||||||
# This file describes the settings to be used by the documentation system
|
# This file describes the settings to be used by the documentation system
|
||||||
# Doxygen (www.doxygen.org) for a project.
|
# Doxygen (www.doxygen.org) for a project.
|
||||||
|
|
@ -54,7 +54,7 @@ PROJECT_NUMBER = $(COCKATRICE_REF)
|
||||||
# for a project that appears at the top of each page and should give viewers a
|
# for a project that appears at the top of each page and should give viewers a
|
||||||
# quick idea about the purpose of the project. Keep the description short.
|
# quick idea about the purpose of the project. Keep the description short.
|
||||||
|
|
||||||
PROJECT_BRIEF = "A cross-platform virtual tabletop for multiplayer card games"
|
PROJECT_BRIEF = "A virtual tabletop for multiplayer card games"
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||||
# in the documentation. The maximum height of the logo should not exceed 55
|
# in the documentation. The maximum height of the logo should not exceed 55
|
||||||
|
|
@ -361,6 +361,20 @@ EXTENSION_MAPPING =
|
||||||
|
|
||||||
MARKDOWN_SUPPORT = YES
|
MARKDOWN_SUPPORT = YES
|
||||||
|
|
||||||
|
# If the MARKDOWN_STRICT tag is enabled then Doxygen treats text in comments as
|
||||||
|
# Markdown formatted also in cases where Doxygen's native markup format
|
||||||
|
# conflicts with that of Markdown. This is only relevant in cases where
|
||||||
|
# backticks are used. Doxygen's native markup style allows a single quote to end
|
||||||
|
# a text fragment started with a backtick and then treat it as a piece of quoted
|
||||||
|
# text, whereas in Markdown such text fragment is treated as verbatim and only
|
||||||
|
# ends when a second matching backtick is found. Also, Doxygen's native markup
|
||||||
|
# format requires double quotes to be escaped when they appear in a backtick
|
||||||
|
# section, whereas this is not needed for Markdown.
|
||||||
|
# The default value is: YES.
|
||||||
|
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
||||||
|
|
||||||
|
MARKDOWN_STRICT = YES
|
||||||
|
|
||||||
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
|
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
|
||||||
# to that level are automatically included in the table of contents, even if
|
# to that level are automatically included in the table of contents, even if
|
||||||
# they do not have an id attribute.
|
# they do not have an id attribute.
|
||||||
|
|
@ -392,8 +406,8 @@ AUTOLINK_SUPPORT = YES
|
||||||
|
|
||||||
# This tag specifies a list of words that, when matching the start of a word in
|
# This tag specifies a list of words that, when matching the start of a word in
|
||||||
# the documentation, will suppress auto links generation, if it is enabled via
|
# the documentation, will suppress auto links generation, if it is enabled via
|
||||||
# AUTOLINK_SUPPORT. This list does not affect links explicitly created using \#
|
# AUTOLINK_SUPPORT. This list does not affect links explicitly created using #
|
||||||
# or the \link or commands.
|
# or the \link or \ref commands.
|
||||||
# This tag requires that the tag AUTOLINK_SUPPORT is set to YES.
|
# This tag requires that the tag AUTOLINK_SUPPORT is set to YES.
|
||||||
|
|
||||||
AUTOLINK_IGNORE_WORDS =
|
AUTOLINK_IGNORE_WORDS =
|
||||||
|
|
@ -510,9 +524,9 @@ LOOKUP_CACHE_SIZE = 0
|
||||||
# which effectively disables parallel processing. Please report any issues you
|
# which effectively disables parallel processing. Please report any issues you
|
||||||
# encounter. Generating dot graphs in parallel is controlled by the
|
# encounter. Generating dot graphs in parallel is controlled by the
|
||||||
# DOT_NUM_THREADS setting.
|
# DOT_NUM_THREADS setting.
|
||||||
# Minimum value: 0, maximum value: 32, default value: 1.
|
# Minimum value: 0, maximum value: 512, default value: 1.
|
||||||
|
|
||||||
NUM_PROC_THREADS = 1
|
NUM_PROC_THREADS = 0
|
||||||
|
|
||||||
# If the TIMESTAMP tag is set different from NO then each generated page will
|
# If the TIMESTAMP tag is set different from NO then each generated page will
|
||||||
# contain the date or date and time when the page was generated. Setting this to
|
# contain the date or date and time when the page was generated. Setting this to
|
||||||
|
|
@ -779,6 +793,27 @@ GENERATE_BUGLIST = YES
|
||||||
|
|
||||||
GENERATE_DEPRECATEDLIST= YES
|
GENERATE_DEPRECATEDLIST= YES
|
||||||
|
|
||||||
|
# The GENERATE_REQUIREMENTS tag can be used to enable (YES) or disable (NO) the
|
||||||
|
# requirements page. When enabled, this page is automatically created when at
|
||||||
|
# least one comment block with a \requirement command appears in the input.
|
||||||
|
# The default value is: YES.
|
||||||
|
|
||||||
|
GENERATE_REQUIREMENTS = YES
|
||||||
|
|
||||||
|
# The REQ_TRACEABILITY_INFO tag controls if traceability information is shown on
|
||||||
|
# the requirements page (only relevant when using \requirement comment blocks).
|
||||||
|
# The setting NO will disable the traceablility information altogether. The
|
||||||
|
# setting UNSATISFIED_ONLY will show a list of requirements that are missing a
|
||||||
|
# satisfies relation (through the command: \satisfies). Similarly the setting
|
||||||
|
# UNVERIFIED_ONLY will show a list of requirements that are missing a verifies
|
||||||
|
# relation (through the command: \verifies). Setting the tag to YES (the
|
||||||
|
# default) will show both lists if applicable.
|
||||||
|
# Possible values are: YES, NO, UNSATISFIED_ONLY and UNVERIFIED_ONLY.
|
||||||
|
# The default value is: YES.
|
||||||
|
# This tag requires that the tag GENERATE_REQUIREMENTS is set to YES.
|
||||||
|
|
||||||
|
REQ_TRACEABILITY_INFO = YES
|
||||||
|
|
||||||
# The ENABLED_SECTIONS tag can be used to enable conditional documentation
|
# The ENABLED_SECTIONS tag can be used to enable conditional documentation
|
||||||
# sections, marked by \if <section_label> ... \endif and \cond <section_label>
|
# sections, marked by \if <section_label> ... \endif and \cond <section_label>
|
||||||
# ... \endcond blocks.
|
# ... \endcond blocks.
|
||||||
|
|
@ -1068,8 +1103,9 @@ RECURSIVE = YES
|
||||||
|
|
||||||
EXCLUDE = build/ \
|
EXCLUDE = build/ \
|
||||||
cmake/ \
|
cmake/ \
|
||||||
vcpkg/ \
|
doc/doxygen/theme/docs/ \
|
||||||
webclient/
|
doc/doxygen/theme/include/ \
|
||||||
|
vcpkg/
|
||||||
|
|
||||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||||
|
|
@ -1430,7 +1466,9 @@ HTML_STYLESHEET =
|
||||||
# documentation.
|
# documentation.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_EXTRA_STYLESHEET = doc/doxygen/css/doxygen_style.css
|
HTML_EXTRA_STYLESHEET = doc/doxygen/theme/doxygen-awesome.css \
|
||||||
|
doc/doxygen/css/hide_nav_sync.css \
|
||||||
|
doc/doxygen/css/cockatrice_docs_style.css
|
||||||
|
|
||||||
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
||||||
# other source files which should be copied to the HTML output directory. Note
|
# other source files which should be copied to the HTML output directory. Note
|
||||||
|
|
@ -1453,7 +1491,7 @@ HTML_EXTRA_FILES = doc/doxygen/js/graph_toggle.js
|
||||||
# The default value is: AUTO_LIGHT.
|
# The default value is: AUTO_LIGHT.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_COLORSTYLE = AUTO_DARK
|
HTML_COLORSTYLE = LIGHT
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||||
# will adjust the colors in the style sheet and background images according to
|
# will adjust the colors in the style sheet and background images according to
|
||||||
|
|
@ -1764,7 +1802,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
DISABLE_INDEX = YES
|
DISABLE_INDEX = NO
|
||||||
|
|
||||||
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
|
||||||
# structure should be generated to display hierarchical information. If the tag
|
# structure should be generated to display hierarchical information. If the tag
|
||||||
|
|
@ -1883,7 +1921,7 @@ USE_MATHJAX = NO
|
||||||
# regards to the different settings, so it is possible that also other MathJax
|
# regards to the different settings, so it is possible that also other MathJax
|
||||||
# settings have to be changed when switching between the different MathJax
|
# settings have to be changed when switching between the different MathJax
|
||||||
# versions.
|
# versions.
|
||||||
# Possible values are: MathJax_2 and MathJax_3.
|
# Possible values are: MathJax_2, MathJax_3 and MathJax_4.
|
||||||
# The default value is: MathJax_2.
|
# The default value is: MathJax_2.
|
||||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||||
|
|
||||||
|
|
@ -1892,9 +1930,10 @@ MATHJAX_VERSION = MathJax_2
|
||||||
# When MathJax is enabled you can set the default output format to be used for
|
# When MathJax is enabled you can set the default output format to be used for
|
||||||
# the MathJax output. For more details about the output format see MathJax
|
# the MathJax output. For more details about the output format see MathJax
|
||||||
# version 2 (see:
|
# version 2 (see:
|
||||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
|
# https://docs.mathjax.org/en/v2.7/output.html), MathJax version 3 (see:
|
||||||
|
# https://docs.mathjax.org/en/v3.2/output/index.html) and MathJax version 4
|
||||||
# (see:
|
# (see:
|
||||||
# http://docs.mathjax.org/en/latest/web/components/output.html).
|
# https://docs.mathjax.org/en/v4.0/output/index.htm).
|
||||||
# Possible values are: HTML-CSS (which is slower, but has the best
|
# Possible values are: HTML-CSS (which is slower, but has the best
|
||||||
# compatibility. This is the name for Mathjax version 2, for MathJax version 3
|
# compatibility. This is the name for Mathjax version 2, for MathJax version 3
|
||||||
# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
|
# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
|
||||||
|
|
@ -1907,36 +1946,50 @@ MATHJAX_VERSION = MathJax_2
|
||||||
MATHJAX_FORMAT = HTML-CSS
|
MATHJAX_FORMAT = HTML-CSS
|
||||||
|
|
||||||
# When MathJax is enabled you need to specify the location relative to the HTML
|
# When MathJax is enabled you need to specify the location relative to the HTML
|
||||||
# output directory using the MATHJAX_RELPATH option. The destination directory
|
# output directory using the MATHJAX_RELPATH option. For Mathjax version 2 the
|
||||||
# should contain the MathJax.js script. For instance, if the mathjax directory
|
# destination directory should contain the MathJax.js script. For instance, if
|
||||||
# is located at the same level as the HTML output directory, then
|
# the mathjax directory is located at the same level as the HTML output
|
||||||
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
|
# directory, then MATHJAX_RELPATH should be ../mathjax.s For Mathjax versions 3
|
||||||
# Content Delivery Network so you can quickly see the result without installing
|
# and 4 the destination directory should contain the tex-<format>.js script
|
||||||
# MathJax. However, it is strongly recommended to install a local copy of
|
# (where <format> is either chtml or svg). The default value points to the
|
||||||
# MathJax from https://www.mathjax.org before deployment. The default value is:
|
# MathJax Content Delivery Network so you can quickly see the result without
|
||||||
|
# installing MathJax. However, it is strongly recommended to install a local
|
||||||
|
# copy of MathJax from https://www.mathjax.org before deployment. The default
|
||||||
|
# value is:
|
||||||
# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
|
# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
|
||||||
# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
|
# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
|
||||||
|
# - in case of MathJax version 4: https://cdn.jsdelivr.net/npm/mathjax@4
|
||||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||||
|
|
||||||
MATHJAX_RELPATH =
|
MATHJAX_RELPATH =
|
||||||
|
|
||||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||||
# extension names that should be enabled during MathJax rendering. For example
|
# extension names that should be enabled during MathJax rendering. For example
|
||||||
# for MathJax version 2 (see
|
# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7/tex.html):
|
||||||
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
|
|
||||||
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
||||||
# For example for MathJax version 3 (see
|
# For example for MathJax version 3 (see
|
||||||
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
|
# https://docs.mathjax.org/en/v3.2/input/tex/extensions/):
|
||||||
# MATHJAX_EXTENSIONS = ams
|
# MATHJAX_EXTENSIONS = ams
|
||||||
|
# For example for MathJax version 4 (see
|
||||||
|
# https://docs.mathjax.org/en/v4.0/input/tex/extensions/):
|
||||||
|
# MATHJAX_EXTENSIONS = units
|
||||||
|
# Note that for Mathjax version 4 quite a few extensions are already
|
||||||
|
# automatically loaded. To disable a package in Mathjax version 4 one can use
|
||||||
|
# the package name prepended with a minus sign (- like MATHJAX_EXTENSIONS +=
|
||||||
|
# -textmacros)
|
||||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||||
|
|
||||||
MATHJAX_EXTENSIONS =
|
MATHJAX_EXTENSIONS =
|
||||||
|
|
||||||
# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces
|
# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces
|
||||||
# of code that will be used on startup of the MathJax code. See the MathJax site
|
# of code that will be used on startup of the MathJax code. See the Mathjax site
|
||||||
# (see:
|
# for more details:
|
||||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
|
# - MathJax version 2 (see:
|
||||||
# example see the documentation.
|
# https://docs.mathjax.org/en/v2.7/)
|
||||||
|
# - MathJax version 3 (see:
|
||||||
|
# https://docs.mathjax.org/en/v3.2/)
|
||||||
|
# - MathJax version 4 (see:
|
||||||
|
# https://docs.mathjax.org/en/v4.0/) For an example see the documentation.
|
||||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||||
|
|
||||||
MATHJAX_CODEFILE =
|
MATHJAX_CODEFILE =
|
||||||
|
|
@ -2597,7 +2650,7 @@ HAVE_DOT = YES
|
||||||
# processors available in the system. You can set it explicitly to a value
|
# processors available in the system. You can set it explicitly to a value
|
||||||
# larger than 0 to get control over the balance between CPU load and processing
|
# larger than 0 to get control over the balance between CPU load and processing
|
||||||
# speed.
|
# speed.
|
||||||
# Minimum value: 0, maximum value: 32, default value: 0.
|
# Minimum value: 0, maximum value: 512, default value: 0.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
DOT_NUM_THREADS = 0
|
DOT_NUM_THREADS = 0
|
||||||
|
|
|
||||||
12
README.md
|
|
@ -8,7 +8,7 @@
|
||||||
<a href="#related-repositories">Related</a> <b>|</b>
|
<a href="#related-repositories">Related</a> <b>|</b>
|
||||||
<a href="#community-resources-">Community</a> <b>|</b>
|
<a href="#community-resources-">Community</a> <b>|</b>
|
||||||
<a href="#contribute">Contribute</a> <b>|</b>
|
<a href="#contribute">Contribute</a> <b>|</b>
|
||||||
<a href="#build---">Build</a> <b>|</b>
|
<a href="#build--">Build</a> <b>|</b>
|
||||||
<a href="#run">Run</a>
|
<a href="#run">Run</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
|
|
||||||
Cockatrice is an open-source, multiplatform application for playing tabletop card games over a network. The program's server design prevents users from manipulating the game for unfair advantage. The client also provides a single-player mode, which allows users to brew while offline.<br><br>
|
Cockatrice is an open-source, multiplatform application for playing tabletop card games over a network. The program's server design prevents users from manipulating the game for unfair advantage. The client also provides a single-player mode, which allows users to brew while offline.<br><br>
|
||||||
This project uses <kbd>C++</kbd> and the <kbd>Qt</kbd> libraries.<br>
|
This project uses <kbd>C++</kbd> and the <kbd>Qt</kbd> libraries.<br>
|
||||||
First work on a webclient with <kbd>Typescript</kbd> was started as well.<br>
|
|
||||||
|
|
||||||
|
|
||||||
# Download [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice&search=0)
|
# Download [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice&search=0)
|
||||||
|
|
@ -48,11 +47,12 @@ Latest <kbd>beta</kbd> version:
|
||||||
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Code to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) for use in Cockatrice
|
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Code to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) for use in Cockatrice
|
||||||
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official Cockatrice webpage
|
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official Cockatrice webpage
|
||||||
- [io.github.Cockatrice.cockatrice](https://github.com/flathub/io.github.Cockatrice.cockatrice): Configuration of our Linux `flatpak` package hosted at [Flathub](https://flathub.org/en/apps/io.github.Cockatrice.cockatrice)
|
- [io.github.Cockatrice.cockatrice](https://github.com/flathub/io.github.Cockatrice.cockatrice): Configuration of our Linux `flatpak` package hosted at [Flathub](https://flathub.org/en/apps/io.github.Cockatrice.cockatrice)
|
||||||
|
- [Webatrice](https://github.com/Cockatrice/Webatrice): Web client for Cockatrice servers (TypeScript / React)
|
||||||
|
|
||||||
|
|
||||||
# Community Resources [](https://discord.gg/3Z9yzmA)
|
# Community Resources [](https://discord.gg/3Z9yzmA)
|
||||||
|
|
||||||
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other projet contributors (`#dev` channel) or fellow users of the app. Come here to talk about the application, features, or just to hang out.
|
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other project contributors (`#dev` channel) or fellow users of the app. Come here to talk about the application, features, or just to hang out.
|
||||||
- [Official Website](https://cockatrice.github.io)
|
- [Official Website](https://cockatrice.github.io)
|
||||||
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki)
|
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki)
|
||||||
- [Official Discord](https://discord.gg/3Z9yzmA)
|
- [Official Discord](https://discord.gg/3Z9yzmA)
|
||||||
|
|
@ -107,12 +107,12 @@ Cockatrice tries to use the [Google Developer Documentation Style Guide](https:/
|
||||||
|
|
||||||
### Translation [](https://explore.transifex.com/cockatrice/cockatrice/)
|
### Translation [](https://explore.transifex.com/cockatrice/cockatrice/)
|
||||||
|
|
||||||
Cockatrice uses Transifex to manage translations. You can help us bring <kbd>Cockatrice</kbd>, <kbd>Oracle</kbd> and <kbd>Webatrice</kbd> to your language and just adjust single wordings right from within your browser by visiting our [Transifex project page](https://explore.transifex.com/cockatrice/cockatrice/).<br>
|
Cockatrice uses Transifex to manage translations. You can help us bring <kbd>Cockatrice</kbd> and <kbd>Oracle</kbd> to your language and just adjust single wordings right from within your browser by visiting our [Transifex project page](https://explore.transifex.com/cockatrice/cockatrice/). The [Webatrice](https://github.com/seavor/Webatrice) web client manages its own translations in its repo.<br>
|
||||||
|
|
||||||
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about getting invovled, and join a group of hundreds of others!<br>
|
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about getting involved, and join a group of hundreds of others!<br>
|
||||||
|
|
||||||
|
|
||||||
# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/docker-release.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
|
# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/docker-release.yml?query=branch%3Amaster+event%3Apush)
|
||||||
|
|
||||||
Dependencies: *(for minimum versions search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
|
Dependencies: *(for minimum versions search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
|
||||||
- [Qt](https://www.qt.io/developers/)
|
- [Qt](https://www.qt.io/developers/)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@ if(WITH_ORACLE)
|
||||||
set(_ORACLE_NEEDED Concurrent Network Svg Widgets)
|
set(_ORACLE_NEEDED Concurrent Network Svg Widgets)
|
||||||
endif()
|
endif()
|
||||||
if(TEST)
|
if(TEST)
|
||||||
set(_TEST_NEEDED Widgets)
|
# Union of Qt modules required across all test targets (independent of application targets).
|
||||||
|
# When adding a new test that needs additional Qt modules, add them here rather than in the test's CMakeLists.txt.
|
||||||
|
set(_TEST_NEEDED Concurrent Network Svg Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(REQUIRED_QT_COMPONENTS ${REQUIRED_QT_COMPONENTS} ${_SERVATRICE_NEEDED} ${_COCKATRICE_NEEDED} ${_ORACLE_NEEDED}
|
set(REQUIRED_QT_COMPONENTS ${REQUIRED_QT_COMPONENTS} ${_SERVATRICE_NEEDED} ${_COCKATRICE_NEEDED} ${_ORACLE_NEEDED}
|
||||||
|
|
@ -40,7 +42,7 @@ list(REMOVE_DUPLICATES REQUIRED_QT_COMPONENTS)
|
||||||
if(NOT FORCE_USE_QT5)
|
if(NOT FORCE_USE_QT5)
|
||||||
# Linguist is now a component in Qt6 instead of an external package
|
# Linguist is now a component in Qt6 instead of an external package
|
||||||
find_package(
|
find_package(
|
||||||
Qt6 6.2.3
|
Qt6 6.4.2
|
||||||
COMPONENTS ${REQUIRED_QT_COMPONENTS} Linguist
|
COMPONENTS ${REQUIRED_QT_COMPONENTS} Linguist
|
||||||
QUIET HINTS ${Qt6_DIR}
|
QUIET HINTS ${Qt6_DIR}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ SetCompressor LZMA
|
||||||
Var NormalDestDir
|
Var NormalDestDir
|
||||||
Var PortableDestDir
|
Var PortableDestDir
|
||||||
Var PortableMode
|
Var PortableMode
|
||||||
|
Var ReinstallMode
|
||||||
|
|
||||||
!include LogicLib.nsh
|
!include LogicLib.nsh
|
||||||
!include FileFunc.nsh
|
!include FileFunc.nsh
|
||||||
|
|
@ -26,14 +27,25 @@ Var PortableMode
|
||||||
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Cockatrice.$\r$\n$\r$\nClick Next to continue."
|
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Cockatrice.$\r$\n$\r$\nClick Next to continue."
|
||||||
!define MUI_FINISHPAGE_RUN "$INSTDIR/cockatrice.exe"
|
!define MUI_FINISHPAGE_RUN "$INSTDIR/cockatrice.exe"
|
||||||
!define MUI_FINISHPAGE_RUN_TEXT "Run 'Cockatrice' now"
|
!define MUI_FINISHPAGE_RUN_TEXT "Run 'Cockatrice' now"
|
||||||
|
!define MUI_ICON "${NSIS_SOURCE_PATH}\cockatrice\resources\appicon.ico"
|
||||||
|
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
|
||||||
!insertmacro MUI_PAGE_WELCOME
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
|
||||||
!insertmacro MUI_PAGE_LICENSE "${NSIS_SOURCE_PATH}\LICENSE"
|
!insertmacro MUI_PAGE_LICENSE "${NSIS_SOURCE_PATH}\LICENSE"
|
||||||
|
|
||||||
Page Custom PortableModePageCreate PortableModePageLeave
|
Page Custom PortableModePageCreate PortableModePageLeave
|
||||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE componentsPagePre
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE componentsPagePre
|
||||||
!insertmacro MUI_PAGE_COMPONENTS
|
!insertmacro MUI_PAGE_COMPONENTS
|
||||||
|
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
|
||||||
!insertmacro MUI_PAGE_DIRECTORY
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
|
||||||
!insertmacro MUI_PAGE_INSTFILES
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE SkipIfReinstall
|
||||||
!insertmacro MUI_PAGE_FINISH
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
!insertmacro MUI_UNPAGE_CONFIRM
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
|
@ -72,6 +84,7 @@ ${IfNot} ${Errors}
|
||||||
MessageBox MB_ICONINFORMATION|MB_SETFOREGROUND "\
|
MessageBox MB_ICONINFORMATION|MB_SETFOREGROUND "\
|
||||||
/PORTABLE : Install in portable mode$\n\
|
/PORTABLE : Install in portable mode$\n\
|
||||||
/S : Silent install$\n\
|
/S : Silent install$\n\
|
||||||
|
/R : Silent upgrade$\n\
|
||||||
/D=%directory% : Specify destination directory$\n"
|
/D=%directory% : Specify destination directory$\n"
|
||||||
Quit
|
Quit
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
@ -89,6 +102,16 @@ ${Else}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
|
ClearErrors
|
||||||
|
${GetOptions} $9 "/R" $8
|
||||||
|
${IfNot} ${Errors}
|
||||||
|
StrCpy $ReinstallMode 1
|
||||||
|
SetSilent silent
|
||||||
|
SetAutoClose true
|
||||||
|
${Else}
|
||||||
|
StrCpy $ReinstallMode 0
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
${If} $InstDir == ""
|
${If} $InstDir == ""
|
||||||
; User did not use /D to specify a directory,
|
; User did not use /D to specify a directory,
|
||||||
; we need to set a default based on the install mode
|
; we need to set a default based on the install mode
|
||||||
|
|
@ -96,6 +119,22 @@ ${If} $InstDir == ""
|
||||||
${EndIf}
|
${EndIf}
|
||||||
Call SetModeDestinationFromInstdir
|
Call SetModeDestinationFromInstdir
|
||||||
|
|
||||||
|
; --- Detect portable install when using /R ---
|
||||||
|
${If} $ReinstallMode = 1
|
||||||
|
IfFileExists "$InstDir\portable.dat" 0 not_portable
|
||||||
|
StrCpy $PortableMode 1
|
||||||
|
Goto portable_done
|
||||||
|
|
||||||
|
not_portable:
|
||||||
|
StrCpy $PortableMode 0
|
||||||
|
|
||||||
|
portable_done:
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${If} $ReinstallMode = 1
|
||||||
|
Call AutoUninstallIfNeeded
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
Function un.onInit
|
Function un.onInit
|
||||||
|
|
@ -125,8 +164,46 @@ ${Else}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
Function SkipIfReinstall
|
||||||
|
${If} $ReinstallMode = 1
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
Function AutoUninstallIfNeeded
|
||||||
|
|
||||||
|
SetShellVarContext all
|
||||||
|
|
||||||
|
; --- 32-bit uninstall ---
|
||||||
|
SetRegView 32
|
||||||
|
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
|
||||||
|
|
||||||
|
StrCmp $R0 "" done32
|
||||||
|
DetailPrint "Removing previous version (32-bit)..."
|
||||||
|
ExecWait '$R0'
|
||||||
|
|
||||||
|
done32:
|
||||||
|
|
||||||
|
; --- 64-bit uninstall ---
|
||||||
|
${If} ${RunningX64}
|
||||||
|
SetRegView 64
|
||||||
|
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "QuietUninstallString"
|
||||||
|
|
||||||
|
StrCmp $R0 "" done64
|
||||||
|
DetailPrint "Removing previous version (64-bit)..."
|
||||||
|
ExecWait '$R0'
|
||||||
|
|
||||||
|
done64:
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
Function PortableModePageCreate
|
Function PortableModePageCreate
|
||||||
|
|
||||||
|
${If} $ReinstallMode = 1
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
Call SetModeDestinationFromInstdir ; If the user clicks BACK on the directory page we will remember their mode specific directory
|
Call SetModeDestinationFromInstdir ; If the user clicks BACK on the directory page we will remember their mode specific directory
|
||||||
!insertmacro MUI_HEADER_TEXT "Install Mode" "Choose how you want to install Cockatrice."
|
!insertmacro MUI_HEADER_TEXT "Install Mode" "Choose how you want to install Cockatrice."
|
||||||
nsDialogs::Create 1018
|
nsDialogs::Create 1018
|
||||||
|
|
@ -158,6 +235,11 @@ ${EndIf}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
Function componentsPagePre
|
Function componentsPagePre
|
||||||
|
|
||||||
|
${If} $ReinstallMode = 1
|
||||||
|
Return
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
${If} $PortableMode = 0
|
${If} $PortableMode = 0
|
||||||
SetShellVarContext all
|
SetShellVarContext all
|
||||||
|
|
||||||
|
|
@ -167,8 +249,12 @@ ${If} $PortableMode = 0
|
||||||
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString"
|
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString"
|
||||||
StrCmp $R0 "" done32
|
StrCmp $R0 "" done32
|
||||||
|
|
||||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst32
|
${If} $ReinstallMode = 0
|
||||||
Abort
|
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst32
|
||||||
|
Abort
|
||||||
|
${Else}
|
||||||
|
Goto uninst32
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
uninst32:
|
uninst32:
|
||||||
ClearErrors
|
ClearErrors
|
||||||
|
|
@ -183,8 +269,12 @@ ${If} $PortableMode = 0
|
||||||
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString"
|
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "UninstallString"
|
||||||
StrCmp $R0 "" done64
|
StrCmp $R0 "" done64
|
||||||
|
|
||||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst64
|
${If} $ReinstallMode = 0
|
||||||
Abort
|
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "A previous version of Cockatrice must be uninstalled before installing the new one." IDOK uninst64
|
||||||
|
Abort
|
||||||
|
${Else}
|
||||||
|
Goto uninst64
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
uninst64:
|
uninst64:
|
||||||
ClearErrors
|
ClearErrors
|
||||||
|
|
@ -276,6 +366,12 @@ ${Else}
|
||||||
FileWrite $0 "PORTABLE"
|
FileWrite $0 "PORTABLE"
|
||||||
FileClose $0
|
FileClose $0
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
|
${If} $ReinstallMode = 1
|
||||||
|
IfFileExists "$INSTDIR\cockatrice.exe" 0 +2
|
||||||
|
Exec '"$INSTDIR\cockatrice.exe"'
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Start menu item" SecStartMenu
|
Section "Start menu item" SecStartMenu
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,8 @@ set(PROJECT_VERSION_FRIENDLY "${PROJECT_VERSION} (${GIT_COMMIT_DATE_FRIENDLY})")
|
||||||
# Format: <program name>[-ReleaseName]-MAJ.MIN.PATCH[-prerelease_label]
|
# Format: <program name>[-ReleaseName]-MAJ.MIN.PATCH[-prerelease_label]
|
||||||
set(PROJECT_VERSION_FILENAME "${PROJECT_NAME}")
|
set(PROJECT_VERSION_FILENAME "${PROJECT_NAME}")
|
||||||
if(PROJECT_VERSION_RELEASENAME)
|
if(PROJECT_VERSION_RELEASENAME)
|
||||||
set(PROJECT_VERSION_FILENAME "${PROJECT_VERSION_FILENAME}-${PROJECT_VERSION_RELEASENAME}")
|
string(REPLACE " " "-" PROJECT_VERSION_RELEASENAME_SAFE "${PROJECT_VERSION_RELEASENAME}")
|
||||||
|
set(PROJECT_VERSION_FILENAME "${PROJECT_VERSION_FILENAME}-${PROJECT_VERSION_RELEASENAME_SAFE}")
|
||||||
endif()
|
endif()
|
||||||
set(PROJECT_VERSION_FILENAME "${PROJECT_VERSION_FILENAME}-${PROJECT_VERSION}")
|
set(PROJECT_VERSION_FILENAME "${PROJECT_VERSION_FILENAME}-${PROJECT_VERSION}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
project(gtest-download LANGUAGES NONE)
|
project(gtest-download LANGUAGES NONE)
|
||||||
|
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
ExternalProject_Add(googletest
|
externalproject_add(
|
||||||
URL https://github.com/google/googletest/archive/release-1.11.0.zip
|
googletest
|
||||||
URL_HASH SHA1=9ffb7b5923f4a8fcdabf2f42c6540cce299f44c0
|
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.zip
|
||||||
|
URL_HASH SHA1=f638fa0e724760e2ba07ff8cfba32cd644e1ce28
|
||||||
SOURCE_DIR "${CMAKE_BINARY_DIR}/gtest-src"
|
SOURCE_DIR "${CMAKE_BINARY_DIR}/gtest-src"
|
||||||
BINARY_DIR "${CMAKE_BINARY_DIR}/gtest-build"
|
BINARY_DIR "${CMAKE_BINARY_DIR}/gtest-build"
|
||||||
CONFIGURE_COMMAND ""
|
CONFIGURE_COMMAND ""
|
||||||
BUILD_COMMAND ""
|
BUILD_COMMAND ""
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
TEST_COMMAND ""
|
TEST_COMMAND ""
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${
|
||||||
set(cockatrice_SOURCES
|
set(cockatrice_SOURCES
|
||||||
${VERSION_STRING_CPP}
|
${VERSION_STRING_CPP}
|
||||||
# sort by alphabetical order, so that there is no debate about where to add new sources to the list
|
# sort by alphabetical order, so that there is no debate about where to add new sources to the list
|
||||||
|
src/client/network/connection_controller/remote_connection_controller.cpp
|
||||||
src/client/network/update/client/update_downloader.cpp
|
src/client/network/update/client/update_downloader.cpp
|
||||||
src/client/network/interfaces/deck_stats_interface.cpp
|
src/client/network/interfaces/deck_stats_interface.cpp
|
||||||
src/client/network/interfaces/tapped_out_interface.cpp
|
src/client/network/interfaces/tapped_out_interface.cpp
|
||||||
|
|
@ -39,6 +40,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp
|
src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp
|
||||||
src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp
|
src/interface/widgets/dialogs/dlg_load_deck_from_website.cpp
|
||||||
src/interface/widgets/dialogs/dlg_load_remote_deck.cpp
|
src/interface/widgets/dialogs/dlg_load_remote_deck.cpp
|
||||||
|
src/interface/widgets/dialogs/dlg_local_game_options.cpp
|
||||||
src/interface/widgets/dialogs/dlg_manage_sets.cpp
|
src/interface/widgets/dialogs/dlg_manage_sets.cpp
|
||||||
src/interface/widgets/dialogs/dlg_register.cpp
|
src/interface/widgets/dialogs/dlg_register.cpp
|
||||||
src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp
|
src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp
|
||||||
|
|
@ -47,74 +49,80 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
src/interface/widgets/dialogs/dlg_tip_of_the_day.cpp
|
||||||
src/interface/widgets/dialogs/dlg_update.cpp
|
src/interface/widgets/dialogs/dlg_update.cpp
|
||||||
src/interface/widgets/dialogs/dlg_view_log.cpp
|
src/interface/widgets/dialogs/dlg_view_log.cpp
|
||||||
|
src/interface/widgets/dialogs/override_printing_warning.cpp
|
||||||
src/interface/widgets/dialogs/tip_of_the_day.cpp
|
src/interface/widgets/dialogs/tip_of_the_day.cpp
|
||||||
src/filters/deck_filter_string.cpp
|
src/filters/deck_filter_string.cpp
|
||||||
src/filters/filter_builder.cpp
|
src/filters/filter_builder.cpp
|
||||||
src/filters/filter_tree_model.cpp
|
src/filters/filter_tree_model.cpp
|
||||||
src/filters/syntax_help.cpp
|
src/filters/syntax_help.cpp
|
||||||
src/game/abstract_game.cpp
|
src/game/abstract_game.cpp
|
||||||
src/game/board/abstract_card_drag_item.cpp
|
src/game/arrow_registry.cpp
|
||||||
src/game/board/abstract_card_item.cpp
|
src/game_graphics/board/abstract_card_drag_item.cpp
|
||||||
src/game/board/abstract_counter.cpp
|
src/game_graphics/board/abstract_card_item.cpp
|
||||||
src/game/board/arrow_item.cpp
|
src/game_graphics/board/abstract_counter.cpp
|
||||||
src/game/board/arrow_target.cpp
|
src/game/board/arrow_data.cpp
|
||||||
src/game/board/card_drag_item.cpp
|
src/game_graphics/board/arrow_item.cpp
|
||||||
src/game/board/card_item.cpp
|
src/game_graphics/board/arrow_target.cpp
|
||||||
|
src/game_graphics/board/card_drag_item.cpp
|
||||||
|
src/game_graphics/board/card_item.cpp
|
||||||
src/game/board/card_list.cpp
|
src/game/board/card_list.cpp
|
||||||
src/game/board/counter_general.cpp
|
src/game/board/card_state.cpp
|
||||||
src/game/board/translate_counter_name.cpp
|
src/game_graphics/board/counter_general.cpp
|
||||||
src/game/deckview/deck_view.cpp
|
src/game/board/counter_state.cpp
|
||||||
src/game/deckview/deck_view_container.cpp
|
src/game_graphics/board/translate_counter_name.cpp
|
||||||
src/game/deckview/tabbed_deck_view_container.cpp
|
src/game_graphics/deckview/deck_view.cpp
|
||||||
src/game/dialogs/dlg_create_token.cpp
|
src/game_graphics/deckview/deck_view_container.cpp
|
||||||
src/game/dialogs/dlg_move_top_cards_until.cpp
|
src/game_graphics/deckview/tabbed_deck_view_container.cpp
|
||||||
src/game/dialogs/dlg_roll_dice.cpp
|
src/game_graphics/dialogs/dlg_create_token.cpp
|
||||||
|
src/game_graphics/dialogs/dlg_move_top_cards_until.cpp
|
||||||
|
src/game_graphics/dialogs/dlg_roll_dice.cpp
|
||||||
src/game/game.cpp
|
src/game/game.cpp
|
||||||
src/game/game_event_handler.cpp
|
src/game/game_event_handler.cpp
|
||||||
src/game/game_meta_info.cpp
|
src/game/game_meta_info.cpp
|
||||||
src/game/game_scene.cpp
|
src/game_graphics/game_scene.cpp
|
||||||
src/game/game_state.cpp
|
src/game/game_state.cpp
|
||||||
src/game/game_view.cpp
|
src/game_graphics/game_view.cpp
|
||||||
src/game/hand_counter.cpp
|
src/game_graphics/hand_counter.cpp
|
||||||
src/game/log/message_log_widget.cpp
|
src/game_graphics/log/message_log_widget.cpp
|
||||||
src/game/phase.cpp
|
src/game/phase.cpp
|
||||||
src/game/phases_toolbar.cpp
|
src/game_graphics/phases_toolbar.cpp
|
||||||
src/game/player/menu/card_menu.cpp
|
src/game_graphics/player/menu/card_menu.cpp
|
||||||
src/game/player/menu/custom_zone_menu.cpp
|
src/game_graphics/player/menu/custom_zone_menu.cpp
|
||||||
src/game/player/menu/grave_menu.cpp
|
src/game_graphics/player/menu/grave_menu.cpp
|
||||||
src/game/player/menu/hand_menu.cpp
|
src/game_graphics/player/menu/hand_menu.cpp
|
||||||
src/game/player/menu/library_menu.cpp
|
src/game_graphics/player/menu/library_menu.cpp
|
||||||
src/game/player/menu/move_menu.cpp
|
src/game_graphics/player/menu/move_menu.cpp
|
||||||
src/game/player/menu/player_menu.cpp
|
src/game_graphics/player/menu/player_menu.cpp
|
||||||
src/game/player/menu/pt_menu.cpp
|
src/game_graphics/player/menu/pt_menu.cpp
|
||||||
src/game/player/menu/rfg_menu.cpp
|
src/game_graphics/player/menu/rfg_menu.cpp
|
||||||
src/game/player/menu/say_menu.cpp
|
src/game_graphics/player/menu/say_menu.cpp
|
||||||
src/game/player/menu/sideboard_menu.cpp
|
src/game_graphics/player/menu/sideboard_menu.cpp
|
||||||
src/game/player/menu/utility_menu.cpp
|
src/game_graphics/player/menu/utility_menu.cpp
|
||||||
src/game/player/player.cpp
|
|
||||||
src/game/player/player_actions.cpp
|
src/game/player/player_actions.cpp
|
||||||
src/game/player/player_area.cpp
|
src/game_graphics/player/player_area.cpp
|
||||||
|
src/game_graphics/player/player_dialogs.cpp
|
||||||
src/game/player/player_event_handler.cpp
|
src/game/player/player_event_handler.cpp
|
||||||
src/game/player/player_graphics_item.cpp
|
src/game_graphics/player/player_graphics_item.cpp
|
||||||
src/game/player/player_info.cpp
|
src/game/player/player_info.cpp
|
||||||
src/game/player/player_list_widget.cpp
|
src/game_graphics/player/player_list_widget.cpp
|
||||||
|
src/game/player/player_logic.cpp
|
||||||
src/game/player/player_manager.cpp
|
src/game/player/player_manager.cpp
|
||||||
src/game/player/player_target.cpp
|
src/game_graphics/player/player_target.cpp
|
||||||
src/game/replay.cpp
|
src/game/replay.cpp
|
||||||
src/game/zones/card_zone.cpp
|
src/game/zones/card_zone_logic.cpp
|
||||||
src/game/zones/hand_zone.cpp
|
src/game/zones/hand_zone_logic.cpp
|
||||||
src/game/zones/logic/card_zone_logic.cpp
|
src/game/zones/pile_zone_logic.cpp
|
||||||
src/game/zones/logic/hand_zone_logic.cpp
|
src/game/zones/stack_zone_logic.cpp
|
||||||
src/game/zones/logic/pile_zone_logic.cpp
|
src/game/zones/table_zone_logic.cpp
|
||||||
src/game/zones/logic/stack_zone_logic.cpp
|
src/game/zones/view_zone_logic.cpp
|
||||||
src/game/zones/logic/table_zone_logic.cpp
|
src/game_graphics/zones/card_zone.cpp
|
||||||
src/game/zones/logic/view_zone_logic.cpp
|
src/game_graphics/zones/hand_zone.cpp
|
||||||
src/game/zones/pile_zone.cpp
|
src/game_graphics/zones/pile_zone.cpp
|
||||||
src/game/zones/select_zone.cpp
|
src/game_graphics/zones/select_zone.cpp
|
||||||
src/game/zones/stack_zone.cpp
|
src/game_graphics/zones/stack_zone.cpp
|
||||||
src/game/zones/table_zone.cpp
|
src/game_graphics/zones/table_zone.cpp
|
||||||
src/game/zones/view_zone.cpp
|
src/game_graphics/zones/view_zone.cpp
|
||||||
src/game/zones/view_zone_widget.cpp
|
src/game_graphics/zones/view_zone_widget.cpp
|
||||||
src/game_graphics/board/abstract_graphics_item.cpp
|
src/game_graphics/board/abstract_graphics_item.cpp
|
||||||
src/interface/card_picture_loader/card_picture_loader.cpp
|
src/interface/card_picture_loader/card_picture_loader.cpp
|
||||||
src/interface/card_picture_loader/card_picture_loader_local.cpp
|
src/interface/card_picture_loader/card_picture_loader_local.cpp
|
||||||
|
|
@ -127,7 +135,13 @@ set(cockatrice_SOURCES
|
||||||
src/interface/layouts/overlap_layout.cpp
|
src/interface/layouts/overlap_layout.cpp
|
||||||
src/interface/widgets/utility/line_edit_completer.cpp
|
src/interface/widgets/utility/line_edit_completer.cpp
|
||||||
src/interface/pixel_map_generator.cpp
|
src/interface/pixel_map_generator.cpp
|
||||||
|
src/interface/theme_config.cpp
|
||||||
src/interface/theme_manager.cpp
|
src/interface/theme_manager.cpp
|
||||||
|
src/interface/palette_editor/color_button.cpp
|
||||||
|
src/interface/palette_editor/palette_generator.cpp
|
||||||
|
src/interface/palette_editor/quick_setup_panel.cpp
|
||||||
|
src/interface/palette_editor/palette_grid_widget.cpp
|
||||||
|
src/interface/palette_editor/palette_editor_dialog.cpp
|
||||||
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
|
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
|
||||||
src/interface/widgets/cards/additional_info/mana_cost_widget.cpp
|
src/interface/widgets/cards/additional_info/mana_cost_widget.cpp
|
||||||
src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp
|
src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp
|
||||||
|
|
@ -169,6 +183,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_single_display_widget.cpp
|
src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_single_display_widget.cpp
|
||||||
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_total_widget.cpp
|
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_total_widget.cpp
|
||||||
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_category_widget.cpp
|
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_category_widget.cpp
|
||||||
|
src/interface/widgets/deck_editor/card_database_view.cpp
|
||||||
src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
|
src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
||||||
|
|
@ -178,6 +193,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
|
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
|
||||||
src/interface/widgets/deck_editor/deck_state_manager.cpp
|
src/interface/widgets/deck_editor/deck_state_manager.cpp
|
||||||
|
src/interface/widgets/deck_editor/printing_disabled_info_widget.cpp
|
||||||
src/interface/widgets/general/background_sources.cpp
|
src/interface/widgets/general/background_sources.cpp
|
||||||
src/interface/widgets/general/display/background_plate_widget.cpp
|
src/interface/widgets/general/display/background_plate_widget.cpp
|
||||||
src/interface/widgets/general/display/banner_widget.cpp
|
src/interface/widgets/general/display/banner_widget.cpp
|
||||||
|
|
@ -203,6 +219,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/printing_selector/printing_selector.cpp
|
src/interface/widgets/printing_selector/printing_selector.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_display_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_display_widget.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
|
||||||
|
src/interface/widgets/printing_selector/printing_selector_placeholder_widget.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_search_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_search_widget.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp
|
||||||
src/interface/widgets/printing_selector/printing_selector_card_sorting_widget.cpp
|
src/interface/widgets/printing_selector/printing_selector_card_sorting_widget.cpp
|
||||||
|
|
@ -212,6 +229,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/replay/replay_manager.cpp
|
src/interface/widgets/replay/replay_manager.cpp
|
||||||
src/interface/widgets/replay/replay_timeline_widget.cpp
|
src/interface/widgets/replay/replay_timeline_widget.cpp
|
||||||
src/interface/widgets/server/chat_view/chat_view.cpp
|
src/interface/widgets/server/chat_view/chat_view.cpp
|
||||||
|
src/interface/widgets/server/game_filter_configs.cpp
|
||||||
src/interface/widgets/server/game_selector.cpp
|
src/interface/widgets/server/game_selector.cpp
|
||||||
src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
|
src/interface/widgets/server/game_selector_quick_filter_toolbar.cpp
|
||||||
src/interface/widgets/server/games_model.cpp
|
src/interface/widgets/server/games_model.cpp
|
||||||
|
|
@ -223,11 +241,22 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/server/user/user_info_connection.cpp
|
src/interface/widgets/server/user/user_info_connection.cpp
|
||||||
src/interface/widgets/server/user/user_list_manager.cpp
|
src/interface/widgets/server/user/user_list_manager.cpp
|
||||||
src/interface/widgets/server/user/user_list_widget.cpp
|
src/interface/widgets/server/user/user_list_widget.cpp
|
||||||
|
src/interface/widgets/settings_page/appearance_settings_page.cpp
|
||||||
|
src/interface/widgets/settings_page/deck_editor_settings_page.cpp
|
||||||
|
src/interface/widgets/settings_page/general_settings_page.cpp
|
||||||
|
src/interface/widgets/settings_page/messages_settings_page.cpp
|
||||||
|
src/interface/widgets/settings_page/shortcut_settings_page.cpp
|
||||||
|
src/interface/widgets/settings_page/sound_settings_page.cpp
|
||||||
|
src/interface/widgets/settings_page/storage_settings_page.cpp
|
||||||
|
src/interface/widgets/settings_page/user_interface_settings_page.cpp
|
||||||
src/interface/widgets/utility/custom_line_edit.cpp
|
src/interface/widgets/utility/custom_line_edit.cpp
|
||||||
src/interface/widgets/utility/get_text_with_max.cpp
|
src/interface/widgets/utility/get_text_with_max.cpp
|
||||||
src/interface/widgets/utility/sequence_edit.cpp
|
src/interface/widgets/utility/sequence_edit.cpp
|
||||||
|
src/interface/widgets/utility/visibility_change_listener.cpp
|
||||||
|
src/interface/widgets/utility/visibility_change_listener.h
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
||||||
|
src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_format_legality_filter_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp
|
||||||
|
|
@ -236,6 +265,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_display_widget.cpp
|
||||||
src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
src/interface/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
||||||
src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp
|
src/interface/widgets/visual_deck_editor/visual_deck_display_options_widget.cpp
|
||||||
|
src/interface/widgets/visual_deck_editor/visual_deck_editor_placeholder_widget.cpp
|
||||||
src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
|
src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
|
||||||
src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
|
src/interface/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
|
||||||
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
||||||
|
|
@ -317,6 +347,8 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h
|
||||||
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp
|
||||||
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
|
||||||
|
src/interface/widgets/utility/compact_push_button.cpp
|
||||||
|
src/interface/widgets/utility/compact_push_button.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(sounds)
|
add_subdirectory(sounds)
|
||||||
|
|
@ -531,6 +563,7 @@ if(WIN32)
|
||||||
DIRECTORY "${CMAKE_BINARY_DIR}/cockatrice/"
|
DIRECTORY "${CMAKE_BINARY_DIR}/cockatrice/"
|
||||||
DESTINATION ./
|
DESTINATION ./
|
||||||
FILES_MATCHING
|
FILES_MATCHING
|
||||||
|
PATTERN "CMakeFiles" EXCLUDE
|
||||||
PATTERN "*.ini"
|
PATTERN "*.ini"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -556,6 +589,9 @@ if(WIN32)
|
||||||
PATTERN "styles/qopensslbackend.dll"
|
PATTERN "styles/qopensslbackend.dll"
|
||||||
PATTERN "styles/qschannelbackend.dll"
|
PATTERN "styles/qschannelbackend.dll"
|
||||||
PATTERN "styles/qwindowsvistastyle.dll"
|
PATTERN "styles/qwindowsvistastyle.dll"
|
||||||
|
PATTERN "styles/qwindows11style.dll"
|
||||||
|
PATTERN "styles/qmodernwindowsstyle.dll"
|
||||||
|
PATTERN "styles/qmodernwindowsstyled.dll"
|
||||||
PATTERN "tls/qcertonlybackend.dll"
|
PATTERN "tls/qcertonlybackend.dll"
|
||||||
PATTERN "tls/qopensslbackend.dll"
|
PATTERN "tls/qopensslbackend.dll"
|
||||||
PATTERN "tls/qschannelbackend.dll"
|
PATTERN "tls/qschannelbackend.dll"
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,24 @@
|
||||||
<file>resources/icons/arrow_top_green.svg</file>
|
<file>resources/icons/arrow_top_green.svg</file>
|
||||||
<file>resources/icons/arrow_up_green.svg</file>
|
<file>resources/icons/arrow_up_green.svg</file>
|
||||||
<file>resources/icons/arrow_undo.svg</file>
|
<file>resources/icons/arrow_undo.svg</file>
|
||||||
|
<file>resources/icons/circle_half_stroke.svg</file>
|
||||||
<file>resources/icons/clearsearch.svg</file>
|
<file>resources/icons/clearsearch.svg</file>
|
||||||
<file>resources/icons/cogwheel.svg</file>
|
<file>resources/icons/cogwheel.svg</file>
|
||||||
<file>resources/icons/conceded.svg</file>
|
<file>resources/icons/conceded.svg</file>
|
||||||
<file>resources/icons/decrement.svg</file>
|
<file>resources/icons/decrement.svg</file>
|
||||||
<file>resources/icons/delete.svg</file>
|
<file>resources/icons/delete.svg</file>
|
||||||
|
<file>resources/icons/dragon.svg</file>
|
||||||
<file>resources/icons/dropdown_collapsed.svg</file>
|
<file>resources/icons/dropdown_collapsed.svg</file>
|
||||||
<file>resources/icons/dropdown_expanded.svg</file>
|
<file>resources/icons/dropdown_expanded.svg</file>
|
||||||
|
<file>resources/icons/filter.svg</file>
|
||||||
|
<file>resources/icons/floppy_disk.svg</file>
|
||||||
<file>resources/icons/forgot_password.svg</file>
|
<file>resources/icons/forgot_password.svg</file>
|
||||||
|
<file>resources/icons/gear.svg</file>
|
||||||
<file>resources/icons/increment.svg</file>
|
<file>resources/icons/increment.svg</file>
|
||||||
<file>resources/icons/info.svg</file>
|
<file>resources/icons/info.svg</file>
|
||||||
<file>resources/icons/lock.svg</file>
|
<file>resources/icons/lock.svg</file>
|
||||||
<file>resources/icons/not_ready_start.svg</file>
|
<file>resources/icons/not_ready_start.svg</file>
|
||||||
|
<file>resources/icons/pen_to_square.svg</file>
|
||||||
<file>resources/icons/pencil.svg</file>
|
<file>resources/icons/pencil.svg</file>
|
||||||
<file>resources/icons/pin.svg</file>
|
<file>resources/icons/pin.svg</file>
|
||||||
<file>resources/icons/player.svg</file>
|
<file>resources/icons/player.svg</file>
|
||||||
|
|
@ -34,10 +40,13 @@
|
||||||
<file>resources/icons/reload.svg</file>
|
<file>resources/icons/reload.svg</file>
|
||||||
<file>resources/icons/remove_row.svg</file>
|
<file>resources/icons/remove_row.svg</file>
|
||||||
<file>resources/icons/rename.svg</file>
|
<file>resources/icons/rename.svg</file>
|
||||||
|
<file>resources/icons/scale_balanced.svg</file>
|
||||||
<file>resources/icons/scales.svg</file>
|
<file>resources/icons/scales.svg</file>
|
||||||
|
<file>resources/icons/scroll.svg</file>
|
||||||
<file>resources/icons/search.svg</file>
|
<file>resources/icons/search.svg</file>
|
||||||
<file>resources/icons/settings.svg</file>
|
<file>resources/icons/settings.svg</file>
|
||||||
<file>resources/icons/share.svg</file>
|
<file>resources/icons/share.svg</file>
|
||||||
|
<file>resources/icons/sort_arrow_down.svg</file>
|
||||||
<file>resources/icons/spectator.svg</file>
|
<file>resources/icons/spectator.svg</file>
|
||||||
<file>resources/icons/swap.svg</file>
|
<file>resources/icons/swap.svg</file>
|
||||||
<file>resources/icons/sync.svg</file>
|
<file>resources/icons/sync.svg</file>
|
||||||
|
|
@ -46,18 +55,22 @@
|
||||||
<file>resources/icons/view.svg</file>
|
<file>resources/icons/view.svg</file>
|
||||||
|
|
||||||
<file>resources/icons/mana/B.svg</file>
|
<file>resources/icons/mana/B.svg</file>
|
||||||
|
<file>resources/icons/mana/C.svg</file>
|
||||||
<file>resources/icons/mana/G.svg</file>
|
<file>resources/icons/mana/G.svg</file>
|
||||||
<file>resources/icons/mana/R.svg</file>
|
<file>resources/icons/mana/R.svg</file>
|
||||||
<file>resources/icons/mana/U.svg</file>
|
<file>resources/icons/mana/U.svg</file>
|
||||||
<file>resources/icons/mana/W.svg</file>
|
<file>resources/icons/mana/W.svg</file>
|
||||||
|
|
||||||
<file>resources/backgrounds/home.png</file>
|
<file>resources/backgrounds/home.png</file>
|
||||||
|
<file>resources/backgrounds/card_triplet.svg</file>
|
||||||
|
<file>resources/backgrounds/placeholder_printing_selector.svg</file>
|
||||||
|
|
||||||
<file>resources/config/general.svg</file>
|
<file>resources/config/general.svg</file>
|
||||||
<file>resources/config/appearance.svg</file>
|
<file>resources/config/appearance.svg</file>
|
||||||
<file>resources/config/interface.svg</file>
|
<file>resources/config/interface.svg</file>
|
||||||
<file>resources/config/messages.svg</file>
|
<file>resources/config/messages.svg</file>
|
||||||
<file>resources/config/deckeditor.svg</file>
|
<file>resources/config/deckeditor.svg</file>
|
||||||
|
<file>resources/config/storage.svg</file>
|
||||||
<file>resources/config/shorcuts.svg</file>
|
<file>resources/config/shorcuts.svg</file>
|
||||||
<file>resources/config/sound.svg</file>
|
<file>resources/config/sound.svg</file>
|
||||||
<file>resources/config/debug.ini</file>
|
<file>resources/config/debug.ini</file>
|
||||||
|
|
|
||||||
31
cockatrice/resources/backgrounds/card_triplet.svg
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
width="250"
|
||||||
|
id="svg13"
|
||||||
|
height="231.66667"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs13" />
|
||||||
|
<g
|
||||||
|
transform="matrix(1.705559,0,0,1.705559,-18.310328,-4.2419088)"
|
||||||
|
id="g13">
|
||||||
|
<path
|
||||||
|
d="M 90.069854,3.479957 C 89.356513,1.2235709 86.980392,-0.01102897 84.723451,0.70218215 L 3.4767601,26.377781 C 1.2199188,27.090982 -0.01486587,29.46663 0.69839437,31.723116 L 33.512365,135.52112 c 0.713341,2.25639 3.089462,3.49099 5.346403,2.77777 l 81.246672,-25.6756 c 2.25684,-0.71319 3.49163,-3.08884 2.77837,-5.34533 L 90.074852,3.479957 Z"
|
||||||
|
style="display:none;fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
d="m 110.61293,7.4983294 c -0.36657,-2.337853 -2.53055,-3.9150142 -4.86886,-3.5484627 L 21.563382,17.14452 c -2.338314,0.366502 -3.915784,2.529976 -3.549207,4.867929 L 34.876507,129.55893 c 0.366577,2.33786 2.530549,3.91502 4.868863,3.54847 l 84.18069,-13.19466 c 2.33831,-0.3665 3.91578,-2.52997 3.5492,-4.86793 L 110.61093,7.4983294 Z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path4" />
|
||||||
|
<path
|
||||||
|
d="m 130.53623,15.555064 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 41.067426 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 V 124.41102 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208344 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7" />
|
||||||
|
<path
|
||||||
|
d="m 149.43988,26.480639 c 0.38018,-2.335754 -1.1846,-4.508374 -3.52082,-4.88852 L 61.817351,7.9076636 C 59.481136,7.5275576 57.308066,9.0920839 56.927894,11.427736 L 39.439773,118.87426 c -0.380182,2.33576 1.184602,4.50838 3.520816,4.88852 l 84.102711,13.68346 c 2.33622,0.38011 4.50929,-1.18442 4.88946,-3.52007 L 149.43688,26.479639 Z"
|
||||||
|
style="display:inline;fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path10" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.-->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
width="172.65051"
|
||||||
|
id="svg13"
|
||||||
|
height="213.30714"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs13" /><g
|
||||||
|
transform="matrix(1.705559,0,0,1.705559,-97.653345,-68.741256)"
|
||||||
|
id="g13"><path
|
||||||
|
d="m 151.48519,45.063813 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 62.016385 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 V 153.91977 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208345 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7" /><path
|
||||||
|
d="m 154.70135,48.441704 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 65.232545 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 V 157.29767 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208345 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7-5" /><path
|
||||||
|
d="m 157.98403,51.75453 c 0,-2.366441 -1.89356,-4.259575 -4.26046,-4.259575 H 68.515228 c -2.366905,0 -4.260468,1.893134 -4.260468,4.259575 v 108.85596 c 0,2.36644 1.893563,4.25957 4.260468,4.25957 h 85.208342 c 2.3669,0 4.26046,-1.89313 4.26046,-4.25957 z"
|
||||||
|
style="fill:#c0c0c0;fill-opacity:1;stroke:#989898;stroke-width:1;stroke-opacity:1"
|
||||||
|
id="path7-6" /></g><path
|
||||||
|
d="m 196.24576,207.42361 c 0,0.11213 0,0.22413 0,0.33621 -0.0498,4.54511 -4.18399,7.63329 -8.72909,7.63329 h -12.19086 c -3.29988,0 -5.97713,2.67727 -5.97713,5.97712 0,0.4234 0.0498,0.83433 0.12449,1.23279 0.26149,1.27014 0.80939,2.49046 1.34485,3.72325 0.75959,1.71843 1.50674,3.4244 1.50674,5.22998 0,3.95986 -2.68971,7.55859 -6.64956,7.72046 -0.43583,0.0128 -0.87166,0.025 -1.31995,0.025 -17.60761,0 -31.878,-14.27038 -31.878,-31.878 0,-17.60761 14.28284,-31.878 31.89046,-31.878 17.60762,0 31.87801,14.27039 31.87801,31.878 z m -47.81703,3.98475 c 0,-2.20407 -1.78067,-3.98475 -3.98473,-3.98475 -2.20407,0 -3.98477,1.78068 -3.98477,3.98475 0,2.20406 1.7807,3.98475 3.98477,3.98475 2.20406,0 3.98473,-1.78069 3.98473,-3.98475 z m 0,-11.95426 c 2.20407,0 3.98477,-1.78068 3.98477,-3.98475 0,-2.20407 -1.7807,-3.98475 -3.98477,-3.98475 -2.20405,0 -3.98473,1.78068 -3.98473,3.98475 0,2.20407 1.78068,3.98475 3.98473,3.98475 z m 19.92376,-11.95424 c 0,-2.20408 -1.78068,-3.98477 -3.98473,-3.98477 -2.20407,0 -3.98477,1.78069 -3.98477,3.98477 0,2.20405 1.7807,3.98474 3.98477,3.98474 2.20405,0 3.98473,-1.78069 3.98473,-3.98474 z m 11.95426,11.95424 c 2.20407,0 3.98475,-1.78068 3.98475,-3.98475 0,-2.20407 -1.78068,-3.98475 -3.98475,-3.98475 -2.20406,0 -3.98475,1.78068 -3.98475,3.98475 0,2.20407 1.78069,3.98475 3.98475,3.98475 z"
|
||||||
|
id="path1"
|
||||||
|
style="display:none;fill:#3b3b3b;fill-opacity:1;stroke:#000000;stroke-width:2.53798;stroke-dasharray:none;stroke-opacity:1" /><path
|
||||||
|
d="M 126.20915,54.574783 82.324247,83.8512 c -5.76807,3.845383 -9.435059,10.089163 -10.029703,16.90777 12.348823,2.53716 22.081191,12.26955 24.638191,24.63819 6.838435,-0.59465 13.062395,-4.26163 16.907775,-10.0297 l 29.2566,-43.904722 c 1.32804,-2.001984 2.04162,-4.340923 2.04162,-6.75915 0,-6.719506 -5.45092,-12.170428 -12.17043,-12.170428 -2.3984,0 -4.75718,0.713573 -6.75915,2.041623 z M 88.052677,131.81933 c 0,-12.26953 -9.930593,-22.20012 -22.200138,-22.20012 -12.269532,0 -22.200126,9.93059 -22.200126,22.20012 0,0.77305 0.03966,1.54609 0.118929,2.2993 0.356787,3.46877 -2.021792,7.21505 -5.510393,7.21505 h -0.951431 c -3.508409,0 -6.342895,2.83447 -6.342895,6.3429 0,3.5084 2.834486,6.34289 6.342895,6.34289 h 28.543021 c 12.269545,0 22.200138,-9.93059 22.200138,-22.20014 z"
|
||||||
|
id="path1-2"
|
||||||
|
style="fill:#989898;fill-opacity:1;stroke-width:0.198215" /></svg>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
|
|
@ -28,6 +28,8 @@
|
||||||
#dlg_tip_of_the_day = true
|
#dlg_tip_of_the_day = true
|
||||||
#dlg_update = true
|
#dlg_update = true
|
||||||
|
|
||||||
|
#general_settings_page = true
|
||||||
|
|
||||||
#settings_cache = true
|
#settings_cache = true
|
||||||
#servers_settings = true
|
#servers_settings = true
|
||||||
#shortcuts_settings = true
|
#shortcuts_settings = true
|
||||||
|
|
|
||||||
799
cockatrice/resources/config/storage.svg
Normal file
|
|
@ -0,0 +1,799 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
width="62.636364"
|
||||||
|
height="62.090908"
|
||||||
|
id="svg2"
|
||||||
|
sodipodi:version="0.32"
|
||||||
|
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
|
||||||
|
sodipodi:docname="storage.svg"
|
||||||
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
version="1.0"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs4"><linearGradient
|
||||||
|
id="linearGradient3169"><stop
|
||||||
|
style="stop-color:#0000ff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3171" /><stop
|
||||||
|
style="stop-color:#000067;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3173" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient4766"><stop
|
||||||
|
style="stop-color:#784421;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4768" /><stop
|
||||||
|
style="stop-color:#3d2210;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4770" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient4758"><stop
|
||||||
|
style="stop-color:#a05a2c;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4760" /><stop
|
||||||
|
style="stop-color:#3d2210;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop4762" /></linearGradient><inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="0 : 526.18109 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||||
|
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||||
|
id="perspective10" /><inkscape:perspective
|
||||||
|
id="perspective2484"
|
||||||
|
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||||
|
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_x="0 : 526.18109 : 1"
|
||||||
|
sodipodi:type="inkscape:persp3d" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4758"
|
||||||
|
id="linearGradient4764"
|
||||||
|
x1="466.09601"
|
||||||
|
y1="485.96021"
|
||||||
|
x2="715.14801"
|
||||||
|
y2="485.96021"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4766"
|
||||||
|
id="linearGradient4772"
|
||||||
|
x1="496.548"
|
||||||
|
y1="485.26816"
|
||||||
|
x2="683.31201"
|
||||||
|
y2="485.26816"
|
||||||
|
gradientUnits="userSpaceOnUse" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3169"
|
||||||
|
id="radialGradient3175"
|
||||||
|
cx="120.07376"
|
||||||
|
cy="56.138123"
|
||||||
|
fx="120.07376"
|
||||||
|
fy="56.138123"
|
||||||
|
r="82.790039"
|
||||||
|
gradientTransform="matrix(1,0,0,0.2116376,0,44.257186)"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient6482"
|
||||||
|
id="linearGradient6488"
|
||||||
|
x1="32.18182"
|
||||||
|
y1="3.2835093"
|
||||||
|
x2="32.18182"
|
||||||
|
y2="13.02554"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.0281354,0,0,1.0429299,85.21874,131.0326)" /><linearGradient
|
||||||
|
id="linearGradient6482"><stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6484" /><stop
|
||||||
|
style="stop-color:#00ff00;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6486" /></linearGradient><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient6464"
|
||||||
|
id="linearGradient6470"
|
||||||
|
x1="32.090908"
|
||||||
|
y1="1.8181819"
|
||||||
|
x2="31.09091"
|
||||||
|
y2="62.909088"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(0,-0.1818182)" /><linearGradient
|
||||||
|
id="linearGradient6464"><stop
|
||||||
|
style="stop-color:#0061ff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop6466" /><stop
|
||||||
|
style="stop-color:#001c4c;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop6468" /></linearGradient><linearGradient
|
||||||
|
y2="62.909088"
|
||||||
|
x2="31.09091"
|
||||||
|
y1="1.8181819"
|
||||||
|
x1="32.090908"
|
||||||
|
gradientTransform="translate(86.2151,131.5372)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient4477"
|
||||||
|
xlink:href="#linearGradient6464"
|
||||||
|
inkscape:collect="always" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient2916"><stop
|
||||||
|
style="stop-color:white;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2918" /><stop
|
||||||
|
style="stop-color:white;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2920" /></linearGradient><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient2902"><stop
|
||||||
|
style="stop-color:black;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2905" /><stop
|
||||||
|
style="stop-color:black;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2907" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient2064"><stop
|
||||||
|
id="stop2066"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:white;stop-opacity:1;" /><stop
|
||||||
|
style="stop-color:#555753;stop-opacity:0.60000002;"
|
||||||
|
offset="0.5"
|
||||||
|
id="stop2070" /><stop
|
||||||
|
id="stop2068"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#555753;stop-opacity:0;" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient9641"><stop
|
||||||
|
style="stop-color:white;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop9643" /><stop
|
||||||
|
style="stop-color:#888a85;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop9645" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient9633"><stop
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop9635" /><stop
|
||||||
|
style="stop-color:#888a85;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop9639" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient9613"><stop
|
||||||
|
style="stop-color:white;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop9615" /><stop
|
||||||
|
id="stop9619"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:white;stop-opacity:1;" /><stop
|
||||||
|
style="stop-color:#cccfca;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop9617" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient8710"><stop
|
||||||
|
style="stop-color:black;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop8712" /><stop
|
||||||
|
style="stop-color:white;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop8714" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient8631"><stop
|
||||||
|
id="stop8633"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1" /><stop
|
||||||
|
style="stop-color:#eeeeec;stop-opacity:1;"
|
||||||
|
offset="0.2"
|
||||||
|
id="stop8637" /><stop
|
||||||
|
id="stop8635"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#babdb6;stop-opacity:1" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient8625"><stop
|
||||||
|
id="stop8627"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:white;stop-opacity:1" /><stop
|
||||||
|
id="stop8629"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#babdb6;stop-opacity:1" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient8613"><stop
|
||||||
|
style="stop-color:#babdb6;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop8615" /><stop
|
||||||
|
style="stop-color:#2e3436;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop8617" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient5740"><stop
|
||||||
|
style="stop-color:#d0d0cb;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop5742" /><stop
|
||||||
|
style="stop-color:#babdb6;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop5744" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient5690"><stop
|
||||||
|
style="stop-color:white;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop5692" /><stop
|
||||||
|
style="stop-color:#888a85;stop-opacity:0.59848487"
|
||||||
|
offset="1"
|
||||||
|
id="stop5694" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient2899"><stop
|
||||||
|
id="stop2901"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#555753;stop-opacity:1" /><stop
|
||||||
|
id="stop2903"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#2e3436;stop-opacity:1" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient3468"><stop
|
||||||
|
style="stop-color:#fdfdfc;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop3470" /><stop
|
||||||
|
style="stop-color:white;stop-opacity:0.37121212"
|
||||||
|
offset="1"
|
||||||
|
id="stop3472" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient2909"><stop
|
||||||
|
style="stop-color:white;stop-opacity:0;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2911" /><stop
|
||||||
|
id="stop2917"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:white;stop-opacity:1;" /><stop
|
||||||
|
style="stop-color:white;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2913" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient2839"><stop
|
||||||
|
style="stop-color:white;stop-opacity:0.25773194;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2841" /><stop
|
||||||
|
id="stop2847"
|
||||||
|
offset="0.5472973"
|
||||||
|
style="stop-color:white;stop-opacity:1;" /><stop
|
||||||
|
style="stop-color:white;stop-opacity:0.24705882;"
|
||||||
|
offset="0.66243607"
|
||||||
|
id="stop2849" /><stop
|
||||||
|
id="stop2851"
|
||||||
|
offset="0.875"
|
||||||
|
style="stop-color:white;stop-opacity:0.83505154;" /><stop
|
||||||
|
style="stop-color:white;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2843" /></linearGradient><linearGradient
|
||||||
|
id="linearGradient2900"><stop
|
||||||
|
style="stop-color:black;stop-opacity:0;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2902" /><stop
|
||||||
|
id="stop2908"
|
||||||
|
offset="0.5"
|
||||||
|
style="stop-color:black;stop-opacity:1;" /><stop
|
||||||
|
style="stop-color:black;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop2904" /></linearGradient><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3468"
|
||||||
|
id="linearGradient3474"
|
||||||
|
x1="24.748737"
|
||||||
|
y1="35.354588"
|
||||||
|
x2="24.998737"
|
||||||
|
y2="14.997767"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,0.995556,0,-3.931113)" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2902"
|
||||||
|
id="radialGradient4700"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(4.095822,0,0,3.101282,-9.53921,-94.5433)"
|
||||||
|
cx="0"
|
||||||
|
cy="17"
|
||||||
|
fx="0"
|
||||||
|
fy="17"
|
||||||
|
r="2" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2902"
|
||||||
|
id="radialGradient4702"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(4.095822,0,0,3.101282,38.20996,-10.90025)"
|
||||||
|
cx="0"
|
||||||
|
cy="17"
|
||||||
|
fx="0"
|
||||||
|
fy="17"
|
||||||
|
r="2" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2900"
|
||||||
|
id="linearGradient4704"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.047911,0,0,2.067521,1.347566,6.673675)"
|
||||||
|
x1="9.8994951"
|
||||||
|
y1="20"
|
||||||
|
x2="9.8994951"
|
||||||
|
y2="13.979153" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2909"
|
||||||
|
id="linearGradient4711"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,1.42294,10.5,-14.95703)"
|
||||||
|
x1="15.335379"
|
||||||
|
y1="33.06237"
|
||||||
|
x2="20.329321"
|
||||||
|
y2="36.37693" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2909"
|
||||||
|
id="linearGradient4713"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1,0,0,1.42294,-0.875,-15.04578)"
|
||||||
|
x1="15.335379"
|
||||||
|
y1="33.06237"
|
||||||
|
x2="20.329321"
|
||||||
|
y2="36.37693" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2909"
|
||||||
|
id="linearGradient4715"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0.459833,0,-0.391165,1.370105,40.62503,-13.29892)"
|
||||||
|
x1="15.335379"
|
||||||
|
y1="33.06237"
|
||||||
|
x2="20.329321"
|
||||||
|
y2="36.37693" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5740"
|
||||||
|
id="radialGradient5748"
|
||||||
|
cx="25.251999"
|
||||||
|
cy="16.47991"
|
||||||
|
fx="25.251999"
|
||||||
|
fy="16.47991"
|
||||||
|
r="21.980215"
|
||||||
|
gradientTransform="matrix(1.032991,-0.596398,0.575121,0.99614,-12.23456,11.55448)"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2064"
|
||||||
|
id="linearGradient5790"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="18.048874"
|
||||||
|
y1="25.461344"
|
||||||
|
x2="22.211937"
|
||||||
|
y2="12.143078"
|
||||||
|
gradientTransform="matrix(0.940224,0,0,0.931632,1.331811,1.401537)" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8631"
|
||||||
|
id="linearGradient5865"
|
||||||
|
x1="24"
|
||||||
|
y1="36.638382"
|
||||||
|
x2="25.818018"
|
||||||
|
y2="6.8314762"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2839"
|
||||||
|
id="linearGradient7658"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="27.057796"
|
||||||
|
y1="12.669416"
|
||||||
|
x2="32.042896"
|
||||||
|
y2="31.219666" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5690"
|
||||||
|
id="linearGradient8603"
|
||||||
|
x1="20.304037"
|
||||||
|
y1="24.035707"
|
||||||
|
x2="18.498415"
|
||||||
|
y2="40.647167"
|
||||||
|
gradientUnits="userSpaceOnUse" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8613"
|
||||||
|
id="radialGradient8619"
|
||||||
|
cx="7.5177727"
|
||||||
|
cy="30.573555"
|
||||||
|
fx="7.5177727"
|
||||||
|
fy="30.573555"
|
||||||
|
r="0.53125"
|
||||||
|
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
|
||||||
|
gradientUnits="userSpaceOnUse" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient9613"
|
||||||
|
id="radialGradient8623"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.389748,0,0,1.348872,-2.91982,-10.63815)"
|
||||||
|
cx="7.5191436"
|
||||||
|
cy="30.304251"
|
||||||
|
fx="7.5191436"
|
||||||
|
fy="30.304251"
|
||||||
|
r="0.53125" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient9633"
|
||||||
|
id="radialGradient8664"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.569487,0,0,1.523325,-4.288627,-15.92107)"
|
||||||
|
cx="7.5336008"
|
||||||
|
cy="30.307562"
|
||||||
|
fx="7.5336008"
|
||||||
|
fy="30.307562"
|
||||||
|
r="0.53125" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8613"
|
||||||
|
id="radialGradient8666"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
|
||||||
|
cx="7.5177727"
|
||||||
|
cy="30.573555"
|
||||||
|
fx="7.5177727"
|
||||||
|
fy="30.573555"
|
||||||
|
r="0.53125" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8625"
|
||||||
|
id="radialGradient8676"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
|
||||||
|
cx="7.4792061"
|
||||||
|
cy="30.36071"
|
||||||
|
fx="7.4792061"
|
||||||
|
fy="30.36071"
|
||||||
|
r="0.53125" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8613"
|
||||||
|
id="radialGradient8678"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
|
||||||
|
cx="7.5177727"
|
||||||
|
cy="30.573555"
|
||||||
|
fx="7.5177727"
|
||||||
|
fy="30.573555"
|
||||||
|
r="0.53125" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient9641"
|
||||||
|
id="radialGradient8680"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
|
||||||
|
cx="7.4893188"
|
||||||
|
cy="30.337601"
|
||||||
|
fx="7.4893188"
|
||||||
|
fy="30.337601"
|
||||||
|
r="0.53125" /><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8613"
|
||||||
|
id="radialGradient8682"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
|
||||||
|
cx="7.5177727"
|
||||||
|
cy="30.573555"
|
||||||
|
fx="7.5177727"
|
||||||
|
fy="30.573555"
|
||||||
|
r="0.53125" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8710"
|
||||||
|
id="linearGradient8716"
|
||||||
|
x1="40.617188"
|
||||||
|
y1="30.554688"
|
||||||
|
x2="40.710938"
|
||||||
|
y2="30.359375"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8710"
|
||||||
|
id="linearGradient9605"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="40.617188"
|
||||||
|
y1="30.554688"
|
||||||
|
x2="40.710938"
|
||||||
|
y2="30.359375"
|
||||||
|
gradientTransform="matrix(0.602867,-0.797841,0.797841,0.602867,-41.12611,44.62773)" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8710"
|
||||||
|
id="linearGradient9649"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="40.617188"
|
||||||
|
y1="30.554688"
|
||||||
|
x2="40.710938"
|
||||||
|
y2="30.359375"
|
||||||
|
gradientTransform="rotate(-30.000012,-5.5813167,76.089146)" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient8710"
|
||||||
|
id="linearGradient9654"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="40.617188"
|
||||||
|
y1="30.554688"
|
||||||
|
x2="40.710938"
|
||||||
|
y2="30.359375"
|
||||||
|
gradientTransform="matrix(0.707107,0.527555,-0.707107,0.527555,29.0058,-24.09196)" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2916"
|
||||||
|
id="linearGradient2973"
|
||||||
|
x1="12.5"
|
||||||
|
y1="43.1875"
|
||||||
|
x2="12.5"
|
||||||
|
y2="34.045513"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2899"
|
||||||
|
id="linearGradient5655"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="53.812813"
|
||||||
|
y1="43.573235"
|
||||||
|
x2="-2.8138931"
|
||||||
|
y2="35.500015"
|
||||||
|
gradientTransform="translate(0,50)" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2902"
|
||||||
|
id="linearGradient2992"
|
||||||
|
x1="21.9375"
|
||||||
|
y1="39"
|
||||||
|
x2="21.9375"
|
||||||
|
y2="37.995617"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2902"
|
||||||
|
id="linearGradient2910"
|
||||||
|
x1="22.101398"
|
||||||
|
y1="27.658131"
|
||||||
|
x2="22.971142"
|
||||||
|
y2="20.903238"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(0,2)" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2916"
|
||||||
|
id="linearGradient2922"
|
||||||
|
x1="24.847851"
|
||||||
|
y1="28.908398"
|
||||||
|
x2="24.847851"
|
||||||
|
y2="25.757175"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(0,2)" /></defs><sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="5.8830488"
|
||||||
|
inkscape:cx="-3.9945275"
|
||||||
|
inkscape:cy="-14.363301"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1408"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#505050" /><metadata
|
||||||
|
id="metadata7"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-86.987816,-132.85536)"><rect
|
||||||
|
style="fill:url(#linearGradient4477);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-opacity:1"
|
||||||
|
id="rect6462"
|
||||||
|
width="61.636364"
|
||||||
|
height="61.090908"
|
||||||
|
x="87.487816"
|
||||||
|
y="133.35536"
|
||||||
|
ry="5.6363635" /><rect
|
||||||
|
style="fill:url(#linearGradient6488);fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||||
|
id="rect6472"
|
||||||
|
width="59.796619"
|
||||||
|
height="13.251164"
|
||||||
|
x="88.407707"
|
||||||
|
y="134.45705"
|
||||||
|
ry="4.7325583" /><g
|
||||||
|
inkscape:label="Livello 1"
|
||||||
|
id="layer1-3"
|
||||||
|
style="display:inline"
|
||||||
|
transform="matrix(1.1537183,0,0,1.1537183,91.003924,136.40297)"><g
|
||||||
|
id="g3519"
|
||||||
|
style="opacity:0.7"
|
||||||
|
transform="matrix(1.030831,0,0,1.151147,-0.73609,-12.57431)"
|
||||||
|
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90"><rect
|
||||||
|
transform="scale(-1)"
|
||||||
|
y="-48.024086"
|
||||||
|
x="-9.5392103"
|
||||||
|
height="12.405126"
|
||||||
|
width="8.1916437"
|
||||||
|
id="rect2884"
|
||||||
|
style="opacity:1;fill:url(#radialGradient4700);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /><rect
|
||||||
|
y="35.618961"
|
||||||
|
x="38.209965"
|
||||||
|
height="12.405126"
|
||||||
|
width="8.1916437"
|
||||||
|
id="rect2894"
|
||||||
|
style="opacity:1;fill:url(#radialGradient4702);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /><rect
|
||||||
|
y="35.618961"
|
||||||
|
x="9.5392103"
|
||||||
|
height="12.405126"
|
||||||
|
width="28.670753"
|
||||||
|
id="rect2898"
|
||||||
|
style="opacity:1;fill:url(#linearGradient4704);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /></g><g
|
||||||
|
id="g5672"
|
||||||
|
transform="translate(0,-48.99747)"><path
|
||||||
|
sodipodi:nodetypes="ccccccccccccc"
|
||||||
|
id="rect2010"
|
||||||
|
d="M 4.5182287,80.500013 H 43.481768 c 0.564099,0 1.018229,0.45413 1.018229,1.018229 v 2.963543 c 0,1.315584 -0.450231,3.018228 -2.455729,3.018228 L 40.5,87.5 v 1 h -33 v -1 l -1.8567713,1.3e-5 c -1.2712053,0 -2.1432282,-0.884627 -2.1432282,-2.255665 v -3.726106 c 0,-0.564099 0.4541297,-1.018229 1.0182282,-1.018229 z"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient5655);fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><path
|
||||||
|
transform="translate(0,50)"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2973);stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
d="m 4.59375,31.59375 v 3.729743 c 0,0.599619 0.3756505,1.104854 0.8863276,1.104854 H 42.426407 c 0.512469,0 0.979843,-0.507235 0.979843,-1.016466 V 31.59375 Z"
|
||||||
|
id="path2076"
|
||||||
|
sodipodi:nodetypes="ccccccc" /><g
|
||||||
|
transform="translate(0,50)"
|
||||||
|
style="opacity:0.5"
|
||||||
|
id="g4706"><path
|
||||||
|
style="opacity:0.109524;fill:url(#linearGradient4711);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 26.144738,32.088747 c 0,0 -1.502602,5.533939 -3.226175,5.911253 0,0 6.231378,-0.125771 6.231378,-0.125771 1.387072,-0.317461 3.358758,-5.785482 3.358758,-5.785482 z"
|
||||||
|
id="path2907"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90" /><path
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="path2892"
|
||||||
|
d="m 14.769738,32 c 0,0 -1.502602,5.533939 -3.226175,5.911253 0,0 6.231378,-0.125771 6.231378,-0.125771 C 19.162013,37.468021 21.133699,32 21.133699,32 Z"
|
||||||
|
style="opacity:0.109524;fill:url(#linearGradient4713);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="path2896"
|
||||||
|
d="m 34.886139,32 c 0,0 -2.212224,5.328458 -3.108503,5.691761 0,0 2.899969,-0.121101 2.899969,-0.121101 C 35.402697,37.264987 37.8125,32 37.8125,32 Z"
|
||||||
|
style="opacity:0.109524;fill:url(#linearGradient4715);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /></g></g><path
|
||||||
|
style="fill:url(#radialGradient5748);fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 11.693127,10.498788 h 24.572566 c 1.68417,0 2.396517,0.117479 3.040019,2.385005 l 5.074491,17.881119 c 0.501024,1.765471 -1.355848,2.735101 -3.040018,2.735101 H 6.6186312 c -1.868408,0 -3.4893833,-1.181417 -3.0400182,-2.735101 L 8.8290448,12.611497 c 0.5683008,-1.964905 1.1799122,-2.112709 2.8640822,-2.112709 z"
|
||||||
|
id="rect1879"
|
||||||
|
sodipodi:nodetypes="cczzcczzc"
|
||||||
|
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90" /><path
|
||||||
|
sodipodi:type="inkscape:offset"
|
||||||
|
inkscape:radius="-0.5"
|
||||||
|
inkscape:original="M 11.6875 10.5 C 10.00333 10.5 9.4120513 10.660095 8.84375 12.625 L 3.59375 30.75 C 3.1443849 32.303684 4.7565918 33.500002 6.625 33.5 L 41.34375 33.5 C 43.02792 33.5 44.876024 32.515471 44.375 30.75 L 39.3125 12.875 C 38.668998 10.607474 37.965419 10.5 36.28125 10.5 L 11.6875 10.5 z "
|
||||||
|
style="display:inline;opacity:0.462406;fill:url(#linearGradient7658);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="path5806"
|
||||||
|
d="m 11.6875,11 c -0.826242,0 -1.28475,0.05742 -1.5625,0.242188 -0.2777497,0.184768 -0.5284825,0.580009 -0.8007812,1.521484 l -5.2500001,18.125 c -0.1708248,0.590628 0.021709,1.039316 0.4902344,1.4375 C 5.0329784,32.724356 5.7975106,33.000001 6.625,33 h 34.71875 c 0.744655,0 1.538941,-0.232575 2.03125,-0.609375 0.492309,-0.3768 0.719298,-0.799984 0.519531,-1.503906 l -5.0625,-17.875 C 38.52278,11.922001 38.224454,11.462814 37.910156,11.253906 37.595859,11.044998 37.112699,11 36.28125,11 Z" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8623);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8621"
|
||||||
|
transform="matrix(-2.628602,0,0,1.777765,27.79309,-23.77739)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><path
|
||||||
|
style="fill:none;fill-opacity:1;stroke:url(#linearGradient5790);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 16.110953,12.552805 c -0.573581,0 -1.02837,0.431821 -1.02837,0.989859 l -0.940223,3.230801 c -2.859962,1.276514 -4.6423552,3.099073 -4.6423552,5.123976 0,3.856957 6.4790242,6.987239 14.4853222,6.98724 8.006296,0 14.514705,-3.130284 14.514704,-6.98724 0,-2.039034 -1.835591,-3.875388 -4.730501,-5.153089 l -0.940224,-3.201688 c 0,-0.558038 -0.454788,-0.989859 -1.02837,-0.989859 z"
|
||||||
|
id="path2784"
|
||||||
|
sodipodi:nodetypes="cccssscccc" /><path
|
||||||
|
style="display:inline;fill:none;fill-opacity:1;stroke:url(#linearGradient3474);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 11.6875,11.500005 c -0.803124,0 -1.097168,0.07051 -1.21875,0.155556 -0.121582,0.08504 -0.357707,0.40212 -0.6875,1.306667 l -5.25,18.137786 c -0.1337204,0.366765 -0.054827,0.533865 0.3125,0.84 0.3673267,0.306136 1.066693,0.56 1.78125,0.560001 h 34.71875 c 0.639793,0 1.393345,-0.237954 1.78125,-0.52889 0.387905,-0.290935 0.488311,-0.382809 0.3125,-0.871111 L 38.375,13.242228 c -0.377206,-1.04766 -0.68208,-1.439297 -0.84375,-1.555556 -0.16167,-0.116259 -0.443711,-0.186667 -1.25,-0.186667 z"
|
||||||
|
id="path3394"
|
||||||
|
sodipodi:nodetypes="csccsccsccscc" /><g
|
||||||
|
id="g5657"
|
||||||
|
transform="translate(7,-1)"
|
||||||
|
style="opacity:0.302857"><rect
|
||||||
|
ry="0.74712253"
|
||||||
|
rx="0.75130093"
|
||||||
|
y="35.500008"
|
||||||
|
x="18.499996"
|
||||||
|
height="1.9999924"
|
||||||
|
width="14.000004"
|
||||||
|
id="rect5641"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
|
||||||
|
y="36"
|
||||||
|
x="19"
|
||||||
|
height="1"
|
||||||
|
width="1"
|
||||||
|
id="rect5645"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
|
||||||
|
y="36"
|
||||||
|
x="22"
|
||||||
|
height="1"
|
||||||
|
width="1"
|
||||||
|
id="rect5647"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
|
||||||
|
y="36"
|
||||||
|
x="24"
|
||||||
|
height="1"
|
||||||
|
width="1"
|
||||||
|
id="rect5649"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
|
||||||
|
y="36"
|
||||||
|
x="26"
|
||||||
|
height="1"
|
||||||
|
width="1"
|
||||||
|
id="rect5651"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
|
||||||
|
y="36"
|
||||||
|
x="29"
|
||||||
|
height="1"
|
||||||
|
width="2"
|
||||||
|
id="rect5653"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /></g><path
|
||||||
|
sodipodi:type="inkscape:offset"
|
||||||
|
inkscape:radius="-0.44194174"
|
||||||
|
inkscape:original="M 16.125 12.5625 C 15.55142 12.5625 15.09375 12.973212 15.09375 13.53125 L 14.15625 16.78125 C 11.296288 18.057765 9.5 19.881347 9.5 21.90625 C 9.5 25.763206 15.993702 28.874999 24 28.875 C 32.006296 28.874999 38.500001 25.763206 38.5 21.90625 C 38.5 19.867215 36.67616 18.027701 33.78125 16.75 L 32.84375 13.53125 C 32.843748 12.973212 32.386082 12.5625 31.8125 12.5625 L 16.125 12.5625 z "
|
||||||
|
style="display:inline;fill:url(#linearGradient5865);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="path5857"
|
||||||
|
d="m 16.125,13.003906 c -0.362612,0 -0.589844,0.210942 -0.589844,0.527344 a 0.44198593,0.44198593 0 0 1 -0.01758,0.123047 l -0.9375,3.25 a 0.44198593,0.44198593 0 0 1 -0.24414,0.28125 c -1.389903,0.620369 -2.504368,1.368471 -3.25586,2.177734 -0.751491,0.809263 -1.1386718,1.661199 -1.1386717,2.542969 0,1.680455 1.4530107,3.311153 3.9980467,4.533203 2.545037,1.22205 6.114654,1.99414 10.060547,1.994141 3.945892,-1e-6 7.51551,-0.772091 10.060547,-1.994141 2.545037,-1.22205 3.998047,-2.852748 3.998047,-4.533203 0,-0.887751 -0.391823,-1.747213 -1.154297,-2.5625 -0.762474,-0.815287 -1.893636,-1.568394 -3.300781,-2.189453 a 0.44198593,0.44198593 0 0 1 -0.246094,-0.28125 l -0.9375,-3.21875 a 0.44198593,0.44198593 0 0 1 -0.01758,-0.123047 c -10e-7,-0.316404 -0.22723,-0.527344 -0.589844,-0.527344 z" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:0.0530303;fill-rule:nonzero;stroke:url(#linearGradient8603);stroke-width:2.52015;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8595"
|
||||||
|
transform="matrix(0.449978,0,0,0.349909,16.36363,12.21469)"
|
||||||
|
cx="16.970562"
|
||||||
|
cy="25.107418"
|
||||||
|
rx="7.7781744"
|
||||||
|
ry="4.2868347" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8619);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8611"
|
||||||
|
transform="matrix(1.411772,0,0,0.969697,-3.014767,0.848485)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8664);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.462594;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8660"
|
||||||
|
transform="matrix(-2.628602,0,0,1.777765,60.79309,-23.77739)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8666);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8662"
|
||||||
|
transform="matrix(1.411772,0,0,0.969697,29.98523,0.848485)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8676);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8668"
|
||||||
|
transform="matrix(-2.628602,0,0,1.777765,31.79309,-40.77739)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8678);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8670"
|
||||||
|
transform="matrix(1.411772,0,0,0.969697,0.985233,-16.15152)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8680);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8672"
|
||||||
|
transform="matrix(-2.628602,0,0,1.777765,56.3029,-40.77739)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><ellipse
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8682);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="path8674"
|
||||||
|
transform="matrix(1.411772,0,0,0.969697,25.49504,-16.15152)"
|
||||||
|
cx="7.625"
|
||||||
|
cy="30.578125"
|
||||||
|
rx="0.53125"
|
||||||
|
ry="0.515625" /><path
|
||||||
|
style="opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient8716);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 40.328109,30.261401 0.874999,0.430332"
|
||||||
|
id="path8700" /><path
|
||||||
|
style="display:inline;opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9605);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 7.330186,30.695906 8.201031,30.257228"
|
||||||
|
id="path9603" /><path
|
||||||
|
style="display:inline;opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9649);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 11.263531,13.446473 0.972937,-0.06482"
|
||||||
|
id="path9647" /><path
|
||||||
|
style="display:inline;opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9654);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 36.124038,13.147874 0.314427,0.688634"
|
||||||
|
id="path9652" /><rect
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.12;fill:url(#linearGradient2992);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.681836;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
id="rect2984"
|
||||||
|
width="32.03125"
|
||||||
|
height="1"
|
||||||
|
x="8"
|
||||||
|
y="38" /><path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.12;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2910);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||||
|
d="M 10.460155,15.082355 6.8513979,27.675762 C 8.2982685,28.375511 10.625,29.167061 10.429825,31.533131 H 37.299883 C 37.869398,29.640915 39.875,28.375 41.34614,28.25 L 37.498106,15.082355 32.350135,12.523347 H 14.318912 Z"
|
||||||
|
id="path1997"
|
||||||
|
sodipodi:nodetypes="ccccccccc" /><path
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
id="path2912"
|
||||||
|
d="m 7.9763979,27.050762 c 1.4468706,0.699749 3.1789321,1.433241 3.4256991,3.357369 H 36.857941 C 37.427456,28.515915 38.875,27.5 40.34614,27.375 Z"
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.834286;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2922);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 40 KiB |
|
|
@ -47,6 +47,6 @@ searches are case insensitive.
|
||||||
<dd>[t:aggro OR o:control](#t:aggro OR o:control) <small>(Any deck filename that contains either aggro or control)</small></dd>
|
<dd>[t:aggro OR o:control](#t:aggro OR o:control) <small>(Any deck filename that contains either aggro or control)</small></dd>
|
||||||
|
|
||||||
<dt>Grouping:</dt>
|
<dt>Grouping:</dt>
|
||||||
<dd><a href="#red -([[]]:100 or aggro)">red -([[]]:100 or aggro)</a> <small>(Any deck that has red in its filename but is not 100 cards or has aggro in its filename)</small></dd>
|
<dd><a href="#red -([[]]:100 OR aggro)">red -([[]]:100 OR aggro)</a> <small>(Any deck that has red in its filename but is not 100 cards or has aggro in its filename)</small></dd>
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
@ -51,20 +51,20 @@ In this list of examples below, each entry has an explanation and can be clicked
|
||||||
|
|
||||||
<dt><u>E</u>dition:</dt>
|
<dt><u>E</u>dition:</dt>
|
||||||
<dd>[set:lea](#set:lea) <small>(Cards that appear in Alpha, which has the set code LEA)</small></dd>
|
<dd>[set:lea](#set:lea) <small>(Cards that appear in Alpha, which has the set code LEA)</small></dd>
|
||||||
<dd>[e:lea or e:leb](#e:lea or e:leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
|
<dd>[e:lea OR e:leb](#e:lea OR e:leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
|
||||||
|
|
||||||
<dt>Negate:</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>
|
<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>
|
<dt>Branching:</dt>
|
||||||
<dd>[t:sliver or o:changeling](#t:sliver or o:changeling) <small>(Any card that is either a sliver or has changeling)</small></dd>
|
<dd>[t:sliver OR o:changeling](#t:sliver OR o:changeling) <small>(Any card that is either a sliver or has changeling)</small></dd>
|
||||||
|
|
||||||
<dt>Grouping:</dt>
|
<dt>Grouping:</dt>
|
||||||
<dd><a href="#t:angel -(angel or c:w)">t:angel -(angel or c:w)</a> <small>(Any angel that doesn't have angel in its name and isn't white)</small></dd>
|
<dd><a href="#t:angel -(angel OR c:w)">t:angel -(angel OR c:w)</a> <small>(Any angel that doesn't have angel in its name and isn't white)</small></dd>
|
||||||
|
|
||||||
<dt>Regular Expression:</dt>
|
<dt>Regular Expression:</dt>
|
||||||
<dd>[/^fell/](#/^fell/) <small>(Any card name that begins with "fell")</small></dd>
|
<dd>[/^fell/](#/^fell/) <small>(Any card name that begins with "fell")</small></dd>
|
||||||
<dd>[o:/counter target .* spell/](#o:/counter target .* spell/) <small>(Any card text with "counter target *something* spell")</small></dd>
|
<dd>[o:/counter target .* spell/](#o:/counter target .* spell/) <small>(Any card text with "counter target *something* spell")</small></dd>
|
||||||
<dd>[o:/for each .* and\/or .*/](#o:/for each .* and\/or .*/) <small>(/'s can be escaped with a \)</small></dd>
|
<dd>[o:/for each .* and\/or .*/](#o:/for each .* and\/or .*/) <small>(/'s can be escaped with a \)</small></dd>
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
1
cockatrice/resources/icons/circle_half_stroke.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M512 320C512 214 426 128 320 128L320 512C426 512 512 426 512 320zM64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576C178.6 576 64 461.4 64 320z"/></svg>
|
||||||
|
After Width: | Height: | Size: 410 B |
1
cockatrice/resources/icons/dragon.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M352 188.5L300.1 175.5C293.6 173.9 288.8 168.4 288.1 161.7C287.4 155 290.9 148.6 296.8 145.6L337.6 125.2L294.3 92.7C288.8 88.6 286.5 81.4 288.7 74.8C290.9 68.2 297.1 64 304 64L464 64C494.2 64 522.7 78.2 540.8 102.4L598.4 179.2C604.6 187.5 608 197.6 608 208C608 234.5 586.5 256 560 256L538.5 256C521.5 256 505.2 249.3 493.2 237.3L479.9 224L447.9 224L447.9 245.5C447.9 270.3 460.7 293.4 481.7 306.6L588.3 373.2C620.4 393.3 639.9 428.4 639.9 466.3C639.9 526.9 590.8 576.1 530.1 576.1L32.3 576C29 576 25.7 575.6 22.7 574.6C13.5 571.8 6 565 2.3 556C1 552.7 .1 549.1 0 545.3C-.2 541.6 .3 538 1.3 534.6C4.1 525.4 10.9 517.9 19.9 514.2C22.9 513 26.1 512.2 29.4 512L433.3 476C441.6 475.3 448 468.3 448 459.9C448 455.6 446.3 451.5 443.3 448.5L398.9 404.1C368.9 374.1 352 333.4 352 291L352 188.5zM512 136.3C512 136.2 512 136.1 512 136C512 135.9 512 135.8 512 135.7L512 136.3zM510.7 143.7L464.3 132.1C464.1 133.4 464 134.7 464 136C464 149.3 474.7 160 488 160C498.6 160 507.5 153.2 510.7 143.7zM130.9 180.5C147.2 166 171.3 164.3 189.4 176.4L320 263.4L320 290.9C320 323.7 328.4 355.7 344 383.9L112 383.9C105.3 383.9 99.3 379.7 97 373.5C94.7 367.3 96.5 360.2 101.6 355.8L171 296.3L18.4 319.8C11.4 320.9 4.5 317.2 1.5 310.8C-1.5 304.4 .1 296.8 5.4 292L130.9 180.5z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
12
cockatrice/resources/icons/filter.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="800px" height="800px" viewBox="0 0 971.986 971.986"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M370.216,459.3c10.2,11.1,15.8,25.6,15.8,40.6v442c0,26.601,32.1,40.101,51.1,21.4l123.3-141.3
|
||||||
|
c16.5-19.8,25.6-29.601,25.6-49.2V500c0-15,5.7-29.5,15.8-40.601L955.615,75.5c26.5-28.8,6.101-75.5-33.1-75.5h-873
|
||||||
|
c-39.2,0-59.7,46.6-33.1,75.5L370.216,459.3z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 676 B |
1
cockatrice/resources/icons/floppy_disk.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M160 96C124.7 96 96 124.7 96 160L96 480C96 515.3 124.7 544 160 544L480 544C515.3 544 544 515.3 544 480L544 237.3C544 220.3 537.3 204 525.3 192L448 114.7C436 102.7 419.7 96 402.7 96L160 96zM192 192C192 174.3 206.3 160 224 160L384 160C401.7 160 416 174.3 416 192L416 256C416 273.7 401.7 288 384 288L224 288C206.3 288 192 273.7 192 256L192 192zM320 352C355.3 352 384 380.7 384 416C384 451.3 355.3 480 320 480C284.7 480 256 451.3 256 416C256 380.7 284.7 352 320 352z"/></svg>
|
||||||
|
After Width: | Height: | Size: 693 B |
1
cockatrice/resources/icons/gear.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M259.1 73.5C262.1 58.7 275.2 48 290.4 48L350.2 48C365.4 48 378.5 58.7 381.5 73.5L396 143.5C410.1 149.5 423.3 157.2 435.3 166.3L503.1 143.8C517.5 139 533.3 145 540.9 158.2L570.8 210C578.4 223.2 575.7 239.8 564.3 249.9L511 297.3C511.9 304.7 512.3 312.3 512.3 320C512.3 327.7 511.8 335.3 511 342.7L564.4 390.2C575.8 400.3 578.4 417 570.9 430.1L541 481.9C533.4 495 517.6 501.1 503.2 496.3L435.4 473.8C423.3 482.9 410.1 490.5 396.1 496.6L381.7 566.5C378.6 581.4 365.5 592 350.4 592L290.6 592C275.4 592 262.3 581.3 259.3 566.5L244.9 496.6C230.8 490.6 217.7 482.9 205.6 473.8L137.5 496.3C123.1 501.1 107.3 495.1 99.7 481.9L69.8 430.1C62.2 416.9 64.9 400.3 76.3 390.2L129.7 342.7C128.8 335.3 128.4 327.7 128.4 320C128.4 312.3 128.9 304.7 129.7 297.3L76.3 249.8C64.9 239.7 62.3 223 69.8 209.9L99.7 158.1C107.3 144.9 123.1 138.9 137.5 143.7L205.3 166.2C217.4 157.1 230.6 149.5 244.6 143.4L259.1 73.5zM320.3 400C364.5 399.8 400.2 363.9 400 319.7C399.8 275.5 363.9 239.8 319.7 240C275.5 240.2 239.8 276.1 240 320.3C240.2 364.5 276.1 400.2 320.3 400z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
72
cockatrice/resources/icons/mana/C.svg
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="169.33115mm"
|
||||||
|
height="169.59981mm"
|
||||||
|
viewBox="0 0 169.33115 169.59981"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:export-filename="C.svg"
|
||||||
|
inkscape:export-xdpi="96.000015"
|
||||||
|
inkscape:export-ydpi="96.000015"
|
||||||
|
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
|
||||||
|
sodipodi:docname="colorless.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:zoom="0.71535494"
|
||||||
|
inkscape:cx="397.00572"
|
||||||
|
inkscape:cy="536.09751"
|
||||||
|
inkscape:window-width="1853"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1">
|
||||||
|
<inkscape:page
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="169.33115"
|
||||||
|
height="169.59981"
|
||||||
|
id="page2"
|
||||||
|
margin="0"
|
||||||
|
bleed="0" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-20.334425,-63.700102)">
|
||||||
|
<ellipse
|
||||||
|
style="fill:#cccccc;stroke:#000000;stroke-width:0.165333;stroke-linecap:round"
|
||||||
|
id="path1"
|
||||||
|
cx="-30.617094"
|
||||||
|
cy="179.22736"
|
||||||
|
transform="matrix(0.70654605,-0.70766707,0.70654608,0.70766704,0,0)"
|
||||||
|
rx="84.650612"
|
||||||
|
ry="84.65062" />
|
||||||
|
<rect
|
||||||
|
style="fill:none;stroke:#000000;stroke-width:14.5003;stroke-linecap:round;stroke-linejoin:bevel;stroke-dasharray:none"
|
||||||
|
id="rect1"
|
||||||
|
width="84.683701"
|
||||||
|
height="84.683769"
|
||||||
|
x="-221.60611"
|
||||||
|
y="-73.174698"
|
||||||
|
ry="0.084683768"
|
||||||
|
transform="matrix(-0.7073973,-0.70681615,0.7073973,-0.70681615,0,0)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
1
cockatrice/resources/icons/pen_to_square.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M535.6 85.7C513.7 63.8 478.3 63.8 456.4 85.7L432 110.1L529.9 208L554.3 183.6C576.2 161.7 576.2 126.3 554.3 104.4L535.6 85.7zM236.4 305.7C230.3 311.8 225.6 319.3 222.9 327.6L193.3 416.4C190.4 425 192.7 434.5 199.1 441C205.5 447.5 215 449.7 223.7 446.8L312.5 417.2C320.7 414.5 328.2 409.8 334.4 403.7L496 241.9L398.1 144L236.4 305.7zM160 128C107 128 64 171 64 224L64 480C64 533 107 576 160 576L416 576C469 576 512 533 512 480L512 384C512 366.3 497.7 352 480 352C462.3 352 448 366.3 448 384L448 480C448 497.7 433.7 512 416 512L160 512C142.3 512 128 497.7 128 480L128 224C128 206.3 142.3 192 160 192L256 192C273.7 192 288 177.7 288 160C288 142.3 273.7 128 256 128L160 128z"/></svg>
|
||||||
|
After Width: | Height: | Size: 899 B |
1
cockatrice/resources/icons/scale_balanced.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M384 96L512 96C529.7 96 544 110.3 544 128C544 145.7 529.7 160 512 160L398.4 160C393.2 185.8 375.5 207.1 352 217.3L352 512L512 512C529.7 512 544 526.3 544 544C544 561.7 529.7 576 512 576L128 576C110.3 576 96 561.7 96 544C96 526.3 110.3 512 128 512L288 512L288 217.3C264.5 207 246.8 185.7 241.6 160L128 160C110.3 160 96 145.7 96 128C96 110.3 110.3 96 128 96L256 96C270.6 76.6 293.8 64 320 64C346.2 64 369.4 76.6 384 96zM439.6 384L584.4 384L512 259.8L439.6 384zM512 480C449.1 480 396.8 446 386 401.1C383.4 390.1 387 378.8 392.7 369L487.9 205.8C492.9 197.2 502.1 192 512 192C521.9 192 531.1 197.3 536.1 205.8L631.3 369C637 378.8 640.6 390.1 638 401.1C627.2 445.9 574.9 480 512 480zM126.8 259.8L54.4 384L199.3 384L126.8 259.8zM.9 401.1C-1.7 390.1 1.9 378.8 7.6 369L102.8 205.8C107.8 197.2 117 192 126.9 192C136.8 192 146 197.3 151 205.8L246.2 369C251.9 378.8 255.5 390.1 252.9 401.1C242.1 445.9 189.8 480 126.9 480C64 480 11.7 446 .9 401.1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
1
cockatrice/resources/icons/scroll.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M32 176C32 134.5 63.6 100.4 104 96.4L104 96L384 96C437 96 480 139 480 192L480 368L304 368C264.2 368 232 400.2 232 440L232 500C232 524.3 212.3 544 188 544C163.7 544 144 524.3 144 500L144 272L80 272C53.5 272 32 250.5 32 224L32 176zM268.8 544C275.9 530.9 280 515.9 280 500L280 440C280 426.7 290.7 416 304 416L552 416C565.3 416 576 426.7 576 440L576 464C576 508.2 540.2 544 496 544L268.8 544zM112 144C94.3 144 80 158.3 80 176L80 224L144 224L144 176C144 158.3 129.7 144 112 144z"/></svg>
|
||||||
|
After Width: | Height: | Size: 704 B |
1
cockatrice/resources/icons/sort_arrow_down.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M278.6 438.6L182.6 534.6C170.1 547.1 149.8 547.1 137.3 534.6L41.3 438.6C28.8 426.1 28.8 405.8 41.3 393.3C53.8 380.8 74.1 380.8 86.6 393.3L128 434.7L128 128C128 110.3 142.3 96 160 96C177.7 96 192 110.3 192 128L192 434.7L233.4 393.3C245.9 380.8 266.2 380.8 278.7 393.3C291.2 405.8 291.2 426.1 278.7 438.6zM352 544C334.3 544 320 529.7 320 512C320 494.3 334.3 480 352 480L384 480C401.7 480 416 494.3 416 512C416 529.7 401.7 544 384 544L352 544zM352 416C334.3 416 320 401.7 320 384C320 366.3 334.3 352 352 352L448 352C465.7 352 480 366.3 480 384C480 401.7 465.7 416 448 416L352 416zM352 288C334.3 288 320 273.7 320 256C320 238.3 334.3 224 352 224L512 224C529.7 224 544 238.3 544 256C544 273.7 529.7 288 512 288L352 288zM352 160C334.3 160 320 145.7 320 128C320 110.3 334.3 96 352 96L576 96C593.7 96 608 110.3 608 128C608 145.7 593.7 160 576 160L352 160z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,587 @@
|
||||||
|
#include "remote_connection_controller.h"
|
||||||
|
|
||||||
|
#include "../../settings/cache_settings.h"
|
||||||
|
#include "../interface/widgets/dialogs/dlg_connect.h"
|
||||||
|
#include "../interface/widgets/dialogs/dlg_forgot_password_challenge.h"
|
||||||
|
#include "../interface/widgets/dialogs/dlg_forgot_password_request.h"
|
||||||
|
#include "../interface/widgets/dialogs/dlg_forgot_password_reset.h"
|
||||||
|
#include "../interface/widgets/dialogs/dlg_register.h"
|
||||||
|
#include "../interface/widgets/utility/get_text_with_max.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QThread>
|
||||||
|
#include <libcockatrice/network/client/remote/remote_client.h>
|
||||||
|
#include <libcockatrice/protocol/pb/response.pb.h>
|
||||||
|
|
||||||
|
ConnectionController::ConnectionController(QWidget *dialogParent, QObject *parent)
|
||||||
|
: QObject(parent), dialogParent(dialogParent)
|
||||||
|
{
|
||||||
|
remoteClient = new RemoteClient(nullptr, &SettingsCache::instance());
|
||||||
|
|
||||||
|
clientThread = new QThread(this);
|
||||||
|
remoteClient->moveToThread(clientThread);
|
||||||
|
clientThread->start();
|
||||||
|
|
||||||
|
wireClientSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionController::~ConnectionController()
|
||||||
|
{
|
||||||
|
remoteClient->deleteLater();
|
||||||
|
clientThread->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::wireClientSignals()
|
||||||
|
{
|
||||||
|
connect(remoteClient, &RemoteClient::connectionClosedEventReceived, this,
|
||||||
|
&ConnectionController::onConnectionClosedEvent);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::serverShutdownEventReceived, this,
|
||||||
|
&ConnectionController::onServerShutdownEvent);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::statusChanged, this, &ConnectionController::onStatusChanged);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::userInfoChanged, this, &ConnectionController::onUserInfoReceived,
|
||||||
|
Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::loginError, this,
|
||||||
|
[this](Response::ResponseCode r, QString rs, quint32 et, QList<QString> mf) {
|
||||||
|
onLoginError(static_cast<int>(r), rs, et, mf);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::registerError, this,
|
||||||
|
[this](Response::ResponseCode r, QString rs, quint32 et) { onRegisterError(static_cast<int>(r), rs, et); });
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::activateError, this, &ConnectionController::onActivateError);
|
||||||
|
connect(remoteClient, &RemoteClient::socketError, this, &ConnectionController::onSocketError);
|
||||||
|
connect(remoteClient, &RemoteClient::serverTimeout, this, &ConnectionController::onServerTimeout);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::protocolVersionMismatch, this,
|
||||||
|
&ConnectionController::onProtocolVersionMismatch);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::registerAccepted, this, &ConnectionController::onRegisterAccepted);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::registerAcceptedNeedsActivate, this,
|
||||||
|
&ConnectionController::onRegisterAcceptedNeedsActivate);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::activateAccepted, this, &ConnectionController::onActivateAccepted);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::notifyUserAboutUpdate, this, &ConnectionController::onNotifyUserAboutUpdate);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::sigForgotPasswordSuccess, this,
|
||||||
|
&ConnectionController::onForgotPasswordSuccess);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::sigForgotPasswordError, this, &ConnectionController::onForgotPasswordError);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::sigPromptForForgotPasswordReset, this,
|
||||||
|
&ConnectionController::onPromptForgotPasswordReset);
|
||||||
|
|
||||||
|
connect(remoteClient, &RemoteClient::sigPromptForForgotPasswordChallenge, this,
|
||||||
|
&ConnectionController::onPromptForgotPasswordChallenge);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::connectToServer()
|
||||||
|
{
|
||||||
|
dlgConnect = new DlgConnect(dialogParent);
|
||||||
|
connect(dlgConnect, &DlgConnect::sigStartForgotPasswordRequest, this, &ConnectionController::forgotPasswordRequest);
|
||||||
|
|
||||||
|
if (dlgConnect->exec()) {
|
||||||
|
remoteClient->connectToServer(dlgConnect->getHost(), static_cast<unsigned int>(dlgConnect->getPort()),
|
||||||
|
dlgConnect->getPlayerName(), dlgConnect->getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::connectToServerDirect(const QString &host,
|
||||||
|
unsigned int port,
|
||||||
|
const QString &playerName,
|
||||||
|
const QString &password)
|
||||||
|
{
|
||||||
|
remoteClient->connectToServer(host, port, playerName, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::disconnectFromServer()
|
||||||
|
{
|
||||||
|
remoteClient->disconnectFromServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::registerToServer()
|
||||||
|
{
|
||||||
|
DlgRegister dlg(dialogParent);
|
||||||
|
if (dlg.exec()) {
|
||||||
|
remoteClient->registerToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()), dlg.getPlayerName(),
|
||||||
|
dlg.getPassword(), dlg.getEmail(), dlg.getCountry(), dlg.getRealName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::forgotPasswordRequest()
|
||||||
|
{
|
||||||
|
DlgForgotPasswordRequest dlg(dialogParent);
|
||||||
|
if (dlg.exec()) {
|
||||||
|
remoteClient->requestForgotPasswordToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()),
|
||||||
|
dlg.getPlayerName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onConnectionClosedEvent(const Event_ConnectionClosed &event)
|
||||||
|
{
|
||||||
|
remoteClient->disconnectFromServer();
|
||||||
|
|
||||||
|
QString reasonStr;
|
||||||
|
switch (event.reason()) {
|
||||||
|
case Event_ConnectionClosed::USER_LIMIT_REACHED: {
|
||||||
|
reasonStr = tr("The server has reached its maximum user capacity, please check back later.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Event_ConnectionClosed::TOO_MANY_CONNECTIONS: {
|
||||||
|
reasonStr = tr("There are too many concurrent connections from your address.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Event_ConnectionClosed::BANNED: {
|
||||||
|
reasonStr = tr("Banned by moderator");
|
||||||
|
if (event.has_end_time()) {
|
||||||
|
reasonStr.append(
|
||||||
|
"\n" + tr("Expected end time: %1").arg(QDateTime::fromSecsSinceEpoch(event.end_time()).toString()));
|
||||||
|
} else {
|
||||||
|
reasonStr.append("\n" + tr("This ban lasts indefinitely."));
|
||||||
|
}
|
||||||
|
if (event.has_reason_str()) {
|
||||||
|
reasonStr.append("\n\n" + QString::fromStdString(event.reason_str()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Event_ConnectionClosed::SERVER_SHUTDOWN: {
|
||||||
|
reasonStr = tr("Scheduled server shutdown.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Event_ConnectionClosed::USERNAMEINVALID: {
|
||||||
|
reasonStr = tr("Invalid username.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Event_ConnectionClosed::LOGGEDINELSEWERE: {
|
||||||
|
reasonStr = tr("You have been logged out due to logging in at another location.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
reasonStr = QString::fromStdString(event.reason_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox::critical(dialogParent, tr("Connection closed"),
|
||||||
|
tr("The server has terminated your connection.\nReason: %1").arg(reasonStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onServerShutdownEvent(const Event_ServerShutdown &event)
|
||||||
|
{
|
||||||
|
serverShutdownMessageBox.setInformativeText(tr("The server is going to be restarted in %n minute(s).\nAll running "
|
||||||
|
"games will be lost.\nReason for shutdown: %1",
|
||||||
|
"", event.minutes())
|
||||||
|
.arg(QString::fromStdString(event.reason())));
|
||||||
|
serverShutdownMessageBox.setIconPixmap(QPixmap("theme:cockatrice").scaled(64, 64));
|
||||||
|
serverShutdownMessageBox.setText(tr("Scheduled server shutdown"));
|
||||||
|
serverShutdownMessageBox.setWindowModality(Qt::ApplicationModal);
|
||||||
|
serverShutdownMessageBox.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onStatusChanged(ClientStatus status)
|
||||||
|
{
|
||||||
|
// Update the window title first, then let MainWindow handle its own UI
|
||||||
|
// state via the forwarded signal
|
||||||
|
updateWindowTitle();
|
||||||
|
emit statusChanged(status);
|
||||||
|
|
||||||
|
// TabSupervisor::stop() needs calling on disconnect; start() is driven by
|
||||||
|
// onUserInfoReceived → tabSupervisorStartRequested.
|
||||||
|
if (status == StatusDisconnected) {
|
||||||
|
emit tabSupervisorStopRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onUserInfoReceived(const ServerInfo_User &info)
|
||||||
|
{
|
||||||
|
emit tabSupervisorStartRequested(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onLoginError(int r,
|
||||||
|
QString reasonStr,
|
||||||
|
quint32 endTime,
|
||||||
|
const QList<QString> &missingFeatures)
|
||||||
|
{
|
||||||
|
switch (static_cast<Response::ResponseCode>(r)) {
|
||||||
|
case Response::RespClientUpdateRequired: {
|
||||||
|
QString formatted = "Missing Features: ";
|
||||||
|
for (int i = 0; i < missingFeatures.size(); ++i) {
|
||||||
|
formatted.append(QString("\n %1").arg(QChar(0x2022)) + " " + missingFeatures.value(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox msgBox(dialogParent);
|
||||||
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
|
msgBox.setWindowTitle(tr("Failed Login"));
|
||||||
|
msgBox.setText(tr("Your client seems to be missing features this server requires for connection.") +
|
||||||
|
"\n\n" + tr("To update your client, go to 'Help -> Check for Client Updates'."));
|
||||||
|
msgBox.setDetailedText(formatted);
|
||||||
|
msgBox.exec();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespWrongPassword: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("Incorrect username or password. "
|
||||||
|
"Please check your authentication information and try again."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespWouldOverwriteOldSession: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("There is already an active session using this user name.\n"
|
||||||
|
"Please close that session first and re-login."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespUserIsBanned: {
|
||||||
|
QString bannedStr =
|
||||||
|
endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString())
|
||||||
|
: tr("You are banned indefinitely.");
|
||||||
|
if (!reasonStr.isEmpty()) {
|
||||||
|
bannedStr.append("\n\n" + reasonStr);
|
||||||
|
}
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), bannedStr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespUsernameInvalid: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), extractInvalidUsernameMessage(reasonStr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespRegistrationRequired: {
|
||||||
|
if (QMessageBox::question(dialogParent, tr("Error"),
|
||||||
|
tr("This server requires user registration. Do you want to register now?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||||
|
registerToServer();
|
||||||
|
}
|
||||||
|
return; // don't re-prompt connect
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespClientIdRequired: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("This server requires client IDs. Your client is either failing to generate an "
|
||||||
|
"ID or you are running a modified client.\n"
|
||||||
|
"Please close and reopen your client to try again."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespContextError: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("An internal error has occurred, please close and reopen Cockatrice before "
|
||||||
|
"trying again.\nIf the error persists, ensure you are running the latest "
|
||||||
|
"version of the software and if needed contact the software developers."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespAccountNotActivated: {
|
||||||
|
bool ok = false;
|
||||||
|
QString token =
|
||||||
|
getTextWithMax(dialogParent, tr("Account activation"),
|
||||||
|
tr("Your account has not been activated yet.\n"
|
||||||
|
"You need to provide the activation token received in the activation email."),
|
||||||
|
QLineEdit::Normal, QString(), &ok);
|
||||||
|
|
||||||
|
if (ok && !token.isEmpty()) {
|
||||||
|
remoteClient->activateToServer(token);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
remoteClient->disconnectFromServer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Response::RespServerFull: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Server Full"),
|
||||||
|
tr("The server has reached its maximum user capacity, please check back later."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("Unknown login error: %1").arg(r) +
|
||||||
|
tr("\nThis usually means that your client version is out of date, and the server "
|
||||||
|
"sent a reply your client doesn't understand."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-open the connect dialog after any handled error
|
||||||
|
connectToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onRegisterError(int r, QString reasonStr, quint32 endTime)
|
||||||
|
{
|
||||||
|
switch (static_cast<Response::ResponseCode>(r)) {
|
||||||
|
case Response::RespRegistrationDisabled: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Registration denied"),
|
||||||
|
tr("Registration is currently disabled on this server"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespUserAlreadyExists: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Registration denied"),
|
||||||
|
tr("There is already an existing account with the same user name."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespEmailRequiredToRegister: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Registration denied"),
|
||||||
|
tr("It's mandatory to specify a valid email address when registering."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespEmailBlackListed: {
|
||||||
|
if (reasonStr.isEmpty()) {
|
||||||
|
reasonStr =
|
||||||
|
"The email address provider used during registration has been blocked from use on this server.";
|
||||||
|
}
|
||||||
|
QMessageBox::critical(dialogParent, tr("Registration denied"), reasonStr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespTooManyRequests: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Registration denied"),
|
||||||
|
tr("It appears you are attempting to register a new account on this server yet you "
|
||||||
|
"already have an account registered with the email provided. This server "
|
||||||
|
"restricts the number of accounts a user can register per address. Please "
|
||||||
|
"contact the server operator for further assistance or to obtain your "
|
||||||
|
"credential information."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespPasswordTooShort: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Registration denied"), tr("Password too short."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespUserIsBanned: {
|
||||||
|
QString bannedStr =
|
||||||
|
endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString())
|
||||||
|
: tr("You are banned indefinitely.");
|
||||||
|
if (!reasonStr.isEmpty()) {
|
||||||
|
bannedStr.append("\n\n" + reasonStr);
|
||||||
|
}
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), bannedStr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespUsernameInvalid: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), extractInvalidUsernameMessage(reasonStr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespRegistrationFailed: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("Registration failed for a technical problem on the server."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Response::RespNotConnected: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), tr("The connection to the server has been lost."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("Unknown registration error: %1").arg(r) +
|
||||||
|
tr("\nThis usually means that your client version is out of date, and the server "
|
||||||
|
"sent a reply your client doesn't understand."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onActivateError()
|
||||||
|
{
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), tr("Account activation failed"));
|
||||||
|
remoteClient->disconnectFromServer();
|
||||||
|
connectToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onSocketError(const QString &errorStr)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), tr("Socket error: %1").arg(errorStr));
|
||||||
|
connectToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onServerTimeout()
|
||||||
|
{
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"), tr("Server timeout"));
|
||||||
|
connectToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onProtocolVersionMismatch(int localVersion, int remoteVersion)
|
||||||
|
{
|
||||||
|
if (localVersion > remoteVersion) {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("You are trying to connect to an obsolete server. Please downgrade your Cockatrice "
|
||||||
|
"version or connect to a suitable server.\n"
|
||||||
|
"Local version is %1, remote version is %2.")
|
||||||
|
.arg(localVersion)
|
||||||
|
.arg(remoteVersion));
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(dialogParent, tr("Error"),
|
||||||
|
tr("Your Cockatrice client is obsolete. Please update your Cockatrice version.\n"
|
||||||
|
"Local version is %1, remote version is %2.")
|
||||||
|
.arg(localVersion)
|
||||||
|
.arg(remoteVersion));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onRegisterAccepted()
|
||||||
|
{
|
||||||
|
QMessageBox::information(dialogParent, tr("Success"), tr("Registration accepted.\nWill now login."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onRegisterAcceptedNeedsActivate()
|
||||||
|
{
|
||||||
|
// Server will send activation email; nothing to display here.
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onActivateAccepted()
|
||||||
|
{
|
||||||
|
QMessageBox::information(dialogParent, tr("Success"), tr("Account activation accepted.\nWill now login."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onNotifyUserAboutUpdate()
|
||||||
|
{
|
||||||
|
QMessageBox::information(
|
||||||
|
dialogParent, tr("Information"),
|
||||||
|
tr("This server supports additional features that your client doesn't have.\n"
|
||||||
|
"This is most likely not a problem, but this message might mean there is a new version of "
|
||||||
|
"Cockatrice available or this server is running a custom or pre-release version.\n\n"
|
||||||
|
"To update your client, go to Help -> Check for Updates."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onForgotPasswordSuccess()
|
||||||
|
{
|
||||||
|
QMessageBox::information(
|
||||||
|
dialogParent, tr("Reset Password"),
|
||||||
|
tr("Your password has been reset successfully, you can now log in using the new credentials."));
|
||||||
|
SettingsCache::instance().servers().setFPHostName("");
|
||||||
|
SettingsCache::instance().servers().setFPPort("");
|
||||||
|
SettingsCache::instance().servers().setFPPlayerName("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onForgotPasswordError()
|
||||||
|
{
|
||||||
|
QMessageBox::warning(
|
||||||
|
dialogParent, tr("Reset Password"),
|
||||||
|
tr("Failed to reset user account password, please contact the server operator to reset your password."));
|
||||||
|
SettingsCache::instance().servers().setFPHostName("");
|
||||||
|
SettingsCache::instance().servers().setFPPort("");
|
||||||
|
SettingsCache::instance().servers().setFPPlayerName("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onPromptForgotPasswordReset()
|
||||||
|
{
|
||||||
|
QMessageBox::information(dialogParent, tr("Reset Password"),
|
||||||
|
tr("Activation request received, please check your email for an activation token."));
|
||||||
|
DlgForgotPasswordReset dlg(dialogParent);
|
||||||
|
if (dlg.exec()) {
|
||||||
|
remoteClient->submitForgotPasswordResetToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()),
|
||||||
|
dlg.getPlayerName(), dlg.getToken(), dlg.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::onPromptForgotPasswordChallenge()
|
||||||
|
{
|
||||||
|
DlgForgotPasswordChallenge dlg(dialogParent);
|
||||||
|
if (dlg.exec()) {
|
||||||
|
remoteClient->submitForgotPasswordChallengeToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()),
|
||||||
|
dlg.getPlayerName(), dlg.getEmail());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionController::updateWindowTitle()
|
||||||
|
{
|
||||||
|
const QString appName = QStringLiteral("Cockatrice");
|
||||||
|
QString title;
|
||||||
|
|
||||||
|
switch (remoteClient->getStatus()) {
|
||||||
|
case StatusConnecting: {
|
||||||
|
title = appName + " - " + tr("Connecting to %1...").arg(remoteClient->peerName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StatusRegistering: {
|
||||||
|
title = appName + " - " +
|
||||||
|
tr("Registering to %1 as %2...").arg(remoteClient->peerName()).arg(remoteClient->getUserName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StatusDisconnected: {
|
||||||
|
title = appName + " - " + tr("Disconnected");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StatusLoggingIn: {
|
||||||
|
title = appName + " - " + tr("Connected, logging in at %1").arg(remoteClient->peerName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StatusLoggedIn: {
|
||||||
|
title = remoteClient->getUserName() + "@" + remoteClient->peerName();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StatusRequestingForgotPassword:
|
||||||
|
case StatusSubmitForgotPasswordChallenge:
|
||||||
|
case StatusSubmitForgotPasswordReset:
|
||||||
|
title = appName + " - " +
|
||||||
|
tr("Requesting forgotten password to %1 as %2...")
|
||||||
|
.arg(remoteClient->peerName())
|
||||||
|
.arg(remoteClient->getUserName());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
title = appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit windowTitleChanged(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
QString ConnectionController::extractInvalidUsernameMessage(QString &in)
|
||||||
|
{
|
||||||
|
QString out = tr("Invalid username.") + "<br/>";
|
||||||
|
QStringList rules = in.split(QChar('|'));
|
||||||
|
|
||||||
|
if (rules.size() == 7 || rules.size() == 9) {
|
||||||
|
out += tr("Your username must respect these rules:") + "<ul>";
|
||||||
|
|
||||||
|
out += "<li>" + tr("is %1 - %2 characters long").arg(rules.at(0)).arg(rules.at(1)) + "</li>";
|
||||||
|
out += "<li>" + tr("can %1 contain lowercase characters").arg((rules.at(2).toInt() > 0) ? "" : tr("NOT")) +
|
||||||
|
"</li>";
|
||||||
|
out += "<li>" + tr("can %1 contain uppercase characters").arg((rules.at(3).toInt() > 0) ? "" : tr("NOT")) +
|
||||||
|
"</li>";
|
||||||
|
out +=
|
||||||
|
"<li>" + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "</li>";
|
||||||
|
|
||||||
|
if (rules.at(6).size() > 0) {
|
||||||
|
out += "<li>" + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "</li>";
|
||||||
|
}
|
||||||
|
|
||||||
|
out += "<li>" +
|
||||||
|
tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) +
|
||||||
|
"</li>";
|
||||||
|
|
||||||
|
if (rules.size() == 9) {
|
||||||
|
if (rules.at(7).size() > 0) {
|
||||||
|
QString words = rules.at(7).toHtmlEscaped();
|
||||||
|
if (words.startsWith("\n")) {
|
||||||
|
out += tr("no unacceptable language as specified by these server rules:",
|
||||||
|
"note that the following lines will not be translated");
|
||||||
|
for (QString &line : words.split("\n", Qt::SkipEmptyParts)) {
|
||||||
|
out += "<li>" + line + "</li>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out += "<li>" + tr("can not contain any of the following words: %1").arg(words) + "</li>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rules.at(8).size() > 0) {
|
||||||
|
out += "<li>" +
|
||||||
|
tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) +
|
||||||
|
"</li>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out += "</ul>";
|
||||||
|
} else {
|
||||||
|
out += tr("You may only use A-Z, a-z, 0-9, _, ., and - in your username.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
#ifndef COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H
|
||||||
|
#define COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H
|
||||||
|
|
||||||
|
#include "abstract_client.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QThread>
|
||||||
|
#include <libcockatrice/protocol/pb/event_connection_closed.pb.h>
|
||||||
|
#include <libcockatrice/protocol/pb/event_server_shutdown.pb.h>
|
||||||
|
|
||||||
|
class RemoteClient;
|
||||||
|
class ServerInfo_User;
|
||||||
|
class DlgConnect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Owns the RemoteClient and its worker thread.
|
||||||
|
* Encapsulates all connection, authentication, and registration logic so that
|
||||||
|
* MainWindow only needs to react to high-level signals.
|
||||||
|
*/
|
||||||
|
class ConnectionController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConnectionController(QWidget *dialogParent, QObject *parent = nullptr);
|
||||||
|
~ConnectionController() override;
|
||||||
|
|
||||||
|
RemoteClient *client() const
|
||||||
|
{
|
||||||
|
return remoteClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerToServer();
|
||||||
|
void forgotPasswordRequest();
|
||||||
|
void connectToServer();
|
||||||
|
void
|
||||||
|
connectToServerDirect(const QString &host, unsigned int port, const QString &playerName, const QString &password);
|
||||||
|
void disconnectFromServer();
|
||||||
|
|
||||||
|
void refreshWindowTitle()
|
||||||
|
{
|
||||||
|
updateWindowTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void windowTitleChanged(const QString &title);
|
||||||
|
|
||||||
|
void tabSupervisorStartRequested(const ServerInfo_User &info);
|
||||||
|
void tabSupervisorStopRequested();
|
||||||
|
|
||||||
|
// Passes the raw ClientStatus through so MainWindow can drive its own
|
||||||
|
// action enable/disable logic
|
||||||
|
void statusChanged(ClientStatus status);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// Slots wired directly to RemoteClient signals
|
||||||
|
void onStatusChanged(ClientStatus status);
|
||||||
|
void onUserInfoReceived(const ServerInfo_User &info);
|
||||||
|
void onLoginError(int r, QString reasonStr, quint32 endTime, const QList<QString> &missingFeatures);
|
||||||
|
void onRegisterAccepted();
|
||||||
|
void onRegisterAcceptedNeedsActivate();
|
||||||
|
void onRegisterError(int r, QString reasonStr, quint32 endTime);
|
||||||
|
void onActivateAccepted();
|
||||||
|
void onActivateError();
|
||||||
|
void onProtocolVersionMismatch(int localVersion, int remoteVersion);
|
||||||
|
void onNotifyUserAboutUpdate();
|
||||||
|
void onConnectionClosedEvent(const Event_ConnectionClosed &event);
|
||||||
|
void onServerShutdownEvent(const Event_ServerShutdown &event);
|
||||||
|
void onSocketError(const QString &errorStr);
|
||||||
|
void onServerTimeout();
|
||||||
|
|
||||||
|
// Forgot-password flow
|
||||||
|
void onForgotPasswordSuccess();
|
||||||
|
void onForgotPasswordError();
|
||||||
|
void onPromptForgotPasswordReset();
|
||||||
|
void onPromptForgotPasswordChallenge();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void wireClientSignals();
|
||||||
|
void updateWindowTitle();
|
||||||
|
|
||||||
|
/** Parse the server's pipe-delimited username-rule string into HTML. */
|
||||||
|
static QString extractInvalidUsernameMessage(QString &in);
|
||||||
|
|
||||||
|
RemoteClient *remoteClient{nullptr};
|
||||||
|
QThread *clientThread{nullptr};
|
||||||
|
QWidget *dialogParent{nullptr}; // used as parent for QMessageBox / dialog calls
|
||||||
|
|
||||||
|
// Persistent so it can be updated in-place by onServerShutdownEvent
|
||||||
|
QMessageBox serverShutdownMessageBox;
|
||||||
|
|
||||||
|
// Kept as a member so the forgot-password signal can be wired to it
|
||||||
|
DlgConnect *dlgConnect{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_REMOTE_CONNECTION_CONTROLLER_H
|
||||||
|
|
@ -6,12 +6,12 @@
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/deck_list/deck_list.h>
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||||
#include <version_string.h>
|
#include <version_string.h>
|
||||||
|
|
||||||
DeckStatsInterface::DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent)
|
DeckStatsInterface::DeckStatsInterface(QObject *parent) : QObject(parent)
|
||||||
: QObject(parent), cardDatabase(_cardDatabase)
|
|
||||||
{
|
{
|
||||||
manager = new QNetworkAccessManager(this);
|
manager = new QNetworkAccessManager(this);
|
||||||
connect(manager, &QNetworkAccessManager::finished, this, &DeckStatsInterface::queryFinished);
|
connect(manager, &QNetworkAccessManager::finished, this, &DeckStatsInterface::queryFinished);
|
||||||
|
|
@ -70,8 +70,8 @@ void DeckStatsInterface::analyzeDeck(const DeckList &deck)
|
||||||
|
|
||||||
void DeckStatsInterface::copyDeckWithoutTokens(const DeckList &source, DeckList &destination)
|
void DeckStatsInterface::copyDeckWithoutTokens(const DeckList &source, DeckList &destination)
|
||||||
{
|
{
|
||||||
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
|
auto copyIfNotAToken = [&destination](const auto node, const auto card) {
|
||||||
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
CardInfoPtr dbCard = CardDatabaseManager::query()->getCardInfo(card->getName());
|
||||||
if (dbCard && !dbCard->getIsToken()) {
|
if (dbCard && !dbCard->getIsToken()) {
|
||||||
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1);
|
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1);
|
||||||
addedCard->setNumber(card->getNumber());
|
addedCard->setNumber(card->getNumber());
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
/**
|
/**
|
||||||
* @file deck_stats_interface.h
|
* @file deck_stats_interface.h
|
||||||
* @ingroup ApiInterfaces
|
* @ingroup ApiInterfaces
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef DECKSTATS_INTERFACE_H
|
#ifndef DECKSTATS_INTERFACE_H
|
||||||
#define DECKSTATS_INTERFACE_H
|
#define DECKSTATS_INTERFACE_H
|
||||||
|
|
||||||
#include <libcockatrice/card/database/card_database.h>
|
|
||||||
#include <libcockatrice/deck_list/deck_list.h>
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
|
|
@ -21,8 +20,6 @@ class DeckStatsInterface : public QObject
|
||||||
private:
|
private:
|
||||||
QNetworkAccessManager *manager;
|
QNetworkAccessManager *manager;
|
||||||
|
|
||||||
CardDatabase &cardDatabase;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deckstats doesn't recognize token cards, and instead tries to find the
|
* Deckstats doesn't recognize token cards, and instead tries to find the
|
||||||
* closest non-token card instead. So we construct a new deck which has no
|
* closest non-token card instead. So we construct a new deck which has no
|
||||||
|
|
@ -35,7 +32,7 @@ private slots:
|
||||||
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
|
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
|
explicit DeckStatsInterface(QObject *parent = nullptr);
|
||||||
void analyzeDeck(const DeckList &deck);
|
void analyzeDeck(const DeckList &deck);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/deck_list/deck_list.h>
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||||
#include <version_string.h>
|
#include <version_string.h>
|
||||||
|
|
||||||
TappedOutInterface::TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent)
|
TappedOutInterface::TappedOutInterface(QObject *parent) : QObject(parent)
|
||||||
: QObject(parent), cardDatabase(_cardDatabase)
|
|
||||||
{
|
{
|
||||||
manager = new QNetworkAccessManager(this);
|
manager = new QNetworkAccessManager(this);
|
||||||
connect(manager, &QNetworkAccessManager::finished, this, &TappedOutInterface::queryFinished);
|
connect(manager, &QNetworkAccessManager::finished, this, &TappedOutInterface::queryFinished);
|
||||||
|
|
@ -89,22 +89,26 @@ void TappedOutInterface::analyzeDeck(const DeckList &deck)
|
||||||
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
|
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
||||||
|
// we interpret the redirect and open it in the browser instead, do not follow redirects
|
||||||
|
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
|
||||||
|
|
||||||
manager->post(request, data);
|
manager->post(request, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard)
|
void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard)
|
||||||
{
|
{
|
||||||
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
|
auto copyMainOrSide = [&mainboard, &sideboard](const auto node, const auto card) {
|
||||||
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
CardInfoPtr dbCard = CardDatabaseManager::query()->getCardInfo(card->getName());
|
||||||
if (!dbCard || dbCard->getIsToken())
|
if (!dbCard || dbCard->getIsToken()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DecklistCardNode *addedCard;
|
DecklistCardNode *addedCard;
|
||||||
if (node->getName() == DECK_ZONE_SIDE)
|
if (node->getName() == DECK_ZONE_SIDE) {
|
||||||
addedCard = sideboard.addCard(card->getName(), node->getName(), -1);
|
addedCard = sideboard.addCard(card->getName(), node->getName(), -1);
|
||||||
else
|
} else {
|
||||||
addedCard = mainboard.addCard(card->getName(), node->getName(), -1);
|
addedCard = mainboard.addCard(card->getName(), node->getName(), -1);
|
||||||
|
}
|
||||||
addedCard->setNumber(card->getNumber());
|
addedCard->setNumber(card->getNumber());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* @file tapped_out_interface.h
|
* @file tapped_out_interface.h
|
||||||
* @ingroup ApiInterfaces
|
* @ingroup ApiInterfaces
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef TAPPEDOUT_INTERFACE_H
|
#ifndef TAPPEDOUT_INTERFACE_H
|
||||||
#define TAPPEDOUT_INTERFACE_H
|
#define TAPPEDOUT_INTERFACE_H
|
||||||
|
|
||||||
#include <libcockatrice/card/database/card_database.h>
|
#include <QLoggingCategory>
|
||||||
#include <libcockatrice/deck_list/deck_list.h>
|
#include <QObject>
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(TappedOutInterfaceLog, "tapped_out_interface");
|
inline Q_LOGGING_CATEGORY(TappedOutInterfaceLog, "tapped_out_interface");
|
||||||
|
|
||||||
|
|
@ -29,14 +29,13 @@ class TappedOutInterface : public QObject
|
||||||
private:
|
private:
|
||||||
QNetworkAccessManager *manager;
|
QNetworkAccessManager *manager;
|
||||||
|
|
||||||
CardDatabase &cardDatabase;
|
|
||||||
void copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard);
|
void copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard);
|
||||||
private slots:
|
private slots:
|
||||||
void queryFinished(QNetworkReply *reply);
|
void queryFinished(QNetworkReply *reply);
|
||||||
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
|
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
|
explicit TappedOutInterface(QObject *parent = nullptr);
|
||||||
void analyzeDeck(const DeckList &deck);
|
void analyzeDeck(const DeckList &deck);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file deck_link_to_api_transformer.h
|
* @file deck_link_to_api_transformer.h
|
||||||
* @ingroup ApiInterfaces
|
* @ingroup ApiInterfaces
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef DECK_LINK_TO_API_TRANSFORMER_H
|
#ifndef DECK_LINK_TO_API_TRANSFORMER_H
|
||||||
#define DECK_LINK_TO_API_TRANSFORMER_H
|
#define DECK_LINK_TO_API_TRANSFORMER_H
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
/**
|
/**
|
||||||
* @file interface_json_deck_parser.h
|
* @file interface_json_deck_parser.h
|
||||||
* @ingroup ApiInterfaces
|
* @ingroup ApiInterfaces
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef INTERFACE_JSON_DECK_PARSER_H
|
#ifndef INTERFACE_JSON_DECK_PARSER_H
|
||||||
#define INTERFACE_JSON_DECK_PARSER_H
|
#define INTERFACE_JSON_DECK_PARSER_H
|
||||||
|
|
||||||
#include "../../../interface/deck_loader/card_node_function.h"
|
#include "../../../interface/deck_loader/card_node_function.h"
|
||||||
#include "../../../interface/deck_loader/deck_loader.h"
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <libcockatrice/card/import/card_name_normalizer.h>
|
||||||
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
|
||||||
class IJsonDeckParser
|
class IJsonDeckParser
|
||||||
{
|
{
|
||||||
|
|
@ -49,7 +50,7 @@ public:
|
||||||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
deckList.loadFromStream_Plain(outStream, false);
|
deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer());
|
||||||
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
return deckList;
|
return deckList;
|
||||||
|
|
@ -96,7 +97,7 @@ public:
|
||||||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
deckList.loadFromStream_Plain(outStream, false);
|
deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer());
|
||||||
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
QJsonObject commandersObj = obj.value("commanders").toObject();
|
QJsonObject commandersObj = obj.value("commanders").toObject();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file spoiler_background_updater.h
|
* @file spoiler_background_updater.h
|
||||||
* @ingroup Client
|
* @ingroup Client
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
|
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
|
||||||
#define COCKATRICE_SPOILER_DOWNLOADER_H
|
#define COCKATRICE_SPOILER_DOWNLOADER_H
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file client_update_checker.h
|
* @file client_update_checker.h
|
||||||
* @ingroup ClientUpdate
|
* @ingroup ClientUpdate
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef CLIENT_UPDATE_CHECKER_H
|
#ifndef CLIENT_UPDATE_CHECKER_H
|
||||||
#define CLIENT_UPDATE_CHECKER_H
|
#define CLIENT_UPDATE_CHECKER_H
|
||||||
|
|
|
||||||
|
|
@ -129,8 +129,9 @@ void StableReleaseChannel::releaseListFinished()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lastRelease)
|
if (!lastRelease) {
|
||||||
lastRelease = new Release;
|
lastRelease = new Release;
|
||||||
|
}
|
||||||
|
|
||||||
lastRelease->setName(resultMap["name"].toString());
|
lastRelease->setName(resultMap["name"].toString());
|
||||||
lastRelease->setDescriptionUrl(resultMap["html_url"].toString());
|
lastRelease->setDescriptionUrl(resultMap["html_url"].toString());
|
||||||
|
|
@ -246,8 +247,9 @@ void BetaReleaseChannel::releaseListFinished()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastRelease == nullptr)
|
if (lastRelease == nullptr) {
|
||||||
lastRelease = new Release;
|
lastRelease = new Release;
|
||||||
|
}
|
||||||
|
|
||||||
lastRelease->setCommitHash(resultMap["target_commitish"].toString());
|
lastRelease->setCommitHash(resultMap["target_commitish"].toString());
|
||||||
lastRelease->setPublishDate(resultMap["published_at"].toDate());
|
lastRelease->setPublishDate(resultMap["published_at"].toDate());
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file release_channel.h
|
* @file release_channel.h
|
||||||
* @ingroup ClientUpdate
|
* @ingroup ClientUpdate
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef RELEASECHANNEL_H
|
#ifndef RELEASECHANNEL_H
|
||||||
#define RELEASECHANNEL_H
|
#define RELEASECHANNEL_H
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@ UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(
|
||||||
void UpdateDownloader::beginDownload(QUrl downloadUrl)
|
void UpdateDownloader::beginDownload(QUrl downloadUrl)
|
||||||
{
|
{
|
||||||
// Save the original URL because we need it for the filename
|
// Save the original URL because we need it for the filename
|
||||||
if (originalUrl.isEmpty())
|
if (originalUrl.isEmpty()) {
|
||||||
originalUrl = downloadUrl;
|
originalUrl = downloadUrl;
|
||||||
|
}
|
||||||
|
|
||||||
response = netMan->get(QNetworkRequest(downloadUrl));
|
response = netMan->get(QNetworkRequest(downloadUrl));
|
||||||
connect(response, &QNetworkReply::finished, this, &UpdateDownloader::fileFinished);
|
connect(response, &QNetworkReply::finished, this, &UpdateDownloader::fileFinished);
|
||||||
|
|
@ -21,8 +22,9 @@ void UpdateDownloader::beginDownload(QUrl downloadUrl)
|
||||||
|
|
||||||
void UpdateDownloader::downloadError(QNetworkReply::NetworkError)
|
void UpdateDownloader::downloadError(QNetworkReply::NetworkError)
|
||||||
{
|
{
|
||||||
if (response == nullptr)
|
if (response == nullptr) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emit error(response->errorString().toUtf8());
|
emit error(response->errorString().toUtf8());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file update_downloader.h
|
* @file update_downloader.h
|
||||||
* @ingroup ClientUpdate
|
* @ingroup ClientUpdate
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
|
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
|
||||||
#define COCKATRICE_UPDATEDOWNLOADER_H
|
#define COCKATRICE_UPDATEDOWNLOADER_H
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include "cache_settings.h"
|
#include "cache_settings.h"
|
||||||
|
|
||||||
|
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
|
||||||
|
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
|
||||||
#include "../network/update/client/release_channel.h"
|
#include "../network/update/client/release_channel.h"
|
||||||
#include "card_counter_settings.h"
|
#include "card_counter_settings.h"
|
||||||
#include "version_string.h"
|
#include "version_string.h"
|
||||||
|
|
@ -24,10 +26,11 @@ SettingsCache &SettingsCache::instance()
|
||||||
|
|
||||||
QString SettingsCache::getDataPath()
|
QString SettingsCache::getDataPath()
|
||||||
{
|
{
|
||||||
if (isPortableBuild)
|
if (isPortableBuild) {
|
||||||
return qApp->applicationDirPath() + "/data";
|
return qApp->applicationDirPath() + "/data";
|
||||||
else
|
} else {
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
|
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SettingsCache::getSettingsPath()
|
QString SettingsCache::getSettingsPath()
|
||||||
|
|
@ -37,10 +40,11 @@ QString SettingsCache::getSettingsPath()
|
||||||
|
|
||||||
QString SettingsCache::getCachePath() const
|
QString SettingsCache::getCachePath() const
|
||||||
{
|
{
|
||||||
if (isPortableBuild)
|
if (isPortableBuild) {
|
||||||
return qApp->applicationDirPath() + "/cache";
|
return qApp->applicationDirPath() + "/cache";
|
||||||
else
|
} else {
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SettingsCache::getNetworkCachePath() const
|
QString SettingsCache::getNetworkCachePath() const
|
||||||
|
|
@ -50,14 +54,17 @@ QString SettingsCache::getNetworkCachePath() const
|
||||||
|
|
||||||
void SettingsCache::translateLegacySettings()
|
void SettingsCache::translateLegacySettings()
|
||||||
{
|
{
|
||||||
if (isPortableBuild)
|
if (isPortableBuild) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Layouts
|
// Layouts
|
||||||
QFile layoutFile(getSettingsPath() + "layouts/deckLayout.ini");
|
QFile layoutFile(getSettingsPath() + "layouts/deckLayout.ini");
|
||||||
if (layoutFile.exists())
|
if (layoutFile.exists()) {
|
||||||
if (layoutFile.copy(getSettingsPath() + "layouts.ini"))
|
if (layoutFile.copy(getSettingsPath() + "layouts.ini")) {
|
||||||
layoutFile.remove();
|
layoutFile.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QStringList usedKeys;
|
QStringList usedKeys;
|
||||||
QSettings legacySetting;
|
QSettings legacySetting;
|
||||||
|
|
@ -116,10 +123,11 @@ void SettingsCache::translateLegacySettings()
|
||||||
gameFilters().setHideIgnoredUserGames(legacySetting.value("hide_ignored_user_games").toBool());
|
gameFilters().setHideIgnoredUserGames(legacySetting.value("hide_ignored_user_games").toBool());
|
||||||
gameFilters().setMinPlayers(legacySetting.value("min_players").toInt());
|
gameFilters().setMinPlayers(legacySetting.value("min_players").toInt());
|
||||||
|
|
||||||
if (legacySetting.value("max_players").toInt() > 1)
|
if (legacySetting.value("max_players").toInt() > 1) {
|
||||||
gameFilters().setMaxPlayers(legacySetting.value("max_players").toInt());
|
gameFilters().setMaxPlayers(legacySetting.value("max_players").toInt());
|
||||||
else
|
} else {
|
||||||
gameFilters().setMaxPlayers(99); // This prevents a bug where no games will show if max was not set before
|
gameFilters().setMaxPlayers(99); // This prevents a bug where no games will show if max was not set before
|
||||||
|
}
|
||||||
|
|
||||||
QStringList allFilters = legacySetting.allKeys();
|
QStringList allFilters = legacySetting.allKeys();
|
||||||
for (int i = 0; i < allFilters.size(); ++i) {
|
for (int i = 0; i < allFilters.size(); ++i) {
|
||||||
|
|
@ -135,8 +143,9 @@ void SettingsCache::translateLegacySettings()
|
||||||
|
|
||||||
QStringList allLegacyKeys = legacySetting.allKeys();
|
QStringList allLegacyKeys = legacySetting.allKeys();
|
||||||
for (int i = 0; i < allLegacyKeys.size(); ++i) {
|
for (int i = 0; i < allLegacyKeys.size(); ++i) {
|
||||||
if (usedKeys.contains(allLegacyKeys.at(i)))
|
if (usedKeys.contains(allLegacyKeys.at(i))) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
settings->setValue(allLegacyKeys.at(i), legacySetting.value(allLegacyKeys.at(i)));
|
settings->setValue(allLegacyKeys.at(i), legacySetting.value(allLegacyKeys.at(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -147,8 +156,9 @@ QString SettingsCache::getSafeConfigPath(QString configEntry, QString defaultPat
|
||||||
// if the config settings is empty or refers to a not-existing folder,
|
// if the config settings is empty or refers to a not-existing folder,
|
||||||
// ensure that the defaut path exists and return it
|
// ensure that the defaut path exists and return it
|
||||||
if (tmp.isEmpty() || !QDir(tmp).exists()) {
|
if (tmp.isEmpty() || !QDir(tmp).exists()) {
|
||||||
if (!QDir().mkpath(defaultPath))
|
if (!QDir().mkpath(defaultPath)) {
|
||||||
qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath;
|
qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath;
|
||||||
|
}
|
||||||
tmp = defaultPath;
|
tmp = defaultPath;
|
||||||
}
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
|
|
@ -159,8 +169,9 @@ QString SettingsCache::getSafeConfigFilePath(QString configEntry, QString defaul
|
||||||
QString tmp = settings->value(configEntry).toString();
|
QString tmp = settings->value(configEntry).toString();
|
||||||
// if the config settings is empty or refers to a not-existing file,
|
// if the config settings is empty or refers to a not-existing file,
|
||||||
// return the default Path
|
// return the default Path
|
||||||
if (!QFile::exists(tmp) || tmp.isEmpty())
|
if (!QFile::exists(tmp) || tmp.isEmpty()) {
|
||||||
tmp = std::move(defaultPath);
|
tmp = std::move(defaultPath);
|
||||||
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,8 +179,9 @@ SettingsCache::SettingsCache()
|
||||||
{
|
{
|
||||||
// first, figure out if we are running in portable mode
|
// first, figure out if we are running in portable mode
|
||||||
isPortableBuild = QFile::exists(qApp->applicationDirPath() + "/portable.dat");
|
isPortableBuild = QFile::exists(qApp->applicationDirPath() + "/portable.dat");
|
||||||
if (isPortableBuild)
|
if (isPortableBuild) {
|
||||||
qCInfo(SettingsCacheLog) << "Portable mode enabled";
|
qCInfo(SettingsCacheLog) << "Portable mode enabled";
|
||||||
|
}
|
||||||
|
|
||||||
// define a dummy context that will be used where needed
|
// define a dummy context that will be used where needed
|
||||||
QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
|
QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
|
||||||
|
|
@ -189,8 +201,9 @@ SettingsCache::SettingsCache()
|
||||||
|
|
||||||
cardCounterSettings = new CardCounterSettings(settingsPath, this);
|
cardCounterSettings = new CardCounterSettings(settingsPath, this);
|
||||||
|
|
||||||
if (!QFile(settingsPath + "global.ini").exists())
|
if (!QFile(settingsPath + "global.ini").exists()) {
|
||||||
translateLegacySettings();
|
translateLegacySettings();
|
||||||
|
}
|
||||||
|
|
||||||
// updates - don't reorder them or their index in the settings won't match
|
// updates - don't reorder them or their index in the settings won't match
|
||||||
// append channels one by one, or msvc will add them in the wrong order.
|
// append channels one by one, or msvc will add them in the wrong order.
|
||||||
|
|
@ -211,6 +224,7 @@ SettingsCache::SettingsCache()
|
||||||
startupCardUpdateCheckAlwaysUpdate = settings->value("personal/startupCardUpdateCheckAlwaysUpdate", false).toBool();
|
startupCardUpdateCheckAlwaysUpdate = settings->value("personal/startupCardUpdateCheckAlwaysUpdate", false).toBool();
|
||||||
cardUpdateCheckInterval = settings->value("personal/cardUpdateCheckInterval", 7).toInt();
|
cardUpdateCheckInterval = settings->value("personal/cardUpdateCheckInterval", 7).toInt();
|
||||||
lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate();
|
lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate();
|
||||||
|
alwaysEnableNewSets = settings->value("personal/alwaysEnableNewSets", false).toBool();
|
||||||
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
|
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
|
||||||
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
|
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
|
||||||
|
|
||||||
|
|
@ -239,6 +253,7 @@ SettingsCache::SettingsCache()
|
||||||
|
|
||||||
homeTabBackgroundSource = settings->value("home/background", "themed").toString();
|
homeTabBackgroundSource = settings->value("home/background", "themed").toString();
|
||||||
homeTabBackgroundShuffleFrequency = settings->value("home/background/shuffleTimer", 0).toInt();
|
homeTabBackgroundShuffleFrequency = settings->value("home/background/shuffleTimer", 0).toInt();
|
||||||
|
homeTabDisplayCardName = settings->value("home/background/displayCardName", true).toBool();
|
||||||
|
|
||||||
tabVisualDeckStorageOpen = settings->value("tabs/visualDeckStorage", true).toBool();
|
tabVisualDeckStorageOpen = settings->value("tabs/visualDeckStorage", true).toBool();
|
||||||
tabServerOpen = settings->value("tabs/server", true).toBool();
|
tabServerOpen = settings->value("tabs/server", true).toBool();
|
||||||
|
|
@ -255,21 +270,30 @@ SettingsCache::SettingsCache()
|
||||||
settings->setValue("personal/pixmapCacheSize", pixmapCacheSize);
|
settings->setValue("personal/pixmapCacheSize", pixmapCacheSize);
|
||||||
settings->setValue("personal/picturedownloadhq", false);
|
settings->setValue("personal/picturedownloadhq", false);
|
||||||
settings->setValue("revert/pixmapCacheSize", true);
|
settings->setValue("revert/pixmapCacheSize", true);
|
||||||
} else
|
} else {
|
||||||
pixmapCacheSize = settings->value("personal/pixmapCacheSize", PIXMAPCACHE_SIZE_DEFAULT).toInt();
|
pixmapCacheSize = settings->value("personal/pixmapCacheSize", PIXMAPCACHE_SIZE_DEFAULT).toInt();
|
||||||
|
}
|
||||||
// sanity check
|
// sanity check
|
||||||
if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX)
|
if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX) {
|
||||||
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
|
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
|
networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
|
||||||
redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt();
|
redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt();
|
||||||
|
cardPictureLoaderCacheMethod =
|
||||||
|
settings
|
||||||
|
->value("personal/cardPictureLoaderCacheMethod",
|
||||||
|
static_cast<int>(CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE))
|
||||||
|
.toInt();
|
||||||
|
localCardImageStorageNamingScheme =
|
||||||
|
settings
|
||||||
|
->value("personal/localCardImageStorageNamingScheme",
|
||||||
|
static_cast<int>(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_Set_Collector))
|
||||||
|
.toInt();
|
||||||
|
|
||||||
picDownload = settings->value("personal/picturedownload", true).toBool();
|
picDownload = settings->value("personal/picturedownload", true).toBool();
|
||||||
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
|
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
|
||||||
|
|
||||||
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
|
||||||
tokenDialogGeometry = settings->value("interface/token_dialog_geometry").toByteArray();
|
|
||||||
setsDialogGeometry = settings->value("interface/sets_dialog_geometry").toByteArray();
|
|
||||||
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
||||||
spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool();
|
spectatorNotificationsEnabled = settings->value("interface/specnotificationsenabled", false).toBool();
|
||||||
buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool();
|
buddyConnectNotificationsEnabled = settings->value("interface/buddyconnectnotificationsenabled", true).toBool();
|
||||||
|
|
@ -279,7 +303,6 @@ SettingsCache::SettingsCache()
|
||||||
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
|
doNotDeleteArrowsInSubPhases = settings->value("interface/doNotDeleteArrowsInSubPhases", true).toBool();
|
||||||
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
|
startingHandSize = settings->value("interface/startinghandsize", 7).toInt();
|
||||||
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
|
annotateTokens = settings->value("interface/annotatetokens", false).toBool();
|
||||||
tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray();
|
|
||||||
knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
|
knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
|
||||||
useTearOffMenus = settings->value("interface/usetearoffmenus", true).toBool();
|
useTearOffMenus = settings->value("interface/usetearoffmenus", true).toBool();
|
||||||
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
|
cardViewInitialRowsMax = settings->value("interface/cardViewInitialRowsMax", 14).toInt();
|
||||||
|
|
@ -287,6 +310,9 @@ SettingsCache::SettingsCache()
|
||||||
closeEmptyCardView = settings->value("interface/closeEmptyCardView", true).toBool();
|
closeEmptyCardView = settings->value("interface/closeEmptyCardView", true).toBool();
|
||||||
focusCardViewSearchBar = settings->value("interface/focusCardViewSearchBar", true).toBool();
|
focusCardViewSearchBar = settings->value("interface/focusCardViewSearchBar", true).toBool();
|
||||||
|
|
||||||
|
showDragSelectionCount = settings->value("interface/showlassoselectioncount", true).toBool();
|
||||||
|
showTotalSelectionCount = settings->value("interface/showpersistentselectioncount", true).toBool();
|
||||||
|
|
||||||
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
|
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
|
||||||
showGameSelectorFilterToolbar = settings->value("menu/showgameselectorfiltertoolbar", true).toBool();
|
showGameSelectorFilterToolbar = settings->value("menu/showgameselectorfiltertoolbar", true).toBool();
|
||||||
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
|
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
|
||||||
|
|
@ -309,6 +335,7 @@ SettingsCache::SettingsCache()
|
||||||
visualDeckStorageDefaultTagsList =
|
visualDeckStorageDefaultTagsList =
|
||||||
settings->value("interface/visualdeckstoragedefaulttagslist", defaultTags).toStringList();
|
settings->value("interface/visualdeckstoragedefaulttagslist", defaultTags).toStringList();
|
||||||
visualDeckStorageSearchFolderNames = settings->value("interface/visualdeckstoragesearchfoldernames", true).toBool();
|
visualDeckStorageSearchFolderNames = settings->value("interface/visualdeckstoragesearchfoldernames", true).toBool();
|
||||||
|
visualDeckStorageShowColorIdentity = settings->value("interface/visualdeckstorageshowcoloridentity", true).toBool();
|
||||||
visualDeckStorageShowBannerCardComboBox =
|
visualDeckStorageShowBannerCardComboBox =
|
||||||
settings->value("interface/visualdeckstorageshowbannercardcombobox", true).toBool();
|
settings->value("interface/visualdeckstorageshowbannercardcombobox", true).toBool();
|
||||||
visualDeckStorageShowTagsOnDeckPreviews =
|
visualDeckStorageShowTagsOnDeckPreviews =
|
||||||
|
|
@ -361,6 +388,7 @@ SettingsCache::SettingsCache()
|
||||||
|
|
||||||
ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool();
|
ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool();
|
||||||
ignoreUnregisteredUserMessages = settings->value("chat/ignore_unregistered_messages", false).toBool();
|
ignoreUnregisteredUserMessages = settings->value("chat/ignore_unregistered_messages", false).toBool();
|
||||||
|
ignoreNonBuddyUserMessages = settings->value("chat/ignore_nonbuddy_messages", false).toBool();
|
||||||
|
|
||||||
scaleCards = settings->value("cards/scaleCards", true).toBool();
|
scaleCards = settings->value("cards/scaleCards", true).toBool();
|
||||||
verticalCardOverlapPercent = settings->value("cards/verticalCardOverlapPercent", 33).toInt();
|
verticalCardOverlapPercent = settings->value("cards/verticalCardOverlapPercent", 33).toInt();
|
||||||
|
|
@ -387,6 +415,13 @@ SettingsCache::SettingsCache()
|
||||||
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
|
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
|
||||||
shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
|
shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
|
||||||
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
||||||
|
|
||||||
|
// Local game settings use "localgameoptions/" prefix to keep them separate
|
||||||
|
// from server game settings which use "game/" prefix
|
||||||
|
localGameRememberSettings = settings->value("localgameoptions/remembersettings", false).toBool();
|
||||||
|
localGameMaxPlayers = settings->value("localgameoptions/maxplayers", 1).toInt();
|
||||||
|
localGameStartingLifeTotal = settings->value("localgameoptions/startinglifetotal", 20).toInt();
|
||||||
|
|
||||||
clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
|
clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
|
||||||
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
|
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
|
||||||
}
|
}
|
||||||
|
|
@ -594,6 +629,13 @@ void SettingsCache::setHomeTabBackgroundShuffleFrequency(int _frequency)
|
||||||
emit homeTabBackgroundShuffleFrequencyChanged();
|
emit homeTabBackgroundShuffleFrequencyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setHomeTabDisplayCardName(QT_STATE_CHANGED_T _displayCardName)
|
||||||
|
{
|
||||||
|
homeTabDisplayCardName = static_cast<bool>(_displayCardName);
|
||||||
|
settings->setValue("home/background/displayCardName", homeTabDisplayCardName);
|
||||||
|
emit homeTabDisplayCardNameChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setTabVisualDeckStorageOpen(bool value)
|
void SettingsCache::setTabVisualDeckStorageOpen(bool value)
|
||||||
{
|
{
|
||||||
tabVisualDeckStorageOpen = value;
|
tabVisualDeckStorageOpen = value;
|
||||||
|
|
@ -704,12 +746,6 @@ void SettingsCache::setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens)
|
||||||
settings->setValue("interface/annotatetokens", annotateTokens);
|
settings->setValue("interface/annotatetokens", annotateTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes)
|
|
||||||
{
|
|
||||||
tabGameSplitterSizes = _tabGameSplitterSizes;
|
|
||||||
settings->setValue("interface/tabgame_splittersizes", tabGameSplitterSizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
|
void SettingsCache::setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts)
|
||||||
{
|
{
|
||||||
showShortcuts = static_cast<bool>(_showShortcuts);
|
showShortcuts = static_cast<bool>(_showShortcuts);
|
||||||
|
|
@ -760,8 +796,9 @@ void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
|
||||||
|
|
||||||
void SettingsCache::setIncludeRebalancedCards(bool _includeRebalancedCards)
|
void SettingsCache::setIncludeRebalancedCards(bool _includeRebalancedCards)
|
||||||
{
|
{
|
||||||
if (includeRebalancedCards == _includeRebalancedCards)
|
if (includeRebalancedCards == _includeRebalancedCards) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
includeRebalancedCards = _includeRebalancedCards;
|
includeRebalancedCards = _includeRebalancedCards;
|
||||||
settings->setValue("cards/includerebalancedcards", includeRebalancedCards);
|
settings->setValue("cards/includerebalancedcards", includeRebalancedCards);
|
||||||
|
|
@ -821,6 +858,13 @@ void SettingsCache::setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T val
|
||||||
settings->setValue("interface/visualdeckstoragesearchfoldernames", visualDeckStorageSearchFolderNames);
|
settings->setValue("interface/visualdeckstoragesearchfoldernames", visualDeckStorageSearchFolderNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setVisualDeckStorageShowColorIdentity(QT_STATE_CHANGED_T value)
|
||||||
|
{
|
||||||
|
visualDeckStorageShowColorIdentity = value;
|
||||||
|
settings->setValue("interface/visualdeckstorageshowcoloridentity", visualDeckStorageShowColorIdentity);
|
||||||
|
emit visualDeckStorageShowColorIdentityChanged(visualDeckStorageShowColorIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox)
|
void SettingsCache::setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox)
|
||||||
{
|
{
|
||||||
visualDeckStorageShowBannerCardComboBox = _showBannerCardComboBox;
|
visualDeckStorageShowBannerCardComboBox = _showBannerCardComboBox;
|
||||||
|
|
@ -1074,22 +1118,10 @@ void SettingsCache::setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignore
|
||||||
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setMainWindowGeometry(const QByteArray &_mainWindowGeometry)
|
void SettingsCache::setIgnoreNonBuddyUserMessages(QT_STATE_CHANGED_T _ignoreNonBuddyUserMessages)
|
||||||
{
|
{
|
||||||
mainWindowGeometry = _mainWindowGeometry;
|
ignoreNonBuddyUserMessages = static_cast<bool>(_ignoreNonBuddyUserMessages);
|
||||||
settings->setValue("interface/main_window_geometry", mainWindowGeometry);
|
settings->setValue("chat/ignore_nonbuddy_messages", ignoreNonBuddyUserMessages);
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setTokenDialogGeometry(const QByteArray &_tokenDialogGeometry)
|
|
||||||
{
|
|
||||||
tokenDialogGeometry = _tokenDialogGeometry;
|
|
||||||
settings->setValue("interface/token_dialog_geometry", tokenDialogGeometry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingsCache::setSetsDialogGeometry(const QByteArray &_setsDialogGeometry)
|
|
||||||
{
|
|
||||||
setsDialogGeometry = _setsDialogGeometry;
|
|
||||||
settings->setValue("interface/sets_dialog_geometry", setsDialogGeometry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
||||||
|
|
@ -1099,6 +1131,13 @@ void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
||||||
emit pixmapCacheSizeChanged(pixmapCacheSize);
|
emit pixmapCacheSizeChanged(pixmapCacheSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setCardImageCacheMethod(const CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod)
|
||||||
|
{
|
||||||
|
cardPictureLoaderCacheMethod = static_cast<int>(_cardImageCachingMethod);
|
||||||
|
settings->setValue("personal/cardPictureLoaderCacheMethod", cardPictureLoaderCacheMethod);
|
||||||
|
emit cardPictureLoaderCacheMethodChanged(cardPictureLoaderCacheMethod);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
|
void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
|
||||||
{
|
{
|
||||||
networkCacheSize = _networkCacheSize;
|
networkCacheSize = _networkCacheSize;
|
||||||
|
|
@ -1113,6 +1152,14 @@ void SettingsCache::setNetworkRedirectCacheTtl(const int _redirectCacheTtl)
|
||||||
emit redirectCacheTtlChanged(redirectCacheTtl);
|
emit redirectCacheTtlChanged(redirectCacheTtl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setLocalCardImageStorageNamingScheme(
|
||||||
|
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme)
|
||||||
|
{
|
||||||
|
localCardImageStorageNamingScheme = static_cast<int>(_localCardImageStorageNamingScheme);
|
||||||
|
settings->setValue("personal/localCardImageStorageNamingScheme", localCardImageStorageNamingScheme);
|
||||||
|
emit localCardImageStorageNamingSchemeChanged(localCardImageStorageNamingScheme);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setClientID(const QString &_clientID)
|
void SettingsCache::setClientID(const QString &_clientID)
|
||||||
{
|
{
|
||||||
clientID = _clientID;
|
clientID = _clientID;
|
||||||
|
|
@ -1127,257 +1174,21 @@ void SettingsCache::setClientVersion(const QString &_clientVersion)
|
||||||
|
|
||||||
QStringList SettingsCache::getCountries() const
|
QStringList SettingsCache::getCountries() const
|
||||||
{
|
{
|
||||||
static QStringList countries = QStringList() << "ad"
|
static const QStringList countries = {
|
||||||
<< "ae"
|
"ad", "ae", "af", "ag", "ai", "al", "am", "ao", "aq", "ar", "as", "at", "au", "aw", "ax", "az", "ba", "bb",
|
||||||
<< "af"
|
"bd", "be", "bf", "bg", "bh", "bi", "bj", "bl", "bm", "bn", "bo", "bq", "br", "bs", "bt", "bv", "bw", "by",
|
||||||
<< "ag"
|
"bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cw", "cx",
|
||||||
<< "ai"
|
"cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er", "es", "et", "eu", "fi", "fj",
|
||||||
<< "al"
|
"fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr",
|
||||||
<< "am"
|
"gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq",
|
||||||
<< "ao"
|
"ir", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz",
|
||||||
<< "aq"
|
"la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mf", "mg", "mh",
|
||||||
<< "ar"
|
"mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc",
|
||||||
<< "as"
|
"ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl",
|
||||||
<< "at"
|
"pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se",
|
||||||
<< "au"
|
"sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st", "sv", "sx", "sy", "sz", "tc", "td",
|
||||||
<< "aw"
|
"tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "um", "us",
|
||||||
<< "ax"
|
"uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "xk", "ye", "yt", "za", "zm", "zw"};
|
||||||
<< "az"
|
|
||||||
<< "ba"
|
|
||||||
<< "bb"
|
|
||||||
<< "bd"
|
|
||||||
<< "be"
|
|
||||||
<< "bf"
|
|
||||||
<< "bg"
|
|
||||||
<< "bh"
|
|
||||||
<< "bi"
|
|
||||||
<< "bj"
|
|
||||||
<< "bl"
|
|
||||||
<< "bm"
|
|
||||||
<< "bn"
|
|
||||||
<< "bo"
|
|
||||||
<< "bq"
|
|
||||||
<< "br"
|
|
||||||
<< "bs"
|
|
||||||
<< "bt"
|
|
||||||
<< "bv"
|
|
||||||
<< "bw"
|
|
||||||
<< "by"
|
|
||||||
<< "bz"
|
|
||||||
<< "ca"
|
|
||||||
<< "cc"
|
|
||||||
<< "cd"
|
|
||||||
<< "cf"
|
|
||||||
<< "cg"
|
|
||||||
<< "ch"
|
|
||||||
<< "ci"
|
|
||||||
<< "ck"
|
|
||||||
<< "cl"
|
|
||||||
<< "cm"
|
|
||||||
<< "cn"
|
|
||||||
<< "co"
|
|
||||||
<< "cr"
|
|
||||||
<< "cu"
|
|
||||||
<< "cv"
|
|
||||||
<< "cw"
|
|
||||||
<< "cx"
|
|
||||||
<< "cy"
|
|
||||||
<< "cz"
|
|
||||||
<< "de"
|
|
||||||
<< "dj"
|
|
||||||
<< "dk"
|
|
||||||
<< "dm"
|
|
||||||
<< "do"
|
|
||||||
<< "dz"
|
|
||||||
<< "ec"
|
|
||||||
<< "ee"
|
|
||||||
<< "eg"
|
|
||||||
<< "eh"
|
|
||||||
<< "er"
|
|
||||||
<< "es"
|
|
||||||
<< "et"
|
|
||||||
<< "eu"
|
|
||||||
<< "fi"
|
|
||||||
<< "fj"
|
|
||||||
<< "fk"
|
|
||||||
<< "fm"
|
|
||||||
<< "fo"
|
|
||||||
<< "fr"
|
|
||||||
<< "ga"
|
|
||||||
<< "gb"
|
|
||||||
<< "gd"
|
|
||||||
<< "ge"
|
|
||||||
<< "gf"
|
|
||||||
<< "gg"
|
|
||||||
<< "gh"
|
|
||||||
<< "gi"
|
|
||||||
<< "gl"
|
|
||||||
<< "gm"
|
|
||||||
<< "gn"
|
|
||||||
<< "gp"
|
|
||||||
<< "gq"
|
|
||||||
<< "gr"
|
|
||||||
<< "gs"
|
|
||||||
<< "gt"
|
|
||||||
<< "gu"
|
|
||||||
<< "gw"
|
|
||||||
<< "gy"
|
|
||||||
<< "hk"
|
|
||||||
<< "hm"
|
|
||||||
<< "hn"
|
|
||||||
<< "hr"
|
|
||||||
<< "ht"
|
|
||||||
<< "hu"
|
|
||||||
<< "id"
|
|
||||||
<< "ie"
|
|
||||||
<< "il"
|
|
||||||
<< "im"
|
|
||||||
<< "in"
|
|
||||||
<< "io"
|
|
||||||
<< "iq"
|
|
||||||
<< "ir"
|
|
||||||
<< "is"
|
|
||||||
<< "it"
|
|
||||||
<< "je"
|
|
||||||
<< "jm"
|
|
||||||
<< "jo"
|
|
||||||
<< "jp"
|
|
||||||
<< "ke"
|
|
||||||
<< "kg"
|
|
||||||
<< "kh"
|
|
||||||
<< "ki"
|
|
||||||
<< "km"
|
|
||||||
<< "kn"
|
|
||||||
<< "kp"
|
|
||||||
<< "kr"
|
|
||||||
<< "kw"
|
|
||||||
<< "ky"
|
|
||||||
<< "kz"
|
|
||||||
<< "la"
|
|
||||||
<< "lb"
|
|
||||||
<< "lc"
|
|
||||||
<< "li"
|
|
||||||
<< "lk"
|
|
||||||
<< "lr"
|
|
||||||
<< "ls"
|
|
||||||
<< "lt"
|
|
||||||
<< "lu"
|
|
||||||
<< "lv"
|
|
||||||
<< "ly"
|
|
||||||
<< "ma"
|
|
||||||
<< "mc"
|
|
||||||
<< "md"
|
|
||||||
<< "me"
|
|
||||||
<< "mf"
|
|
||||||
<< "mg"
|
|
||||||
<< "mh"
|
|
||||||
<< "mk"
|
|
||||||
<< "ml"
|
|
||||||
<< "mm"
|
|
||||||
<< "mn"
|
|
||||||
<< "mo"
|
|
||||||
<< "mp"
|
|
||||||
<< "mq"
|
|
||||||
<< "mr"
|
|
||||||
<< "ms"
|
|
||||||
<< "mt"
|
|
||||||
<< "mu"
|
|
||||||
<< "mv"
|
|
||||||
<< "mw"
|
|
||||||
<< "mx"
|
|
||||||
<< "my"
|
|
||||||
<< "mz"
|
|
||||||
<< "na"
|
|
||||||
<< "nc"
|
|
||||||
<< "ne"
|
|
||||||
<< "nf"
|
|
||||||
<< "ng"
|
|
||||||
<< "ni"
|
|
||||||
<< "nl"
|
|
||||||
<< "no"
|
|
||||||
<< "np"
|
|
||||||
<< "nr"
|
|
||||||
<< "nu"
|
|
||||||
<< "nz"
|
|
||||||
<< "om"
|
|
||||||
<< "pa"
|
|
||||||
<< "pe"
|
|
||||||
<< "pf"
|
|
||||||
<< "pg"
|
|
||||||
<< "ph"
|
|
||||||
<< "pk"
|
|
||||||
<< "pl"
|
|
||||||
<< "pm"
|
|
||||||
<< "pn"
|
|
||||||
<< "pr"
|
|
||||||
<< "ps"
|
|
||||||
<< "pt"
|
|
||||||
<< "pw"
|
|
||||||
<< "py"
|
|
||||||
<< "qa"
|
|
||||||
<< "re"
|
|
||||||
<< "ro"
|
|
||||||
<< "rs"
|
|
||||||
<< "ru"
|
|
||||||
<< "rw"
|
|
||||||
<< "sa"
|
|
||||||
<< "sb"
|
|
||||||
<< "sc"
|
|
||||||
<< "sd"
|
|
||||||
<< "se"
|
|
||||||
<< "sg"
|
|
||||||
<< "sh"
|
|
||||||
<< "si"
|
|
||||||
<< "sj"
|
|
||||||
<< "sk"
|
|
||||||
<< "sl"
|
|
||||||
<< "sm"
|
|
||||||
<< "sn"
|
|
||||||
<< "so"
|
|
||||||
<< "sr"
|
|
||||||
<< "ss"
|
|
||||||
<< "st"
|
|
||||||
<< "sv"
|
|
||||||
<< "sx"
|
|
||||||
<< "sy"
|
|
||||||
<< "sz"
|
|
||||||
<< "tc"
|
|
||||||
<< "td"
|
|
||||||
<< "tf"
|
|
||||||
<< "tg"
|
|
||||||
<< "th"
|
|
||||||
<< "tj"
|
|
||||||
<< "tk"
|
|
||||||
<< "tl"
|
|
||||||
<< "tm"
|
|
||||||
<< "tn"
|
|
||||||
<< "to"
|
|
||||||
<< "tr"
|
|
||||||
<< "tt"
|
|
||||||
<< "tv"
|
|
||||||
<< "tw"
|
|
||||||
<< "tz"
|
|
||||||
<< "ua"
|
|
||||||
<< "ug"
|
|
||||||
<< "um"
|
|
||||||
<< "us"
|
|
||||||
<< "uy"
|
|
||||||
<< "uz"
|
|
||||||
<< "va"
|
|
||||||
<< "vc"
|
|
||||||
<< "ve"
|
|
||||||
<< "vg"
|
|
||||||
<< "vi"
|
|
||||||
<< "vn"
|
|
||||||
<< "vu"
|
|
||||||
<< "wf"
|
|
||||||
<< "ws"
|
|
||||||
<< "xk"
|
|
||||||
<< "ye"
|
|
||||||
<< "yt"
|
|
||||||
<< "za"
|
|
||||||
<< "zm"
|
|
||||||
<< "zw";
|
|
||||||
|
|
||||||
return countries;
|
return countries;
|
||||||
}
|
}
|
||||||
|
|
@ -1484,12 +1295,36 @@ void SettingsCache::setLastCardUpdateCheck(QDate value)
|
||||||
settings->setValue("personal/lastCardUpdateCheck", lastCardUpdateCheck);
|
settings->setValue("personal/lastCardUpdateCheck", lastCardUpdateCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setAlwaysEnableNewSets(bool value)
|
||||||
|
{
|
||||||
|
alwaysEnableNewSets = value;
|
||||||
|
settings->setValue("personal/alwaysEnableNewSets", alwaysEnableNewSets);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
|
void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
|
||||||
{
|
{
|
||||||
rememberGameSettings = _rememberGameSettings;
|
rememberGameSettings = _rememberGameSettings;
|
||||||
settings->setValue("game/remembergamesettings", rememberGameSettings);
|
settings->setValue("game/remembergamesettings", rememberGameSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setLocalGameRememberSettings(bool value)
|
||||||
|
{
|
||||||
|
localGameRememberSettings = value;
|
||||||
|
settings->setValue("localgameoptions/remembersettings", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setLocalGameMaxPlayers(int value)
|
||||||
|
{
|
||||||
|
localGameMaxPlayers = value;
|
||||||
|
settings->setValue("localgameoptions/maxplayers", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setLocalGameStartingLifeTotal(int value)
|
||||||
|
{
|
||||||
|
localGameStartingLifeTotal = value;
|
||||||
|
settings->setValue("localgameoptions/startinglifetotal", value);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate)
|
void SettingsCache::setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate)
|
||||||
{
|
{
|
||||||
notifyAboutUpdates = static_cast<bool>(_notifyaboutupdate);
|
notifyAboutUpdates = static_cast<bool>(_notifyaboutupdate);
|
||||||
|
|
@ -1523,14 +1358,27 @@ void SettingsCache::setMaxFontSize(int _max)
|
||||||
|
|
||||||
void SettingsCache::setRoundCardCorners(bool _roundCardCorners)
|
void SettingsCache::setRoundCardCorners(bool _roundCardCorners)
|
||||||
{
|
{
|
||||||
if (_roundCardCorners == roundCardCorners)
|
if (_roundCardCorners == roundCardCorners) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
roundCardCorners = _roundCardCorners;
|
roundCardCorners = _roundCardCorners;
|
||||||
settings->setValue("cards/roundcardcorners", _roundCardCorners);
|
settings->setValue("cards/roundcardcorners", _roundCardCorners);
|
||||||
emit roundCardCornersChanged(roundCardCorners);
|
emit roundCardCornersChanged(roundCardCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setShowDragSelectionCount(QT_STATE_CHANGED_T _showDragSelectionCount)
|
||||||
|
{
|
||||||
|
showDragSelectionCount = static_cast<bool>(_showDragSelectionCount);
|
||||||
|
settings->setValue("interface/showlassoselectioncount", showDragSelectionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setShowTotalSelectionCount(QT_STATE_CHANGED_T _showTotalSelectionCount)
|
||||||
|
{
|
||||||
|
showTotalSelectionCount = static_cast<bool>(_showTotalSelectionCount);
|
||||||
|
settings->setValue("interface/showpersistentselectioncount", showTotalSelectionCount);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::loadPaths()
|
void SettingsCache::loadPaths()
|
||||||
{
|
{
|
||||||
QString dataPath = getDataPath();
|
QString dataPath = getDataPath();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* @file cache_settings.h
|
* @file cache_settings.h
|
||||||
* @ingroup Settings
|
* @ingroup Settings
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef SETTINGSCACHE_H
|
#ifndef SETTINGSCACHE_H
|
||||||
#define SETTINGSCACHE_H
|
#define SETTINGSCACHE_H
|
||||||
|
|
||||||
|
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
|
||||||
|
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
|
||||||
#include "shortcuts_settings.h"
|
#include "shortcuts_settings.h"
|
||||||
|
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
|
|
@ -143,6 +145,7 @@ signals:
|
||||||
void themeChanged();
|
void themeChanged();
|
||||||
void homeTabBackgroundSourceChanged();
|
void homeTabBackgroundSourceChanged();
|
||||||
void homeTabBackgroundShuffleFrequencyChanged();
|
void homeTabBackgroundShuffleFrequencyChanged();
|
||||||
|
void homeTabDisplayCardNameChanged();
|
||||||
void picDownloadChanged();
|
void picDownloadChanged();
|
||||||
void showStatusBarChanged(bool state);
|
void showStatusBarChanged(bool state);
|
||||||
void showGameSelectorFilterToolbarChanged(bool state);
|
void showGameSelectorFilterToolbarChanged(bool state);
|
||||||
|
|
@ -157,6 +160,7 @@ signals:
|
||||||
void deckEditorTagsWidgetVisibleChanged(bool _visible);
|
void deckEditorTagsWidgetVisibleChanged(bool _visible);
|
||||||
void visualDeckStorageShowTagFilterChanged(bool _visible);
|
void visualDeckStorageShowTagFilterChanged(bool _visible);
|
||||||
void visualDeckStorageDefaultTagsListChanged();
|
void visualDeckStorageDefaultTagsListChanged();
|
||||||
|
void visualDeckStorageShowColorIdentityChanged(bool _visible);
|
||||||
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
|
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
|
||||||
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
|
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
|
||||||
void visualDeckStorageCardSizeChanged();
|
void visualDeckStorageCardSizeChanged();
|
||||||
|
|
@ -179,9 +183,12 @@ signals:
|
||||||
void soundThemeChanged();
|
void soundThemeChanged();
|
||||||
void ignoreUnregisteredUsersChanged();
|
void ignoreUnregisteredUsersChanged();
|
||||||
void ignoreUnregisteredUserMessagesChanged();
|
void ignoreUnregisteredUserMessagesChanged();
|
||||||
|
void ignoreNonBuddyUserMessagesChanged();
|
||||||
void pixmapCacheSizeChanged(int newSizeInMBs);
|
void pixmapCacheSizeChanged(int newSizeInMBs);
|
||||||
void networkCacheSizeChanged(int newSizeInMBs);
|
void networkCacheSizeChanged(int newSizeInMBs);
|
||||||
void redirectCacheTtlChanged(int newTtl);
|
void redirectCacheTtlChanged(int newTtl);
|
||||||
|
void cardPictureLoaderCacheMethodChanged(int cardPictureLoaderCacheMethod);
|
||||||
|
void localCardImageStorageNamingSchemeChanged(int localCardImageStorageNamingScheme);
|
||||||
void masterVolumeChanged(int value);
|
void masterVolumeChanged(int value);
|
||||||
void chatMentionCompleterChanged();
|
void chatMentionCompleterChanged();
|
||||||
void downloadSpoilerTimeIndexChanged();
|
void downloadSpoilerTimeIndexChanged();
|
||||||
|
|
@ -203,9 +210,6 @@ private:
|
||||||
DebugSettings *debugSettings;
|
DebugSettings *debugSettings;
|
||||||
CardCounterSettings *cardCounterSettings;
|
CardCounterSettings *cardCounterSettings;
|
||||||
|
|
||||||
QByteArray mainWindowGeometry;
|
|
||||||
QByteArray tokenDialogGeometry;
|
|
||||||
QByteArray setsDialogGeometry;
|
|
||||||
QString lang;
|
QString lang;
|
||||||
QString deckPath, filtersPath, replaysPath, picsPath, redirectCachePath, customPicsPath, cardDatabasePath,
|
QString deckPath, filtersPath, replaysPath, picsPath, redirectCachePath, customPicsPath, cardDatabasePath,
|
||||||
customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
|
customCardDatabasePath, themesPath, spoilerDatabasePath, tokenDatabasePath, themeName, homeTabBackgroundSource;
|
||||||
|
|
@ -217,11 +221,13 @@ private:
|
||||||
bool checkCardUpdatesOnStartup;
|
bool checkCardUpdatesOnStartup;
|
||||||
int cardUpdateCheckInterval;
|
int cardUpdateCheckInterval;
|
||||||
QDate lastCardUpdateCheck;
|
QDate lastCardUpdateCheck;
|
||||||
|
bool alwaysEnableNewSets;
|
||||||
bool notifyAboutUpdates;
|
bool notifyAboutUpdates;
|
||||||
bool notifyAboutNewVersion;
|
bool notifyAboutNewVersion;
|
||||||
bool showTipsOnStartup;
|
bool showTipsOnStartup;
|
||||||
QList<int> seenTips;
|
QList<int> seenTips;
|
||||||
int homeTabBackgroundShuffleFrequency;
|
int homeTabBackgroundShuffleFrequency;
|
||||||
|
bool homeTabDisplayCardName;
|
||||||
bool mbDownloadSpoilers;
|
bool mbDownloadSpoilers;
|
||||||
int updateReleaseChannel;
|
int updateReleaseChannel;
|
||||||
int maxFontSize;
|
int maxFontSize;
|
||||||
|
|
@ -235,7 +241,6 @@ private:
|
||||||
bool doNotDeleteArrowsInSubPhases;
|
bool doNotDeleteArrowsInSubPhases;
|
||||||
int startingHandSize;
|
int startingHandSize;
|
||||||
bool annotateTokens;
|
bool annotateTokens;
|
||||||
QByteArray tabGameSplitterSizes;
|
|
||||||
bool showShortcuts;
|
bool showShortcuts;
|
||||||
bool showGameSelectorFilterToolbar;
|
bool showGameSelectorFilterToolbar;
|
||||||
bool displayCardNames;
|
bool displayCardNames;
|
||||||
|
|
@ -249,6 +254,7 @@ private:
|
||||||
bool deckEditorTagsWidgetVisible;
|
bool deckEditorTagsWidgetVisible;
|
||||||
int visualDeckStorageSortingOrder;
|
int visualDeckStorageSortingOrder;
|
||||||
bool visualDeckStorageShowFolders;
|
bool visualDeckStorageShowFolders;
|
||||||
|
bool visualDeckStorageShowColorIdentity;
|
||||||
bool visualDeckStorageShowBannerCardComboBox;
|
bool visualDeckStorageShowBannerCardComboBox;
|
||||||
bool visualDeckStorageShowTagsOnDeckPreviews;
|
bool visualDeckStorageShowTagsOnDeckPreviews;
|
||||||
bool visualDeckStorageShowTagFilter;
|
bool visualDeckStorageShowTagFilter;
|
||||||
|
|
@ -289,6 +295,7 @@ private:
|
||||||
QString soundThemeName;
|
QString soundThemeName;
|
||||||
bool ignoreUnregisteredUsers;
|
bool ignoreUnregisteredUsers;
|
||||||
bool ignoreUnregisteredUserMessages;
|
bool ignoreUnregisteredUserMessages;
|
||||||
|
bool ignoreNonBuddyUserMessages;
|
||||||
QString picUrl;
|
QString picUrl;
|
||||||
QString picUrlFallback;
|
QString picUrlFallback;
|
||||||
QString clientID;
|
QString clientID;
|
||||||
|
|
@ -302,6 +309,8 @@ private:
|
||||||
int pixmapCacheSize;
|
int pixmapCacheSize;
|
||||||
int networkCacheSize;
|
int networkCacheSize;
|
||||||
int redirectCacheTtl;
|
int redirectCacheTtl;
|
||||||
|
int cardPictureLoaderCacheMethod;
|
||||||
|
int localCardImageStorageNamingScheme;
|
||||||
bool scaleCards;
|
bool scaleCards;
|
||||||
int verticalCardOverlapPercent;
|
int verticalCardOverlapPercent;
|
||||||
bool showMessagePopups;
|
bool showMessagePopups;
|
||||||
|
|
@ -330,10 +339,18 @@ private:
|
||||||
[[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
[[nodiscard]] QString getSafeConfigFilePath(QString configEntry, QString defaultPath) const;
|
||||||
void loadPaths();
|
void loadPaths();
|
||||||
bool rememberGameSettings;
|
bool rememberGameSettings;
|
||||||
|
|
||||||
|
// Local game settings (separate from server game settings in game/*)
|
||||||
|
bool localGameRememberSettings;
|
||||||
|
int localGameMaxPlayers;
|
||||||
|
int localGameStartingLifeTotal;
|
||||||
|
|
||||||
QList<ReleaseChannel *> releaseChannels;
|
QList<ReleaseChannel *> releaseChannels;
|
||||||
bool isPortableBuild;
|
bool isPortableBuild;
|
||||||
bool roundCardCorners;
|
bool roundCardCorners;
|
||||||
bool showStatusBar;
|
bool showStatusBar;
|
||||||
|
bool showDragSelectionCount;
|
||||||
|
bool showTotalSelectionCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SettingsCache();
|
SettingsCache();
|
||||||
|
|
@ -341,18 +358,6 @@ public:
|
||||||
QString getSettingsPath();
|
QString getSettingsPath();
|
||||||
[[nodiscard]] QString getCachePath() const;
|
[[nodiscard]] QString getCachePath() const;
|
||||||
[[nodiscard]] QString getNetworkCachePath() const;
|
[[nodiscard]] QString getNetworkCachePath() const;
|
||||||
[[nodiscard]] const QByteArray &getMainWindowGeometry() const
|
|
||||||
{
|
|
||||||
return mainWindowGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] const QByteArray &getTokenDialogGeometry() const
|
|
||||||
{
|
|
||||||
return tokenDialogGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] const QByteArray &getSetsDialogGeometry() const
|
|
||||||
{
|
|
||||||
return setsDialogGeometry;
|
|
||||||
}
|
|
||||||
[[nodiscard]] QString getLang() const
|
[[nodiscard]] QString getLang() const
|
||||||
{
|
{
|
||||||
return lang;
|
return lang;
|
||||||
|
|
@ -413,6 +418,10 @@ public:
|
||||||
{
|
{
|
||||||
return homeTabBackgroundShuffleFrequency;
|
return homeTabBackgroundShuffleFrequency;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getHomeTabDisplayCardName() const
|
||||||
|
{
|
||||||
|
return homeTabDisplayCardName;
|
||||||
|
}
|
||||||
[[nodiscard]] bool getTabVisualDeckStorageOpen() const
|
[[nodiscard]] bool getTabVisualDeckStorageOpen() const
|
||||||
{
|
{
|
||||||
return tabVisualDeckStorageOpen;
|
return tabVisualDeckStorageOpen;
|
||||||
|
|
@ -457,6 +466,14 @@ public:
|
||||||
{
|
{
|
||||||
return showStatusBar;
|
return showStatusBar;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getShowDragSelectionCount() const
|
||||||
|
{
|
||||||
|
return showDragSelectionCount;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool getShowTotalSelectionCount() const
|
||||||
|
{
|
||||||
|
return showTotalSelectionCount;
|
||||||
|
}
|
||||||
[[nodiscard]] bool getNotificationsEnabled() const
|
[[nodiscard]] bool getNotificationsEnabled() const
|
||||||
{
|
{
|
||||||
return notificationsEnabled;
|
return notificationsEnabled;
|
||||||
|
|
@ -494,6 +511,10 @@ public:
|
||||||
return getLastCardUpdateCheck().daysTo(QDateTime::currentDateTime().date()) >= getCardUpdateCheckInterval() &&
|
return getLastCardUpdateCheck().daysTo(QDateTime::currentDateTime().date()) >= getCardUpdateCheckInterval() &&
|
||||||
getLastCardUpdateCheck() != QDateTime::currentDateTime().date();
|
getLastCardUpdateCheck() != QDateTime::currentDateTime().date();
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getAlwaysEnableNewSets() const
|
||||||
|
{
|
||||||
|
return alwaysEnableNewSets;
|
||||||
|
}
|
||||||
[[nodiscard]] bool getNotifyAboutUpdates() const override
|
[[nodiscard]] bool getNotifyAboutUpdates() const override
|
||||||
{
|
{
|
||||||
return notifyAboutUpdates;
|
return notifyAboutUpdates;
|
||||||
|
|
@ -547,10 +568,6 @@ public:
|
||||||
{
|
{
|
||||||
return annotateTokens;
|
return annotateTokens;
|
||||||
}
|
}
|
||||||
[[nodiscard]] QByteArray getTabGameSplitterSizes() const
|
|
||||||
{
|
|
||||||
return tabGameSplitterSizes;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool getShowShortcuts() const
|
[[nodiscard]] bool getShowShortcuts() const
|
||||||
{
|
{
|
||||||
return showShortcuts;
|
return showShortcuts;
|
||||||
|
|
@ -615,6 +632,10 @@ public:
|
||||||
{
|
{
|
||||||
return visualDeckStorageSearchFolderNames;
|
return visualDeckStorageSearchFolderNames;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getVisualDeckStorageShowColorIdentity() const
|
||||||
|
{
|
||||||
|
return visualDeckStorageShowColorIdentity;
|
||||||
|
}
|
||||||
[[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
|
[[nodiscard]] bool getVisualDeckStorageShowBannerCardComboBox() const
|
||||||
{
|
{
|
||||||
return visualDeckStorageShowBannerCardComboBox;
|
return visualDeckStorageShowBannerCardComboBox;
|
||||||
|
|
@ -769,10 +790,18 @@ public:
|
||||||
{
|
{
|
||||||
return ignoreUnregisteredUserMessages;
|
return ignoreUnregisteredUserMessages;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getIgnoreNonBuddyUserMessages() const
|
||||||
|
{
|
||||||
|
return ignoreNonBuddyUserMessages;
|
||||||
|
}
|
||||||
[[nodiscard]] int getPixmapCacheSize() const
|
[[nodiscard]] int getPixmapCacheSize() const
|
||||||
{
|
{
|
||||||
return pixmapCacheSize;
|
return pixmapCacheSize;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] CardPictureLoaderCacheMethod::CacheMethod getCardPictureLoaderCacheMethod() const
|
||||||
|
{
|
||||||
|
return static_cast<CardPictureLoaderCacheMethod::CacheMethod>(cardPictureLoaderCacheMethod);
|
||||||
|
}
|
||||||
[[nodiscard]] int getNetworkCacheSizeInMB() const
|
[[nodiscard]] int getNetworkCacheSizeInMB() const
|
||||||
{
|
{
|
||||||
return networkCacheSize;
|
return networkCacheSize;
|
||||||
|
|
@ -781,6 +810,10 @@ public:
|
||||||
{
|
{
|
||||||
return redirectCacheTtl;
|
return redirectCacheTtl;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] CardPictureLoaderLocalSchemes::NamingScheme getLocalCardImageStorageNamingScheme() const
|
||||||
|
{
|
||||||
|
return static_cast<CardPictureLoaderLocalSchemes::NamingScheme>(localCardImageStorageNamingScheme);
|
||||||
|
}
|
||||||
[[nodiscard]] bool getScaleCards() const
|
[[nodiscard]] bool getScaleCards() const
|
||||||
{
|
{
|
||||||
return scaleCards;
|
return scaleCards;
|
||||||
|
|
@ -870,6 +903,18 @@ public:
|
||||||
{
|
{
|
||||||
return rememberGameSettings;
|
return rememberGameSettings;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool getLocalGameRememberSettings() const
|
||||||
|
{
|
||||||
|
return localGameRememberSettings;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getLocalGameMaxPlayers() const
|
||||||
|
{
|
||||||
|
return localGameMaxPlayers;
|
||||||
|
}
|
||||||
|
[[nodiscard]] int getLocalGameStartingLifeTotal() const
|
||||||
|
{
|
||||||
|
return localGameStartingLifeTotal;
|
||||||
|
}
|
||||||
[[nodiscard]] int getKeepAlive() const override
|
[[nodiscard]] int getKeepAlive() const override
|
||||||
{
|
{
|
||||||
return keepalive;
|
return keepalive;
|
||||||
|
|
@ -983,9 +1028,6 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void setDownloadSpoilerStatus(bool _spoilerStatus);
|
void setDownloadSpoilerStatus(bool _spoilerStatus);
|
||||||
|
|
||||||
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
|
|
||||||
void setTokenDialogGeometry(const QByteArray &_tokenDialog);
|
|
||||||
void setSetsDialogGeometry(const QByteArray &_setsDialog);
|
|
||||||
void setLang(const QString &_lang);
|
void setLang(const QString &_lang);
|
||||||
void setShowTipsOnStartup(bool _showTipsOnStartup);
|
void setShowTipsOnStartup(bool _showTipsOnStartup);
|
||||||
void setSeenTips(const QList<int> &_seenTips);
|
void setSeenTips(const QList<int> &_seenTips);
|
||||||
|
|
@ -1001,6 +1043,7 @@ public slots:
|
||||||
void setThemeName(const QString &_themeName);
|
void setThemeName(const QString &_themeName);
|
||||||
void setHomeTabBackgroundSource(const QString &_backgroundSource);
|
void setHomeTabBackgroundSource(const QString &_backgroundSource);
|
||||||
void setHomeTabBackgroundShuffleFrequency(int _frequency);
|
void setHomeTabBackgroundShuffleFrequency(int _frequency);
|
||||||
|
void setHomeTabDisplayCardName(QT_STATE_CHANGED_T _displayCardName);
|
||||||
void setTabVisualDeckStorageOpen(bool value);
|
void setTabVisualDeckStorageOpen(bool value);
|
||||||
void setTabServerOpen(bool value);
|
void setTabServerOpen(bool value);
|
||||||
void setTabAccountOpen(bool value);
|
void setTabAccountOpen(bool value);
|
||||||
|
|
@ -1021,7 +1064,6 @@ public slots:
|
||||||
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
|
void setDoNotDeleteArrowsInSubPhases(QT_STATE_CHANGED_T _doNotDeleteArrowsInSubPhases);
|
||||||
void setStartingHandSize(int _startingHandSize);
|
void setStartingHandSize(int _startingHandSize);
|
||||||
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
|
void setAnnotateTokens(QT_STATE_CHANGED_T _annotateTokens);
|
||||||
void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes);
|
|
||||||
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
|
void setShowShortcuts(QT_STATE_CHANGED_T _showShortcuts);
|
||||||
void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
|
void setShowGameSelectorFilterToolbar(QT_STATE_CHANGED_T _showGameSelectorFilterToolbar);
|
||||||
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
|
void setDisplayCardNames(QT_STATE_CHANGED_T _displayCardNames);
|
||||||
|
|
@ -1038,6 +1080,7 @@ public slots:
|
||||||
void setVisualDeckStorageShowTagFilter(QT_STATE_CHANGED_T _showTags);
|
void setVisualDeckStorageShowTagFilter(QT_STATE_CHANGED_T _showTags);
|
||||||
void setVisualDeckStorageDefaultTagsList(QStringList _defaultTagsList);
|
void setVisualDeckStorageDefaultTagsList(QStringList _defaultTagsList);
|
||||||
void setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T value);
|
void setVisualDeckStorageSearchFolderNames(QT_STATE_CHANGED_T value);
|
||||||
|
void setVisualDeckStorageShowColorIdentity(QT_STATE_CHANGED_T value);
|
||||||
void setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox);
|
void setVisualDeckStorageShowBannerCardComboBox(QT_STATE_CHANGED_T _showBannerCardComboBox);
|
||||||
void setVisualDeckStorageShowTagsOnDeckPreviews(QT_STATE_CHANGED_T _showTags);
|
void setVisualDeckStorageShowTagsOnDeckPreviews(QT_STATE_CHANGED_T _showTags);
|
||||||
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
|
||||||
|
|
@ -1074,9 +1117,13 @@ public slots:
|
||||||
void setSoundThemeName(const QString &_soundThemeName);
|
void setSoundThemeName(const QString &_soundThemeName);
|
||||||
void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers);
|
void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers);
|
||||||
void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages);
|
void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages);
|
||||||
|
void setIgnoreNonBuddyUserMessages(QT_STATE_CHANGED_T _ignoreNonBuddyUserMessages);
|
||||||
void setPixmapCacheSize(const int _pixmapCacheSize);
|
void setPixmapCacheSize(const int _pixmapCacheSize);
|
||||||
|
void setCardImageCacheMethod(CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod);
|
||||||
void setNetworkCacheSizeInMB(const int _networkCacheSize);
|
void setNetworkCacheSizeInMB(const int _networkCacheSize);
|
||||||
void setNetworkRedirectCacheTtl(const int _redirectCacheTtl);
|
void setNetworkRedirectCacheTtl(const int _redirectCacheTtl);
|
||||||
|
void setLocalCardImageStorageNamingScheme(
|
||||||
|
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme);
|
||||||
void setCardScaling(const QT_STATE_CHANGED_T _scaleCards);
|
void setCardScaling(const QT_STATE_CHANGED_T _scaleCards);
|
||||||
void setStackCardOverlapPercent(const int _verticalCardOverlapPercent);
|
void setStackCardOverlapPercent(const int _verticalCardOverlapPercent);
|
||||||
void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups);
|
void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups);
|
||||||
|
|
@ -1099,16 +1146,21 @@ public slots:
|
||||||
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
|
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
|
||||||
void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
|
void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
|
||||||
void setRememberGameSettings(const bool _rememberGameSettings);
|
void setRememberGameSettings(const bool _rememberGameSettings);
|
||||||
|
void setLocalGameRememberSettings(bool value);
|
||||||
|
void setLocalGameMaxPlayers(int value);
|
||||||
|
void setLocalGameStartingLifeTotal(int value);
|
||||||
void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
|
void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
|
||||||
void setStartupCardUpdateCheckPromptForUpdate(bool value);
|
void setStartupCardUpdateCheckPromptForUpdate(bool value);
|
||||||
void setStartupCardUpdateCheckAlwaysUpdate(bool value);
|
void setStartupCardUpdateCheckAlwaysUpdate(bool value);
|
||||||
void setCardUpdateCheckInterval(int value);
|
void setCardUpdateCheckInterval(int value);
|
||||||
void setLastCardUpdateCheck(QDate value);
|
void setLastCardUpdateCheck(QDate value);
|
||||||
|
void setAlwaysEnableNewSets(bool value);
|
||||||
void setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate);
|
void setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate);
|
||||||
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
|
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
|
||||||
void setUpdateReleaseChannelIndex(int value);
|
void setUpdateReleaseChannelIndex(int value);
|
||||||
void setMaxFontSize(int _max);
|
void setMaxFontSize(int _max);
|
||||||
void setRoundCardCorners(bool _roundCardCorners);
|
void setRoundCardCorners(bool _roundCardCorners);
|
||||||
|
void setShowDragSelectionCount(QT_STATE_CHANGED_T _showDragSelectionCount);
|
||||||
|
void setShowTotalSelectionCount(QT_STATE_CHANGED_T _showTotalSelectionCount);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,13 @@ CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *p
|
||||||
|
|
||||||
void CardCounterSettings::setColor(int counterId, const QColor &color)
|
void CardCounterSettings::setColor(int counterId, const QColor &color)
|
||||||
{
|
{
|
||||||
|
QSettings settings = getSettings();
|
||||||
|
|
||||||
QString key = QString("cards/counters/%1/color").arg(counterId);
|
QString key = QString("cards/counters/%1/color").arg(counterId);
|
||||||
|
|
||||||
if (settings.value(key).value<QColor>() == color)
|
if (settings.value(key).value<QColor>() == color) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
settings.setValue(key, color);
|
settings.setValue(key, color);
|
||||||
emit colorChanged(counterId, color);
|
emit colorChanged(counterId, color);
|
||||||
|
|
@ -36,7 +39,7 @@ QColor CardCounterSettings::color(int counterId) const
|
||||||
defaultColor = QColor::fromHsv(h, s, v);
|
defaultColor = QColor::fromHsv(h, s, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings.value(QString("cards/counters/%1/color").arg(counterId), defaultColor).value<QColor>();
|
return getSettings().value(QString("cards/counters/%1/color").arg(counterId), defaultColor).value<QColor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CardCounterSettings::displayName(int counterId) const
|
QString CardCounterSettings::displayName(int counterId) const
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file card_counter_settings.h
|
* @file card_counter_settings.h
|
||||||
* @ingroup GameSettings
|
* @ingroup GameSettings
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef CARD_COUNTER_SETTINGS_H
|
#ifndef CARD_COUNTER_SETTINGS_H
|
||||||
#define CARD_COUNTER_SETTINGS_H
|
#define CARD_COUNTER_SETTINGS_H
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file shortcut_treeview.h
|
* @file shortcut_treeview.h
|
||||||
* @ingroup CoreSettings
|
* @ingroup CoreSettings
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef SHORTCUT_TREEVIEW_H
|
#ifndef SHORTCUT_TREEVIEW_H
|
||||||
#define SHORTCUT_TREEVIEW_H
|
#define SHORTCUT_TREEVIEW_H
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,13 @@ ShortcutsSettings::ShortcutsSettings(const QString &settingsPath, QObject *paren
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PR 5079 changes Textbox/unfocusTextBox to Player/unfocusTextBox and tab_game/aFocusChat to Player/aFocusChat.
|
/**
|
||||||
/// A migration is necessary to let players keep their already configured shortcuts.
|
* @brief Migrates legacy shortcut key names to current naming scheme.
|
||||||
|
*
|
||||||
|
* PR 5079 changed Textbox/unfocusTextBox to Player/unfocusTextBox and
|
||||||
|
* tab_game/aFocusChat to Player/aFocusChat. This migration allows players
|
||||||
|
* to keep their already configured shortcuts.
|
||||||
|
*/
|
||||||
void ShortcutsSettings::migrateShortcuts()
|
void ShortcutsSettings::migrateShortcuts()
|
||||||
{
|
{
|
||||||
if (QFile(settingsFilePath).exists()) {
|
if (QFile(settingsFilePath).exists()) {
|
||||||
|
|
@ -236,9 +241,7 @@ bool ShortcutsSettings::isValid(const QString &name, const QString &sequences) c
|
||||||
return findOverlaps(name, sequences).isEmpty();
|
return findOverlaps(name, sequences).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @brief Checks if the shortcut is a shortcut that is active in all windows. */
|
||||||
* Checks if the shortcut is a shortcut that is active in all windows
|
|
||||||
*/
|
|
||||||
static bool isAlwaysActiveShortcut(const QString &shortcutName)
|
static bool isAlwaysActiveShortcut(const QString &shortcutName)
|
||||||
{
|
{
|
||||||
return shortcutName.startsWith("MainWindow") || shortcutName.startsWith("Tabs");
|
return shortcutName.startsWith("MainWindow") || shortcutName.startsWith("Tabs");
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file shortcuts_settings.h
|
* @file shortcuts_settings.h
|
||||||
* @ingroup CoreSettings
|
* @ingroup CoreSettings
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef SHORTCUTSSETTINGS_H
|
#ifndef SHORTCUTSSETTINGS_H
|
||||||
#define SHORTCUTSSETTINGS_H
|
#define SHORTCUTSSETTINGS_H
|
||||||
|
|
@ -501,7 +501,7 @@ private:
|
||||||
{"Player/aUntapAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Untap All"),
|
{"Player/aUntapAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Untap All"),
|
||||||
parseSequenceString("Ctrl+U"),
|
parseSequenceString("Ctrl+U"),
|
||||||
ShortcutGroup::Playing_Area)},
|
ShortcutGroup::Playing_Area)},
|
||||||
{"Player/aDoesntUntap", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Toggle Untap"),
|
{"Player/aDoesntUntap", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Toggle Skip Untapping"),
|
||||||
parseSequenceString("Alt+U"),
|
parseSequenceString("Alt+U"),
|
||||||
ShortcutGroup::Playing_Area)},
|
ShortcutGroup::Playing_Area)},
|
||||||
{"Player/aFlip", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Turn Card Over"),
|
{"Player/aFlip", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Turn Card Over"),
|
||||||
|
|
@ -513,6 +513,9 @@ private:
|
||||||
{"Player/aPlay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Play Card"),
|
{"Player/aPlay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Play Card"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Playing_Area)},
|
ShortcutGroup::Playing_Area)},
|
||||||
|
{"Player/aPlayFacedown", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Play Card, Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Playing_Area)},
|
||||||
{"Player/aAttach", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Attach Card..."),
|
{"Player/aAttach", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Attach Card..."),
|
||||||
parseSequenceString("Ctrl+Alt+A"),
|
parseSequenceString("Ctrl+Alt+A"),
|
||||||
ShortcutGroup::Playing_Area)},
|
ShortcutGroup::Playing_Area)},
|
||||||
|
|
@ -534,6 +537,9 @@ private:
|
||||||
{"Player/aSetAnnotation", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Annotation..."),
|
{"Player/aSetAnnotation", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Annotation..."),
|
||||||
parseSequenceString("Alt+N"),
|
parseSequenceString("Alt+N"),
|
||||||
ShortcutGroup::Playing_Area)},
|
ShortcutGroup::Playing_Area)},
|
||||||
|
{"Player/aReduceLifeByPower", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Reduce Life by Power"),
|
||||||
|
parseSequenceString("Ctrl+Shift+L"),
|
||||||
|
ShortcutGroup::Playing_Area)},
|
||||||
{"Player/aSelectAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Zone"),
|
{"Player/aSelectAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Zone"),
|
||||||
parseSequenceString("Ctrl+A"),
|
parseSequenceString("Ctrl+A"),
|
||||||
ShortcutGroup::Playing_Area)},
|
ShortcutGroup::Playing_Area)},
|
||||||
|
|
@ -560,12 +566,9 @@ private:
|
||||||
{"Player/aMoveToTopLibrary", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"),
|
{"Player/aMoveToTopLibrary", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_selected)},
|
ShortcutGroup::Move_selected)},
|
||||||
{"Player/aPlayFacedown", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Battlefield, Face Down"),
|
{"Player/aMoveToTable", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Battlefield"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_selected)},
|
ShortcutGroup::Move_selected)},
|
||||||
{"Player/aPlay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Battlefield"),
|
|
||||||
parseSequenceString(""),
|
|
||||||
ShortcutGroup::Move_selected)},
|
|
||||||
{"Player/aViewHand",
|
{"Player/aViewHand",
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Hand"), parseSequenceString(""), ShortcutGroup::View)},
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Hand"), parseSequenceString(""), ShortcutGroup::View)},
|
||||||
{"Player/aViewGraveyard",
|
{"Player/aViewGraveyard",
|
||||||
|
|
@ -598,11 +601,19 @@ private:
|
||||||
{"Player/aMoveTopCardsToGraveyard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
{"Player/aMoveTopCardsToGraveyard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
||||||
parseSequenceString("Alt+M"),
|
parseSequenceString("Alt+M"),
|
||||||
ShortcutGroup::Move_top)},
|
ShortcutGroup::Move_top)},
|
||||||
|
{"Player/aMoveTopCardsToGraveyardFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_top)},
|
||||||
{"Player/aMoveTopCardToExile",
|
{"Player/aMoveTopCardToExile",
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_top)},
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_top)},
|
||||||
{"Player/aMoveTopCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
{"Player/aMoveTopCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_top)},
|
ShortcutGroup::Move_top)},
|
||||||
|
{"Player/aMoveTopCardsToExileFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_top)},
|
||||||
{"Player/aMoveTopCardsUntil", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Stack Until Found"),
|
{"Player/aMoveTopCardsUntil", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Stack Until Found"),
|
||||||
parseSequenceString("Ctrl+Shift+Y"),
|
parseSequenceString("Ctrl+Shift+Y"),
|
||||||
ShortcutGroup::Move_top)},
|
ShortcutGroup::Move_top)},
|
||||||
|
|
@ -620,11 +631,19 @@ private:
|
||||||
{"Player/aMoveBottomCardsToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
{"Player/aMoveBottomCardsToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_bottom)},
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardsToGraveFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aMoveBottomCardToExile",
|
{"Player/aMoveBottomCardToExile",
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_bottom)},
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aMoveBottomCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
{"Player/aMoveBottomCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_bottom)},
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardsToExileFaceDown",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple), Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aMoveBottomCardToTop", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"),
|
{"Player/aMoveBottomCardToTop", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_bottom)},
|
ShortcutGroup::Move_bottom)},
|
||||||
|
|
@ -648,6 +667,9 @@ private:
|
||||||
{"Player/aRollDie", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Roll Dice..."),
|
{"Player/aRollDie", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Roll Dice..."),
|
||||||
parseSequenceString("Ctrl+I"),
|
parseSequenceString("Ctrl+I"),
|
||||||
ShortcutGroup::Gameplay)},
|
ShortcutGroup::Gameplay)},
|
||||||
|
{"Player/aFlipCoin", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Flip Coin"),
|
||||||
|
parseSequenceString("Ctrl+Shift+I"),
|
||||||
|
ShortcutGroup::Gameplay)},
|
||||||
{"Player/aShuffle", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Shuffle Library"),
|
{"Player/aShuffle", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Shuffle Library"),
|
||||||
parseSequenceString("Ctrl+S"),
|
parseSequenceString("Ctrl+S"),
|
||||||
ShortcutGroup::Gameplay)},
|
ShortcutGroup::Gameplay)},
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,9 @@ QStringMap &SoundEngine::getAvailableThemes()
|
||||||
dir.setPath(SettingsCache::instance().getDataPath() + "/sounds");
|
dir.setPath(SettingsCache::instance().getDataPath() + "/sounds");
|
||||||
|
|
||||||
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
||||||
if (!availableThemes.contains(themeName))
|
if (!availableThemes.contains(themeName)) {
|
||||||
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load themes from cockatrice system dir
|
// load themes from cockatrice system dir
|
||||||
|
|
@ -121,8 +122,9 @@ QStringMap &SoundEngine::getAvailableThemes()
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
||||||
if (!availableThemes.contains(themeName))
|
if (!availableThemes.contains(themeName)) {
|
||||||
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return availableThemes;
|
return availableThemes;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file sound_engine.h
|
* @file sound_engine.h
|
||||||
* @ingroup Core
|
* @ingroup Core
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef SOUNDENGINE_H
|
#ifndef SOUNDENGINE_H
|
||||||
#define SOUNDENGINE_H
|
#define SOUNDENGINE_H
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ GenericQuery <- String
|
||||||
|
|
||||||
NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["].
|
NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["].
|
||||||
NonSingleQuoteUnlessEscaped <- "\\\'". / !['].
|
NonSingleQuoteUnlessEscaped <- "\\\'". / !['].
|
||||||
UnescapedStringListPart <- !['":<>=! ].
|
UnescapedStringListPart <- !['":<>()=! ].
|
||||||
SingleApostropheString <- (UnescapedStringListPart+ ws*)* ['] (UnescapedStringListPart+ ws*)*
|
SingleApostropheString <- (UnescapedStringListPart+ ws*)* ['] (UnescapedStringListPart+ ws*)*
|
||||||
|
|
||||||
String <- SingleApostropheString / UnescapedStringListPart+ / ["] <NonDoubleQuoteUnlessEscaped*> ["] / ['] <NonSingleQuoteUnlessEscaped*> [']
|
String <- SingleApostropheString / UnescapedStringListPart+ / ["] <NonDoubleQuoteUnlessEscaped*> ["] / ['] <NonSingleQuoteUnlessEscaped*> [']
|
||||||
|
|
@ -88,20 +88,27 @@ static void setupParserRules()
|
||||||
const auto arg = std::any_cast<int>(sv[1]);
|
const auto arg = std::any_cast<int>(sv[1]);
|
||||||
const auto op = std::any_cast<QString>(sv[0]);
|
const auto op = std::any_cast<QString>(sv[0]);
|
||||||
|
|
||||||
if (op == ">")
|
if (op == ">") {
|
||||||
return [=](const int s) { return s > arg; };
|
return [=](const int s) { return s > arg; };
|
||||||
if (op == ">=")
|
}
|
||||||
|
if (op == ">=") {
|
||||||
return [=](const int s) { return s >= arg; };
|
return [=](const int s) { return s >= arg; };
|
||||||
if (op == "<")
|
}
|
||||||
|
if (op == "<") {
|
||||||
return [=](const int s) { return s < arg; };
|
return [=](const int s) { return s < arg; };
|
||||||
if (op == "<=")
|
}
|
||||||
|
if (op == "<=") {
|
||||||
return [=](const int s) { return s <= arg; };
|
return [=](const int s) { return s <= arg; };
|
||||||
if (op == "=")
|
}
|
||||||
|
if (op == "=") {
|
||||||
return [=](const int s) { return s == arg; };
|
return [=](const int s) { return s == arg; };
|
||||||
if (op == ":")
|
}
|
||||||
|
if (op == ":") {
|
||||||
return [=](const int s) { return s == arg; };
|
return [=](const int s) { return s == arg; };
|
||||||
if (op == "!=")
|
}
|
||||||
|
if (op == "!=") {
|
||||||
return [=](const int s) { return s != arg; };
|
return [=](const int s) { return s != arg; };
|
||||||
|
}
|
||||||
return [](int) { return false; };
|
return [](int) { return false; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file deck_filter_string.h
|
* @file deck_filter_string.h
|
||||||
* @ingroup DeckStorageWidgets
|
* @ingroup DeckStorageWidgets
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef DECK_FILTER_STRING_H
|
#ifndef DECK_FILTER_STRING_H
|
||||||
#define DECK_FILTER_STRING_H
|
#define DECK_FILTER_STRING_H
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,15 @@ FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
filterCombo = new QComboBox;
|
filterCombo = new QComboBox;
|
||||||
filterCombo->setObjectName("filterCombo");
|
filterCombo->setObjectName("filterCombo");
|
||||||
for (int i = 0; i < CardFilter::AttrEnd; i++)
|
for (int i = 0; i < CardFilter::AttrEnd; i++) {
|
||||||
filterCombo->addItem(CardFilter::attrName(static_cast<CardFilter::Attr>(i)), QVariant(i));
|
filterCombo->addItem(CardFilter::attrName(static_cast<CardFilter::Attr>(i)), QVariant(i));
|
||||||
|
}
|
||||||
|
|
||||||
typeCombo = new QComboBox;
|
typeCombo = new QComboBox;
|
||||||
typeCombo->setObjectName("typeCombo");
|
typeCombo->setObjectName("typeCombo");
|
||||||
for (int i = 0; i < CardFilter::TypeEnd; i++)
|
for (int i = 0; i < CardFilter::TypeEnd; i++) {
|
||||||
typeCombo->addItem(CardFilter::typeName(static_cast<CardFilter::Type>(i)), QVariant(i));
|
typeCombo->addItem(CardFilter::typeName(static_cast<CardFilter::Type>(i)), QVariant(i));
|
||||||
|
}
|
||||||
|
|
||||||
QPushButton *ok = new QPushButton(QPixmap("theme:icons/increment"), QString());
|
QPushButton *ok = new QPushButton(QPixmap("theme:icons/increment"), QString());
|
||||||
ok->setObjectName("ok");
|
ok->setObjectName("ok");
|
||||||
|
|
@ -53,8 +55,9 @@ FilterBuilder::~FilterBuilder()
|
||||||
|
|
||||||
void FilterBuilder::destroyFilter()
|
void FilterBuilder::destroyFilter()
|
||||||
{
|
{
|
||||||
if (fltr)
|
if (fltr) {
|
||||||
delete fltr;
|
delete fltr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int comboCurrentIntData(const QComboBox *combo)
|
static int comboCurrentIntData(const QComboBox *combo)
|
||||||
|
|
@ -67,8 +70,9 @@ void FilterBuilder::emit_add()
|
||||||
QString txt;
|
QString txt;
|
||||||
|
|
||||||
txt = edit->text();
|
txt = edit->text();
|
||||||
if (txt.length() < 1)
|
if (txt.length() < 1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
destroyFilter();
|
destroyFilter();
|
||||||
fltr = new CardFilter(txt, static_cast<CardFilter::Type>(comboCurrentIntData(typeCombo)),
|
fltr = new CardFilter(txt, static_cast<CardFilter::Type>(comboCurrentIntData(typeCombo)),
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file filter_builder.h
|
* @file filter_builder.h
|
||||||
* @ingroup CardDatabaseModelFilters
|
* @ingroup CardDatabaseModelFilters
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef FILTERBUILDER_H
|
#ifndef FILTERBUILDER_H
|
||||||
#define FILTERBUILDER_H
|
#define FILTERBUILDER_H
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,9 @@ void FilterTreeModel::proxyBeginInsertRow(const FilterTreeNode *node, int i)
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
idx = node->index();
|
idx = node->index();
|
||||||
if (idx >= 0)
|
if (idx >= 0) {
|
||||||
beginInsertRows(createIndex(idx, 0, (void *)node), i, i);
|
beginInsertRows(createIndex(idx, 0, (void *)node), i, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
|
void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
|
||||||
|
|
@ -32,8 +33,9 @@ void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
idx = node->index();
|
idx = node->index();
|
||||||
if (idx >= 0)
|
if (idx >= 0) {
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
|
void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
|
||||||
|
|
@ -41,8 +43,9 @@ void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
idx = node->index();
|
idx = node->index();
|
||||||
if (idx >= 0)
|
if (idx >= 0) {
|
||||||
beginRemoveRows(createIndex(idx, 0, (void *)node), i, i);
|
beginRemoveRows(createIndex(idx, 0, (void *)node), i, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
|
void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
|
||||||
|
|
@ -50,8 +53,9 @@ void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
idx = node->index();
|
idx = node->index();
|
||||||
if (idx >= 0)
|
if (idx >= 0) {
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
|
FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
|
||||||
|
|
@ -59,12 +63,14 @@ FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
|
||||||
void *ip;
|
void *ip;
|
||||||
FilterTreeNode *node;
|
FilterTreeNode *node;
|
||||||
|
|
||||||
if (!idx.isValid())
|
if (!idx.isValid()) {
|
||||||
return fTree;
|
return fTree;
|
||||||
|
}
|
||||||
|
|
||||||
ip = idx.internalPointer();
|
ip = idx.internalPointer();
|
||||||
if (ip == NULL)
|
if (ip == NULL) {
|
||||||
return fTree;
|
return fTree;
|
||||||
|
}
|
||||||
|
|
||||||
node = static_cast<FilterTreeNode *>(ip);
|
node = static_cast<FilterTreeNode *>(ip);
|
||||||
return node;
|
return node;
|
||||||
|
|
@ -145,14 +151,16 @@ int FilterTreeModel::rowCount(const QModelIndex &parent) const
|
||||||
const FilterTreeNode *node;
|
const FilterTreeNode *node;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (parent.column() > 0)
|
if (parent.column() > 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
node = indexToNode(parent);
|
node = indexToNode(parent);
|
||||||
if (node)
|
if (node) {
|
||||||
result = node->childCount();
|
result = node->childCount();
|
||||||
else
|
} else {
|
||||||
result = 0;
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -166,14 +174,17 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
const FilterTreeNode *node;
|
const FilterTreeNode *node;
|
||||||
|
|
||||||
if (!index.isValid())
|
if (!index.isValid()) {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
if (index.column() >= columnCount())
|
}
|
||||||
|
if (index.column() >= columnCount()) {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
node = indexToNode(index);
|
node = indexToNode(index);
|
||||||
if (node == NULL)
|
if (node == NULL) {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::FontRole:
|
case Qt::FontRole:
|
||||||
|
|
@ -190,10 +201,11 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
|
||||||
case Qt::WhatsThisRole:
|
case Qt::WhatsThisRole:
|
||||||
return node->text();
|
return node->text();
|
||||||
case Qt::CheckStateRole:
|
case Qt::CheckStateRole:
|
||||||
if (node->isEnabled())
|
if (node->isEnabled()) {
|
||||||
return Qt::Checked;
|
return Qt::Checked;
|
||||||
else
|
} else {
|
||||||
return Qt::Unchecked;
|
return Qt::Unchecked;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
@ -205,22 +217,27 @@ bool FilterTreeModel::setData(const QModelIndex &index, const QVariant &value, i
|
||||||
{
|
{
|
||||||
FilterTreeNode *node;
|
FilterTreeNode *node;
|
||||||
|
|
||||||
if (!index.isValid())
|
if (!index.isValid()) {
|
||||||
return false;
|
return false;
|
||||||
if (index.column() >= columnCount())
|
}
|
||||||
|
if (index.column() >= columnCount()) {
|
||||||
return false;
|
return false;
|
||||||
if (role != Qt::CheckStateRole)
|
}
|
||||||
|
if (role != Qt::CheckStateRole) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
node = indexToNode(index);
|
node = indexToNode(index);
|
||||||
if (node == NULL || node == fTree)
|
if (node == NULL || node == fTree) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
|
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
|
||||||
if (state == Qt::Checked)
|
if (state == Qt::Checked) {
|
||||||
node->enable();
|
node->enable();
|
||||||
else
|
} else {
|
||||||
node->disable();
|
node->disable();
|
||||||
|
}
|
||||||
|
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -231,16 +248,19 @@ Qt::ItemFlags FilterTreeModel::flags(const QModelIndex &index) const
|
||||||
const FilterTreeNode *node;
|
const FilterTreeNode *node;
|
||||||
Qt::ItemFlags result;
|
Qt::ItemFlags result;
|
||||||
|
|
||||||
if (!index.isValid())
|
if (!index.isValid()) {
|
||||||
return Qt::NoItemFlags;
|
return Qt::NoItemFlags;
|
||||||
|
}
|
||||||
|
|
||||||
node = indexToNode(index);
|
node = indexToNode(index);
|
||||||
if (node == NULL)
|
if (node == NULL) {
|
||||||
return Qt::NoItemFlags;
|
return Qt::NoItemFlags;
|
||||||
|
}
|
||||||
|
|
||||||
result = Qt::ItemIsEnabled;
|
result = Qt::ItemIsEnabled;
|
||||||
if (node == fTree)
|
if (node == fTree) {
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result |= Qt::ItemIsSelectable;
|
result |= Qt::ItemIsSelectable;
|
||||||
result |= Qt::ItemIsUserCheckable;
|
result |= Qt::ItemIsUserCheckable;
|
||||||
|
|
@ -252,8 +272,9 @@ QModelIndex FilterTreeModel::nodeIndex(const FilterTreeNode *node, int row, int
|
||||||
{
|
{
|
||||||
FilterTreeNode *child;
|
FilterTreeNode *child;
|
||||||
|
|
||||||
if (column > 0 || row >= node->childCount())
|
if (column > 0 || row >= node->childCount()) {
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
child = node->nodeAt(row);
|
child = node->nodeAt(row);
|
||||||
return createIndex(row, column, child);
|
return createIndex(row, column, child);
|
||||||
|
|
@ -263,12 +284,14 @@ QModelIndex FilterTreeModel::index(int row, int column, const QModelIndex &paren
|
||||||
{
|
{
|
||||||
const FilterTreeNode *node;
|
const FilterTreeNode *node;
|
||||||
|
|
||||||
if (!hasIndex(row, column, parent))
|
if (!hasIndex(row, column, parent)) {
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
node = indexToNode(parent);
|
node = indexToNode(parent);
|
||||||
if (node == NULL)
|
if (node == NULL) {
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
return nodeIndex(node, row, column);
|
return nodeIndex(node, row, column);
|
||||||
}
|
}
|
||||||
|
|
@ -279,18 +302,21 @@ QModelIndex FilterTreeModel::parent(const QModelIndex &ind) const
|
||||||
FilterTreeNode *parent;
|
FilterTreeNode *parent;
|
||||||
QModelIndex idx;
|
QModelIndex idx;
|
||||||
|
|
||||||
if (!ind.isValid())
|
if (!ind.isValid()) {
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
node = indexToNode(ind);
|
node = indexToNode(ind);
|
||||||
if (node == NULL || node == fTree)
|
if (node == NULL || node == fTree) {
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
parent = node->parent();
|
parent = node->parent();
|
||||||
if (parent) {
|
if (parent) {
|
||||||
int row = parent->index();
|
int row = parent->index();
|
||||||
if (row < 0)
|
if (row < 0) {
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
}
|
||||||
idx = createIndex(row, 0, parent);
|
idx = createIndex(row, 0, parent);
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
@ -304,18 +330,22 @@ bool FilterTreeModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||||
int i, last;
|
int i, last;
|
||||||
|
|
||||||
last = row + count - 1;
|
last = row + count - 1;
|
||||||
if (!parent.isValid() || count < 1 || row < 0)
|
if (!parent.isValid() || count < 1 || row < 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
node = indexToNode(parent);
|
node = indexToNode(parent);
|
||||||
if (node == NULL || last >= node->childCount())
|
if (node == NULL || last >= node->childCount()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++) {
|
||||||
node->deleteAt(row);
|
node->deleteAt(row);
|
||||||
|
}
|
||||||
|
|
||||||
if (node != fTree && node->childCount() < 1)
|
if (node != fTree && node->childCount() < 1) {
|
||||||
return removeRow(parent.row(), parent.parent());
|
return removeRow(parent.row(), parent.parent());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file filter_tree_model.h
|
* @file filter_tree_model.h
|
||||||
* @ingroup CardDatabaseModelFilters
|
* @ingroup CardDatabaseModelFilters
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef FILTERTREEMODEL_H
|
#ifndef FILTERTREEMODEL_H
|
||||||
#define FILTERTREEMODEL_H
|
#define FILTERTREEMODEL_H
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
* @file syntax_help.h
|
* @file syntax_help.h
|
||||||
* @ingroup CardDatabaseModelFilters
|
* @ingroup CardDatabaseModelFilters
|
||||||
* @ingroup DeckStorageWidgets
|
* @ingroup DeckStorageWidgets
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef SEARCH_SYNTAX_HELP_H
|
#ifndef SEARCH_SYNTAX_HELP_H
|
||||||
#define SEARCH_SYNTAX_HELP_H
|
#define SEARCH_SYNTAX_HELP_H
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
#include "abstract_game.h"
|
#include "abstract_game.h"
|
||||||
|
|
||||||
#include "player/player.h"
|
#include "../interface/widgets/tabs/tab_game.h"
|
||||||
|
#include "player/player_logic.h"
|
||||||
|
|
||||||
AbstractGame::AbstractGame(TabGame *_tab) : tab(_tab)
|
AbstractGame::AbstractGame(QObject *_parent) : QObject(_parent)
|
||||||
{
|
{
|
||||||
gameMetaInfo = new GameMetaInfo(this);
|
gameMetaInfo = new GameMetaInfo(this);
|
||||||
gameEventHandler = new GameEventHandler(this);
|
gameEventHandler = new GameEventHandler(this);
|
||||||
|
|
@ -23,10 +24,11 @@ AbstractClient *AbstractGame::getClientForPlayer(int playerId) const
|
||||||
}
|
}
|
||||||
|
|
||||||
return gameState->getClients().at(playerId);
|
return gameState->getClients().at(playerId);
|
||||||
} else if (gameState->getClients().isEmpty())
|
} else if (gameState->getClients().isEmpty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
else
|
} else {
|
||||||
return gameState->getClients().first();
|
return gameState->getClients().first();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractGame::loadReplay(GameReplay *replay)
|
void AbstractGame::loadReplay(GameReplay *replay)
|
||||||
|
|
@ -42,13 +44,15 @@ void AbstractGame::setActiveCard(CardItem *card)
|
||||||
|
|
||||||
CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const
|
CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const
|
||||||
{
|
{
|
||||||
Player *player = playerManager->getPlayer(playerId);
|
PlayerLogic *player = playerManager->getPlayer(playerId);
|
||||||
if (!player)
|
if (!player) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
CardZoneLogic *zone = player->getZones().value(zoneName, 0);
|
CardZoneLogic *zone = player->getZones().value(zoneName, 0);
|
||||||
if (!zone)
|
if (!zone) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return zone->getCard(cardId);
|
return zone->getCard(cardId);
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file abstract_game.h
|
* @file abstract_game.h
|
||||||
* @ingroup GameLogic
|
* @ingroup GameLogic
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef COCKATRICE_ABSTRACT_GAME_H
|
#ifndef COCKATRICE_ABSTRACT_GAME_H
|
||||||
#define COCKATRICE_ABSTRACT_GAME_H
|
#define COCKATRICE_ABSTRACT_GAME_H
|
||||||
|
|
@ -16,26 +16,19 @@
|
||||||
#include <libcockatrice/protocol/pb/game_replay.pb.h>
|
#include <libcockatrice/protocol/pb/game_replay.pb.h>
|
||||||
|
|
||||||
class CardItem;
|
class CardItem;
|
||||||
class TabGame;
|
|
||||||
class AbstractGame : public QObject
|
class AbstractGame : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AbstractGame(TabGame *tab);
|
explicit AbstractGame(QObject *parent);
|
||||||
|
|
||||||
TabGame *tab;
|
|
||||||
GameMetaInfo *gameMetaInfo;
|
GameMetaInfo *gameMetaInfo;
|
||||||
GameState *gameState;
|
GameState *gameState;
|
||||||
GameEventHandler *gameEventHandler;
|
GameEventHandler *gameEventHandler;
|
||||||
PlayerManager *playerManager;
|
PlayerManager *playerManager;
|
||||||
CardItem *activeCard;
|
CardItem *activeCard;
|
||||||
|
|
||||||
TabGame *getTab() const
|
|
||||||
{
|
|
||||||
return tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameMetaInfo *getGameMetaInfo()
|
GameMetaInfo *getGameMetaInfo()
|
||||||
{
|
{
|
||||||
return gameMetaInfo;
|
return gameMetaInfo;
|
||||||
|
|
|
||||||
48
cockatrice/src/game/arrow_registry.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "arrow_registry.h"
|
||||||
|
|
||||||
|
#include "../game_graphics/board/arrow_item.h"
|
||||||
|
|
||||||
|
void ArrowRegistry::insert(QSharedPointer<ArrowData> data, ArrowItem *arrow)
|
||||||
|
{
|
||||||
|
const ArrowKey key{data->creatorId, data->id};
|
||||||
|
|
||||||
|
if (auto *existing = take(data->creatorId, data->id)) {
|
||||||
|
existing->delArrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStore.insert(key, data);
|
||||||
|
items.insert(key, arrow);
|
||||||
|
byPlayer[data->creatorId].insert(data->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrowItem *ArrowRegistry::take(int creatorId, int arrowId)
|
||||||
|
{
|
||||||
|
const ArrowKey key{creatorId, arrowId};
|
||||||
|
dataStore.remove(key);
|
||||||
|
auto &playerSet = byPlayer[creatorId];
|
||||||
|
playerSet.remove(arrowId);
|
||||||
|
if (playerSet.isEmpty()) {
|
||||||
|
byPlayer.remove(creatorId);
|
||||||
|
}
|
||||||
|
return items.take(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrowItem *ArrowRegistry::get(int creatorId, int arrowId) const
|
||||||
|
{
|
||||||
|
return items.value(ArrowKey{creatorId, arrowId}, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArrowRegistry::contains(int creatorId, int arrowId) const
|
||||||
|
{
|
||||||
|
return items.contains(ArrowKey{creatorId, arrowId});
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<int> ArrowRegistry::idsForPlayer(int playerId) const
|
||||||
|
{
|
||||||
|
return byPlayer.value(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ArrowItem *> ArrowRegistry::all() const
|
||||||
|
{
|
||||||
|
return items.values();
|
||||||
|
}
|
||||||
43
cockatrice/src/game/arrow_registry.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef COCKATRICE_ARROW_REGISTRY_H
|
||||||
|
#define COCKATRICE_ARROW_REGISTRY_H
|
||||||
|
|
||||||
|
#include "board/arrow_data.h"
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
class ArrowItem;
|
||||||
|
|
||||||
|
struct ArrowKey
|
||||||
|
{
|
||||||
|
int creatorId;
|
||||||
|
int arrowId;
|
||||||
|
|
||||||
|
bool operator<(const ArrowKey &other) const
|
||||||
|
{
|
||||||
|
if (creatorId != other.creatorId) {
|
||||||
|
return creatorId < other.creatorId;
|
||||||
|
}
|
||||||
|
return arrowId < other.arrowId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArrowRegistry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void insert(QSharedPointer<ArrowData> data, ArrowItem *arrow);
|
||||||
|
ArrowItem *take(int creatorId, int arrowId);
|
||||||
|
|
||||||
|
[[nodiscard]] ArrowItem *get(int creatorId, int arrowId) const;
|
||||||
|
[[nodiscard]] bool contains(int creatorId, int arrowId) const;
|
||||||
|
[[nodiscard]] QSet<int> idsForPlayer(int playerId) const;
|
||||||
|
[[nodiscard]] QList<ArrowItem *> all() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap<ArrowKey, QSharedPointer<ArrowData>> dataStore;
|
||||||
|
QMap<ArrowKey, ArrowItem *> items;
|
||||||
|
QMap<int, QSet<int>> byPlayer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
21
cockatrice/src/game/board/arrow_data.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "arrow_data.h"
|
||||||
|
|
||||||
|
ArrowData ArrowData::fromProto(const ServerInfo_Arrow &arrow, int creatorId, bool isLocalCreator)
|
||||||
|
{
|
||||||
|
ArrowData data;
|
||||||
|
data.creatorId = creatorId;
|
||||||
|
data.isLocalCreator = isLocalCreator;
|
||||||
|
data.id = arrow.id();
|
||||||
|
data.startPlayerId = arrow.start_player_id();
|
||||||
|
data.startZone = QString::fromStdString(arrow.start_zone());
|
||||||
|
data.startCardId = arrow.start_card_id();
|
||||||
|
data.targetPlayerId = arrow.target_player_id();
|
||||||
|
data.color = convertColorToQColor(arrow.arrow_color());
|
||||||
|
|
||||||
|
if (arrow.has_target_zone()) {
|
||||||
|
data.targetZone = QString::fromStdString(arrow.target_zone());
|
||||||
|
data.targetCardId = arrow.target_card_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
30
cockatrice/src/game/board/arrow_data.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef COCKATRICE_ARROW_DATA_H
|
||||||
|
#define COCKATRICE_ARROW_DATA_H
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QString>
|
||||||
|
#include <libcockatrice/protocol/pb/serverinfo_arrow.pb.h>
|
||||||
|
#include <libcockatrice/utility/color.h>
|
||||||
|
|
||||||
|
struct ArrowData
|
||||||
|
{
|
||||||
|
int creatorId = -1;
|
||||||
|
bool isLocalCreator = false;
|
||||||
|
int id = -1;
|
||||||
|
int startPlayerId = -1;
|
||||||
|
QString startZone = "";
|
||||||
|
int startCardId = -1;
|
||||||
|
int targetPlayerId = -1;
|
||||||
|
QString targetZone = "";
|
||||||
|
int targetCardId = -1;
|
||||||
|
QColor color = "";
|
||||||
|
|
||||||
|
static ArrowData fromProto(const ServerInfo_Arrow &arrow, int creatorId, bool isLocalCreator);
|
||||||
|
|
||||||
|
bool isPlayerTargeted() const
|
||||||
|
{
|
||||||
|
return targetZone.isEmpty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_ARROW_DATA_H
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
#include "arrow_target.h"
|
|
||||||
|
|
||||||
#include "../player/player.h"
|
|
||||||
#include "arrow_item.h"
|
|
||||||
|
|
||||||
ArrowTarget::ArrowTarget(Player *_owner, QGraphicsItem *parent)
|
|
||||||
: AbstractGraphicsItem(parent), owner(_owner), beingPointedAt(false)
|
|
||||||
{
|
|
||||||
setFlag(ItemSendsScenePositionChanges);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrowTarget::~ArrowTarget()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < arrowsFrom.size(); ++i) {
|
|
||||||
arrowsFrom[i]->setStartItem(0);
|
|
||||||
arrowsFrom[i]->delArrow();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < arrowsTo.size(); ++i) {
|
|
||||||
arrowsTo[i]->setTargetItem(0);
|
|
||||||
arrowsTo[i]->delArrow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArrowTarget::setBeingPointedAt(bool _beingPointedAt)
|
|
||||||
{
|
|
||||||
beingPointedAt = _beingPointedAt;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ArrowTarget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
|
|
||||||
{
|
|
||||||
if (change == ItemScenePositionHasChanged && scene()) {
|
|
||||||
for (auto *arrow : arrowsFrom)
|
|
||||||
arrow->updatePath();
|
|
||||||
|
|
||||||
for (auto *arrow : arrowsTo)
|
|
||||||
arrow->updatePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
return QGraphicsItem::itemChange(change, value);
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
/**
|
|
||||||
* @file arrow_target.h
|
|
||||||
* @ingroup GameGraphics
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ARROWTARGET_H
|
|
||||||
#define ARROWTARGET_H
|
|
||||||
|
|
||||||
#include "../../game_graphics/board/abstract_graphics_item.h"
|
|
||||||
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
class Player;
|
|
||||||
class ArrowItem;
|
|
||||||
|
|
||||||
class ArrowTarget : public AbstractGraphicsItem
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
protected:
|
|
||||||
Player *owner;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool beingPointedAt;
|
|
||||||
QList<ArrowItem *> arrowsFrom, arrowsTo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ArrowTarget(Player *_owner, QGraphicsItem *parent = nullptr);
|
|
||||||
~ArrowTarget() override;
|
|
||||||
|
|
||||||
[[nodiscard]] Player *getOwner() const
|
|
||||||
{
|
|
||||||
return owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBeingPointedAt(bool _beingPointedAt);
|
|
||||||
[[nodiscard]] bool getBeingPointedAt() const
|
|
||||||
{
|
|
||||||
return beingPointedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] const QList<ArrowItem *> &getArrowsFrom() const
|
|
||||||
{
|
|
||||||
return arrowsFrom;
|
|
||||||
}
|
|
||||||
void addArrowFrom(ArrowItem *arrow)
|
|
||||||
{
|
|
||||||
arrowsFrom.append(arrow);
|
|
||||||
}
|
|
||||||
void removeArrowFrom(ArrowItem *arrow)
|
|
||||||
{
|
|
||||||
arrowsFrom.removeOne(arrow);
|
|
||||||
}
|
|
||||||
[[nodiscard]] const QList<ArrowItem *> &getArrowsTo() const
|
|
||||||
{
|
|
||||||
return arrowsTo;
|
|
||||||
}
|
|
||||||
void addArrowTo(ArrowItem *arrow)
|
|
||||||
{
|
|
||||||
arrowsTo.append(arrow);
|
|
||||||
}
|
|
||||||
void removeArrowTo(ArrowItem *arrow)
|
|
||||||
{
|
|
||||||
arrowsTo.removeOne(arrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "card_list.h"
|
#include "card_list.h"
|
||||||
|
|
||||||
#include "card_item.h"
|
#include "../../game_graphics/board/card_item.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file card_list.h
|
* @file card_list.h
|
||||||
* @ingroup GameLogicCards
|
* @ingroup GameLogicCards
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef CARDLIST_H
|
#ifndef CARDLIST_H
|
||||||
#define CARDLIST_H
|
#define CARDLIST_H
|
||||||
|
|
|
||||||
111
cockatrice/src/game/board/card_state.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
#include "card_state.h"
|
||||||
|
|
||||||
|
void CardState::resetState(bool keepAnnotations)
|
||||||
|
{
|
||||||
|
attacking = false;
|
||||||
|
counters.clear();
|
||||||
|
pt.clear();
|
||||||
|
if (!keepAnnotations) {
|
||||||
|
annotation.clear();
|
||||||
|
}
|
||||||
|
attachedTo = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setZone(CardZoneLogic *_zone)
|
||||||
|
{
|
||||||
|
if (zone == _zone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
zone = _zone;
|
||||||
|
emit zoneChanged(this, zone);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setAttacking(bool _attacking)
|
||||||
|
{
|
||||||
|
if (attacking == _attacking) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
attacking = _attacking;
|
||||||
|
emit attackingChanged(_attacking);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::insertCounter(int id, int value)
|
||||||
|
{
|
||||||
|
counters.insert(id, value);
|
||||||
|
|
||||||
|
emit countersChanged(counters);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setCounter(int id, int value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
counters[id] = value;
|
||||||
|
} else {
|
||||||
|
counters.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit countersChanged(counters);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::clearCounters()
|
||||||
|
{
|
||||||
|
counters.clear();
|
||||||
|
emit countersChanged(counters);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setAnnotation(const QString &_annotation)
|
||||||
|
{
|
||||||
|
if (annotation == _annotation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
annotation = _annotation;
|
||||||
|
emit annotationChanged(annotation);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setPT(const QString &_pt)
|
||||||
|
{
|
||||||
|
if (pt == _pt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pt = _pt;
|
||||||
|
emit ptChanged(pt);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setDoesntUntap(bool _doesntUntap)
|
||||||
|
{
|
||||||
|
if (doesntUntap == _doesntUntap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doesntUntap = _doesntUntap;
|
||||||
|
emit doesntUntapChanged(_doesntUntap);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setDestroyOnZoneChange(bool _destroyOnZoneChange)
|
||||||
|
{
|
||||||
|
if (destroyOnZoneChange == _destroyOnZoneChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyOnZoneChange = _destroyOnZoneChange;
|
||||||
|
emit destroyOnZoneChangeChanged(_destroyOnZoneChange);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CardState::setAttachedTo(CardItem *_attachedTo)
|
||||||
|
{
|
||||||
|
if (attachedTo == _attachedTo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
attachedTo = _attachedTo;
|
||||||
|
emit attachedToChanged(_attachedTo);
|
||||||
|
emit stateChanged();
|
||||||
|
}
|
||||||
103
cockatrice/src/game/board/card_state.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
#ifndef COCKATRICE_CARD_STATE_H
|
||||||
|
#define COCKATRICE_CARD_STATE_H
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class CardZoneLogic;
|
||||||
|
class CardItem;
|
||||||
|
class CardState : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool attacking = false;
|
||||||
|
QMap<int, int> counters;
|
||||||
|
QString annotation;
|
||||||
|
QString pt;
|
||||||
|
bool doesntUntap = false;
|
||||||
|
bool destroyOnZoneChange = false;
|
||||||
|
|
||||||
|
CardItem *attachedTo = nullptr;
|
||||||
|
CardZoneLogic *zone = nullptr;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void stateChanged();
|
||||||
|
|
||||||
|
void attackingChanged(bool newValue);
|
||||||
|
void countersChanged(const QMap<int, int> &newCounters);
|
||||||
|
void annotationChanged(const QString &newAnnotation);
|
||||||
|
void ptChanged(const QString &newPt);
|
||||||
|
void doesntUntapChanged(bool newValue);
|
||||||
|
void destroyOnZoneChangeChanged(bool newValue);
|
||||||
|
void attachedToChanged(CardItem *newAttachedTo);
|
||||||
|
void zoneChanged(CardState *changedCard, CardZoneLogic *newZone);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CardState(QObject *parent, CardZoneLogic *_zone) : QObject(parent), zone(_zone)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetState(bool keepAnnotations);
|
||||||
|
|
||||||
|
CardZoneLogic *getZone() const
|
||||||
|
{
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setZone(CardZoneLogic *_zone);
|
||||||
|
|
||||||
|
bool getAttacking() const
|
||||||
|
{
|
||||||
|
return attacking;
|
||||||
|
}
|
||||||
|
void setAttacking(bool _attacking);
|
||||||
|
|
||||||
|
const QMap<int, int> &getCounters() const
|
||||||
|
{
|
||||||
|
return counters;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertCounter(int id, int value);
|
||||||
|
|
||||||
|
void setCounter(int id, int value);
|
||||||
|
|
||||||
|
void clearCounters();
|
||||||
|
|
||||||
|
QString getAnnotation() const
|
||||||
|
{
|
||||||
|
return annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAnnotation(const QString &_annotation);
|
||||||
|
|
||||||
|
QString getPT() const
|
||||||
|
{
|
||||||
|
return pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPT(const QString &_pt);
|
||||||
|
|
||||||
|
bool getDoesntUntap() const
|
||||||
|
{
|
||||||
|
return doesntUntap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDoesntUntap(bool _doesntUntap);
|
||||||
|
|
||||||
|
bool getDestroyOnZoneChange() const
|
||||||
|
{
|
||||||
|
return destroyOnZoneChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDestroyOnZoneChange(bool _destroyOnZoneChange);
|
||||||
|
|
||||||
|
CardItem *getAttachedTo() const
|
||||||
|
{
|
||||||
|
return attachedTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAttachedTo(CardItem *_attachedTo);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_CARD_STATE_H
|
||||||
24
cockatrice/src/game/board/counter_state.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#include "counter_state.h"
|
||||||
|
|
||||||
|
#include <libcockatrice/utility/color.h>
|
||||||
|
|
||||||
|
CounterState::CounterState(int id, const QString &name, const QColor &color, int radius, int value, QObject *parent)
|
||||||
|
: QObject(parent), id(id), name(name), color(color), radius(radius), value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CounterState *CounterState::fromProto(const ServerInfo_Counter &counter, QObject *parent)
|
||||||
|
{
|
||||||
|
return new CounterState(counter.id(), QString::fromStdString(counter.name()),
|
||||||
|
convertColorToQColor(counter.counter_color()), counter.radius(), counter.count(), parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CounterState::setValue(int newValue)
|
||||||
|
{
|
||||||
|
if (newValue == value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int old = value;
|
||||||
|
value = newValue;
|
||||||
|
emit valueChanged(old, newValue);
|
||||||
|
}
|
||||||
51
cockatrice/src/game/board/counter_state.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef COCKATRICE_COUNTER_STATE_H
|
||||||
|
#define COCKATRICE_COUNTER_STATE_H
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <libcockatrice/protocol/pb/serverinfo_counter.pb.h>
|
||||||
|
|
||||||
|
class CounterState : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
CounterState(int id, const QString &name, const QColor &color, int radius, int value, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
static CounterState *fromProto(const ServerInfo_Counter &counter, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int getId() const
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
QString getName() const
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
QColor getColor() const
|
||||||
|
{
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
int getRadius() const
|
||||||
|
{
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
int getValue() const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(int newValue);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void valueChanged(int oldValue, int newValue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int id;
|
||||||
|
QString name;
|
||||||
|
QColor color;
|
||||||
|
int radius;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_COUNTER_STATE_H
|
||||||
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
#include <libcockatrice/protocol/pb/event_game_joined.pb.h>
|
#include <libcockatrice/protocol/pb/event_game_joined.pb.h>
|
||||||
|
|
||||||
Game::Game(TabGame *_tab,
|
Game::Game(QObject *_parent,
|
||||||
|
bool isLocalGame,
|
||||||
QList<AbstractClient *> &_clients,
|
QList<AbstractClient *> &_clients,
|
||||||
const Event_GameJoined &event,
|
const Event_GameJoined &event,
|
||||||
const QMap<int, QString> &_roomGameTypes)
|
const QMap<int, QString> &_roomGameTypes)
|
||||||
: AbstractGame(_tab)
|
: AbstractGame(_parent)
|
||||||
{
|
{
|
||||||
gameMetaInfo->setFromProto(event.game_info());
|
gameMetaInfo->setFromProto(event.game_info());
|
||||||
gameMetaInfo->setRoomGameTypes(_roomGameTypes);
|
gameMetaInfo->setRoomGameTypes(_roomGameTypes);
|
||||||
gameState = new GameState(this, 0, event.host_id(), tab->getTabSupervisor()->getIsLocalGame(), _clients, false,
|
gameState = new GameState(this, 0, event.host_id(), isLocalGame, _clients, false, event.resuming(), -1, false);
|
||||||
event.resuming(), -1, false);
|
|
||||||
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
|
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
|
||||||
playerManager = new PlayerManager(this, event.player_id(), event.judge(), event.spectator());
|
playerManager = new PlayerManager(this, event.player_id(), event.judge(), event.spectator());
|
||||||
gameMetaInfo->setStarted(false);
|
gameMetaInfo->setStarted(false);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file game.h
|
* @file game.h
|
||||||
* @ingroup GameLogic
|
* @ingroup GameLogic
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef COCKATRICE_GAME_H
|
#ifndef COCKATRICE_GAME_H
|
||||||
#define COCKATRICE_GAME_H
|
#define COCKATRICE_GAME_H
|
||||||
|
|
@ -16,7 +16,8 @@ class Game : public AbstractGame
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Game(TabGame *tab,
|
Game(QObject *parent,
|
||||||
|
bool isLocalGame,
|
||||||
QList<AbstractClient *> &_clients,
|
QList<AbstractClient *> &_clients,
|
||||||
const Event_GameJoined &event,
|
const Event_GameJoined &event,
|
||||||
const QMap<int, QString> &_roomGameTypes);
|
const QMap<int, QString> &_roomGameTypes);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "game_event_handler.h"
|
#include "game_event_handler.h"
|
||||||
|
|
||||||
|
#include "../game_graphics/log/message_log_widget.h"
|
||||||
#include "../interface/widgets/tabs/tab_game.h"
|
#include "../interface/widgets/tabs/tab_game.h"
|
||||||
#include "abstract_game.h"
|
#include "abstract_game.h"
|
||||||
#include "log/message_log_widget.h"
|
|
||||||
|
|
||||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||||
#include <libcockatrice/protocol/get_pb_extension.h>
|
#include <libcockatrice/protocol/get_pb_extension.h>
|
||||||
|
|
@ -36,8 +36,9 @@ GameEventHandler::GameEventHandler(AbstractGame *_game) : QObject(_game), game(_
|
||||||
void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId)
|
void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId)
|
||||||
{
|
{
|
||||||
AbstractClient *client = game->getClientForPlayer(playerId);
|
AbstractClient *client = game->getClientForPlayer(playerId);
|
||||||
if (!client)
|
if (!client) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
|
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
|
||||||
client->sendCommand(pend);
|
client->sendCommand(pend);
|
||||||
|
|
@ -46,8 +47,9 @@ void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId)
|
||||||
void GameEventHandler::sendGameCommand(const google::protobuf::Message &command, int playerId)
|
void GameEventHandler::sendGameCommand(const google::protobuf::Message &command, int playerId)
|
||||||
{
|
{
|
||||||
AbstractClient *client = game->getClientForPlayer(playerId);
|
AbstractClient *client = game->getClientForPlayer(playerId);
|
||||||
if (!client)
|
if (!client) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PendingCommand *pend = prepareGameCommand(command);
|
PendingCommand *pend = prepareGameCommand(command);
|
||||||
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
|
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
|
||||||
|
|
@ -56,8 +58,9 @@ void GameEventHandler::sendGameCommand(const google::protobuf::Message &command,
|
||||||
|
|
||||||
void GameEventHandler::commandFinished(const Response &response)
|
void GameEventHandler::commandFinished(const Response &response)
|
||||||
{
|
{
|
||||||
if (response.response_code() == Response::RespChatFlood)
|
if (response.response_code() == Response::RespChatFlood) {
|
||||||
emit gameFlooded();
|
emit gameFlooded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingCommand *GameEventHandler::prepareGameCommand(const ::google::protobuf::Message &cmd)
|
PendingCommand *GameEventHandler::prepareGameCommand(const ::google::protobuf::Message &cmd)
|
||||||
|
|
@ -96,7 +99,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
|
||||||
|
|
||||||
if (cont.has_forced_by_judge()) {
|
if (cont.has_forced_by_judge()) {
|
||||||
auto id = cont.forced_by_judge();
|
auto id = cont.forced_by_judge();
|
||||||
Player *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr);
|
PlayerLogic *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr);
|
||||||
if (judgep) {
|
if (judgep) {
|
||||||
emit setContextJudgeName(judgep->getPlayerInfo()->getName());
|
emit setContextJudgeName(judgep->getPlayerInfo()->getName());
|
||||||
} else if (game->getPlayerManager()->getSpectators().contains(id)) {
|
} else if (game->getPlayerManager()->getSpectators().contains(id)) {
|
||||||
|
|
@ -117,9 +120,11 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((game->getGameState()->getClients().size() > 1) && (playerId != -1))
|
if ((game->getGameState()->getClients().size() > 1) && (playerId != -1)) {
|
||||||
if (game->getGameState()->getClients().at(playerId) != client)
|
if (game->getGameState()->getClients().at(playerId) != client) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case GameEvent::GAME_STATE_CHANGED:
|
case GameEvent::GAME_STATE_CHANGED:
|
||||||
|
|
@ -155,7 +160,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
|
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
|
||||||
if (!player) {
|
if (!player) {
|
||||||
qCWarning(GameEventHandlerLog) << "unhandled game event: invalid player id";
|
qCWarning(GameEventHandlerLog) << "unhandled game event: invalid player id";
|
||||||
break;
|
break;
|
||||||
|
|
@ -208,11 +213,25 @@ void GameEventHandler::handleChatMessageSent(const QString &chatMessage)
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameEventHandler::handleArrowDeletion(int arrowId)
|
void GameEventHandler::handleArrowDeletion(int creatorId, int arrowId)
|
||||||
{
|
{
|
||||||
Command_DeleteArrow cmd;
|
Command_DeleteArrow cmd;
|
||||||
cmd.set_arrow_id(arrowId);
|
cmd.set_arrow_id(arrowId);
|
||||||
sendGameCommand(cmd);
|
|
||||||
|
auto preparedCommand = prepareGameCommand(cmd);
|
||||||
|
|
||||||
|
connect(preparedCommand, &PendingCommand::finished, this, [creatorId, arrowId, this](const Response &response) {
|
||||||
|
handleArrowDeletionFinished(response, creatorId, arrowId);
|
||||||
|
});
|
||||||
|
|
||||||
|
sendGameCommand(preparedCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameEventHandler::handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId)
|
||||||
|
{
|
||||||
|
if (response.response_code() == Response::RespNameNotFound) {
|
||||||
|
emit arrowDeleted(creatorId, arrowId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameEventHandler::eventSpectatorSay(const Event_GameSay &event,
|
void GameEventHandler::eventSpectatorSay(const Event_GameSay &event,
|
||||||
|
|
@ -256,7 +275,7 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
|
||||||
emit spectatorJoined(prop);
|
emit spectatorJoined(prop);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
|
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
|
||||||
if (!player) {
|
if (!player) {
|
||||||
player = game->getPlayerManager()->addPlayer(playerId, prop.user_info());
|
player = game->getPlayerManager()->addPlayer(playerId, prop.user_info());
|
||||||
emit playerJoined(prop);
|
emit playerJoined(prop);
|
||||||
|
|
@ -284,8 +303,9 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
|
||||||
if (event.game_started() && !game->getGameMetaInfo()->started()) {
|
if (event.game_started() && !game->getGameMetaInfo()->started()) {
|
||||||
game->getGameState()->setResuming(!game->getGameState()->isGameStateKnown());
|
game->getGameState()->setResuming(!game->getGameState()->isGameStateKnown());
|
||||||
game->getGameMetaInfo()->setStarted(event.game_started());
|
game->getGameMetaInfo()->setStarted(event.game_started());
|
||||||
if (game->getGameState()->isGameStateKnown())
|
if (game->getGameState()->isGameStateKnown()) {
|
||||||
emit logGameStart();
|
emit logGameStart();
|
||||||
|
}
|
||||||
game->getGameState()->setActivePlayer(event.active_player_id());
|
game->getGameState()->setActivePlayer(event.active_player_id());
|
||||||
game->getGameState()->setCurrentPhase(event.active_phase());
|
game->getGameState()->setCurrentPhase(event.active_phase());
|
||||||
} else if (!event.game_started() && game->getGameMetaInfo()->started()) {
|
} else if (!event.game_started() && game->getGameMetaInfo()->started()) {
|
||||||
|
|
@ -304,9 +324,10 @@ void GameEventHandler::processCardAttachmentsForPlayers(const Event_GameStateCha
|
||||||
const ServerInfo_Player &playerInfo = event.player_list(i);
|
const ServerInfo_Player &playerInfo = event.player_list(i);
|
||||||
const ServerInfo_PlayerProperties &prop = playerInfo.properties();
|
const ServerInfo_PlayerProperties &prop = playerInfo.properties();
|
||||||
if (!prop.spectator()) {
|
if (!prop.spectator()) {
|
||||||
Player *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0);
|
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0);
|
||||||
if (!player)
|
if (!player) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
player->processCardAttachment(playerInfo);
|
player->processCardAttachment(playerInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -316,9 +337,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
|
||||||
int eventPlayerId,
|
int eventPlayerId,
|
||||||
const GameEventContext &context)
|
const GameEventContext &context)
|
||||||
{
|
{
|
||||||
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
|
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
|
||||||
if (!player)
|
if (!player) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
const ServerInfo_PlayerProperties &prop = event.player_properties();
|
const ServerInfo_PlayerProperties &prop = event.player_properties();
|
||||||
emit playerPropertiesChanged(prop, eventPlayerId);
|
emit playerPropertiesChanged(prop, eventPlayerId);
|
||||||
|
|
||||||
|
|
@ -326,8 +348,9 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
|
||||||
switch (contextType) {
|
switch (contextType) {
|
||||||
case GameEventContext::READY_START: {
|
case GameEventContext::READY_START: {
|
||||||
bool ready = prop.ready_start();
|
bool ready = prop.ready_start();
|
||||||
if (player->getPlayerInfo()->getLocal())
|
if (player->getPlayerInfo()->getLocal()) {
|
||||||
emit localPlayerReadyStateChanged(player->getPlayerInfo()->getId(), ready);
|
emit localPlayerReadyStateChanged(player->getPlayerInfo()->getId(), ready);
|
||||||
|
}
|
||||||
if (ready) {
|
if (ready) {
|
||||||
emit logReadyStart(player);
|
emit logReadyStart(player);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -338,9 +361,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
|
||||||
case GameEventContext::CONCEDE: {
|
case GameEventContext::CONCEDE: {
|
||||||
player->setConceded(true);
|
player->setConceded(true);
|
||||||
|
|
||||||
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
|
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
|
||||||
while (playerIterator.hasNext())
|
while (playerIterator.hasNext()) {
|
||||||
playerIterator.next().value()->updateZones();
|
playerIterator.next().value()->updateZones();
|
||||||
|
}
|
||||||
|
|
||||||
emit logConcede(eventPlayerId);
|
emit logConcede(eventPlayerId);
|
||||||
|
|
||||||
|
|
@ -349,9 +373,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
|
||||||
case GameEventContext::UNCONCEDE: {
|
case GameEventContext::UNCONCEDE: {
|
||||||
player->setConceded(false);
|
player->setConceded(false);
|
||||||
|
|
||||||
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
|
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
|
||||||
while (playerIterator.hasNext())
|
while (playerIterator.hasNext()) {
|
||||||
playerIterator.next().value()->updateZones();
|
playerIterator.next().value()->updateZones();
|
||||||
|
}
|
||||||
|
|
||||||
emit logUnconcede(eventPlayerId);
|
emit logUnconcede(eventPlayerId);
|
||||||
|
|
||||||
|
|
@ -389,15 +414,16 @@ void GameEventHandler::eventJoin(const Event_Join &event, int /*eventPlayerId*/,
|
||||||
QString playerName = QString::fromStdString(playerInfo.user_info().name());
|
QString playerName = QString::fromStdString(playerInfo.user_info().name());
|
||||||
emit addPlayerToAutoCompleteList(playerName);
|
emit addPlayerToAutoCompleteList(playerName);
|
||||||
|
|
||||||
if (game->getPlayerManager()->getPlayers().contains(playerId))
|
if (game->getPlayerManager()->getPlayers().contains(playerId)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (playerInfo.spectator()) {
|
if (playerInfo.spectator()) {
|
||||||
game->getPlayerManager()->addSpectator(playerId, playerInfo);
|
game->getPlayerManager()->addSpectator(playerId, playerInfo);
|
||||||
emit logJoinSpectator(playerName);
|
emit logJoinSpectator(playerName);
|
||||||
emit spectatorJoined(playerInfo);
|
emit spectatorJoined(playerInfo);
|
||||||
} else {
|
} else {
|
||||||
Player *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info());
|
PlayerLogic *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info());
|
||||||
emit logJoinPlayer(newPlayer);
|
emit logJoinPlayer(newPlayer);
|
||||||
emit playerJoined(playerInfo);
|
emit playerJoined(playerInfo);
|
||||||
}
|
}
|
||||||
|
|
@ -425,23 +451,25 @@ QString GameEventHandler::getLeaveReason(Event_Leave::LeaveReason reason)
|
||||||
}
|
}
|
||||||
void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext & /*context*/)
|
void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext & /*context*/)
|
||||||
{
|
{
|
||||||
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
|
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
|
||||||
if (!player)
|
if (!player) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player->clear();
|
||||||
emit playerLeft(eventPlayerId);
|
emit playerLeft(eventPlayerId);
|
||||||
|
|
||||||
emit logLeave(player, getLeaveReason(event.reason()));
|
emit logLeave(player, getLeaveReason(event.reason()));
|
||||||
|
|
||||||
game->getPlayerManager()->removePlayer(eventPlayerId);
|
game->getPlayerManager()->removePlayer(eventPlayerId);
|
||||||
|
|
||||||
player->clear();
|
|
||||||
player->deleteLater();
|
player->deleteLater();
|
||||||
|
|
||||||
// Rearrange all remaining zones so that attachment relationship updates take place
|
// Rearrange all remaining zones so that attachment relationship updates take place
|
||||||
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
|
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
|
||||||
while (playerIterator.hasNext())
|
while (playerIterator.hasNext()) {
|
||||||
playerIterator.next().value()->updateZones();
|
playerIterator.next().value()->updateZones();
|
||||||
|
}
|
||||||
|
|
||||||
emitUserEvent();
|
emitUserEvent();
|
||||||
}
|
}
|
||||||
|
|
@ -460,9 +488,10 @@ void GameEventHandler::eventReverseTurn(const Event_ReverseTurn &event,
|
||||||
int eventPlayerId,
|
int eventPlayerId,
|
||||||
const GameEventContext & /*context*/)
|
const GameEventContext & /*context*/)
|
||||||
{
|
{
|
||||||
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
|
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
|
||||||
if (!player)
|
if (!player) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emit logTurnReversed(player, event.reversed());
|
emit logTurnReversed(player, event.reversed());
|
||||||
}
|
}
|
||||||
|
|
@ -490,9 +519,10 @@ void GameEventHandler::eventSetActivePlayer(const Event_SetActivePlayer &event,
|
||||||
const GameEventContext & /*context*/)
|
const GameEventContext & /*context*/)
|
||||||
{
|
{
|
||||||
game->getGameState()->setActivePlayer(event.active_player_id());
|
game->getGameState()->setActivePlayer(event.active_player_id());
|
||||||
Player *player = game->getPlayerManager()->getPlayer(event.active_player_id());
|
PlayerLogic *player = game->getPlayerManager()->getPlayer(event.active_player_id());
|
||||||
if (!player)
|
if (!player) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
emit logActivePlayer(player);
|
emit logActivePlayer(player);
|
||||||
emitUserEvent();
|
emitUserEvent();
|
||||||
}
|
}
|
||||||
|
|
|
||||||