mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-10 08:14:47 -07:00
Compare commits
222 commits
2026-02-22
...
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 |
1100 changed files with 53872 additions and 92244 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
10
.github/CONTRIBUTING.md
vendored
10
.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
|
||||||
|
|
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
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
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
|
|
||||||
|
|
|
||||||
465
.github/workflows/desktop-build.yml
vendored
465
.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,182 +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
|
|
||||||
|
|
||||||
- distro: Debian
|
allow-failure: yes
|
||||||
version: 11
|
package: skip # We are packaged in Arch already
|
||||||
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")
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
RUN --server --release --package "$package" "${args[@]}"
|
||||||
|
|
||||||
|
# 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: needs.configure.outputs.tag != null && matrix.package != 'skip'
|
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_name: ${{steps.build.outputs.name}}
|
GH_TOKEN: ${{ github.token }}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
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}}
|
|
||||||
subject-path: ${{steps.build.outputs.path}}
|
|
||||||
show-summary: false
|
show-summary: false
|
||||||
|
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}} --repo Cockatrice/Cockatrice
|
run: gh attestation verify "${{ steps.build.outputs.path }}" --repo Cockatrice/Cockatrice
|
||||||
|
|
||||||
build-vcpkg:
|
build-vcpkg:
|
||||||
strategy:
|
strategy:
|
||||||
|
|
@ -253,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.10.*
|
|
||||||
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.10.*
|
|
||||||
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.10.*
|
|
||||||
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.10.*
|
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.10.*
|
|
||||||
qt_arch: win64_msvc2022_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 }}
|
||||||
|
|
@ -468,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
|
||||||
|
|
@ -488,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
|
||||||
|
|
@ -500,52 +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 PDBs (Program Databases)
|
- 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}}-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/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_name: ${{steps.build.outputs.name}}
|
GH_TOKEN: ${{ github.token }}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
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}}
|
|
||||||
subject-path: ${{steps.build.outputs.path}}
|
|
||||||
show-summary: false
|
show-summary: false
|
||||||
|
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}} --repo Cockatrice/Cockatrice
|
run: gh attestation verify "${{ steps.build.outputs.path }}" --repo Cockatrice/Cockatrice
|
||||||
|
|
|
||||||
19
.github/workflows/desktop-lint.yml
vendored
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
|
||||||
|
|
|
||||||
61
.github/workflows/docker-release.yml
vendored
61
.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
|
|
||||||
|
|
|
||||||
26
.github/workflows/documentation-build.yml
vendored
26
.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,22 +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:
|
with:
|
||||||
submodules: recursive
|
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@v2
|
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
|
||||||
|
|
@ -48,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
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
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
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
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
|
|
||||||
|
|
@ -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 "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_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 \
|
||||||
|
|
|
||||||
99
Doxyfile
99
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.
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -1070,8 +1105,7 @@ EXCLUDE = build/ \
|
||||||
cmake/ \
|
cmake/ \
|
||||||
doc/doxygen/theme/docs/ \
|
doc/doxygen/theme/docs/ \
|
||||||
doc/doxygen/theme/include/ \
|
doc/doxygen/theme/include/ \
|
||||||
vcpkg/ \
|
vcpkg/
|
||||||
webclient/
|
|
||||||
|
|
||||||
# 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
|
||||||
|
|
@ -1887,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.
|
||||||
|
|
||||||
|
|
@ -1896,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
|
||||||
|
|
@ -1911,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 =
|
||||||
|
|
@ -2601,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
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
|
||||||
|
|
@ -54,68 +56,73 @@ set(cockatrice_SOURCES
|
||||||
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
|
||||||
|
|
@ -128,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
|
||||||
|
|
@ -170,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
|
||||||
|
|
@ -215,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
|
||||||
|
|
@ -226,6 +241,14 @@ 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
|
||||||
|
|
@ -324,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)
|
||||||
|
|
@ -538,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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -563,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"
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
<file>resources/icons/dragon.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/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/gear.svg</file>
|
||||||
|
|
@ -54,6 +55,7 @@
|
||||||
<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>
|
||||||
|
|
@ -68,6 +70,7 @@
|
||||||
<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>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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
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,16 +51,16 @@ 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>
|
||||||
|
|
|
||||||
12
cockatrice/resources/icons/filter.svg
Normal file
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 |
72
cockatrice/resources/icons/mana/C.svg
Normal file
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 |
|
|
@ -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();
|
||||||
|
|
||||||
|
|
@ -256,14 +270,26 @@ 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();
|
||||||
|
|
@ -284,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();
|
||||||
|
|
@ -359,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();
|
||||||
|
|
@ -385,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();
|
||||||
}
|
}
|
||||||
|
|
@ -759,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);
|
||||||
|
|
@ -1080,6 +1118,12 @@ void SettingsCache::setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignore
|
||||||
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setIgnoreNonBuddyUserMessages(QT_STATE_CHANGED_T _ignoreNonBuddyUserMessages)
|
||||||
|
{
|
||||||
|
ignoreNonBuddyUserMessages = static_cast<bool>(_ignoreNonBuddyUserMessages);
|
||||||
|
settings->setValue("chat/ignore_nonbuddy_messages", ignoreNonBuddyUserMessages);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
||||||
{
|
{
|
||||||
pixmapCacheSize = _pixmapCacheSize;
|
pixmapCacheSize = _pixmapCacheSize;
|
||||||
|
|
@ -1087,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;
|
||||||
|
|
@ -1101,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;
|
||||||
|
|
@ -1115,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;
|
||||||
}
|
}
|
||||||
|
|
@ -1472,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);
|
||||||
|
|
@ -1511,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>
|
||||||
|
|
@ -181,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();
|
||||||
|
|
@ -216,6 +221,7 @@ 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;
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -449,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;
|
||||||
|
|
@ -486,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;
|
||||||
|
|
@ -761,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;
|
||||||
|
|
@ -773,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;
|
||||||
|
|
@ -862,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;
|
||||||
|
|
@ -1064,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);
|
||||||
|
|
@ -1089,15 +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
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
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
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
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
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
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
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
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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file game_event_handler.h
|
* @file game_event_handler.h
|
||||||
* @ingroup GameLogic
|
* @ingroup GameLogic
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef COCKATRICE_GAME_EVENT_HANDLER_H
|
#ifndef COCKATRICE_GAME_EVENT_HANDLER_H
|
||||||
#define COCKATRICE_GAME_EVENT_HANDLER_H
|
#define COCKATRICE_GAME_EVENT_HANDLER_H
|
||||||
|
|
@ -38,7 +38,7 @@ class Event_Kicked;
|
||||||
class Event_ReverseTurn;
|
class Event_ReverseTurn;
|
||||||
class AbstractGame;
|
class AbstractGame;
|
||||||
class PendingCommand;
|
class PendingCommand;
|
||||||
class Player;
|
class PlayerLogic;
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");
|
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");
|
||||||
|
|
||||||
|
|
@ -60,7 +60,8 @@ public:
|
||||||
void handleActivePhaseChanged(int phase);
|
void handleActivePhaseChanged(int phase);
|
||||||
void handleGameLeft();
|
void handleGameLeft();
|
||||||
void handleChatMessageSent(const QString &chatMessage);
|
void handleChatMessageSent(const QString &chatMessage);
|
||||||
void handleArrowDeletion(int arrowId);
|
void handleArrowDeletion(int creatorId, int arrowId);
|
||||||
|
void handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId);
|
||||||
|
|
||||||
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
|
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
|
||||||
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
|
||||||
|
|
@ -95,7 +96,7 @@ public slots:
|
||||||
signals:
|
signals:
|
||||||
void emitUserEvent();
|
void emitUserEvent();
|
||||||
void addPlayerToAutoCompleteList(QString playerName);
|
void addPlayerToAutoCompleteList(QString playerName);
|
||||||
void localPlayerDeckSelected(Player *localPlayer, int playerId, ServerInfo_Player playerInfo);
|
void localPlayerDeckSelected(PlayerLogic *localPlayer, int playerId, ServerInfo_Player playerInfo);
|
||||||
void remotePlayerDeckSelected(QString deckList, int playerId, QString playerName);
|
void remotePlayerDeckSelected(QString deckList, int playerId, QString playerName);
|
||||||
void remotePlayersDecksSelected(QVector<QPair<int, QPair<QString, QString>>> opponentDecks);
|
void remotePlayersDecksSelected(QVector<QPair<int, QPair<QString, QString>>> opponentDecks);
|
||||||
void localPlayerSideboardLocked(int playerId, bool sideboardLocked);
|
void localPlayerSideboardLocked(int playerId, bool sideboardLocked);
|
||||||
|
|
@ -112,21 +113,22 @@ signals:
|
||||||
void containerProcessingStarted(GameEventContext context);
|
void containerProcessingStarted(GameEventContext context);
|
||||||
void setContextJudgeName(QString judgeName);
|
void setContextJudgeName(QString judgeName);
|
||||||
void containerProcessingDone();
|
void containerProcessingDone();
|
||||||
|
void arrowDeleted(int creatorId, int arrowId);
|
||||||
void logSpectatorSay(ServerInfo_User userInfo, QString message);
|
void logSpectatorSay(ServerInfo_User userInfo, QString message);
|
||||||
void logSpectatorLeave(QString name, QString reason);
|
void logSpectatorLeave(QString name, QString reason);
|
||||||
void logGameStart();
|
void logGameStart();
|
||||||
void logReadyStart(Player *player);
|
void logReadyStart(PlayerLogic *player);
|
||||||
void logNotReadyStart(Player *player);
|
void logNotReadyStart(PlayerLogic *player);
|
||||||
void logDeckSelect(Player *player, QString deckHash, int sideboardSize);
|
void logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize);
|
||||||
void logSideboardLockSet(Player *player, bool sideboardLocked);
|
void logSideboardLockSet(PlayerLogic *player, bool sideboardLocked);
|
||||||
void logConnectionStateChanged(Player *player, bool connected);
|
void logConnectionStateChanged(PlayerLogic *player, bool connected);
|
||||||
void logJoinSpectator(QString spectatorName);
|
void logJoinSpectator(QString spectatorName);
|
||||||
void logJoinPlayer(Player *player);
|
void logJoinPlayer(PlayerLogic *player);
|
||||||
void logLeave(Player *player, QString reason);
|
void logLeave(PlayerLogic *player, QString reason);
|
||||||
void logKicked();
|
void logKicked();
|
||||||
void logTurnReversed(Player *player, bool reversed);
|
void logTurnReversed(PlayerLogic *player, bool reversed);
|
||||||
void logGameClosed();
|
void logGameClosed();
|
||||||
void logActivePlayer(Player *activePlayer);
|
void logActivePlayer(PlayerLogic *activePlayer);
|
||||||
void logActivePhaseChanged(int activePhase);
|
void logActivePhaseChanged(int activePhase);
|
||||||
void logConcede(int playerId);
|
void logConcede(int playerId);
|
||||||
void logUnconcede(int playerId);
|
void logUnconcede(int playerId);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file game_meta_info.h
|
* @file game_meta_info.h
|
||||||
* @ingroup GameLogic
|
* @ingroup GameLogic
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef GAME_META_INFO_H
|
#ifndef GAME_META_INFO_H
|
||||||
#define GAME_META_INFO_H
|
#define GAME_META_INFO_H
|
||||||
|
|
@ -87,15 +87,17 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void setStarted(bool s)
|
void setStarted(bool s)
|
||||||
{
|
{
|
||||||
if (gameInfo_.started() == s)
|
if (gameInfo_.started() == s) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
gameInfo_.set_started(s);
|
gameInfo_.set_started(s);
|
||||||
emit startedChanged(s);
|
emit startedChanged(s);
|
||||||
}
|
}
|
||||||
void setSpectatorsOmniscient(bool v)
|
void setSpectatorsOmniscient(bool v)
|
||||||
{
|
{
|
||||||
if (gameInfo_.spectators_omniscient() == v)
|
if (gameInfo_.spectators_omniscient() == v) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
gameInfo_.set_spectators_omniscient(v);
|
gameInfo_.set_spectators_omniscient(v);
|
||||||
emit spectatorsOmniscienceChanged(v);
|
emit spectatorsOmniscienceChanged(v);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file game_state.h
|
* @file game_state.h
|
||||||
* @ingroup GameLogic
|
* @ingroup GameLogic
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef COCKATRICE_GAME_STATE_H
|
#ifndef COCKATRICE_GAME_STATE_H
|
||||||
#define COCKATRICE_GAME_STATE_H
|
#define COCKATRICE_GAME_STATE_H
|
||||||
|
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
#include "game_view.h"
|
|
||||||
|
|
||||||
#include "../client/settings/cache_settings.h"
|
|
||||||
#include "game_scene.h"
|
|
||||||
|
|
||||||
#include <QAction>
|
|
||||||
#include <QResizeEvent>
|
|
||||||
#include <QRubberBand>
|
|
||||||
|
|
||||||
GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, parent), rubberBand(0)
|
|
||||||
{
|
|
||||||
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
|
|
||||||
setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
|
|
||||||
setFocusPolicy(Qt::ClickFocus);
|
|
||||||
setViewportUpdateMode(BoundingRectViewportUpdate);
|
|
||||||
|
|
||||||
connect(scene, &GameScene::sceneRectChanged, this, &GameView::updateSceneRect);
|
|
||||||
|
|
||||||
connect(scene, &GameScene::sigStartRubberBand, this, &GameView::startRubberBand);
|
|
||||||
connect(scene, &GameScene::sigResizeRubberBand, this, &GameView::resizeRubberBand);
|
|
||||||
connect(scene, &GameScene::sigStopRubberBand, this, &GameView::stopRubberBand);
|
|
||||||
|
|
||||||
aCloseMostRecentZoneView = new QAction(this);
|
|
||||||
|
|
||||||
connect(aCloseMostRecentZoneView, &QAction::triggered, scene, &GameScene::closeMostRecentZoneView);
|
|
||||||
addAction(aCloseMostRecentZoneView);
|
|
||||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
|
||||||
&GameView::refreshShortcuts);
|
|
||||||
refreshShortcuts();
|
|
||||||
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameView::resizeEvent(QResizeEvent *event)
|
|
||||||
{
|
|
||||||
QGraphicsView::resizeEvent(event);
|
|
||||||
|
|
||||||
GameScene *s = dynamic_cast<GameScene *>(scene());
|
|
||||||
if (s)
|
|
||||||
s->processViewSizeChange(event->size());
|
|
||||||
|
|
||||||
updateSceneRect(scene()->sceneRect());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameView::updateSceneRect(const QRectF &rect)
|
|
||||||
{
|
|
||||||
fitInView(rect, Qt::KeepAspectRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameView::startRubberBand(const QPointF &_selectionOrigin)
|
|
||||||
{
|
|
||||||
selectionOrigin = _selectionOrigin;
|
|
||||||
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
|
|
||||||
rubberBand->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameView::resizeRubberBand(const QPointF &cursorPoint)
|
|
||||||
{
|
|
||||||
if (rubberBand)
|
|
||||||
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), cursorPoint.toPoint()).normalized());
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameView::stopRubberBand()
|
|
||||||
{
|
|
||||||
rubberBand->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameView::refreshShortcuts()
|
|
||||||
{
|
|
||||||
aCloseMostRecentZoneView->setShortcuts(
|
|
||||||
SettingsCache::instance().shortcuts().getShortcut("Player/aCloseMostRecentZoneView"));
|
|
||||||
}
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
/**
|
|
||||||
* @file message_log_widget.h
|
|
||||||
* @ingroup GameWidgets
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MESSAGELOGWIDGET_H
|
|
||||||
#define MESSAGELOGWIDGET_H
|
|
||||||
|
|
||||||
#include "../../interface/widgets/server/chat_view/chat_view.h"
|
|
||||||
#include "../zones/logic/card_zone_logic.h"
|
|
||||||
|
|
||||||
class AbstractGame;
|
|
||||||
class CardItem;
|
|
||||||
class GameEventContext;
|
|
||||||
class Player;
|
|
||||||
class PlayerEventHandler;
|
|
||||||
|
|
||||||
class MessageLogWidget : public ChatView
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
private:
|
|
||||||
enum MessageContext
|
|
||||||
{
|
|
||||||
MessageContext_None,
|
|
||||||
MessageContext_MoveCard,
|
|
||||||
MessageContext_Mulligan
|
|
||||||
};
|
|
||||||
|
|
||||||
MessageContext currentContext;
|
|
||||||
QString messagePrefix, messageSuffix;
|
|
||||||
|
|
||||||
static QPair<QString, QString> getFromStr(CardZoneLogic *zone, QString cardName, int position, bool ownerChange);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void connectToPlayerEventHandler(PlayerEventHandler *player);
|
|
||||||
MessageLogWidget(TabSupervisor *_tabSupervisor, AbstractGame *_game, QWidget *parent = nullptr);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void containerProcessingDone();
|
|
||||||
void containerProcessingStarted(const GameEventContext &context);
|
|
||||||
void logAlwaysRevealTopCard(Player *player, CardZoneLogic *zone, bool reveal);
|
|
||||||
void logAlwaysLookAtTopCard(Player *player, CardZoneLogic *zone, bool reveal);
|
|
||||||
void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName);
|
|
||||||
void logConcede(int playerId);
|
|
||||||
void logUnconcede(int playerId);
|
|
||||||
void logConnectionStateChanged(Player *player, bool connectionState);
|
|
||||||
void logCreateArrow(Player *player,
|
|
||||||
Player *startPlayer,
|
|
||||||
QString startCard,
|
|
||||||
Player *targetPlayer,
|
|
||||||
QString targetCard,
|
|
||||||
bool playerTarget);
|
|
||||||
void logCreateToken(Player *player, QString cardName, QString pt, bool faceDown);
|
|
||||||
void logDeckSelect(Player *player, QString deckHash, int sideboardSize);
|
|
||||||
void logDestroyCard(Player *player, QString cardName);
|
|
||||||
void logDrawCards(Player *player, int number, bool deckIsEmpty);
|
|
||||||
void logDumpZone(Player *player, CardZoneLogic *zone, int numberCards, bool isReversed = false);
|
|
||||||
void logFlipCard(Player *player, QString cardName, bool faceDown);
|
|
||||||
void logGameClosed();
|
|
||||||
void logGameStart();
|
|
||||||
void logGameFlooded();
|
|
||||||
void logJoin(Player *player);
|
|
||||||
void logJoinSpectator(QString name);
|
|
||||||
void logKicked();
|
|
||||||
void logLeave(Player *player, QString reason);
|
|
||||||
void logLeaveSpectator(QString name, QString reason);
|
|
||||||
void logNotReadyStart(Player *player);
|
|
||||||
void logMoveCard(Player *player,
|
|
||||||
CardItem *card,
|
|
||||||
CardZoneLogic *startZone,
|
|
||||||
int oldX,
|
|
||||||
CardZoneLogic *targetZone,
|
|
||||||
int newX);
|
|
||||||
void logMulligan(Player *player, int number);
|
|
||||||
void logReplayStarted(int gameId);
|
|
||||||
void logReadyStart(Player *player);
|
|
||||||
void logRevealCards(Player *player,
|
|
||||||
CardZoneLogic *zone,
|
|
||||||
int cardId,
|
|
||||||
QString cardName,
|
|
||||||
Player *otherPlayer,
|
|
||||||
bool faceDown,
|
|
||||||
int amount,
|
|
||||||
bool isLentToAnotherPlayer);
|
|
||||||
void logReverseTurn(Player *player, bool reversed);
|
|
||||||
void logRollDie(Player *player, int sides, const QList<uint> &rolls);
|
|
||||||
void logSay(Player *player, QString message);
|
|
||||||
void logSetActivePhase(int phase);
|
|
||||||
void logSetActivePlayer(Player *player);
|
|
||||||
void logSetAnnotation(Player *player, CardItem *card, QString newAnnotation);
|
|
||||||
void logSetCardCounter(Player *player, QString cardName, int counterId, int value, int oldValue);
|
|
||||||
void logSetCounter(Player *player, QString counterName, int value, int oldValue);
|
|
||||||
void logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap);
|
|
||||||
void logSetPT(Player *player, CardItem *card, QString newPT);
|
|
||||||
void logSetSideboardLock(Player *player, bool locked);
|
|
||||||
void logSetTapped(Player *player, CardItem *card, bool tapped);
|
|
||||||
void logShuffle(Player *player, CardZoneLogic *zone, int start, int end);
|
|
||||||
void logSpectatorSay(const ServerInfo_User &spectator, QString message);
|
|
||||||
void logUnattachCard(Player *player, QString cardName);
|
|
||||||
void logUndoDraw(Player *player, QString cardName);
|
|
||||||
void setContextJudgeName(QString player);
|
|
||||||
void appendHtmlServerMessage(const QString &html,
|
|
||||||
bool optionalIsBold = false,
|
|
||||||
QString optionalFontColor = QString()) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file phase.h
|
* @file phase.h
|
||||||
* @ingroup GameLogic
|
* @ingroup GameLogic
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef PHASE_H
|
#ifndef PHASE_H
|
||||||
#define PHASE_H
|
#define PHASE_H
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* @file event_processing_options.h
|
* @file event_processing_options.h
|
||||||
* @ingroup GameLogicPlayers
|
* @ingroup GameLogicPlayers
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
*/
|
||||||
|
//! \todo Document this file.
|
||||||
|
|
||||||
#ifndef COCKATRICE_EVENT_PROCESSING_OPTIONS_H
|
#ifndef COCKATRICE_EVENT_PROCESSING_OPTIONS_H
|
||||||
#define COCKATRICE_EVENT_PROCESSING_OPTIONS_H
|
#define COCKATRICE_EVENT_PROCESSING_OPTIONS_H
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
/**
|
|
||||||
* @file custom_zone_menu.h
|
|
||||||
* @ingroup GameMenusZones
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef COCKATRICE_CUSTOM_ZONE_MENU_H
|
|
||||||
#define COCKATRICE_CUSTOM_ZONE_MENU_H
|
|
||||||
|
|
||||||
#include <QMenu>
|
|
||||||
|
|
||||||
class Player;
|
|
||||||
class CustomZoneMenu : public QMenu
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit CustomZoneMenu(Player *player);
|
|
||||||
void retranslateUi();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Player *player;
|
|
||||||
private slots:
|
|
||||||
void clearCustomZonesMenu();
|
|
||||||
void addViewCustomZoneActionToCustomZoneMenu(QString zoneName);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // COCKATRICE_CUSTOM_ZONE_MENU_H
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
||||||
#include "player_menu.h"
|
|
||||||
|
|
||||||
#include "../../../interface/widgets/tabs/tab_game.h"
|
|
||||||
#include "../../board/card_item.h"
|
|
||||||
#include "../../zones/hand_zone.h"
|
|
||||||
#include "../../zones/pile_zone.h"
|
|
||||||
#include "../../zones/table_zone.h"
|
|
||||||
#include "card_menu.h"
|
|
||||||
#include "hand_menu.h"
|
|
||||||
|
|
||||||
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
|
|
||||||
|
|
||||||
PlayerMenu::PlayerMenu(Player *_player) : player(_player)
|
|
||||||
{
|
|
||||||
playerMenu = new TearOffMenu();
|
|
||||||
|
|
||||||
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
|
||||||
handMenu = new HandMenu(player, player->getPlayerActions(), playerMenu);
|
|
||||||
playerMenu->addMenu(handMenu);
|
|
||||||
|
|
||||||
libraryMenu = new LibraryMenu(player, playerMenu);
|
|
||||||
playerMenu->addMenu(libraryMenu);
|
|
||||||
} else {
|
|
||||||
handMenu = nullptr;
|
|
||||||
libraryMenu = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
graveMenu = new GraveyardMenu(player, playerMenu);
|
|
||||||
playerMenu->addMenu(graveMenu);
|
|
||||||
|
|
||||||
rfgMenu = new RfgMenu(player, playerMenu);
|
|
||||||
playerMenu->addMenu(rfgMenu);
|
|
||||||
|
|
||||||
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
|
||||||
sideboardMenu = new SideboardMenu(player, playerMenu);
|
|
||||||
playerMenu->addMenu(sideboardMenu);
|
|
||||||
|
|
||||||
customZonesMenu = new CustomZoneMenu(player);
|
|
||||||
playerMenu->addMenu(customZonesMenu);
|
|
||||||
playerMenu->addSeparator();
|
|
||||||
|
|
||||||
countersMenu = playerMenu->addMenu(QString());
|
|
||||||
|
|
||||||
utilityMenu = new UtilityMenu(player, playerMenu);
|
|
||||||
} else {
|
|
||||||
sideboardMenu = nullptr;
|
|
||||||
customZonesMenu = nullptr;
|
|
||||||
countersMenu = nullptr;
|
|
||||||
utilityMenu = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player->getPlayerInfo()->getLocal()) {
|
|
||||||
sayMenu = new SayMenu(player);
|
|
||||||
playerMenu->addMenu(sayMenu);
|
|
||||||
} else {
|
|
||||||
sayMenu = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
|
||||||
&PlayerMenu::refreshShortcuts);
|
|
||||||
refreshShortcuts();
|
|
||||||
|
|
||||||
retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerMenu::setMenusForGraphicItems()
|
|
||||||
{
|
|
||||||
player->getGraphicsItem()->getTableZoneGraphicsItem()->setMenu(playerMenu);
|
|
||||||
player->getGraphicsItem()->getGraveyardZoneGraphicsItem()->setMenu(graveMenu, graveMenu->aViewGraveyard);
|
|
||||||
player->getGraphicsItem()->getRfgZoneGraphicsItem()->setMenu(rfgMenu, rfgMenu->aViewRfg);
|
|
||||||
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
|
||||||
player->getGraphicsItem()->getHandZoneGraphicsItem()->setMenu(handMenu);
|
|
||||||
player->getGraphicsItem()->getDeckZoneGraphicsItem()->setMenu(libraryMenu, libraryMenu->aDrawCard);
|
|
||||||
player->getGraphicsItem()->getSideboardZoneGraphicsItem()->setMenu(sideboardMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QMenu *PlayerMenu::updateCardMenu(const CardItem *card)
|
|
||||||
{
|
|
||||||
if (!card) {
|
|
||||||
emit cardMenuUpdated(nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If is spectator (as spectators don't need card menus), return
|
|
||||||
// only update the menu if the card is actually selected
|
|
||||||
if ((player->getGame()->getPlayerManager()->isSpectator() && !player->getGame()->getPlayerManager()->isJudge()) ||
|
|
||||||
player->getGame()->getActiveCard() != card) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMenu *menu = new CardMenu(player, card, shortcutsActive);
|
|
||||||
emit cardMenuUpdated(menu);
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerMenu::retranslateUi()
|
|
||||||
{
|
|
||||||
playerMenu->setTitle(tr("Player \"%1\"").arg(player->getPlayerInfo()->getName()));
|
|
||||||
|
|
||||||
if (handMenu) {
|
|
||||||
handMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
if (libraryMenu) {
|
|
||||||
libraryMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
graveMenu->retranslateUi();
|
|
||||||
rfgMenu->retranslateUi();
|
|
||||||
|
|
||||||
if (sideboardMenu) {
|
|
||||||
sideboardMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (countersMenu) {
|
|
||||||
countersMenu->setTitle(tr("&Counters"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customZonesMenu) {
|
|
||||||
customZonesMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
|
||||||
while (counterIterator.hasNext()) {
|
|
||||||
counterIterator.next().value()->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (utilityMenu) {
|
|
||||||
utilityMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sayMenu) {
|
|
||||||
sayMenu->setTitle(tr("S&ay"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerMenu::refreshShortcuts()
|
|
||||||
{
|
|
||||||
if (shortcutsActive) {
|
|
||||||
// Judges get access to every player's menus but only want shortcuts to be set for their own.
|
|
||||||
if (player->getPlayerInfo()->getLocalOrJudge() && !player->getPlayerInfo()->getLocal()) {
|
|
||||||
setShortcutsInactive();
|
|
||||||
} else {
|
|
||||||
setShortcutsActive();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setShortcutsInactive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerMenu::setShortcutsActive()
|
|
||||||
{
|
|
||||||
shortcutsActive = true;
|
|
||||||
|
|
||||||
if (handMenu) {
|
|
||||||
handMenu->setShortcutsActive();
|
|
||||||
}
|
|
||||||
if (libraryMenu) {
|
|
||||||
libraryMenu->setShortcutsActive();
|
|
||||||
}
|
|
||||||
graveMenu->setShortcutsActive();
|
|
||||||
// No shortcuts for RfgMenu yet
|
|
||||||
|
|
||||||
if (sideboardMenu) {
|
|
||||||
sideboardMenu->setShortcutsActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
|
||||||
while (counterIterator.hasNext()) {
|
|
||||||
counterIterator.next().value()->setShortcutsActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (utilityMenu) {
|
|
||||||
utilityMenu->setShortcutsActive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerMenu::setShortcutsInactive()
|
|
||||||
{
|
|
||||||
shortcutsActive = false;
|
|
||||||
|
|
||||||
if (handMenu) {
|
|
||||||
handMenu->setShortcutsInactive();
|
|
||||||
}
|
|
||||||
if (libraryMenu) {
|
|
||||||
libraryMenu->setShortcutsInactive();
|
|
||||||
}
|
|
||||||
graveMenu->setShortcutsInactive();
|
|
||||||
// No shortcuts for RfgMenu yet
|
|
||||||
|
|
||||||
if (sideboardMenu) {
|
|
||||||
sideboardMenu->setShortcutsInactive();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
|
||||||
while (counterIterator.hasNext()) {
|
|
||||||
counterIterator.next().value()->setShortcutsInactive();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (utilityMenu) {
|
|
||||||
utilityMenu->setShortcutsInactive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
/**
|
|
||||||
* @file player_menu.h
|
|
||||||
* @ingroup GameMenusPlayers
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef COCKATRICE_PLAYER_MENU_H
|
|
||||||
#define COCKATRICE_PLAYER_MENU_H
|
|
||||||
|
|
||||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
|
||||||
#include "../player.h"
|
|
||||||
#include "custom_zone_menu.h"
|
|
||||||
#include "grave_menu.h"
|
|
||||||
#include "hand_menu.h"
|
|
||||||
#include "library_menu.h"
|
|
||||||
#include "rfg_menu.h"
|
|
||||||
#include "say_menu.h"
|
|
||||||
#include "sideboard_menu.h"
|
|
||||||
#include "utility_menu.h"
|
|
||||||
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class CardItem;
|
|
||||||
class PlayerMenu : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void cardMenuUpdated(QMenu *cardMenu);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setMenusForGraphicItems();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void refreshShortcuts();
|
|
||||||
|
|
||||||
public:
|
|
||||||
PlayerMenu(Player *player);
|
|
||||||
void retranslateUi();
|
|
||||||
|
|
||||||
QMenu *updateCardMenu(const CardItem *card);
|
|
||||||
|
|
||||||
[[nodiscard]] QMenu *getPlayerMenu() const
|
|
||||||
{
|
|
||||||
return playerMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] QMenu *getCountersMenu()
|
|
||||||
{
|
|
||||||
return countersMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] LibraryMenu *getLibraryMenu() const
|
|
||||||
{
|
|
||||||
return libraryMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] UtilityMenu *getUtilityMenu() const
|
|
||||||
{
|
|
||||||
return utilityMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool getShortcutsActive() const
|
|
||||||
{
|
|
||||||
return shortcutsActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setShortcutsActive();
|
|
||||||
void setShortcutsInactive();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Player *player;
|
|
||||||
TearOffMenu *playerMenu;
|
|
||||||
QMenu *countersMenu;
|
|
||||||
HandMenu *handMenu;
|
|
||||||
LibraryMenu *libraryMenu;
|
|
||||||
SideboardMenu *sideboardMenu;
|
|
||||||
GraveyardMenu *graveMenu;
|
|
||||||
RfgMenu *rfgMenu;
|
|
||||||
UtilityMenu *utilityMenu;
|
|
||||||
SayMenu *sayMenu;
|
|
||||||
CustomZoneMenu *customZonesMenu;
|
|
||||||
|
|
||||||
bool shortcutsActive;
|
|
||||||
|
|
||||||
void initSayMenu();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // COCKATRICE_PLAYER_MENU_H
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
#include "say_menu.h"
|
|
||||||
|
|
||||||
#include "../../../client/settings/cache_settings.h"
|
|
||||||
#include "../player.h"
|
|
||||||
#include "../player_actions.h"
|
|
||||||
|
|
||||||
SayMenu::SayMenu(Player *_player) : player(_player)
|
|
||||||
{
|
|
||||||
connect(&SettingsCache::instance().messages(), &MessageSettings::messageMacrosChanged, this, &SayMenu::initSayMenu);
|
|
||||||
initSayMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SayMenu::initSayMenu()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
int count = SettingsCache::instance().messages().getCount();
|
|
||||||
setEnabled(count > 0);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
auto *newAction = new QAction(SettingsCache::instance().messages().getMessageAt(i), this);
|
|
||||||
if (i < 10) {
|
|
||||||
newAction->setShortcut(QKeySequence("Ctrl+" + QString::number((i + 1) % 10)));
|
|
||||||
}
|
|
||||||
connect(newAction, &QAction::triggered, player->getPlayerActions(), &PlayerActions::actSayMessage);
|
|
||||||
addAction(newAction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue