mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
Compare commits
113 commits
2026-02-22
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
339 changed files with 38067 additions and 29899 deletions
|
|
@ -9,20 +9,18 @@ RUN apt-get update && \
|
||||||
file \
|
file \
|
||||||
g++ \
|
g++ \
|
||||||
git \
|
git \
|
||||||
libgl-dev \
|
|
||||||
liblzma-dev \
|
liblzma-dev \
|
||||||
libmariadb-dev-compat \
|
libmariadb-dev-compat \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt6multimedia6 \
|
libqt5multimedia5-plugins \
|
||||||
libqt6sql6-mysql \
|
libqt5sql5-mysql \
|
||||||
libqt6svg6-dev \
|
libqt5svg5-dev \
|
||||||
libqt6websockets6-dev \
|
libqt5websockets5-dev \
|
||||||
ninja-build \
|
ninja-build \
|
||||||
protobuf-compiler \
|
protobuf-compiler \
|
||||||
qt6-image-formats-plugins \
|
qt5-image-formats-plugins \
|
||||||
qt6-l10n-tools \
|
qtmultimedia5-dev \
|
||||||
qt6-multimedia-dev \
|
qttools5-dev \
|
||||||
qt6-tools-dev \
|
qttools5-dev-tools \
|
||||||
qt6-tools-dev-tools \
|
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
|
||||||
29
.ci/Ubuntu26.04/Dockerfile
Normal file
29
.ci/Ubuntu26.04/Dockerfile
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
FROM ubuntu:26.04
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
ca-certificates \
|
||||||
|
ccache \
|
||||||
|
clang-format \
|
||||||
|
cmake \
|
||||||
|
file \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
libgl-dev \
|
||||||
|
liblzma-dev \
|
||||||
|
libmariadb-dev-compat \
|
||||||
|
libprotobuf-dev \
|
||||||
|
libqt6multimedia6 \
|
||||||
|
libqt6sql6-mysql \
|
||||||
|
ninja-build \
|
||||||
|
protobuf-compiler \
|
||||||
|
qt6-image-formats-plugins \
|
||||||
|
qt6-l10n-tools \
|
||||||
|
qt6-multimedia-dev \
|
||||||
|
qt6-svg-dev \
|
||||||
|
qt6-tools-dev \
|
||||||
|
qt6-tools-dev-tools \
|
||||||
|
qt6-websockets-dev \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
@ -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
|
||||||
|
|
@ -251,9 +271,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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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,6 +17,7 @@ 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>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>
|
||||||
|
|
@ -28,6 +28,8 @@ Available pre-compiled binaries for installation:
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
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!
|
||||||
|
|
|
||||||
24
.github/dependabot.yml
vendored
24
.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) & macOS Intel triplet broken with newer releases)
|
||||||
# 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:
|
||||||
|
|
|
||||||
159
.github/workflows/desktop-build.yml
vendored
159
.github/workflows/desktop-build.yml
vendored
|
|
@ -38,15 +38,15 @@ on:
|
||||||
- 'vcpkg.json'
|
- 'vcpkg.json'
|
||||||
- 'vcpkg'
|
- 'vcpkg'
|
||||||
|
|
||||||
# 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}}
|
||||||
|
|
@ -142,21 +142,28 @@ jobs:
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
version: 22.04
|
version: 22.04
|
||||||
package: DEB
|
package: DEB
|
||||||
|
test: skip # Running tests on all distros is superfluous
|
||||||
|
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
version: 24.04
|
version: 24.04
|
||||||
package: DEB
|
package: DEB
|
||||||
|
|
||||||
|
- distro: Ubuntu
|
||||||
|
version: 26.04
|
||||||
|
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}}
|
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
|
||||||
# Cache size over the entire repo is 10Gi:
|
# Cache size over the entire repo is 10Gi:
|
||||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
||||||
CCACHE_SIZE: 500M
|
CCACHE_SIZE: 550M
|
||||||
|
CCACHE_EVICTION_AGE: 7d
|
||||||
CMAKE_GENERATOR: 'Ninja'
|
CMAKE_GENERATOR: 'Ninja'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -180,29 +187,45 @@ jobs:
|
||||||
- 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}}'
|
||||||
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
|
server_only: '${{matrix.server_only}}'
|
||||||
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
|
if [[ $server_only == yes ]]; then
|
||||||
.ci/name_build.sh
|
args+=(--no-client)
|
||||||
|
fi
|
||||||
|
if [[ $GITHUB_REF == "refs/heads/master" ]]; then
|
||||||
|
args+=(--evict-ccache "$CCACHE_EVICTION_AGE")
|
||||||
|
fi
|
||||||
|
args+=(--ccache "$CCACHE_SIZE")
|
||||||
|
args+=(--cmake-generator "$CMAKE_GENERATOR")
|
||||||
|
args+=(--suffix "$SUFFIX")
|
||||||
|
RUN --server --release --package "$package" "${args[@]}"
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
|
||||||
|
- name: Delete remote compiler cache (ccache)
|
||||||
|
if: github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
if gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}; then
|
||||||
|
echo "Cache deleted successfully"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Save updated compiler cache (ccache)
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: actions/cache/save@v5
|
uses: actions/cache/save@v5
|
||||||
with:
|
with:
|
||||||
|
|
@ -212,29 +235,28 @@ jobs:
|
||||||
- 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
|
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
|
archive: false
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- 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}}
|
GH_TOKEN: ${{github.token}}
|
||||||
tag_name: ${{needs.configure.outputs.tag}}
|
tag_name: ${{needs.configure.outputs.tag}}
|
||||||
asset_name: ${{steps.build.outputs.name}}
|
asset_name: ${{steps.build.outputs.fullname}}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
asset_path: ${{steps.build.outputs.path}}
|
||||||
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}}
|
subject-path: ${{steps.build.outputs.path}}
|
||||||
show-summary: false
|
show-summary: false
|
||||||
|
|
||||||
|
|
@ -259,12 +281,12 @@ jobs:
|
||||||
override_target: 13
|
override_target: 13
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS13_Intel"
|
package_suffix: "-macOS13_Intel"
|
||||||
artifact_name: macOS13_Intel-package
|
qt_version: 6.11.*
|
||||||
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
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
ccache_eviction_age: 7d
|
||||||
|
|
||||||
- os: macOS
|
- os: macOS
|
||||||
target: 14
|
target: 14
|
||||||
|
|
@ -274,12 +296,12 @@ jobs:
|
||||||
type: Release
|
type: Release
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS14"
|
package_suffix: "-macOS14"
|
||||||
artifact_name: macOS14-package
|
qt_version: 6.11.*
|
||||||
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
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
ccache_eviction_age: 7d
|
||||||
|
|
||||||
- os: macOS
|
- os: macOS
|
||||||
target: 15
|
target: 15
|
||||||
|
|
@ -289,12 +311,12 @@ jobs:
|
||||||
type: Release
|
type: Release
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-macOS15"
|
package_suffix: "-macOS15"
|
||||||
artifact_name: macOS15-package
|
qt_version: 6.11.*
|
||||||
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
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
ccache_eviction_age: 7d
|
||||||
|
|
||||||
- os: macOS
|
- os: macOS
|
||||||
target: 15
|
target: 15
|
||||||
|
|
@ -302,32 +324,20 @@ jobs:
|
||||||
soc: Apple
|
soc: Apple
|
||||||
xcode: "16.4"
|
xcode: "16.4"
|
||||||
type: Debug
|
type: Debug
|
||||||
qt_version: 6.10.*
|
qt_version: 6.11.*
|
||||||
qt_arch: clang_64
|
qt_arch: clang_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cmake_generator: Ninja
|
cmake_generator: Ninja
|
||||||
use_ccache: 1
|
use_ccache: 1
|
||||||
|
ccache_eviction_age: 7d
|
||||||
- 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
|
type: Release
|
||||||
make_package: 1
|
make_package: 1
|
||||||
package_suffix: "-Win10"
|
package_suffix: "-Win10"
|
||||||
artifact_name: Windows10-installer
|
qt_version: 6.11.*
|
||||||
qt_version: 6.10.*
|
|
||||||
qt_arch: win64_msvc2022_64
|
qt_arch: win64_msvc2022_64
|
||||||
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
qt_modules: qtimageformats qtmultimedia qtwebsockets
|
||||||
cmake_generator: "Visual Studio 17 2022"
|
cmake_generator: "Visual Studio 17 2022"
|
||||||
|
|
@ -336,11 +346,12 @@ jobs:
|
||||||
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:
|
# Cache size over the entire repo is 10Gi:
|
||||||
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
||||||
CCACHE_SIZE: 500M
|
CCACHE_SIZE: 550M
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
@ -351,7 +362,7 @@ jobs:
|
||||||
- name: Add msbuild to PATH
|
- name: 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
|
||||||
|
|
||||||
|
|
@ -371,15 +382,12 @@ jobs:
|
||||||
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: Restore thin Qt ${{ steps.resolve_qt_version.outputs.version }} libraries (${{ matrix.soc }} macOS)
|
||||||
|
|
@ -396,10 +404,10 @@ jobs:
|
||||||
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:
|
||||||
cache: false
|
|
||||||
version: ${{ steps.resolve_qt_version.outputs.version }}
|
version: ${{ steps.resolve_qt_version.outputs.version }}
|
||||||
arch: ${{matrix.qt_arch}}
|
arch: ${{matrix.qt_arch}}
|
||||||
modules: ${{matrix.qt_modules}}
|
modules: ${{matrix.qt_modules}}
|
||||||
|
cache: false
|
||||||
dir: ${{github.workspace}}
|
dir: ${{github.workspace}}
|
||||||
|
|
||||||
- name: Thin Qt libraries (${{ matrix.soc }} macOS)
|
- name: Thin Qt libraries (${{ matrix.soc }} macOS)
|
||||||
|
|
@ -417,11 +425,18 @@ jobs:
|
||||||
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
|
||||||
|
aqtsource: git+https://github.com/miurahr/aqtinstall.git
|
||||||
|
version: ${{ steps.resolve_qt_version.outputs.version }}
|
||||||
arch: ${{matrix.qt_arch}}
|
arch: ${{matrix.qt_arch}}
|
||||||
modules: ${{matrix.qt_modules}}
|
modules: ${{matrix.qt_modules}}
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
|
- name: Install NSIS
|
||||||
|
if: matrix.os == 'Windows'
|
||||||
|
shell: bash
|
||||||
|
run: choco install nsis
|
||||||
|
|
||||||
- name: Setup vcpkg cache
|
- name: Setup vcpkg cache
|
||||||
id: vcpkg-cache
|
id: vcpkg-cache
|
||||||
uses: TAServers/vcpkg-cache@v3
|
uses: TAServers/vcpkg-cache@v3
|
||||||
|
|
@ -448,19 +463,30 @@ jobs:
|
||||||
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'
|
DEVELOPER_DIR: '/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer'
|
||||||
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
||||||
|
CCACHE_EVICTION_AGE: ${{ matrix.ccache_eviction_age }}
|
||||||
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
|
||||||
|
- name: Delete remote compiler cache (ccache)
|
||||||
|
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1 && steps.ccache_restore.outputs.cache-hit
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
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' && matrix.use_ccache == 1
|
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
|
||||||
uses: actions/cache/save@v5
|
uses: actions/cache/save@v5
|
||||||
env:
|
|
||||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
|
||||||
with:
|
with:
|
||||||
path: ${{env.CCACHE_DIR}}
|
path: ${{env.CCACHE_DIR}}
|
||||||
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
|
||||||
- name: Sign app bundle
|
- name: Sign app bundle
|
||||||
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
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 }}
|
||||||
|
|
@ -472,7 +498,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Notarize app bundle
|
- name: Notarize app bundle
|
||||||
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
if: 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_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
|
||||||
|
|
@ -504,19 +530,19 @@ jobs:
|
||||||
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}}
|
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
|
archive: false
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload PDBs (Program Databases)
|
- name: 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
|
name: ${{steps.build.outputs.name}}-PDBs
|
||||||
path: |
|
path: |
|
||||||
build/cockatrice/Release/*.pdb
|
build/cockatrice/Release/*.pdb
|
||||||
build/oracle/Release/*.pdb
|
build/oracle/Release/*.pdb
|
||||||
|
|
@ -524,22 +550,21 @@ jobs:
|
||||||
if-no-files-found: error
|
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}}
|
GH_TOKEN: ${{github.token}}
|
||||||
tag_name: ${{needs.configure.outputs.tag}}
|
tag_name: ${{needs.configure.outputs.tag}}
|
||||||
asset_name: ${{steps.build.outputs.name}}
|
asset_name: ${{steps.build.outputs.fullname}}
|
||||||
asset_path: ${{steps.build.outputs.path}}
|
asset_path: ${{steps.build.outputs.path}}
|
||||||
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}}
|
subject-path: ${{steps.build.outputs.path}}
|
||||||
show-summary: false
|
show-summary: false
|
||||||
|
|
||||||
|
|
|
||||||
4
.github/workflows/desktop-lint.yml
vendored
4
.github/workflows/desktop-lint.yml
vendored
|
|
@ -20,13 +20,13 @@ 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
|
||||||
|
|
|
||||||
20
.github/workflows/docker-release.yml
vendored
20
.github/workflows/docker-release.yml
vendored
|
|
@ -13,6 +13,11 @@ on:
|
||||||
- '.github/workflows/docker-release.yml'
|
- '.github/workflows/docker-release.yml'
|
||||||
- 'Dockerfile'
|
- 'Dockerfile'
|
||||||
|
|
||||||
|
# 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.ref_type != 'tag' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
name: amd64 & arm64
|
name: amd64 & arm64
|
||||||
|
|
@ -27,7 +32,7 @@ jobs:
|
||||||
|
|
||||||
- name: Docker metadata
|
- name: Docker metadata
|
||||||
id: metadata
|
id: metadata
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
ghcr.io/cockatrice/servatrice
|
ghcr.io/cockatrice/servatrice
|
||||||
|
|
@ -41,26 +46,27 @@ jobs:
|
||||||
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
|
||||||
|
|
||||||
- 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: github.ref_type == 'tag'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ github.token }}
|
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:
|
||||||
context: .
|
context: .
|
||||||
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 }}
|
labels: ${{ steps.metadata.outputs.labels }}
|
||||||
cache-from: type=gha
|
annotations: ${{ steps.metadata.outputs.annotations }}
|
||||||
cache-to: type=gha,mode=max
|
cache-from: type=gha,scope=servatrice
|
||||||
|
cache-to: type=gha,mode=max,scope=servatrice
|
||||||
|
|
|
||||||
2
.github/workflows/translations-pull.yml
vendored
2
.github/workflows/translations-pull.yml
vendored
|
|
@ -16,7 +16,7 @@ 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
|
||||||
|
|
|
||||||
4
.github/workflows/translations-push.yml
vendored
4
.github/workflows/translations-push.yml
vendored
|
|
@ -16,7 +16,7 @@ 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
|
||||||
|
|
@ -46,7 +46,7 @@ jobs:
|
||||||
|
|
||||||
- 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: |
|
||||||
|
|
|
||||||
2
.github/workflows/web-lint.yml
vendored
2
.github/workflows/web-lint.yml
vendored
|
|
@ -10,7 +10,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ESLint:
|
ESLint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
|
|
||||||
|
|
@ -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.0.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
|
||||||
|
|
@ -254,7 +254,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 +330,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)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ Latest <kbd>beta</kbd> version:
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
@ -109,7 +109,7 @@ Cockatrice tries to use the [Google Developer Documentation Style Guide](https:/
|
||||||
|
|
||||||
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>, <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>
|
||||||
|
|
||||||
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) [](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,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
|
||||||
|
|
@ -563,6 +564,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>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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 |
|
|
@ -89,6 +89,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@
|
||||||
#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();
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,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();
|
||||||
|
|
@ -385,6 +388,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();
|
||||||
}
|
}
|
||||||
|
|
@ -1115,257 +1125,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;
|
||||||
}
|
}
|
||||||
|
|
@ -1478,6 +1252,24 @@ void SettingsCache::setRememberGameSettings(const bool _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);
|
||||||
|
|
@ -1519,6 +1311,18 @@ void SettingsCache::setRoundCardCorners(bool _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();
|
||||||
|
|
|
||||||
|
|
@ -330,10 +330,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 +457,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;
|
||||||
|
|
@ -862,6 +878,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;
|
||||||
|
|
@ -1089,6 +1117,9 @@ 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);
|
||||||
|
|
@ -1099,5 +1130,7 @@ public slots:
|
||||||
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,6 +11,8 @@ 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)
|
||||||
|
|
@ -36,7 +38,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
|
||||||
|
|
|
||||||
|
|
@ -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)},
|
||||||
|
|
@ -560,12 +563,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 +598,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 +628,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)},
|
||||||
|
|
|
||||||
|
|
@ -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*> [']
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
#include "abstract_game.h"
|
#include "abstract_game.h"
|
||||||
|
|
||||||
|
#include "../interface/widgets/tabs/tab_game.h"
|
||||||
#include "player/player.h"
|
#include "player/player.h"
|
||||||
|
|
||||||
AbstractGame::AbstractGame(TabGame *_tab) : tab(_tab)
|
AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab)
|
||||||
{
|
{
|
||||||
gameMetaInfo = new GameMetaInfo(this);
|
gameMetaInfo = new GameMetaInfo(this);
|
||||||
gameEventHandler = new GameEventHandler(this);
|
gameEventHandler = new GameEventHandler(this);
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
#include "abstract_card_drag_item.h"
|
#include "abstract_card_drag_item.h"
|
||||||
|
|
||||||
#include "../../client/settings/cache_settings.h"
|
#include "../../client/settings/cache_settings.h"
|
||||||
|
#include "../z_values.h"
|
||||||
|
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QGraphicsSceneMouseEvent>
|
#include <QGraphicsSceneMouseEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
static const float CARD_WIDTH_HALF = CARD_WIDTH / 2;
|
|
||||||
static const float CARD_HEIGHT_HALF = CARD_HEIGHT / 2;
|
|
||||||
const QColor GHOST_MASK = QColor(255, 255, 255, 50);
|
const QColor GHOST_MASK = QColor(255, 255, 255, 50);
|
||||||
|
|
||||||
AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||||
|
|
@ -18,19 +17,19 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||||
{
|
{
|
||||||
if (parentDrag) {
|
if (parentDrag) {
|
||||||
parentDrag->addChildDrag(this);
|
parentDrag->addChildDrag(this);
|
||||||
setZValue(2000000007 + hotSpot.x() * 1000000 + hotSpot.y() * 1000 + 1000);
|
setZValue(ZValues::childDragZValue(hotSpot.x(), hotSpot.y()));
|
||||||
connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
|
connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
|
||||||
} else {
|
} else {
|
||||||
hotSpot = QPointF{qBound(0.0, hotSpot.x(), static_cast<qreal>(CARD_WIDTH - 1)),
|
hotSpot = QPointF{qBound(0.0, hotSpot.x(), CardDimensions::WIDTH_F - 1),
|
||||||
qBound(0.0, hotSpot.y(), static_cast<qreal>(CARD_HEIGHT - 1))};
|
qBound(0.0, hotSpot.y(), CardDimensions::HEIGHT_F - 1)};
|
||||||
setCursor(Qt::ClosedHandCursor);
|
setCursor(Qt::ClosedHandCursor);
|
||||||
setZValue(2000000007);
|
setZValue(ZValues::DRAG_ITEM);
|
||||||
}
|
}
|
||||||
if (item->getTapped())
|
if (item->getTapped())
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate(CARD_WIDTH_HALF, CARD_HEIGHT_HALF)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(90)
|
.rotate(90)
|
||||||
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
|
|
||||||
setCacheMode(DeviceCoordinateCache);
|
setCacheMode(DeviceCoordinateCache);
|
||||||
|
|
||||||
|
|
@ -47,7 +46,7 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||||
QPainterPath AbstractCardDragItem::shape() const
|
QPainterPath AbstractCardDragItem::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public:
|
||||||
AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
|
AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
|
||||||
[[nodiscard]] QRectF boundingRect() const override
|
[[nodiscard]] QRectF boundingRect() const override
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
|
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
[[nodiscard]] QPainterPath shape() const override;
|
[[nodiscard]] QPainterPath shape() const override;
|
||||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../../client/settings/cache_settings.h"
|
#include "../../client/settings/cache_settings.h"
|
||||||
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
||||||
#include "../game_scene.h"
|
#include "../game_scene.h"
|
||||||
|
#include "../z_values.h"
|
||||||
|
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
|
|
@ -38,13 +39,13 @@ AbstractCardItem::~AbstractCardItem()
|
||||||
|
|
||||||
QRectF AbstractCardItem::boundingRect() const
|
QRectF AbstractCardItem::boundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
|
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainterPath AbstractCardItem::shape() const
|
QPainterPath AbstractCardItem::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
@ -215,9 +216,9 @@ void AbstractCardItem::setHovered(bool _hovered)
|
||||||
if (_hovered)
|
if (_hovered)
|
||||||
processHoverEvent();
|
processHoverEvent();
|
||||||
isHovered = _hovered;
|
isHovered = _hovered;
|
||||||
setZValue(_hovered ? 2000000004 : realZValue);
|
setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue);
|
||||||
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
|
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
|
||||||
setTransformOriginPoint(_hovered ? CARD_WIDTH / 2 : 0, _hovered ? CARD_HEIGHT / 2 : 0);
|
setTransformOriginPoint(_hovered ? CardDimensions::WIDTH_HALF_F : 0, _hovered ? CardDimensions::HEIGHT_HALF_F : 0);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,9 +274,9 @@ void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
|
||||||
else {
|
else {
|
||||||
tapAngle = tapped ? 90 : 0;
|
tapAngle = tapped ? 90 : 0;
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(tapAngle)
|
.rotate(tapAngle)
|
||||||
.translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define ABSTRACTCARDITEM_H
|
#define ABSTRACTCARDITEM_H
|
||||||
|
|
||||||
#include "../../game_graphics/board/graphics_item_type.h"
|
#include "../../game_graphics/board/graphics_item_type.h"
|
||||||
|
#include "../card_dimensions.h"
|
||||||
#include "arrow_target.h"
|
#include "arrow_target.h"
|
||||||
|
|
||||||
#include <libcockatrice/card/printing/exact_card.h>
|
#include <libcockatrice/card/printing/exact_card.h>
|
||||||
|
|
@ -15,9 +16,6 @@
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
|
|
||||||
const int CARD_WIDTH = 72;
|
|
||||||
const int CARD_HEIGHT = 102;
|
|
||||||
|
|
||||||
class AbstractCardItem : public ArrowTarget
|
class AbstractCardItem : public ArrowTarget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define COUNTER_H
|
#define COUNTER_H
|
||||||
|
|
||||||
#include "../../interface/widgets/menus/tearoff_menu.h"
|
#include "../../interface/widgets/menus/tearoff_menu.h"
|
||||||
|
#include "../player/menu/abstract_player_component.h"
|
||||||
|
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
|
|
@ -18,7 +19,7 @@ class QKeyEvent;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
class AbstractCounter : public QObject, public QGraphicsItem
|
class AbstractCounter : public QObject, public QGraphicsItem, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_INTERFACES(QGraphicsItem)
|
Q_INTERFACES(QGraphicsItem)
|
||||||
|
|
@ -56,10 +57,10 @@ public:
|
||||||
QGraphicsItem *parent = nullptr);
|
QGraphicsItem *parent = nullptr);
|
||||||
~AbstractCounter() override;
|
~AbstractCounter() override;
|
||||||
|
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
void setValue(int _value);
|
void setValue(int _value);
|
||||||
void setShortcutsActive();
|
void setShortcutsActive() override;
|
||||||
void setShortcutsInactive();
|
void setShortcutsInactive() override;
|
||||||
void delCounter();
|
void delCounter();
|
||||||
|
|
||||||
QMenu *getMenu() const
|
QMenu *getMenu() const
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../player/player_actions.h"
|
#include "../player/player_actions.h"
|
||||||
#include "../player/player_target.h"
|
#include "../player/player_target.h"
|
||||||
|
#include "../z_values.h"
|
||||||
#include "../zones/card_zone.h"
|
#include "../zones/card_zone.h"
|
||||||
#include "card_item.h"
|
#include "card_item.h"
|
||||||
|
|
||||||
|
|
@ -18,12 +19,13 @@
|
||||||
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
|
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_delete_arrow.pb.h>
|
#include <libcockatrice/protocol/pb/command_delete_arrow.pb.h>
|
||||||
#include <libcockatrice/utility/color.h>
|
#include <libcockatrice/utility/color.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
|
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
|
||||||
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false),
|
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false),
|
||||||
color(_color), fullColor(true)
|
color(_color), fullColor(true)
|
||||||
{
|
{
|
||||||
setZValue(2000000005);
|
setZValue(ZValues::ARROWS);
|
||||||
|
|
||||||
if (startItem)
|
if (startItem)
|
||||||
startItem->addArrowFrom(this);
|
startItem->addArrowFrom(this);
|
||||||
|
|
@ -238,16 +240,16 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
|
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
|
||||||
if (startZone->getName() == "hand") {
|
if (startZone->getName() == ZoneNames::HAND) {
|
||||||
startCard->playCard(false);
|
startCard->playCard(false);
|
||||||
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
||||||
bool playToStack = SettingsCache::instance().getPlayToStack();
|
bool playToStack = SettingsCache::instance().getPlayToStack();
|
||||||
if (ci &&
|
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
|
||||||
((!playToStack && ci->getUiAttributes().tableRow == 3) ||
|
(playToStack && ci->getUiAttributes().tableRow != 0 &&
|
||||||
(playToStack && ci->getUiAttributes().tableRow != 0 && startCard->getZone()->getName() != "stack")))
|
startCard->getZone()->getName() != ZoneNames::STACK)))
|
||||||
cmd.set_start_zone("stack");
|
cmd.set_start_zone(ZoneNames::STACK);
|
||||||
else
|
else
|
||||||
cmd.set_start_zone(playToStack ? "stack" : "table");
|
cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteInPhase != 0) {
|
if (deleteInPhase != 0) {
|
||||||
|
|
@ -317,7 +319,7 @@ void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
|
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
|
||||||
{
|
{
|
||||||
// do nothing if target is already attached to another card or is not in play
|
// do nothing if target is already attached to another card or is not in play
|
||||||
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != "table") {
|
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,12 +327,12 @@ void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCar
|
||||||
CardZoneLogic *targetZone = targetCard->getZone();
|
CardZoneLogic *targetZone = targetCard->getZone();
|
||||||
|
|
||||||
// move card onto table first if attaching from some other zone
|
// move card onto table first if attaching from some other zone
|
||||||
if (startZone->getName() != "table") {
|
if (startZone->getName() != ZoneNames::TABLE) {
|
||||||
player->getPlayerActions()->playCardToTable(startCard, false);
|
player->getPlayerActions()->playCardToTable(startCard, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_AttachCard cmd;
|
Command_AttachCard cmd;
|
||||||
cmd.set_start_zone("table");
|
cmd.set_start_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_id(startCard->getId());
|
cmd.set_card_id(startCard->getId());
|
||||||
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
|
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone(targetZone->getName().toStdString());
|
cmd.set_target_zone(targetZone->getName().toStdString());
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,10 @@
|
||||||
CardDragItem::CardDragItem(CardItem *_item,
|
CardDragItem::CardDragItem(CardItem *_item,
|
||||||
int _id,
|
int _id,
|
||||||
const QPointF &_hotSpot,
|
const QPointF &_hotSpot,
|
||||||
bool _faceDown,
|
bool _forceFaceDown,
|
||||||
AbstractCardDragItem *parentDrag)
|
AbstractCardDragItem *parentDrag)
|
||||||
: AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), faceDown(_faceDown), occupied(false), currentZone(0)
|
: AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), forceFaceDown(_forceFaceDown), occupied(false),
|
||||||
|
currentZone(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class CardDragItem : public AbstractCardDragItem
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
int id;
|
int id;
|
||||||
bool faceDown;
|
bool forceFaceDown;
|
||||||
bool occupied;
|
bool occupied;
|
||||||
CardZone *currentZone;
|
CardZone *currentZone;
|
||||||
|
|
||||||
|
|
@ -24,15 +24,15 @@ public:
|
||||||
CardDragItem(CardItem *_item,
|
CardDragItem(CardItem *_item,
|
||||||
int _id,
|
int _id,
|
||||||
const QPointF &_hotSpot,
|
const QPointF &_hotSpot,
|
||||||
bool _faceDown,
|
bool _forceFaceDown,
|
||||||
AbstractCardDragItem *parentDrag = 0);
|
AbstractCardDragItem *parentDrag = 0);
|
||||||
int getId() const
|
int getId() const
|
||||||
{
|
{
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
bool getFaceDown() const
|
bool isForceFaceDown() const
|
||||||
{
|
{
|
||||||
return faceDown;
|
return forceFaceDown;
|
||||||
}
|
}
|
||||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
void updatePosition(const QPointF &cursorScenePos) override;
|
void updatePosition(const QPointF &cursorScenePos) override;
|
||||||
|
|
|
||||||
|
|
@ -212,10 +212,12 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets the fields that should be reset after a zone transition
|
||||||
|
*/
|
||||||
void CardItem::resetState(bool keepAnnotations)
|
void CardItem::resetState(bool keepAnnotations)
|
||||||
{
|
{
|
||||||
attacking = false;
|
attacking = false;
|
||||||
facedown = false;
|
|
||||||
counters.clear();
|
counters.clear();
|
||||||
pt.clear();
|
pt.clear();
|
||||||
if (!keepAnnotations) {
|
if (!keepAnnotations) {
|
||||||
|
|
@ -251,10 +253,10 @@ void CardItem::processCardInfo(const ServerInfo_Card &_info)
|
||||||
setDoesntUntap(_info.doesnt_untap());
|
setDoesntUntap(_info.doesnt_untap());
|
||||||
}
|
}
|
||||||
|
|
||||||
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown)
|
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown)
|
||||||
{
|
{
|
||||||
deleteDragItem();
|
deleteDragItem();
|
||||||
dragItem = new CardDragItem(this, _id, _pos, faceDown);
|
dragItem = new CardDragItem(this, _id, _pos, forceFaceDown);
|
||||||
dragItem->setVisible(false);
|
dragItem->setVisible(false);
|
||||||
scene()->addItem(dragItem);
|
scene()->addItem(dragItem);
|
||||||
dragItem->updatePosition(_scenePos);
|
dragItem->updatePosition(_scenePos);
|
||||||
|
|
@ -352,7 +354,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
|
||||||
// Use the buttonDownPos to align the hot spot with the position when
|
// Use the buttonDownPos to align the hot spot with the position when
|
||||||
// the user originally clicked
|
// the user originally clicked
|
||||||
createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), facedown || forceFaceDown);
|
createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), forceFaceDown);
|
||||||
dragItem->grabMouse();
|
dragItem->grabMouse();
|
||||||
|
|
||||||
int childIndex = 0;
|
int childIndex = 0;
|
||||||
|
|
@ -365,7 +367,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
if (zone->getHasCardAttr())
|
if (zone->getHasCardAttr())
|
||||||
childPos = card->pos() - pos();
|
childPos = card->pos() - pos();
|
||||||
else
|
else
|
||||||
childPos = QPointF(childIndex * CARD_WIDTH / 2, 0);
|
childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0);
|
||||||
CardDragItem *drag =
|
CardDragItem *drag =
|
||||||
new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem);
|
new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem);
|
||||||
drag->setPos(dragItem->pos() + childPos);
|
drag->setPos(dragItem->pos() + childPos);
|
||||||
|
|
@ -474,9 +476,9 @@ bool CardItem::animationEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate(CARD_WIDTH_HALF, CARD_HEIGHT_HALF)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(tapAngle)
|
.rotate(tapAngle)
|
||||||
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
setHovered(false);
|
setHovered(false);
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ class QAction;
|
||||||
class QColor;
|
class QColor;
|
||||||
|
|
||||||
const int MAX_COUNTERS_ON_CARD = 999;
|
const int MAX_COUNTERS_ON_CARD = 999;
|
||||||
const float CARD_WIDTH_HALF = CARD_WIDTH / 2;
|
|
||||||
const float CARD_HEIGHT_HALF = CARD_HEIGHT / 2;
|
|
||||||
const int ROTATION_DEGREES_PER_FRAME = 10;
|
const int ROTATION_DEGREES_PER_FRAME = 10;
|
||||||
|
|
||||||
class CardItem : public AbstractCardItem
|
class CardItem : public AbstractCardItem
|
||||||
|
|
@ -142,7 +140,7 @@ public:
|
||||||
void processCardInfo(const ServerInfo_Card &_info);
|
void processCardInfo(const ServerInfo_Card &_info);
|
||||||
|
|
||||||
bool animationEvent();
|
bool animationEvent();
|
||||||
CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown);
|
CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown);
|
||||||
void deleteDragItem();
|
void deleteDragItem();
|
||||||
void drawArrow(const QColor &arrowColor);
|
void drawArrow(const QColor &arrowColor);
|
||||||
void drawAttachArrow();
|
void drawAttachArrow();
|
||||||
|
|
|
||||||
29
cockatrice/src/game/card_dimensions.h
Normal file
29
cockatrice/src/game/card_dimensions.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef CARD_DIMENSIONS_H
|
||||||
|
#define CARD_DIMENSIONS_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file card_dimensions.h
|
||||||
|
* @brief Canonical card dimension constants for layout and Z-value calculations.
|
||||||
|
*
|
||||||
|
* These values represent the logical pixel dimensions of a standard card graphic.
|
||||||
|
* They are used throughout the game scene for layout, rendering, and Z-value computation.
|
||||||
|
*/
|
||||||
|
namespace CardDimensions
|
||||||
|
{
|
||||||
|
/// Card width in pixels
|
||||||
|
constexpr int WIDTH = 72;
|
||||||
|
/// Card height in pixels
|
||||||
|
constexpr int HEIGHT = 102;
|
||||||
|
|
||||||
|
/// Pre-converted for floating-point contexts (Z-value calculations)
|
||||||
|
constexpr qreal WIDTH_F = static_cast<qreal>(WIDTH);
|
||||||
|
constexpr qreal HEIGHT_F = static_cast<qreal>(HEIGHT);
|
||||||
|
|
||||||
|
/// Half-dimensions for centering and rotation transforms
|
||||||
|
constexpr qreal WIDTH_HALF_F = WIDTH_F / 2;
|
||||||
|
constexpr qreal HEIGHT_HALF_F = HEIGHT_F / 2;
|
||||||
|
} // namespace CardDimensions
|
||||||
|
|
||||||
|
#endif // CARD_DIMENSIONS_H
|
||||||
|
|
@ -95,8 +95,9 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
||||||
pen.setJoinStyle(Qt::MiterJoin);
|
pen.setJoinStyle(Qt::MiterJoin);
|
||||||
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
||||||
painter->setPen(pen);
|
painter->setPen(pen);
|
||||||
qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CARD_WIDTH - 3) : 0.0;
|
qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CardDimensions::WIDTH_F - 3) : 0.0;
|
||||||
painter->drawRoundedRect(QRectF(1.5, 1.5, CARD_WIDTH - 3., CARD_HEIGHT - 3.), cardRadius, cardRadius);
|
painter->drawRoundedRect(QRectF(1.5, 1.5, CardDimensions::WIDTH_F - 3, CardDimensions::HEIGHT_F - 3), cardRadius,
|
||||||
|
cardRadius);
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,7 +123,7 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
if (c == this)
|
if (c == this)
|
||||||
continue;
|
continue;
|
||||||
++j;
|
++j;
|
||||||
auto childPos = QPointF(j * CARD_WIDTH / 2, 0);
|
auto childPos = QPointF(j * CardDimensions::WIDTH_HALF_F, 0);
|
||||||
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
|
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
|
||||||
drag->setPos(dragItem->pos() + childPos);
|
drag->setPos(dragItem->pos() + childPos);
|
||||||
scene()->addItem(drag);
|
scene()->addItem(drag);
|
||||||
|
|
@ -204,7 +205,7 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI
|
||||||
painter->setPen(QColor(255, 255, 255, 100));
|
painter->setPen(QColor(255, 255, 255, 100));
|
||||||
painter->drawLine(QPointF(0, yUntilNow - paddingY / 2), QPointF(width, yUntilNow - paddingY / 2));
|
painter->drawLine(QPointF(0, yUntilNow - paddingY / 2), QPointF(width, yUntilNow - paddingY / 2));
|
||||||
}
|
}
|
||||||
qreal thisRowHeight = CARD_HEIGHT * currentRowsAndCols[i].first;
|
qreal thisRowHeight = CardDimensions::HEIGHT_F * currentRowsAndCols[i].first;
|
||||||
QRectF textRect(0, yUntilNow, totalTextWidth, thisRowHeight);
|
QRectF textRect(0, yUntilNow, totalTextWidth, thisRowHeight);
|
||||||
yUntilNow += thisRowHeight + paddingY;
|
yUntilNow += thisRowHeight + paddingY;
|
||||||
|
|
||||||
|
|
@ -260,9 +261,9 @@ QSizeF DeckViewCardContainer::calculateBoundingRect(const QList<QPair<int, int>>
|
||||||
|
|
||||||
// Calculate space needed for cards
|
// Calculate space needed for cards
|
||||||
for (int i = 0; i < rowsAndCols.size(); ++i) {
|
for (int i = 0; i < rowsAndCols.size(); ++i) {
|
||||||
totalHeight += CARD_HEIGHT * rowsAndCols[i].first + paddingY;
|
totalHeight += CardDimensions::HEIGHT_F * rowsAndCols[i].first + paddingY;
|
||||||
if (CARD_WIDTH * rowsAndCols[i].second > totalWidth)
|
if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth)
|
||||||
totalWidth = CARD_WIDTH * rowsAndCols[i].second;
|
totalWidth = CardDimensions::WIDTH_F * rowsAndCols[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY);
|
return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY);
|
||||||
|
|
@ -289,9 +290,10 @@ void DeckViewCardContainer::rearrangeItems(const QList<QPair<int, int>> &rowsAnd
|
||||||
std::sort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName);
|
std::sort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName);
|
||||||
for (int j = 0; j < row.size(); ++j) {
|
for (int j = 0; j < row.size(); ++j) {
|
||||||
DeckViewCard *card = row[j];
|
DeckViewCard *card = row[j];
|
||||||
card->setPos(x + (j % tempCols) * CARD_WIDTH, yUntilNow + (j / tempCols) * CARD_HEIGHT);
|
card->setPos(x + (j % tempCols) * CardDimensions::WIDTH_F,
|
||||||
|
yUntilNow + (j / tempCols) * CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
yUntilNow += tempRows * CARD_HEIGHT + paddingY;
|
yUntilNow += tempRows * CardDimensions::HEIGHT_F + paddingY;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
|
|
@ -392,7 +394,7 @@ void DeckViewScene::applySideboardPlan(const QList<MoveCard_ToZone> &plan)
|
||||||
|
|
||||||
void DeckViewScene::rearrangeItems()
|
void DeckViewScene::rearrangeItems()
|
||||||
{
|
{
|
||||||
const int spacing = CARD_HEIGHT / 3;
|
const int spacing = CardDimensions::HEIGHT / 3;
|
||||||
QList<DeckViewCardContainer *> contList = cardContainers.values();
|
QList<DeckViewCardContainer *> contList = cardContainers.values();
|
||||||
|
|
||||||
// Initialize space requirements
|
// Initialize space requirements
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/filters/filter_string.h>
|
#include <libcockatrice/filters/filter_string.h>
|
||||||
|
|
||||||
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QStringList exprs, uint _numberOfHits, bool autoPlay)
|
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, const MoveTopCardsUntilOptions &options) : QDialog(parent)
|
||||||
: QDialog(parent)
|
|
||||||
{
|
{
|
||||||
exprLabel = new QLabel(tr("Card name (or search expressions):"));
|
exprLabel = new QLabel(tr("Card name (or search expressions):"));
|
||||||
|
|
||||||
|
|
@ -21,13 +20,13 @@ DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QStringList exprs, u
|
||||||
exprComboBox->setFocus();
|
exprComboBox->setFocus();
|
||||||
exprComboBox->setEditable(true);
|
exprComboBox->setEditable(true);
|
||||||
exprComboBox->setInsertPolicy(QComboBox::InsertAtTop);
|
exprComboBox->setInsertPolicy(QComboBox::InsertAtTop);
|
||||||
exprComboBox->insertItems(0, exprs);
|
exprComboBox->insertItems(0, options.exprs);
|
||||||
exprLabel->setBuddy(exprComboBox);
|
exprLabel->setBuddy(exprComboBox);
|
||||||
|
|
||||||
numberOfHitsLabel = new QLabel(tr("Number of hits:"));
|
numberOfHitsLabel = new QLabel(tr("Number of hits:"));
|
||||||
numberOfHitsEdit = new QSpinBox(this);
|
numberOfHitsEdit = new QSpinBox(this);
|
||||||
numberOfHitsEdit->setRange(1, 99);
|
numberOfHitsEdit->setRange(1, 99);
|
||||||
numberOfHitsEdit->setValue(_numberOfHits);
|
numberOfHitsEdit->setValue(options.numberOfHits);
|
||||||
numberOfHitsLabel->setBuddy(numberOfHitsEdit);
|
numberOfHitsLabel->setBuddy(numberOfHitsEdit);
|
||||||
|
|
||||||
auto *grid = new QGridLayout;
|
auto *grid = new QGridLayout;
|
||||||
|
|
@ -35,7 +34,7 @@ DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QStringList exprs, u
|
||||||
grid->addWidget(numberOfHitsEdit, 0, 1);
|
grid->addWidget(numberOfHitsEdit, 0, 1);
|
||||||
|
|
||||||
autoPlayCheckBox = new QCheckBox(tr("Auto play hits"));
|
autoPlayCheckBox = new QCheckBox(tr("Auto play hits"));
|
||||||
autoPlayCheckBox->setChecked(autoPlay);
|
autoPlayCheckBox->setChecked(options.autoPlay);
|
||||||
|
|
||||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgMoveTopCardsUntil::validateAndAccept);
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgMoveTopCardsUntil::validateAndAccept);
|
||||||
|
|
@ -118,6 +117,13 @@ QString DlgMoveTopCardsUntil::getExpr() const
|
||||||
return exprComboBox->currentText();
|
return exprComboBox->currentText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MoveTopCardsUntilOptions DlgMoveTopCardsUntil::getOptions() const
|
||||||
|
{
|
||||||
|
return {.exprs = getExprs(),
|
||||||
|
.numberOfHits = numberOfHitsEdit->text().toInt(),
|
||||||
|
.autoPlay = autoPlayCheckBox->isChecked()};
|
||||||
|
}
|
||||||
|
|
||||||
QStringList DlgMoveTopCardsUntil::getExprs() const
|
QStringList DlgMoveTopCardsUntil::getExprs() const
|
||||||
{
|
{
|
||||||
QStringList exprs;
|
QStringList exprs;
|
||||||
|
|
@ -125,14 +131,4 @@ QStringList DlgMoveTopCardsUntil::getExprs() const
|
||||||
exprs.append(exprComboBox->itemText(i));
|
exprs.append(exprComboBox->itemText(i));
|
||||||
}
|
}
|
||||||
return exprs;
|
return exprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint DlgMoveTopCardsUntil::getNumberOfHits() const
|
|
||||||
{
|
|
||||||
return numberOfHitsEdit->text().toUInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DlgMoveTopCardsUntil::isAutoPlay() const
|
|
||||||
{
|
|
||||||
return autoPlayCheckBox->isChecked();
|
|
||||||
}
|
|
||||||
|
|
@ -16,6 +16,13 @@
|
||||||
|
|
||||||
class FilterString;
|
class FilterString;
|
||||||
|
|
||||||
|
struct MoveTopCardsUntilOptions
|
||||||
|
{
|
||||||
|
QStringList exprs = {};
|
||||||
|
int numberOfHits = 1;
|
||||||
|
bool autoPlay = false;
|
||||||
|
};
|
||||||
|
|
||||||
class DlgMoveTopCardsUntil : public QDialog
|
class DlgMoveTopCardsUntil : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -29,15 +36,12 @@ class DlgMoveTopCardsUntil : public QDialog
|
||||||
void validateAndAccept();
|
void validateAndAccept();
|
||||||
bool validateMatchExists(const FilterString &filterString);
|
bool validateMatchExists(const FilterString &filterString);
|
||||||
|
|
||||||
public:
|
|
||||||
explicit DlgMoveTopCardsUntil(QWidget *parent = nullptr,
|
|
||||||
QStringList exprs = QStringList(),
|
|
||||||
uint numberOfHits = 1,
|
|
||||||
bool autoPlay = false);
|
|
||||||
[[nodiscard]] QString getExpr() const;
|
|
||||||
[[nodiscard]] QStringList getExprs() const;
|
[[nodiscard]] QStringList getExprs() const;
|
||||||
[[nodiscard]] uint getNumberOfHits() const;
|
|
||||||
[[nodiscard]] bool isAutoPlay() const;
|
public:
|
||||||
|
explicit DlgMoveTopCardsUntil(QWidget *parent = nullptr, const MoveTopCardsUntilOptions &options = {});
|
||||||
|
[[nodiscard]] QString getExpr() const;
|
||||||
|
[[nodiscard]] MoveTopCardsUntilOptions getOptions() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DLG_MOVE_TOP_CARDS_UNTIL_H
|
#endif // DLG_MOVE_TOP_CARDS_UNTIL_H
|
||||||
|
|
|
||||||
|
|
@ -429,13 +429,13 @@ void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, c
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QGraphicsView>
|
#include <QGraphicsView>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -410,9 +411,9 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb
|
||||||
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
|
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
|
||||||
addItem(item);
|
addItem(item);
|
||||||
|
|
||||||
if (zoneName == "grave")
|
if (zoneName == ZoneNames::GRAVE)
|
||||||
item->setPos(360, 100);
|
item->setPos(360, 100);
|
||||||
else if (zoneName == "rfg")
|
else if (zoneName == ZoneNames::EXILE)
|
||||||
item->setPos(380, 120);
|
item->setPos(380, 120);
|
||||||
else
|
else
|
||||||
item->setPos(340, 80);
|
item->setPos(340, 80);
|
||||||
|
|
@ -520,9 +521,9 @@ void GameScene::startRubberBand(const QPointF &selectionOrigin)
|
||||||
emit sigStartRubberBand(selectionOrigin);
|
emit sigStartRubberBand(selectionOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameScene::resizeRubberBand(const QPointF &cursorPoint)
|
void GameScene::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
|
||||||
{
|
{
|
||||||
emit sigResizeRubberBand(cursorPoint);
|
emit sigResizeRubberBand(cursorPoint, selectedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameScene::stopRubberBand()
|
void GameScene::stopRubberBand()
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ public:
|
||||||
/** Unregisters a card from animation updates. */
|
/** Unregisters a card from animation updates. */
|
||||||
void unregisterAnimationItem(AbstractCardItem *card);
|
void unregisterAnimationItem(AbstractCardItem *card);
|
||||||
void startRubberBand(const QPointF &selectionOrigin);
|
void startRubberBand(const QPointF &selectionOrigin);
|
||||||
void resizeRubberBand(const QPointF &cursorPoint);
|
void resizeRubberBand(const QPointF &cursorPoint, int selectedCount);
|
||||||
void stopRubberBand();
|
void stopRubberBand();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
@ -196,7 +196,7 @@ protected:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sigStartRubberBand(const QPointF &selectionOrigin);
|
void sigStartRubberBand(const QPointF &selectionOrigin);
|
||||||
void sigResizeRubberBand(const QPointF &cursorPoint);
|
void sigResizeRubberBand(const QPointF &cursorPoint, int selectedCount);
|
||||||
void sigStopRubberBand();
|
void sigStopRubberBand();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,32 @@
|
||||||
#include "game_scene.h"
|
#include "game_scene.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QLabel>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QRubberBand>
|
#include <QRubberBand>
|
||||||
|
|
||||||
|
// QRubberBand calls raise() in showEvent() and changeEvent() to stay on top of siblings.
|
||||||
|
// This subclass disables that behavior so dragCountLabel can appear above it.
|
||||||
|
class SelectionRubberBand : public QRubberBand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using QRubberBand::QRubberBand;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *event) override
|
||||||
|
{
|
||||||
|
QWidget::showEvent(event); // Skip QRubberBand's raise()
|
||||||
|
}
|
||||||
|
|
||||||
|
void changeEvent(QEvent *event) override
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::ZOrderChange) {
|
||||||
|
return; // Skip QRubberBand's raise() on z-order changes
|
||||||
|
}
|
||||||
|
QRubberBand::changeEvent(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, parent), rubberBand(0)
|
GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, parent), rubberBand(0)
|
||||||
{
|
{
|
||||||
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
|
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
|
||||||
|
|
@ -19,6 +42,7 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
|
||||||
connect(scene, &GameScene::sigStartRubberBand, this, &GameView::startRubberBand);
|
connect(scene, &GameScene::sigStartRubberBand, this, &GameView::startRubberBand);
|
||||||
connect(scene, &GameScene::sigResizeRubberBand, this, &GameView::resizeRubberBand);
|
connect(scene, &GameScene::sigResizeRubberBand, this, &GameView::resizeRubberBand);
|
||||||
connect(scene, &GameScene::sigStopRubberBand, this, &GameView::stopRubberBand);
|
connect(scene, &GameScene::sigStopRubberBand, this, &GameView::stopRubberBand);
|
||||||
|
connect(scene, &QGraphicsScene::selectionChanged, this, [this]() { updateTotalSelectionCount(); });
|
||||||
|
|
||||||
aCloseMostRecentZoneView = new QAction(this);
|
aCloseMostRecentZoneView = new QAction(this);
|
||||||
|
|
||||||
|
|
@ -27,7 +51,23 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
|
||||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
||||||
&GameView::refreshShortcuts);
|
&GameView::refreshShortcuts);
|
||||||
refreshShortcuts();
|
refreshShortcuts();
|
||||||
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
|
rubberBand = new SelectionRubberBand(QRubberBand::Rectangle, this);
|
||||||
|
|
||||||
|
const QString countLabelStyle = "color: white; "
|
||||||
|
"font-size: 14px; "
|
||||||
|
"font-weight: bold; "
|
||||||
|
"background-color: rgba(0, 0, 0, 160); "
|
||||||
|
"border-radius: 3px; "
|
||||||
|
"padding: 1px 2px;";
|
||||||
|
|
||||||
|
dragCountLabel = new QLabel(this);
|
||||||
|
dragCountLabel->setStyleSheet(countLabelStyle);
|
||||||
|
dragCountLabel->hide();
|
||||||
|
dragCountLabel->raise();
|
||||||
|
|
||||||
|
totalCountLabel = new QLabel(this);
|
||||||
|
totalCountLabel->setStyleSheet(countLabelStyle);
|
||||||
|
totalCountLabel->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::resizeEvent(QResizeEvent *event)
|
void GameView::resizeEvent(QResizeEvent *event)
|
||||||
|
|
@ -39,6 +79,7 @@ void GameView::resizeEvent(QResizeEvent *event)
|
||||||
s->processViewSizeChange(event->size());
|
s->processViewSizeChange(event->size());
|
||||||
|
|
||||||
updateSceneRect(scene()->sceneRect());
|
updateSceneRect(scene()->sceneRect());
|
||||||
|
updateTotalSelectionCount(event->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::updateSceneRect(const QRectF &rect)
|
void GameView::updateSceneRect(const QRectF &rect)
|
||||||
|
|
@ -48,20 +89,67 @@ void GameView::updateSceneRect(const QRectF &rect)
|
||||||
|
|
||||||
void GameView::startRubberBand(const QPointF &_selectionOrigin)
|
void GameView::startRubberBand(const QPointF &_selectionOrigin)
|
||||||
{
|
{
|
||||||
|
if (!rubberBand)
|
||||||
|
return;
|
||||||
|
|
||||||
selectionOrigin = _selectionOrigin;
|
selectionOrigin = _selectionOrigin;
|
||||||
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
|
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
|
||||||
rubberBand->show();
|
rubberBand->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::resizeRubberBand(const QPointF &cursorPoint)
|
void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
|
||||||
{
|
{
|
||||||
if (rubberBand)
|
if (!rubberBand)
|
||||||
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), cursorPoint.toPoint()).normalized());
|
return;
|
||||||
|
|
||||||
|
constexpr int kLabelPaddingInPixels = 4;
|
||||||
|
|
||||||
|
QPoint cursor = cursorPoint.toPoint();
|
||||||
|
QRect rect = QRect(mapFromScene(selectionOrigin), cursor).normalized();
|
||||||
|
rubberBand->setGeometry(rect);
|
||||||
|
|
||||||
|
if (!SettingsCache::instance().getShowDragSelectionCount()) {
|
||||||
|
dragCountLabel->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedCount > 0) {
|
||||||
|
dragCountLabel->setText(QString::number(selectedCount));
|
||||||
|
dragCountLabel->adjustSize();
|
||||||
|
QSize labelSize = dragCountLabel->size();
|
||||||
|
|
||||||
|
if (rect.width() < labelSize.width() + 2 * kLabelPaddingInPixels ||
|
||||||
|
rect.height() < labelSize.height() + 2 * kLabelPaddingInPixels) {
|
||||||
|
dragCountLabel->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int minX = rect.left() + kLabelPaddingInPixels;
|
||||||
|
const int minY = rect.top() + kLabelPaddingInPixels;
|
||||||
|
|
||||||
|
int x = qMax(minX, cursor.x() - labelSize.width() - kLabelPaddingInPixels);
|
||||||
|
int y = qMax(minY, cursor.y() - labelSize.height() - kLabelPaddingInPixels);
|
||||||
|
|
||||||
|
bool isAtTopLeftCorner = (x == minX) && (y == minY);
|
||||||
|
if (isAtTopLeftCorner) {
|
||||||
|
constexpr int kCursorClearanceInPixels = 16;
|
||||||
|
x = qMin(cursor.x() + kCursorClearanceInPixels, rect.right() - labelSize.width() - kLabelPaddingInPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
dragCountLabel->move(x, y);
|
||||||
|
dragCountLabel->show();
|
||||||
|
} else {
|
||||||
|
dragCountLabel->hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::stopRubberBand()
|
void GameView::stopRubberBand()
|
||||||
{
|
{
|
||||||
|
if (!rubberBand)
|
||||||
|
return;
|
||||||
|
|
||||||
rubberBand->hide();
|
rubberBand->hide();
|
||||||
|
dragCountLabel->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::refreshShortcuts()
|
void GameView::refreshShortcuts()
|
||||||
|
|
@ -69,3 +157,28 @@ void GameView::refreshShortcuts()
|
||||||
aCloseMostRecentZoneView->setShortcuts(
|
aCloseMostRecentZoneView->setShortcuts(
|
||||||
SettingsCache::instance().shortcuts().getShortcut("Player/aCloseMostRecentZoneView"));
|
SettingsCache::instance().shortcuts().getShortcut("Player/aCloseMostRecentZoneView"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameView::updateTotalSelectionCount(const QSize &viewSize)
|
||||||
|
{
|
||||||
|
if (!SettingsCache::instance().getShowTotalSelectionCount()) {
|
||||||
|
totalCountLabel->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = scene()->selectedItems().count();
|
||||||
|
|
||||||
|
if (count > 1) {
|
||||||
|
totalCountLabel->setText(QString::number(count));
|
||||||
|
totalCountLabel->adjustSize();
|
||||||
|
|
||||||
|
constexpr int kMarginInPixels = 10;
|
||||||
|
int availableWidth = viewSize.isValid() ? viewSize.width() : viewport()->width();
|
||||||
|
int availableHeight = viewSize.isValid() ? viewSize.height() : viewport()->height();
|
||||||
|
int x = availableWidth - totalCountLabel->width() - kMarginInPixels;
|
||||||
|
int y = availableHeight - totalCountLabel->height() - kMarginInPixels;
|
||||||
|
totalCountLabel->move(x, y);
|
||||||
|
totalCountLabel->show();
|
||||||
|
} else {
|
||||||
|
totalCountLabel->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <QGraphicsView>
|
#include <QGraphicsView>
|
||||||
|
|
||||||
class GameScene;
|
class GameScene;
|
||||||
|
class QLabel;
|
||||||
class QRubberBand;
|
class QRubberBand;
|
||||||
|
|
||||||
class GameView : public QGraphicsView
|
class GameView : public QGraphicsView
|
||||||
|
|
@ -18,15 +19,18 @@ class GameView : public QGraphicsView
|
||||||
private:
|
private:
|
||||||
QAction *aCloseMostRecentZoneView;
|
QAction *aCloseMostRecentZoneView;
|
||||||
QRubberBand *rubberBand;
|
QRubberBand *rubberBand;
|
||||||
|
QLabel *dragCountLabel;
|
||||||
|
QLabel *totalCountLabel;
|
||||||
QPointF selectionOrigin;
|
QPointF selectionOrigin;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
private slots:
|
private slots:
|
||||||
void startRubberBand(const QPointF &selectionOrigin);
|
void startRubberBand(const QPointF &selectionOrigin);
|
||||||
void resizeRubberBand(const QPointF &cursorPoint);
|
void resizeRubberBand(const QPointF &cursorPoint, int selectedCount);
|
||||||
void stopRubberBand();
|
void stopRubberBand();
|
||||||
void refreshShortcuts();
|
void refreshShortcuts();
|
||||||
|
void updateTotalSelectionCount(const QSize &viewSize = QSize());
|
||||||
public slots:
|
public slots:
|
||||||
void updateSceneRect(const QRectF &rect);
|
void updateSceneRect(const QRectF &rect);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,9 @@
|
||||||
#include <../../client/settings/card_counter_settings.h>
|
#include <../../client/settings/card_counter_settings.h>
|
||||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
|
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
static const QString TABLE_ZONE_NAME = "table";
|
|
||||||
static const QString GRAVE_ZONE_NAME = "grave";
|
|
||||||
static const QString EXILE_ZONE_NAME = "rfg";
|
|
||||||
static const QString HAND_ZONE_NAME = "hand";
|
|
||||||
static const QString DECK_ZONE_NAME = "deck";
|
|
||||||
static const QString SIDEBOARD_ZONE_NAME = "sb";
|
|
||||||
static const QString STACK_ZONE_NAME = "stack";
|
|
||||||
|
|
||||||
static QString sanitizeHtml(QString dirty)
|
static QString sanitizeHtml(QString dirty)
|
||||||
{
|
{
|
||||||
return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
||||||
|
|
@ -37,15 +30,15 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position
|
||||||
QString fromStr;
|
QString fromStr;
|
||||||
QString zoneName = zone->getName();
|
QString zoneName = zone->getName();
|
||||||
|
|
||||||
if (zoneName == TABLE_ZONE_NAME) {
|
if (zoneName == ZoneNames::TABLE) {
|
||||||
fromStr = tr(" from play");
|
fromStr = tr(" from play");
|
||||||
} else if (zoneName == GRAVE_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::GRAVE) {
|
||||||
fromStr = tr(" from their graveyard");
|
fromStr = tr(" from their graveyard");
|
||||||
} else if (zoneName == EXILE_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::EXILE) {
|
||||||
fromStr = tr(" from exile");
|
fromStr = tr(" from exile");
|
||||||
} else if (zoneName == HAND_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::HAND) {
|
||||||
fromStr = tr(" from their hand");
|
fromStr = tr(" from their hand");
|
||||||
} else if (zoneName == DECK_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::DECK) {
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
if (cardName.isEmpty()) {
|
if (cardName.isEmpty()) {
|
||||||
if (ownerChange) {
|
if (ownerChange) {
|
||||||
|
|
@ -61,7 +54,7 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position
|
||||||
fromStr = tr(" from the top of their library");
|
fromStr = tr(" from the top of their library");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (position >= zone->getCards().size() - 1) {
|
} else if (position == zone->getCards().size()) {
|
||||||
if (cardName.isEmpty()) {
|
if (cardName.isEmpty()) {
|
||||||
if (ownerChange) {
|
if (ownerChange) {
|
||||||
cardName = tr("the bottom card of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
cardName = tr("the bottom card of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||||
|
|
@ -83,9 +76,9 @@ MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position
|
||||||
fromStr = tr(" from their library");
|
fromStr = tr(" from their library");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (zoneName == SIDEBOARD_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::SIDEBOARD) {
|
||||||
fromStr = tr(" from sideboard");
|
fromStr = tr(" from sideboard");
|
||||||
} else if (zoneName == STACK_ZONE_NAME) {
|
} else if (zoneName == ZoneNames::STACK) {
|
||||||
fromStr = tr(" from the stack");
|
fromStr = tr(" from the stack");
|
||||||
} else {
|
} else {
|
||||||
fromStr = tr(" from custom zone '%1'").arg(zoneName);
|
fromStr = tr(" from custom zone '%1'").arg(zoneName);
|
||||||
|
|
@ -275,9 +268,9 @@ void MessageLogWidget::logMoveCard(Player *player,
|
||||||
bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer();
|
bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer();
|
||||||
|
|
||||||
// do not log if moved within the same zone
|
// do not log if moved within the same zone
|
||||||
if ((startZoneName == TABLE_ZONE_NAME && targetZoneName == TABLE_ZONE_NAME && !ownerChanged) ||
|
if ((startZoneName == ZoneNames::TABLE && targetZoneName == ZoneNames::TABLE && !ownerChanged) ||
|
||||||
(startZoneName == HAND_ZONE_NAME && targetZoneName == HAND_ZONE_NAME) ||
|
(startZoneName == ZoneNames::HAND && targetZoneName == ZoneNames::HAND) ||
|
||||||
(startZoneName == EXILE_ZONE_NAME && targetZoneName == EXILE_ZONE_NAME)) {
|
(startZoneName == ZoneNames::EXILE && targetZoneName == ZoneNames::EXILE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,20 +299,28 @@ void MessageLogWidget::logMoveCard(Player *player,
|
||||||
|
|
||||||
QString finalStr;
|
QString finalStr;
|
||||||
std::optional<QString> fourthArg;
|
std::optional<QString> fourthArg;
|
||||||
if (targetZoneName == TABLE_ZONE_NAME) {
|
if (targetZoneName == ZoneNames::TABLE) {
|
||||||
soundEngine->playSound("play_card");
|
soundEngine->playSound("play_card");
|
||||||
if (card->getFaceDown()) {
|
if (card->getFaceDown()) {
|
||||||
finalStr = tr("%1 puts %2 into play%3 face down.");
|
finalStr = tr("%1 puts %2 into play%3 face down.");
|
||||||
} else {
|
} else {
|
||||||
finalStr = tr("%1 puts %2 into play%3.");
|
finalStr = tr("%1 puts %2 into play%3.");
|
||||||
}
|
}
|
||||||
} else if (targetZoneName == GRAVE_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::GRAVE) {
|
||||||
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
if (card->getFaceDown()) {
|
||||||
} else if (targetZoneName == EXILE_ZONE_NAME) {
|
finalStr = tr("%1 puts %2%3 into their graveyard face down.");
|
||||||
finalStr = tr("%1 exiles %2%3.");
|
} else {
|
||||||
} else if (targetZoneName == HAND_ZONE_NAME) {
|
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
||||||
|
}
|
||||||
|
} else if (targetZoneName == ZoneNames::EXILE) {
|
||||||
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 exiles %2%3 face down.");
|
||||||
|
} else {
|
||||||
|
finalStr = tr("%1 exiles %2%3.");
|
||||||
|
}
|
||||||
|
} else if (targetZoneName == ZoneNames::HAND) {
|
||||||
finalStr = tr("%1 moves %2%3 to their hand.");
|
finalStr = tr("%1 moves %2%3 to their hand.");
|
||||||
} else if (targetZoneName == DECK_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::DECK) {
|
||||||
if (newX == -1) {
|
if (newX == -1) {
|
||||||
finalStr = tr("%1 puts %2%3 into their library.");
|
finalStr = tr("%1 puts %2%3 into their library.");
|
||||||
} else if (newX >= targetZone->getCards().size()) {
|
} else if (newX >= targetZone->getCards().size()) {
|
||||||
|
|
@ -331,14 +332,22 @@ void MessageLogWidget::logMoveCard(Player *player,
|
||||||
fourthArg = QString::number(newX);
|
fourthArg = QString::number(newX);
|
||||||
finalStr = tr("%1 puts %2%3 into their library %4 cards from the top.");
|
finalStr = tr("%1 puts %2%3 into their library %4 cards from the top.");
|
||||||
}
|
}
|
||||||
} else if (targetZoneName == SIDEBOARD_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::SIDEBOARD) {
|
||||||
finalStr = tr("%1 moves %2%3 to sideboard.");
|
finalStr = tr("%1 moves %2%3 to sideboard.");
|
||||||
} else if (targetZoneName == STACK_ZONE_NAME) {
|
} else if (targetZoneName == ZoneNames::STACK) {
|
||||||
soundEngine->playSound("play_card");
|
soundEngine->playSound("play_card");
|
||||||
finalStr = tr("%1 plays %2%3.");
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 plays %2%3 face down.");
|
||||||
|
} else {
|
||||||
|
finalStr = tr("%1 plays %2%3.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fourthArg = targetZoneName;
|
fourthArg = targetZoneName;
|
||||||
finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 moves %2%3 to custom zone '%4' face down.");
|
||||||
|
} else {
|
||||||
|
finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString message = finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()), cardStr, nameFrom.second);
|
QString message = finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()), cardStr, nameFrom.second);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
|
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable)
|
PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable)
|
||||||
: QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable),
|
: QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable),
|
||||||
|
|
@ -259,7 +260,7 @@ void PhasesToolbar::actNextTurn()
|
||||||
void PhasesToolbar::actUntapAll()
|
void PhasesToolbar::actUntapAll()
|
||||||
{
|
{
|
||||||
Command_SetCardAttr cmd;
|
Command_SetCardAttr cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_attribute(AttrTapped);
|
cmd.set_attribute(AttrTapped);
|
||||||
cmd.set_attr_value("0");
|
cmd.set_attr_value("0");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,20 @@
|
||||||
|
|
||||||
enum CardMenuActionType
|
enum CardMenuActionType
|
||||||
{
|
{
|
||||||
|
// Per-card attribute actions (must be <= cmClone for cardMenuAction() dispatch)
|
||||||
cmTap,
|
cmTap,
|
||||||
cmUntap,
|
cmUntap,
|
||||||
cmDoesntUntap,
|
cmDoesntUntap,
|
||||||
cmFlip,
|
cmFlip,
|
||||||
cmPeek,
|
cmPeek,
|
||||||
cmClone,
|
cmClone,
|
||||||
|
// Move actions (must be > cmClone for cardMenuAction() dispatch)
|
||||||
cmMoveToTopLibrary,
|
cmMoveToTopLibrary,
|
||||||
cmMoveToBottomLibrary,
|
cmMoveToBottomLibrary,
|
||||||
cmMoveToHand,
|
cmMoveToHand,
|
||||||
cmMoveToGraveyard,
|
cmMoveToGraveyard,
|
||||||
cmMoveToExile
|
cmMoveToExile,
|
||||||
|
cmMoveToTable
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_CARD_MENU_ACTION_TYPE_H
|
#endif // COCKATRICE_CARD_MENU_ACTION_TYPE_H
|
||||||
|
|
|
||||||
32
cockatrice/src/game/player/menu/abstract_player_component.h
Normal file
32
cockatrice/src/game/player/menu/abstract_player_component.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* @file abstract_player_component.h
|
||||||
|
* @ingroup GameMenusPlayers
|
||||||
|
* @brief Polymorphic interface for player-bound UI components managed by PlayerMenu.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
|
||||||
|
#define COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interface for player-bound UI components that need shortcut and translation lifecycle management.
|
||||||
|
*
|
||||||
|
* Not a QObject — avoids diamond inheritance with Qt's MOC. Each concrete component
|
||||||
|
* inherits QObject through its Qt base class (QMenu, TearOffMenu, QGraphicsItem, etc.)
|
||||||
|
* and this interface through regular multiple inheritance.
|
||||||
|
*/
|
||||||
|
class AbstractPlayerComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~AbstractPlayerComponent() = default;
|
||||||
|
|
||||||
|
/// Bind keyboard shortcuts. Called when this player gains focus.
|
||||||
|
virtual void setShortcutsActive() = 0;
|
||||||
|
|
||||||
|
/// Unbind keyboard shortcuts. Called when this player loses focus.
|
||||||
|
virtual void setShortcutsInactive() = 0;
|
||||||
|
|
||||||
|
/// Retranslate all user-visible strings. Called on language change.
|
||||||
|
virtual void retranslateUi() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/card/relation/card_relation.h>
|
#include <libcockatrice/card/relation/card_relation.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive)
|
CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive)
|
||||||
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
|
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
|
||||||
|
|
@ -34,6 +35,8 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
|
||||||
connect(aTap, &QAction::triggered, playerActions, &PlayerActions::cardMenuAction);
|
connect(aTap, &QAction::triggered, playerActions, &PlayerActions::cardMenuAction);
|
||||||
aDoesntUntap = new QAction(this);
|
aDoesntUntap = new QAction(this);
|
||||||
aDoesntUntap->setData(cmDoesntUntap);
|
aDoesntUntap->setData(cmDoesntUntap);
|
||||||
|
aDoesntUntap->setCheckable(true);
|
||||||
|
aDoesntUntap->setChecked(card != nullptr && card->getDoesntUntap());
|
||||||
connect(aDoesntUntap, &QAction::triggered, playerActions, &PlayerActions::cardMenuAction);
|
connect(aDoesntUntap, &QAction::triggered, playerActions, &PlayerActions::cardMenuAction);
|
||||||
aAttach = new QAction(this);
|
aAttach = new QAction(this);
|
||||||
connect(aAttach, &QAction::triggered, playerActions, &PlayerActions::actAttach);
|
connect(aAttach, &QAction::triggered, playerActions, &PlayerActions::actAttach);
|
||||||
|
|
@ -107,36 +110,26 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
|
||||||
|
|
||||||
if (revealedCard) {
|
if (revealedCard) {
|
||||||
addAction(aHide);
|
addAction(aHide);
|
||||||
|
addSeparator();
|
||||||
addAction(aClone);
|
addAction(aClone);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aSelectAll);
|
addAction(aSelectAll);
|
||||||
addAction(aSelectColumn);
|
addAction(aSelectColumn);
|
||||||
addRelatedCardView();
|
addRelatedCardView();
|
||||||
} else if (writeableCard) {
|
} else {
|
||||||
|
|
||||||
if (card->getZone()) {
|
if (card->getZone()) {
|
||||||
if (card->getZone()->getName() == "table") {
|
if (card->getZone()->getName() == ZoneNames::TABLE) {
|
||||||
createTableMenu();
|
createTableMenu(writeableCard);
|
||||||
} else if (card->getZone()->getName() == "stack") {
|
} else if (card->getZone()->getName() == ZoneNames::STACK) {
|
||||||
createStackMenu();
|
createStackMenu(writeableCard);
|
||||||
} else if (card->getZone()->getName() == "rfg" || card->getZone()->getName() == "grave") {
|
} else if (card->getZone()->getName() == ZoneNames::EXILE ||
|
||||||
createGraveyardOrExileMenu();
|
card->getZone()->getName() == ZoneNames::GRAVE) {
|
||||||
|
createGraveyardOrExileMenu(writeableCard);
|
||||||
} else {
|
} else {
|
||||||
createHandOrCustomZoneMenu();
|
createHandOrCustomZoneMenu(writeableCard);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
addMenu(new MoveMenu(player));
|
createZonelessMenu(writeableCard);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (card->getZone() && card->getZone()->getName() != "hand") {
|
|
||||||
addAction(aDrawArrow);
|
|
||||||
addSeparator();
|
|
||||||
addRelatedCardView();
|
|
||||||
addRelatedCardActions();
|
|
||||||
addSeparator();
|
|
||||||
addAction(aClone);
|
|
||||||
addSeparator();
|
|
||||||
addAction(aSelectAll);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -152,22 +145,18 @@ void CardMenu::removePlayer(Player *playerToRemove)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createTableMenu()
|
void CardMenu::createTableMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
// Card is on the battlefield
|
// Card is on the battlefield
|
||||||
bool canModifyCard = player->getPlayerInfo()->judge || card->getOwner() == player;
|
|
||||||
|
|
||||||
if (!canModifyCard) {
|
if (!canModifyCard) {
|
||||||
addRelatedCardView();
|
|
||||||
addRelatedCardActions();
|
|
||||||
|
|
||||||
addSeparator();
|
|
||||||
addAction(aDrawArrow);
|
addAction(aDrawArrow);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aClone);
|
addAction(aClone);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aSelectAll);
|
addAction(aSelectAll);
|
||||||
addAction(aSelectRow);
|
addAction(aSelectRow);
|
||||||
|
addRelatedCardView();
|
||||||
|
addRelatedCardActions();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,10 +166,9 @@ void CardMenu::createTableMenu()
|
||||||
if (card->getFaceDown()) {
|
if (card->getFaceDown()) {
|
||||||
addAction(aPeek);
|
addAction(aPeek);
|
||||||
}
|
}
|
||||||
|
addSeparator();
|
||||||
addRelatedCardView();
|
addAction(aClone);
|
||||||
addRelatedCardActions();
|
addMenu(new MoveMenu(player));
|
||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aAttach);
|
addAction(aAttach);
|
||||||
if (card->getAttachedTo()) {
|
if (card->getAttachedTo()) {
|
||||||
|
|
@ -191,9 +179,6 @@ void CardMenu::createTableMenu()
|
||||||
addMenu(new PtMenu(player));
|
addMenu(new PtMenu(player));
|
||||||
addAction(aSetAnnotation);
|
addAction(aSetAnnotation);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aClone);
|
|
||||||
addMenu(new MoveMenu(player));
|
|
||||||
addSeparator();
|
|
||||||
addAction(aSelectAll);
|
addAction(aSelectAll);
|
||||||
addAction(aSelectRow);
|
addAction(aSelectRow);
|
||||||
|
|
||||||
|
|
@ -209,67 +194,81 @@ void CardMenu::createTableMenu()
|
||||||
}
|
}
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addMenu(mCardCounters);
|
addMenu(mCardCounters);
|
||||||
|
addRelatedCardView();
|
||||||
|
addRelatedCardActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createStackMenu()
|
void CardMenu::createStackMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
bool canModifyCard = player->getPlayerInfo()->judge || card->getOwner() == player;
|
|
||||||
|
|
||||||
// Card is on the stack
|
// Card is on the stack
|
||||||
if (canModifyCard) {
|
if (!canModifyCard) {
|
||||||
addAction(aAttach);
|
|
||||||
addAction(aDrawArrow);
|
|
||||||
addSeparator();
|
|
||||||
addAction(aClone);
|
|
||||||
addMenu(new MoveMenu(player));
|
|
||||||
addSeparator();
|
|
||||||
addAction(aSelectAll);
|
|
||||||
} else {
|
|
||||||
addAction(aDrawArrow);
|
addAction(aDrawArrow);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aClone);
|
addAction(aClone);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aSelectAll);
|
addAction(aSelectAll);
|
||||||
|
addRelatedCardView();
|
||||||
|
addRelatedCardActions();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addAction(aPlay);
|
||||||
|
addAction(aPlayFacedown);
|
||||||
|
addSeparator();
|
||||||
|
addAction(aClone);
|
||||||
|
addMenu(new MoveMenu(player));
|
||||||
|
addSeparator();
|
||||||
|
addAction(aAttach);
|
||||||
|
addAction(aDrawArrow);
|
||||||
|
addSeparator();
|
||||||
|
addAction(aSelectAll);
|
||||||
addRelatedCardView();
|
addRelatedCardView();
|
||||||
addRelatedCardActions();
|
addRelatedCardActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createGraveyardOrExileMenu()
|
void CardMenu::createGraveyardOrExileMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
bool canModifyCard = player->getPlayerInfo()->judge || card->getOwner() == player;
|
|
||||||
|
|
||||||
// Card is in the graveyard or exile
|
// Card is in the graveyard or exile
|
||||||
if (canModifyCard) {
|
if (!canModifyCard) {
|
||||||
addAction(aPlay);
|
|
||||||
addAction(aPlayFacedown);
|
|
||||||
|
|
||||||
addSeparator();
|
|
||||||
addAction(aClone);
|
|
||||||
addMenu(new MoveMenu(player));
|
|
||||||
addSeparator();
|
|
||||||
addAction(aSelectAll);
|
|
||||||
addAction(aSelectColumn);
|
|
||||||
|
|
||||||
addSeparator();
|
|
||||||
addAction(aAttach);
|
|
||||||
addAction(aDrawArrow);
|
addAction(aDrawArrow);
|
||||||
} else {
|
addSeparator();
|
||||||
addAction(aClone);
|
addAction(aClone);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aSelectAll);
|
addAction(aSelectAll);
|
||||||
addAction(aSelectColumn);
|
addAction(aSelectColumn);
|
||||||
addSeparator();
|
addRelatedCardView();
|
||||||
addAction(aDrawArrow);
|
addRelatedCardActions();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addAction(aPlay);
|
||||||
|
addAction(aPlayFacedown);
|
||||||
|
addSeparator();
|
||||||
|
addAction(aClone);
|
||||||
|
addMenu(new MoveMenu(player));
|
||||||
|
addSeparator();
|
||||||
|
addAction(aAttach);
|
||||||
|
addAction(aDrawArrow);
|
||||||
|
addSeparator();
|
||||||
|
addAction(aSelectAll);
|
||||||
|
addAction(aSelectColumn);
|
||||||
addRelatedCardView();
|
addRelatedCardView();
|
||||||
addRelatedCardActions();
|
addRelatedCardActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardMenu::createHandOrCustomZoneMenu()
|
void CardMenu::createHandOrCustomZoneMenu(bool canModifyCard)
|
||||||
{
|
{
|
||||||
|
if (!canModifyCard) {
|
||||||
|
addAction(aDrawArrow);
|
||||||
|
addSeparator();
|
||||||
|
addAction(aClone);
|
||||||
|
addSeparator();
|
||||||
|
addAction(aSelectAll);
|
||||||
|
addRelatedCardView();
|
||||||
|
addRelatedCardActions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Card is in hand or a custom zone specified by server
|
// Card is in hand or a custom zone specified by server
|
||||||
addAction(aPlay);
|
addAction(aPlay);
|
||||||
addAction(aPlayFacedown);
|
addAction(aPlayFacedown);
|
||||||
|
|
@ -285,7 +284,7 @@ void CardMenu::createHandOrCustomZoneMenu()
|
||||||
addMenu(new MoveMenu(player));
|
addMenu(new MoveMenu(player));
|
||||||
|
|
||||||
// actions that are really wonky when done from deck or sideboard
|
// actions that are really wonky when done from deck or sideboard
|
||||||
if (card->getZone()->getName() == "hand") {
|
if (card->getZone()->getName() == ZoneNames::HAND) {
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aAttach);
|
addAction(aAttach);
|
||||||
addAction(aDrawArrow);
|
addAction(aDrawArrow);
|
||||||
|
|
@ -298,11 +297,18 @@ void CardMenu::createHandOrCustomZoneMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
addRelatedCardView();
|
addRelatedCardView();
|
||||||
if (card->getZone()->getName() == "hand") {
|
if (card->getZone()->getName() == ZoneNames::HAND) {
|
||||||
addRelatedCardActions();
|
addRelatedCardActions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardMenu::createZonelessMenu(bool canModifyCard)
|
||||||
|
{
|
||||||
|
if (canModifyCard) {
|
||||||
|
addMenu(new MoveMenu(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Populates the menu with an action for each active player.
|
* @brief Populates the menu with an action for each active player.
|
||||||
*
|
*
|
||||||
|
|
@ -446,7 +452,7 @@ void CardMenu::retranslateUi()
|
||||||
aRevealToAll->setText(tr("&All players"));
|
aRevealToAll->setText(tr("&All players"));
|
||||||
//: Turn sideways or back again
|
//: Turn sideways or back again
|
||||||
aTap->setText(tr("&Tap / Untap"));
|
aTap->setText(tr("&Tap / Untap"));
|
||||||
aDoesntUntap->setText(tr("Toggle &normal untapping"));
|
aDoesntUntap->setText(tr("Skip &untapping"));
|
||||||
//: Turn face up/face down
|
//: Turn face up/face down
|
||||||
aFlip->setText(tr("T&urn Over")); // Only the user facing names in client got renamed to "turn over"
|
aFlip->setText(tr("T&urn Over")); // Only the user facing names in client got renamed to "turn over"
|
||||||
// All code and proto bits are still unchanged (flip) for compatibility reasons
|
// All code and proto bits are still unchanged (flip) for compatibility reasons
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,11 @@ class CardMenu : public QMenu
|
||||||
public:
|
public:
|
||||||
explicit CardMenu(Player *player, const CardItem *card, bool shortcutsActive);
|
explicit CardMenu(Player *player, const CardItem *card, bool shortcutsActive);
|
||||||
void removePlayer(Player *playerToRemove);
|
void removePlayer(Player *playerToRemove);
|
||||||
void createTableMenu();
|
void createTableMenu(bool canModifyCard);
|
||||||
void createStackMenu();
|
void createStackMenu(bool canModifyCard);
|
||||||
void createGraveyardOrExileMenu();
|
void createGraveyardOrExileMenu(bool canModifyCard);
|
||||||
void createHandOrCustomZoneMenu();
|
void createHandOrCustomZoneMenu(bool canModifyCard);
|
||||||
|
void createZonelessMenu(bool canModifyCard);
|
||||||
|
|
||||||
QMenu *mCardCounters;
|
QMenu *mCardCounters;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,23 @@
|
||||||
#ifndef COCKATRICE_CUSTOM_ZONE_MENU_H
|
#ifndef COCKATRICE_CUSTOM_ZONE_MENU_H
|
||||||
#define COCKATRICE_CUSTOM_ZONE_MENU_H
|
#define COCKATRICE_CUSTOM_ZONE_MENU_H
|
||||||
|
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class CustomZoneMenu : public QMenu
|
class CustomZoneMenu : public QMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CustomZoneMenu(Player *player);
|
explicit CustomZoneMenu(Player *player);
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
|
void setShortcutsActive() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void setShortcutsInactive() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Player *player;
|
Player *player;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
GraveyardMenu::GraveyardMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
GraveyardMenu::GraveyardMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||||
{
|
{
|
||||||
|
|
@ -39,16 +40,16 @@ void GraveyardMenu::createMoveActions()
|
||||||
|
|
||||||
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
||||||
aMoveGraveToTopLibrary = new QAction(this);
|
aMoveGraveToTopLibrary = new QAction(this);
|
||||||
aMoveGraveToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
aMoveGraveToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||||
|
|
||||||
aMoveGraveToBottomLibrary = new QAction(this);
|
aMoveGraveToBottomLibrary = new QAction(this);
|
||||||
aMoveGraveToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
aMoveGraveToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||||
|
|
||||||
aMoveGraveToHand = new QAction(this);
|
aMoveGraveToHand = new QAction(this);
|
||||||
aMoveGraveToHand->setData(QList<QVariant>() << "hand" << 0);
|
aMoveGraveToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
|
||||||
|
|
||||||
aMoveGraveToRfg = new QAction(this);
|
aMoveGraveToRfg = new QAction(this);
|
||||||
aMoveGraveToRfg->setData(QList<QVariant>() << "rfg" << 0);
|
aMoveGraveToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
|
||||||
|
|
||||||
connect(aMoveGraveToTopLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
connect(aMoveGraveToTopLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||||
connect(aMoveGraveToBottomLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
connect(aMoveGraveToBottomLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,13 @@
|
||||||
#define COCKATRICE_GRAVE_MENU_H
|
#define COCKATRICE_GRAVE_MENU_H
|
||||||
|
|
||||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class GraveyardMenu : public TearOffMenu
|
class GraveyardMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
signals:
|
signals:
|
||||||
|
|
@ -25,9 +26,9 @@ public:
|
||||||
void createViewActions();
|
void createViewActions();
|
||||||
void populateRevealRandomMenuWithActivePlayers();
|
void populateRevealRandomMenuWithActivePlayers();
|
||||||
void onRevealRandomTriggered();
|
void onRevealRandomTriggered();
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
void setShortcutsActive();
|
void setShortcutsActive() override;
|
||||||
void setShortcutsInactive();
|
void setShortcutsInactive() override;
|
||||||
|
|
||||||
QMenu *mRevealRandomGraveyardCard = nullptr;
|
QMenu *mRevealRandomGraveyardCard = nullptr;
|
||||||
QMenu *moveGraveMenu = nullptr;
|
QMenu *moveGraveMenu = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
|
HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||||
{
|
{
|
||||||
|
|
@ -76,13 +77,13 @@ HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : T
|
||||||
|
|
||||||
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
|
||||||
aMoveHandToTopLibrary = new QAction(this);
|
aMoveHandToTopLibrary = new QAction(this);
|
||||||
aMoveHandToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
aMoveHandToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||||
aMoveHandToBottomLibrary = new QAction(this);
|
aMoveHandToBottomLibrary = new QAction(this);
|
||||||
aMoveHandToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
aMoveHandToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||||
aMoveHandToGrave = new QAction(this);
|
aMoveHandToGrave = new QAction(this);
|
||||||
aMoveHandToGrave->setData(QList<QVariant>() << "grave" << 0);
|
aMoveHandToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
|
||||||
aMoveHandToRfg = new QAction(this);
|
aMoveHandToRfg = new QAction(this);
|
||||||
aMoveHandToRfg->setData(QList<QVariant>() << "rfg" << 0);
|
aMoveHandToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
|
||||||
|
|
||||||
auto hand = player->getHandZone();
|
auto hand = player->getHandZone();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define COCKATRICE_HAND_MENU_H
|
#define COCKATRICE_HAND_MENU_H
|
||||||
|
|
||||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
@ -15,7 +16,7 @@
|
||||||
class Player;
|
class Player;
|
||||||
class PlayerActions;
|
class PlayerActions;
|
||||||
|
|
||||||
class HandMenu : public TearOffMenu
|
class HandMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
@ -31,9 +32,9 @@ public:
|
||||||
return mRevealRandomHandCard;
|
return mRevealRandomHandCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
void setShortcutsActive();
|
void setShortcutsActive() override;
|
||||||
void setShortcutsInactive();
|
void setShortcutsInactive() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void populateRevealHandMenuWithActivePlayers();
|
void populateRevealHandMenuWithActivePlayers();
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,10 @@ LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent)
|
||||||
topLibraryMenu->addSeparator();
|
topLibraryMenu->addSeparator();
|
||||||
topLibraryMenu->addAction(aMoveTopCardToGraveyard);
|
topLibraryMenu->addAction(aMoveTopCardToGraveyard);
|
||||||
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
|
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardsToGraveyardFaceDown);
|
||||||
topLibraryMenu->addAction(aMoveTopCardToExile);
|
topLibraryMenu->addAction(aMoveTopCardToExile);
|
||||||
topLibraryMenu->addAction(aMoveTopCardsToExile);
|
topLibraryMenu->addAction(aMoveTopCardsToExile);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardsToExileFaceDown);
|
||||||
topLibraryMenu->addAction(aMoveTopCardsUntil);
|
topLibraryMenu->addAction(aMoveTopCardsUntil);
|
||||||
topLibraryMenu->addSeparator();
|
topLibraryMenu->addSeparator();
|
||||||
topLibraryMenu->addAction(aShuffleTopCards);
|
topLibraryMenu->addAction(aShuffleTopCards);
|
||||||
|
|
@ -66,8 +68,10 @@ LibraryMenu::LibraryMenu(Player *_player, QWidget *parent) : TearOffMenu(parent)
|
||||||
bottomLibraryMenu->addSeparator();
|
bottomLibraryMenu->addSeparator();
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard);
|
bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard);
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard);
|
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyardFaceDown);
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardToExile);
|
bottomLibraryMenu->addAction(aMoveBottomCardToExile);
|
||||||
bottomLibraryMenu->addAction(aMoveBottomCardsToExile);
|
bottomLibraryMenu->addAction(aMoveBottomCardsToExile);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardsToExileFaceDown);
|
||||||
bottomLibraryMenu->addSeparator();
|
bottomLibraryMenu->addSeparator();
|
||||||
bottomLibraryMenu->addAction(aShuffleBottomCards);
|
bottomLibraryMenu->addAction(aShuffleBottomCards);
|
||||||
|
|
||||||
|
|
@ -136,8 +140,14 @@ void LibraryMenu::createMoveActions()
|
||||||
connect(aMoveTopCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToExile);
|
connect(aMoveTopCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToExile);
|
||||||
aMoveTopCardsToGraveyard = new QAction(this);
|
aMoveTopCardsToGraveyard = new QAction(this);
|
||||||
connect(aMoveTopCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToGrave);
|
connect(aMoveTopCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToGrave);
|
||||||
|
aMoveTopCardsToGraveyardFaceDown = new QAction(this);
|
||||||
|
connect(aMoveTopCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveTopCardsToGraveFaceDown);
|
||||||
aMoveTopCardsToExile = new QAction(this);
|
aMoveTopCardsToExile = new QAction(this);
|
||||||
connect(aMoveTopCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToExile);
|
connect(aMoveTopCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToExile);
|
||||||
|
aMoveTopCardsToExileFaceDown = new QAction(this);
|
||||||
|
connect(aMoveTopCardsToExileFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveTopCardsToExileFaceDown);
|
||||||
aMoveTopCardsUntil = new QAction(this);
|
aMoveTopCardsUntil = new QAction(this);
|
||||||
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsUntil);
|
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsUntil);
|
||||||
aMoveTopCardToBottom = new QAction(this);
|
aMoveTopCardToBottom = new QAction(this);
|
||||||
|
|
@ -156,8 +166,14 @@ void LibraryMenu::createMoveActions()
|
||||||
aMoveBottomCardsToGraveyard = new QAction(this);
|
aMoveBottomCardsToGraveyard = new QAction(this);
|
||||||
connect(aMoveBottomCardsToGraveyard, &QAction::triggered, playerActions,
|
connect(aMoveBottomCardsToGraveyard, &QAction::triggered, playerActions,
|
||||||
&PlayerActions::actMoveBottomCardsToGrave);
|
&PlayerActions::actMoveBottomCardsToGrave);
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown = new QAction(this);
|
||||||
|
connect(aMoveBottomCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveBottomCardsToGraveFaceDown);
|
||||||
aMoveBottomCardsToExile = new QAction(this);
|
aMoveBottomCardsToExile = new QAction(this);
|
||||||
connect(aMoveBottomCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToExile);
|
connect(aMoveBottomCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToExile);
|
||||||
|
aMoveBottomCardsToExileFaceDown = new QAction(this);
|
||||||
|
connect(aMoveBottomCardsToExileFaceDown, &QAction::triggered, playerActions,
|
||||||
|
&PlayerActions::actMoveBottomCardsToExileFaceDown);
|
||||||
aMoveBottomCardToTop = new QAction(this);
|
aMoveBottomCardToTop = new QAction(this);
|
||||||
connect(aMoveBottomCardToTop, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToTop);
|
connect(aMoveBottomCardToTop, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToTop);
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +232,9 @@ void LibraryMenu::retranslateUi()
|
||||||
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
|
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
|
||||||
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
|
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
|
||||||
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
|
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
|
||||||
|
aMoveTopCardsToGraveyardFaceDown->setText(tr("Move top cards to graveyard face down..."));
|
||||||
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
|
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
|
||||||
|
aMoveTopCardsToExileFaceDown->setText(tr("Move top cards to exile face down..."));
|
||||||
aMoveTopCardsUntil->setText(tr("Put top cards on stack &until..."));
|
aMoveTopCardsUntil->setText(tr("Put top cards on stack &until..."));
|
||||||
aShuffleTopCards->setText(tr("Shuffle top cards..."));
|
aShuffleTopCards->setText(tr("Shuffle top cards..."));
|
||||||
|
|
||||||
|
|
@ -227,7 +245,9 @@ void LibraryMenu::retranslateUi()
|
||||||
aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard"));
|
aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard"));
|
||||||
aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile"));
|
aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile"));
|
||||||
aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard..."));
|
aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard..."));
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown->setText(tr("Move bottom cards to graveyard face down..."));
|
||||||
aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile..."));
|
aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile..."));
|
||||||
|
aMoveBottomCardsToExileFaceDown->setText(tr("Move bottom cards to exile face down..."));
|
||||||
aMoveBottomCardToTop->setText(tr("Put bottom card on &top"));
|
aMoveBottomCardToTop->setText(tr("Put bottom card on &top"));
|
||||||
aShuffleBottomCards->setText(tr("Shuffle bottom cards..."));
|
aShuffleBottomCards->setText(tr("Shuffle bottom cards..."));
|
||||||
}
|
}
|
||||||
|
|
@ -335,8 +355,10 @@ void LibraryMenu::setShortcutsActive()
|
||||||
aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown"));
|
aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown"));
|
||||||
aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard"));
|
aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard"));
|
||||||
aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard"));
|
aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard"));
|
||||||
|
aMoveTopCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyardFaceDown"));
|
||||||
aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile"));
|
aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile"));
|
||||||
aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile"));
|
aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile"));
|
||||||
|
aMoveTopCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExileFaceDown"));
|
||||||
aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil"));
|
aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil"));
|
||||||
aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom"));
|
aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom"));
|
||||||
aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard"));
|
aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard"));
|
||||||
|
|
@ -345,8 +367,10 @@ void LibraryMenu::setShortcutsActive()
|
||||||
aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown"));
|
aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown"));
|
||||||
aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave"));
|
aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave"));
|
||||||
aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave"));
|
aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave"));
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGraveFaceDown"));
|
||||||
aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile"));
|
aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile"));
|
||||||
aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile"));
|
aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile"));
|
||||||
|
aMoveBottomCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExileFaceDown"));
|
||||||
aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop"));
|
aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -367,8 +391,10 @@ void LibraryMenu::setShortcutsInactive()
|
||||||
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
||||||
|
aMoveTopCardsToGraveyardFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveTopCardToExile->setShortcut(QKeySequence());
|
aMoveTopCardToExile->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
||||||
|
aMoveTopCardsToExileFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsUntil->setShortcut(QKeySequence());
|
aMoveTopCardsUntil->setShortcut(QKeySequence());
|
||||||
aDrawBottomCard->setShortcut(QKeySequence());
|
aDrawBottomCard->setShortcut(QKeySequence());
|
||||||
aDrawBottomCards->setShortcut(QKeySequence());
|
aDrawBottomCards->setShortcut(QKeySequence());
|
||||||
|
|
@ -376,6 +402,8 @@ void LibraryMenu::setShortcutsInactive()
|
||||||
aMoveBottomToPlayFaceDown->setShortcut(QKeySequence());
|
aMoveBottomToPlayFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardToGraveyard->setShortcut(QKeySequence());
|
aMoveBottomCardToGraveyard->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
|
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardsToGraveyardFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardToExile->setShortcut(QKeySequence());
|
aMoveBottomCardToExile->setShortcut(QKeySequence());
|
||||||
aMoveBottomCardsToExile->setShortcut(QKeySequence());
|
aMoveBottomCardsToExile->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardsToExileFaceDown->setShortcut(QKeySequence());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define COCKATRICE_LIBRARY_MENU_H
|
#define COCKATRICE_LIBRARY_MENU_H
|
||||||
|
|
||||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
@ -15,7 +16,7 @@
|
||||||
class Player;
|
class Player;
|
||||||
class PlayerActions;
|
class PlayerActions;
|
||||||
|
|
||||||
class LibraryMenu : public TearOffMenu
|
class LibraryMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public slots:
|
public slots:
|
||||||
|
|
@ -28,15 +29,15 @@ public:
|
||||||
void createShuffleActions();
|
void createShuffleActions();
|
||||||
void createMoveActions();
|
void createMoveActions();
|
||||||
void createViewActions();
|
void createViewActions();
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
void populateRevealLibraryMenuWithActivePlayers();
|
void populateRevealLibraryMenuWithActivePlayers();
|
||||||
void populateLendLibraryMenuWithActivePlayers();
|
void populateLendLibraryMenuWithActivePlayers();
|
||||||
void populateRevealTopCardMenuWithActivePlayers();
|
void populateRevealTopCardMenuWithActivePlayers();
|
||||||
void onRevealLibraryTriggered();
|
void onRevealLibraryTriggered();
|
||||||
void onLendLibraryTriggered();
|
void onLendLibraryTriggered();
|
||||||
void onRevealTopCardTriggered();
|
void onRevealTopCardTriggered();
|
||||||
void setShortcutsActive();
|
void setShortcutsActive() override;
|
||||||
void setShortcutsInactive();
|
void setShortcutsInactive() override;
|
||||||
|
|
||||||
[[nodiscard]] bool isAlwaysRevealTopCardChecked() const
|
[[nodiscard]] bool isAlwaysRevealTopCardChecked() const
|
||||||
{
|
{
|
||||||
|
|
@ -88,7 +89,9 @@ public:
|
||||||
QAction *aMoveTopCardToGraveyard = nullptr;
|
QAction *aMoveTopCardToGraveyard = nullptr;
|
||||||
QAction *aMoveTopCardToExile = nullptr;
|
QAction *aMoveTopCardToExile = nullptr;
|
||||||
QAction *aMoveTopCardsToGraveyard = nullptr;
|
QAction *aMoveTopCardsToGraveyard = nullptr;
|
||||||
|
QAction *aMoveTopCardsToGraveyardFaceDown = nullptr;
|
||||||
QAction *aMoveTopCardsToExile = nullptr;
|
QAction *aMoveTopCardsToExile = nullptr;
|
||||||
|
QAction *aMoveTopCardsToExileFaceDown = nullptr;
|
||||||
QAction *aMoveTopCardsUntil = nullptr;
|
QAction *aMoveTopCardsUntil = nullptr;
|
||||||
QAction *aShuffleTopCards = nullptr;
|
QAction *aShuffleTopCards = nullptr;
|
||||||
|
|
||||||
|
|
@ -100,7 +103,9 @@ public:
|
||||||
QAction *aMoveBottomCardToGraveyard = nullptr;
|
QAction *aMoveBottomCardToGraveyard = nullptr;
|
||||||
QAction *aMoveBottomCardToExile = nullptr;
|
QAction *aMoveBottomCardToExile = nullptr;
|
||||||
QAction *aMoveBottomCardsToGraveyard = nullptr;
|
QAction *aMoveBottomCardsToGraveyard = nullptr;
|
||||||
|
QAction *aMoveBottomCardsToGraveyardFaceDown = nullptr;
|
||||||
QAction *aMoveBottomCardsToExile = nullptr;
|
QAction *aMoveBottomCardsToExile = nullptr;
|
||||||
|
QAction *aMoveBottomCardsToExileFaceDown = nullptr;
|
||||||
QAction *aShuffleBottomCards = nullptr;
|
QAction *aShuffleBottomCards = nullptr;
|
||||||
|
|
||||||
int defaultNumberTopCards = 1;
|
int defaultNumberTopCards = 1;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ MoveMenu::MoveMenu(Player *player) : QMenu(tr("Move to"))
|
||||||
aMoveToBottomLibrary = new QAction(this);
|
aMoveToBottomLibrary = new QAction(this);
|
||||||
aMoveToBottomLibrary->setData(cmMoveToBottomLibrary);
|
aMoveToBottomLibrary->setData(cmMoveToBottomLibrary);
|
||||||
aMoveToXfromTopOfLibrary = new QAction(this);
|
aMoveToXfromTopOfLibrary = new QAction(this);
|
||||||
|
aMoveToTable = new QAction(this);
|
||||||
|
aMoveToTable->setData(cmMoveToTable);
|
||||||
aMoveToGraveyard = new QAction(this);
|
aMoveToGraveyard = new QAction(this);
|
||||||
aMoveToHand = new QAction(this);
|
aMoveToHand = new QAction(this);
|
||||||
aMoveToHand->setData(cmMoveToHand);
|
aMoveToHand->setData(cmMoveToHand);
|
||||||
|
|
@ -22,6 +24,7 @@ MoveMenu::MoveMenu(Player *player) : QMenu(tr("Move to"))
|
||||||
connect(aMoveToBottomLibrary, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
connect(aMoveToBottomLibrary, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
||||||
connect(aMoveToXfromTopOfLibrary, &QAction::triggered, player->getPlayerActions(),
|
connect(aMoveToXfromTopOfLibrary, &QAction::triggered, player->getPlayerActions(),
|
||||||
&PlayerActions::actMoveCardXCardsFromTop);
|
&PlayerActions::actMoveCardXCardsFromTop);
|
||||||
|
connect(aMoveToTable, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
||||||
connect(aMoveToHand, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
connect(aMoveToHand, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
||||||
connect(aMoveToGraveyard, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
connect(aMoveToGraveyard, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
||||||
connect(aMoveToExile, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
connect(aMoveToExile, &QAction::triggered, player->getPlayerActions(), &PlayerActions::cardMenuAction);
|
||||||
|
|
@ -30,6 +33,8 @@ MoveMenu::MoveMenu(Player *player) : QMenu(tr("Move to"))
|
||||||
addAction(aMoveToXfromTopOfLibrary);
|
addAction(aMoveToXfromTopOfLibrary);
|
||||||
addAction(aMoveToBottomLibrary);
|
addAction(aMoveToBottomLibrary);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
|
addAction(aMoveToTable);
|
||||||
|
addSeparator();
|
||||||
addAction(aMoveToHand);
|
addAction(aMoveToHand);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
addAction(aMoveToGraveyard);
|
addAction(aMoveToGraveyard);
|
||||||
|
|
@ -47,6 +52,7 @@ void MoveMenu::setShortcutsActive()
|
||||||
|
|
||||||
aMoveToTopLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToTopLibrary"));
|
aMoveToTopLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToTopLibrary"));
|
||||||
aMoveToBottomLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToBottomLibrary"));
|
aMoveToBottomLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToBottomLibrary"));
|
||||||
|
aMoveToTable->setShortcuts(shortcuts.getShortcut("Player/aMoveToTable"));
|
||||||
aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand"));
|
aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand"));
|
||||||
aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard"));
|
aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard"));
|
||||||
aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile"));
|
aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile"));
|
||||||
|
|
@ -57,7 +63,8 @@ void MoveMenu::retranslateUi()
|
||||||
aMoveToTopLibrary->setText(tr("&Top of library in random order"));
|
aMoveToTopLibrary->setText(tr("&Top of library in random order"));
|
||||||
aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library..."));
|
aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library..."));
|
||||||
aMoveToBottomLibrary->setText(tr("&Bottom of library in random order"));
|
aMoveToBottomLibrary->setText(tr("&Bottom of library in random order"));
|
||||||
|
aMoveToTable->setText(tr("T&able"));
|
||||||
aMoveToHand->setText(tr("&Hand"));
|
aMoveToHand->setText(tr("&Hand"));
|
||||||
aMoveToGraveyard->setText(tr("&Graveyard"));
|
aMoveToGraveyard->setText(tr("&Graveyard"));
|
||||||
aMoveToExile->setText(tr("&Exile"));
|
aMoveToExile->setText(tr("&Exile"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ public:
|
||||||
QAction *aMoveToBottomLibrary = nullptr;
|
QAction *aMoveToBottomLibrary = nullptr;
|
||||||
|
|
||||||
QAction *aMoveToHand = nullptr;
|
QAction *aMoveToHand = nullptr;
|
||||||
|
QAction *aMoveToTable = nullptr;
|
||||||
QAction *aMoveToGraveyard = nullptr;
|
QAction *aMoveToGraveyard = nullptr;
|
||||||
QAction *aMoveToExile = nullptr;
|
QAction *aMoveToExile = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,38 +10,29 @@
|
||||||
|
|
||||||
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
|
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
|
||||||
|
|
||||||
PlayerMenu::PlayerMenu(Player *_player) : player(_player)
|
PlayerMenu::PlayerMenu(Player *_player) : QObject(_player), player(_player)
|
||||||
{
|
{
|
||||||
playerMenu = new TearOffMenu();
|
playerMenu = new TearOffMenu();
|
||||||
|
|
||||||
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
||||||
handMenu = new HandMenu(player, player->getPlayerActions(), playerMenu);
|
handMenu = addManagedMenu<HandMenu>(player, player->getPlayerActions(), playerMenu);
|
||||||
playerMenu->addMenu(handMenu);
|
libraryMenu = addManagedMenu<LibraryMenu>(player, playerMenu);
|
||||||
|
|
||||||
libraryMenu = new LibraryMenu(player, playerMenu);
|
|
||||||
playerMenu->addMenu(libraryMenu);
|
|
||||||
} else {
|
} else {
|
||||||
handMenu = nullptr;
|
handMenu = nullptr;
|
||||||
libraryMenu = nullptr;
|
libraryMenu = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
graveMenu = new GraveyardMenu(player, playerMenu);
|
graveMenu = addManagedMenu<GraveyardMenu>(player, playerMenu);
|
||||||
playerMenu->addMenu(graveMenu);
|
rfgMenu = addManagedMenu<RfgMenu>(player, playerMenu);
|
||||||
|
|
||||||
rfgMenu = new RfgMenu(player, playerMenu);
|
|
||||||
playerMenu->addMenu(rfgMenu);
|
|
||||||
|
|
||||||
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
||||||
sideboardMenu = new SideboardMenu(player, playerMenu);
|
sideboardMenu = addManagedMenu<SideboardMenu>(player, playerMenu);
|
||||||
playerMenu->addMenu(sideboardMenu);
|
customZonesMenu = addManagedMenu<CustomZoneMenu>(player);
|
||||||
|
|
||||||
customZonesMenu = new CustomZoneMenu(player);
|
|
||||||
playerMenu->addMenu(customZonesMenu);
|
|
||||||
playerMenu->addSeparator();
|
playerMenu->addSeparator();
|
||||||
|
|
||||||
countersMenu = playerMenu->addMenu(QString());
|
countersMenu = playerMenu->addMenu(QString());
|
||||||
|
|
||||||
utilityMenu = new UtilityMenu(player, playerMenu);
|
utilityMenu = createManagedComponent<UtilityMenu>(player, playerMenu);
|
||||||
} else {
|
} else {
|
||||||
sideboardMenu = nullptr;
|
sideboardMenu = nullptr;
|
||||||
customZonesMenu = nullptr;
|
customZonesMenu = nullptr;
|
||||||
|
|
@ -50,8 +41,7 @@ PlayerMenu::PlayerMenu(Player *_player) : player(_player)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player->getPlayerInfo()->getLocal()) {
|
if (player->getPlayerInfo()->getLocal()) {
|
||||||
sayMenu = new SayMenu(player);
|
sayMenu = addManagedMenu<SayMenu>(player);
|
||||||
playerMenu->addMenu(sayMenu);
|
|
||||||
} else {
|
} else {
|
||||||
sayMenu = nullptr;
|
sayMenu = nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -99,40 +89,18 @@ void PlayerMenu::retranslateUi()
|
||||||
{
|
{
|
||||||
playerMenu->setTitle(tr("Player \"%1\"").arg(player->getPlayerInfo()->getName()));
|
playerMenu->setTitle(tr("Player \"%1\"").arg(player->getPlayerInfo()->getName()));
|
||||||
|
|
||||||
if (handMenu) {
|
for (auto *component : managedComponents) {
|
||||||
handMenu->retranslateUi();
|
component->retranslateUi();
|
||||||
}
|
|
||||||
if (libraryMenu) {
|
|
||||||
libraryMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
graveMenu->retranslateUi();
|
|
||||||
rfgMenu->retranslateUi();
|
|
||||||
|
|
||||||
if (sideboardMenu) {
|
|
||||||
sideboardMenu->retranslateUi();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (countersMenu) {
|
if (countersMenu) {
|
||||||
countersMenu->setTitle(tr("&Counters"));
|
countersMenu->setTitle(tr("&Counters"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customZonesMenu) {
|
|
||||||
customZonesMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
||||||
while (counterIterator.hasNext()) {
|
while (counterIterator.hasNext()) {
|
||||||
counterIterator.next().value()->retranslateUi();
|
counterIterator.next().value()->retranslateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utilityMenu) {
|
|
||||||
utilityMenu->retranslateUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sayMenu) {
|
|
||||||
sayMenu->setTitle(tr("S&ay"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerMenu::refreshShortcuts()
|
void PlayerMenu::refreshShortcuts()
|
||||||
|
|
@ -153,52 +121,29 @@ void PlayerMenu::setShortcutsActive()
|
||||||
{
|
{
|
||||||
shortcutsActive = true;
|
shortcutsActive = true;
|
||||||
|
|
||||||
if (handMenu) {
|
for (auto *component : managedComponents) {
|
||||||
handMenu->setShortcutsActive();
|
component->setShortcutsActive();
|
||||||
}
|
|
||||||
if (libraryMenu) {
|
|
||||||
libraryMenu->setShortcutsActive();
|
|
||||||
}
|
|
||||||
graveMenu->setShortcutsActive();
|
|
||||||
// No shortcuts for RfgMenu yet
|
|
||||||
|
|
||||||
if (sideboardMenu) {
|
|
||||||
sideboardMenu->setShortcutsActive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Counters implement AbstractPlayerComponent but are iterated via Player::counters
|
||||||
|
// (the authoritative source) rather than managedComponents to avoid a redundant
|
||||||
|
// list that must stay in sync with the map.
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
||||||
while (counterIterator.hasNext()) {
|
while (counterIterator.hasNext()) {
|
||||||
counterIterator.next().value()->setShortcutsActive();
|
counterIterator.next().value()->setShortcutsActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utilityMenu) {
|
|
||||||
utilityMenu->setShortcutsActive();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerMenu::setShortcutsInactive()
|
void PlayerMenu::setShortcutsInactive()
|
||||||
{
|
{
|
||||||
shortcutsActive = false;
|
shortcutsActive = false;
|
||||||
|
|
||||||
if (handMenu) {
|
for (auto *component : managedComponents) {
|
||||||
handMenu->setShortcutsInactive();
|
component->setShortcutsInactive();
|
||||||
}
|
|
||||||
if (libraryMenu) {
|
|
||||||
libraryMenu->setShortcutsInactive();
|
|
||||||
}
|
|
||||||
graveMenu->setShortcutsInactive();
|
|
||||||
// No shortcuts for RfgMenu yet
|
|
||||||
|
|
||||||
if (sideboardMenu) {
|
|
||||||
sideboardMenu->setShortcutsInactive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
QMapIterator<int, AbstractCounter *> counterIterator(player->getCounters());
|
||||||
while (counterIterator.hasNext()) {
|
while (counterIterator.hasNext()) {
|
||||||
counterIterator.next().value()->setShortcutsInactive();
|
counterIterator.next().value()->setShortcutsInactive();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utilityMenu) {
|
|
||||||
utilityMenu->setShortcutsInactive();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* @file player_menu.h
|
* @file player_menu.h
|
||||||
* @ingroup GameMenusPlayers
|
* @ingroup GameMenusPlayers
|
||||||
* @brief TODO: Document this.
|
* @brief Orchestrates lifecycle management for all player-bound UI components.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef COCKATRICE_PLAYER_MENU_H
|
#ifndef COCKATRICE_PLAYER_MENU_H
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "sideboard_menu.h"
|
#include "sideboard_menu.h"
|
||||||
#include "utility_menu.h"
|
#include "utility_menu.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
|
@ -36,7 +37,8 @@ private slots:
|
||||||
void refreshShortcuts();
|
void refreshShortcuts();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlayerMenu(Player *player);
|
explicit PlayerMenu(Player *player);
|
||||||
|
/// Lifecycle methods: delegate to all managedComponents, plus counters separately via player->getCounters().
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
||||||
QMenu *updateCardMenu(const CardItem *card);
|
QMenu *updateCardMenu(const CardItem *card);
|
||||||
|
|
@ -66,7 +68,9 @@ public:
|
||||||
return shortcutsActive;
|
return shortcutsActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Delegates to all managedComponents, plus counters separately.
|
||||||
void setShortcutsActive();
|
void setShortcutsActive();
|
||||||
|
/// Delegates to all managedComponents, plus counters separately.
|
||||||
void setShortcutsInactive();
|
void setShortcutsInactive();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -82,9 +86,26 @@ private:
|
||||||
SayMenu *sayMenu;
|
SayMenu *sayMenu;
|
||||||
CustomZoneMenu *customZonesMenu;
|
CustomZoneMenu *customZonesMenu;
|
||||||
|
|
||||||
bool shortcutsActive;
|
/// Drives AbstractPlayerComponent lifecycle delegation. Counters are iterated separately via player->getCounters().
|
||||||
|
QList<AbstractPlayerComponent *> managedComponents;
|
||||||
|
bool shortcutsActive = false;
|
||||||
|
|
||||||
void initSayMenu();
|
/// Creates component, adds it as a submenu of playerMenu, and registers in managedComponents.
|
||||||
|
template <typename MenuT, typename... Args> MenuT *addManagedMenu(Args &&...args)
|
||||||
|
{
|
||||||
|
auto *menu = new MenuT(std::forward<Args>(args)...);
|
||||||
|
playerMenu->addMenu(menu);
|
||||||
|
managedComponents.append(menu);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates component and registers in managedComponents, but does NOT add it as a submenu.
|
||||||
|
template <typename ComponentT, typename... Args> ComponentT *createManagedComponent(Args &&...args)
|
||||||
|
{
|
||||||
|
auto *component = new ComponentT(std::forward<Args>(args)...);
|
||||||
|
managedComponents.append(component);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_PLAYER_MENU_H
|
#endif // COCKATRICE_PLAYER_MENU_H
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
#include "../player.h"
|
#include "../player.h"
|
||||||
#include "../player_actions.h"
|
#include "../player_actions.h"
|
||||||
|
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
RfgMenu::RfgMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
RfgMenu::RfgMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||||
{
|
{
|
||||||
createMoveActions();
|
createMoveActions();
|
||||||
|
|
@ -30,13 +32,13 @@ void RfgMenu::createMoveActions()
|
||||||
auto rfg = player->getRfgZone();
|
auto rfg = player->getRfgZone();
|
||||||
|
|
||||||
aMoveRfgToTopLibrary = new QAction(this);
|
aMoveRfgToTopLibrary = new QAction(this);
|
||||||
aMoveRfgToTopLibrary->setData(QList<QVariant>() << "deck" << 0);
|
aMoveRfgToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||||
aMoveRfgToBottomLibrary = new QAction(this);
|
aMoveRfgToBottomLibrary = new QAction(this);
|
||||||
aMoveRfgToBottomLibrary->setData(QList<QVariant>() << "deck" << -1);
|
aMoveRfgToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||||
aMoveRfgToHand = new QAction(this);
|
aMoveRfgToHand = new QAction(this);
|
||||||
aMoveRfgToHand->setData(QList<QVariant>() << "hand" << 0);
|
aMoveRfgToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
|
||||||
aMoveRfgToGrave = new QAction(this);
|
aMoveRfgToGrave = new QAction(this);
|
||||||
aMoveRfgToGrave->setData(QList<QVariant>() << "grave" << 0);
|
aMoveRfgToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
|
||||||
|
|
||||||
connect(aMoveRfgToTopLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
connect(aMoveRfgToTopLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||||
connect(aMoveRfgToBottomLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
connect(aMoveRfgToBottomLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,26 @@
|
||||||
#define COCKATRICE_RFG_MENU_H
|
#define COCKATRICE_RFG_MENU_H
|
||||||
|
|
||||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class RfgMenu : public TearOffMenu
|
class RfgMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit RfgMenu(Player *player, QWidget *parent = nullptr);
|
explicit RfgMenu(Player *player, QWidget *parent = nullptr);
|
||||||
void createMoveActions();
|
void createMoveActions();
|
||||||
void createViewActions();
|
void createViewActions();
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
|
void setShortcutsActive() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void setShortcutsInactive() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QMenu *moveRfgMenu = nullptr;
|
QMenu *moveRfgMenu = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,31 @@ SayMenu::SayMenu(Player *_player) : player(_player)
|
||||||
{
|
{
|
||||||
connect(&SettingsCache::instance().messages(), &MessageSettings::messageMacrosChanged, this, &SayMenu::initSayMenu);
|
connect(&SettingsCache::instance().messages(), &MessageSettings::messageMacrosChanged, this, &SayMenu::initSayMenu);
|
||||||
initSayMenu();
|
initSayMenu();
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SayMenu::retranslateUi()
|
||||||
|
{
|
||||||
|
setTitle(tr("S&ay"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SayMenu::setShortcutsActive()
|
||||||
|
{
|
||||||
|
shortcutsActive = true;
|
||||||
|
|
||||||
|
const auto menuActions = actions();
|
||||||
|
for (int i = 0; i < menuActions.size() && i < 10; ++i) {
|
||||||
|
menuActions[i]->setShortcut(QKeySequence("Ctrl+" + QString::number((i + 1) % 10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SayMenu::setShortcutsInactive()
|
||||||
|
{
|
||||||
|
shortcutsActive = false;
|
||||||
|
|
||||||
|
for (auto *action : actions()) {
|
||||||
|
action->setShortcut(QKeySequence());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SayMenu::initSayMenu()
|
void SayMenu::initSayMenu()
|
||||||
|
|
@ -19,10 +44,11 @@ void SayMenu::initSayMenu()
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
auto *newAction = new QAction(SettingsCache::instance().messages().getMessageAt(i), this);
|
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);
|
connect(newAction, &QAction::triggered, player->getPlayerActions(), &PlayerActions::actSayMessage);
|
||||||
addAction(newAction);
|
addAction(newAction);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (shortcutsActive) {
|
||||||
|
setShortcutsActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,27 @@
|
||||||
#ifndef COCKATRICE_SAY_MENU_H
|
#ifndef COCKATRICE_SAY_MENU_H
|
||||||
#define COCKATRICE_SAY_MENU_H
|
#define COCKATRICE_SAY_MENU_H
|
||||||
|
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class SayMenu : public QMenu
|
class SayMenu : public QMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SayMenu(Player *player);
|
explicit SayMenu(Player *player);
|
||||||
|
|
||||||
|
void retranslateUi() override;
|
||||||
|
void setShortcutsActive() override;
|
||||||
|
void setShortcutsInactive() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
void initSayMenu();
|
void initSayMenu();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Player *player;
|
Player *player;
|
||||||
|
bool shortcutsActive = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_SAY_MENU_H
|
#endif // COCKATRICE_SAY_MENU_H
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,20 @@
|
||||||
#ifndef COCKATRICE_SIDEBOARD_MENU_H
|
#ifndef COCKATRICE_SIDEBOARD_MENU_H
|
||||||
#define COCKATRICE_SIDEBOARD_MENU_H
|
#define COCKATRICE_SIDEBOARD_MENU_H
|
||||||
|
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class SideboardMenu : public QMenu
|
class SideboardMenu : public QMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SideboardMenu(Player *player, QMenu *playerMenu);
|
explicit SideboardMenu(Player *player, QMenu *playerMenu);
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
void setShortcutsActive();
|
void setShortcutsActive() override;
|
||||||
void setShortcutsInactive();
|
void setShortcutsInactive() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Player *player;
|
Player *player;
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,19 @@
|
||||||
#ifndef COCKATRICE_UTILITY_MENU_H
|
#ifndef COCKATRICE_UTILITY_MENU_H
|
||||||
#define COCKATRICE_UTILITY_MENU_H
|
#define COCKATRICE_UTILITY_MENU_H
|
||||||
|
|
||||||
|
#include "abstract_player_component.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class UtilityMenu : public QMenu
|
class UtilityMenu : public QMenu, public AbstractPlayerComponent
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public slots:
|
public slots:
|
||||||
void populatePredefinedTokensMenu();
|
void populatePredefinedTokensMenu();
|
||||||
void retranslateUi();
|
void retranslateUi() override;
|
||||||
void setShortcutsActive();
|
void setShortcutsActive() override;
|
||||||
void setShortcutsInactive();
|
void setShortcutsInactive() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit UtilityMenu(Player *player, QMenu *playerMenu);
|
explicit UtilityMenu(Player *player, QMenu *playerMenu);
|
||||||
|
|
|
||||||
|
|
@ -61,15 +61,15 @@ void Player::forwardActionSignalsToEventHandler()
|
||||||
|
|
||||||
void Player::initializeZones()
|
void Player::initializeZones()
|
||||||
{
|
{
|
||||||
addZone(new PileZoneLogic(this, "deck", false, true, false, this));
|
addZone(new PileZoneLogic(this, ZoneNames::DECK, false, true, false, this));
|
||||||
addZone(new PileZoneLogic(this, "grave", false, false, true, this));
|
addZone(new PileZoneLogic(this, ZoneNames::GRAVE, false, false, true, this));
|
||||||
addZone(new PileZoneLogic(this, "rfg", false, false, true, this));
|
addZone(new PileZoneLogic(this, ZoneNames::EXILE, false, false, true, this));
|
||||||
addZone(new PileZoneLogic(this, "sb", false, false, false, this));
|
addZone(new PileZoneLogic(this, ZoneNames::SIDEBOARD, false, false, false, this));
|
||||||
addZone(new TableZoneLogic(this, "table", true, false, true, this));
|
addZone(new TableZoneLogic(this, ZoneNames::TABLE, true, false, true, this));
|
||||||
addZone(new StackZoneLogic(this, "stack", true, false, true, this));
|
addZone(new StackZoneLogic(this, ZoneNames::STACK, true, false, true, this));
|
||||||
bool visibleHand = playerInfo->getLocalOrJudge() ||
|
bool visibleHand = playerInfo->getLocalOrJudge() ||
|
||||||
(game->getPlayerManager()->isSpectator() && game->getGameMetaInfo()->spectatorsOmniscient());
|
(game->getPlayerManager()->isSpectator() && game->getGameMetaInfo()->spectatorsOmniscient());
|
||||||
addZone(new HandZoneLogic(this, "hand", false, false, visibleHand, this));
|
addZone(new HandZoneLogic(this, ZoneNames::HAND, false, false, visibleHand, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::~Player()
|
Player::~Player()
|
||||||
|
|
@ -119,13 +119,13 @@ void Player::setZoneId(int _zoneId)
|
||||||
void Player::processPlayerInfo(const ServerInfo_Player &info)
|
void Player::processPlayerInfo(const ServerInfo_Player &info)
|
||||||
{
|
{
|
||||||
static QSet<QString> builtinZones{/* PileZones */
|
static QSet<QString> builtinZones{/* PileZones */
|
||||||
"deck", "grave", "rfg", "sb",
|
ZoneNames::DECK, ZoneNames::GRAVE, ZoneNames::EXILE, ZoneNames::SIDEBOARD,
|
||||||
/* TableZone */
|
/* TableZone */
|
||||||
"table",
|
ZoneNames::TABLE,
|
||||||
/* StackZone */
|
/* StackZone */
|
||||||
"stack",
|
ZoneNames::STACK,
|
||||||
/* HandZone */
|
/* HandZone */
|
||||||
"hand"};
|
ZoneNames::HAND};
|
||||||
clearCounters();
|
clearCounters();
|
||||||
clearArrows();
|
clearArrows();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <libcockatrice/filters/filter_string.h>
|
#include <libcockatrice/filters/filter_string.h>
|
||||||
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
|
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/game_event.pb.h>
|
#include <libcockatrice/protocol/pb/game_event.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PlayerLog, "player");
|
inline Q_LOGGING_CATEGORY(PlayerLog, "player");
|
||||||
|
|
||||||
|
|
@ -155,37 +156,37 @@ public:
|
||||||
|
|
||||||
PileZoneLogic *getDeckZone()
|
PileZoneLogic *getDeckZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("deck"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::DECK));
|
||||||
}
|
}
|
||||||
|
|
||||||
PileZoneLogic *getGraveZone()
|
PileZoneLogic *getGraveZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("grave"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::GRAVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
PileZoneLogic *getRfgZone()
|
PileZoneLogic *getRfgZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("rfg"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::EXILE));
|
||||||
}
|
}
|
||||||
|
|
||||||
PileZoneLogic *getSideboardZone()
|
PileZoneLogic *getSideboardZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<PileZoneLogic *>(zones.value("sb"));
|
return qobject_cast<PileZoneLogic *>(zones.value(ZoneNames::SIDEBOARD));
|
||||||
}
|
}
|
||||||
|
|
||||||
TableZoneLogic *getTableZone()
|
TableZoneLogic *getTableZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<TableZoneLogic *>(zones.value("table"));
|
return qobject_cast<TableZoneLogic *>(zones.value(ZoneNames::TABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
StackZoneLogic *getStackZone()
|
StackZoneLogic *getStackZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<StackZoneLogic *>(zones.value("stack"));
|
return qobject_cast<StackZoneLogic *>(zones.value(ZoneNames::STACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
HandZoneLogic *getHandZone()
|
HandZoneLogic *getHandZone()
|
||||||
{
|
{
|
||||||
return qobject_cast<HandZoneLogic *>(zones.value("hand"));
|
return qobject_cast<HandZoneLogic *>(zones.value(ZoneNames::HAND));
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractCounter *addCounter(const ServerInfo_Counter &counter);
|
AbstractCounter *addCounter(const ServerInfo_Counter &counter);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../../interface/widgets/tabs/tab_game.h"
|
#include "../../interface/widgets/tabs/tab_game.h"
|
||||||
#include "../../interface/widgets/utility/get_text_with_max.h"
|
#include "../../interface/widgets/utility/get_text_with_max.h"
|
||||||
#include "../board/card_item.h"
|
#include "../board/card_item.h"
|
||||||
|
#include "../client/settings/card_counter_settings.h"
|
||||||
#include "../dialogs/dlg_move_top_cards_until.h"
|
#include "../dialogs/dlg_move_top_cards_until.h"
|
||||||
#include "../dialogs/dlg_roll_dice.h"
|
#include "../dialogs/dlg_roll_dice.h"
|
||||||
#include "../zones/hand_zone.h"
|
#include "../zones/hand_zone.h"
|
||||||
|
|
@ -27,12 +28,15 @@
|
||||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||||
|
#include <libcockatrice/utility/expression.h>
|
||||||
#include <libcockatrice/utility/trice_limits.h>
|
#include <libcockatrice/utility/trice_limits.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
// milliseconds in between triggers of the move top cards until action
|
// milliseconds in between triggers of the move top cards until action
|
||||||
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
|
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
|
||||||
|
|
||||||
PlayerActions::PlayerActions(Player *_player) : player(_player), lastTokenTableRow(0), movingCardsUntil(false)
|
PlayerActions::PlayerActions(Player *_player)
|
||||||
|
: QObject(_player), player(_player), lastTokenTableRow(0), movingCardsUntil(false)
|
||||||
{
|
{
|
||||||
moveTopCardTimer = new QTimer(this);
|
moveTopCardTimer = new QTimer(this);
|
||||||
moveTopCardTimer->setInterval(MOVE_TOP_CARD_UNTIL_INTERVAL);
|
moveTopCardTimer->setInterval(MOVE_TOP_CARD_UNTIL_INTERVAL);
|
||||||
|
|
@ -63,25 +67,25 @@ void PlayerActions::playCard(CardItem *card, bool faceDown)
|
||||||
int tableRow = info.getUiAttributes().tableRow;
|
int tableRow = info.getUiAttributes().tableRow;
|
||||||
bool playToStack = SettingsCache::instance().getPlayToStack();
|
bool playToStack = SettingsCache::instance().getPlayToStack();
|
||||||
QString currentZone = card->getZone()->getName();
|
QString currentZone = card->getZone()->getName();
|
||||||
if (currentZone == "stack" && tableRow == 3) {
|
if (!faceDown && currentZone == ZoneNames::STACK && tableRow == 3) {
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
} else if (!faceDown &&
|
} else if (!faceDown && ((!playToStack && tableRow == 3) ||
|
||||||
((!playToStack && tableRow == 3) || ((playToStack && tableRow != 0) && currentZone != "stack"))) {
|
((playToStack && tableRow != 0) && currentZone != ZoneNames::STACK))) {
|
||||||
cmd.set_target_zone("stack");
|
cmd.set_target_zone(ZoneNames::STACK);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
} else {
|
} else {
|
||||||
tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
||||||
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - tableRow));
|
QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(tableRow));
|
||||||
cardToMove->set_face_down(faceDown);
|
cardToMove->set_face_down(faceDown);
|
||||||
if (!faceDown) {
|
if (!faceDown) {
|
||||||
cardToMove->set_pt(info.getPowTough().toStdString());
|
cardToMove->set_pt(info.getPowTough().toStdString());
|
||||||
}
|
}
|
||||||
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
||||||
if (tableRow != 3)
|
if (tableRow != 3)
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(gridPoint.x());
|
cmd.set_x(gridPoint.x());
|
||||||
cmd.set_y(gridPoint.y());
|
cmd.set_y(gridPoint.y());
|
||||||
}
|
}
|
||||||
|
|
@ -113,18 +117,13 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown)
|
||||||
const CardInfo &info = exactCard.getInfo();
|
const CardInfo &info = exactCard.getInfo();
|
||||||
|
|
||||||
int tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
int tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
||||||
// default instant/sorcery cards to the noncreatures row
|
QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(tableRow));
|
||||||
if (tableRow > 2) {
|
|
||||||
tableRow = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - tableRow));
|
|
||||||
cardToMove->set_face_down(faceDown);
|
cardToMove->set_face_down(faceDown);
|
||||||
if (!faceDown) {
|
if (!faceDown) {
|
||||||
cardToMove->set_pt(info.getPowTough().toStdString());
|
cardToMove->set_pt(info.getPowTough().toStdString());
|
||||||
}
|
}
|
||||||
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
cardToMove->set_tapped(!faceDown && info.getUiAttributes().cipt);
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(gridPoint.x());
|
cmd.set_x(gridPoint.x());
|
||||||
cmd.set_y(gridPoint.y());
|
cmd.set_y(gridPoint.y());
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -132,12 +131,12 @@ void PlayerActions::playCardToTable(const CardItem *card, bool faceDown)
|
||||||
|
|
||||||
void PlayerActions::actViewLibrary()
|
void PlayerActions::actViewLibrary()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "deck", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actViewHand()
|
void PlayerActions::actViewHand()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "hand", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::HAND, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -181,7 +180,7 @@ void PlayerActions::actViewTopCards()
|
||||||
deckSize, 1, &ok);
|
deckSize, 1, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
defaultNumberTopCards = number;
|
defaultNumberTopCards = number;
|
||||||
player->getGameScene()->toggleZoneView(player, "deck", number);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,14 +193,14 @@ void PlayerActions::actViewBottomCards()
|
||||||
deckSize, 1, &ok);
|
deckSize, 1, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
player->getGameScene()->toggleZoneView(player, "deck", number, true);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::DECK, number, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actAlwaysRevealTopCard()
|
void PlayerActions::actAlwaysRevealTopCard()
|
||||||
{
|
{
|
||||||
Command_ChangeZoneProperties cmd;
|
Command_ChangeZoneProperties cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_always_reveal_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysRevealTopCardChecked());
|
cmd.set_always_reveal_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysRevealTopCardChecked());
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -210,7 +209,7 @@ void PlayerActions::actAlwaysRevealTopCard()
|
||||||
void PlayerActions::actAlwaysLookAtTopCard()
|
void PlayerActions::actAlwaysLookAtTopCard()
|
||||||
{
|
{
|
||||||
Command_ChangeZoneProperties cmd;
|
Command_ChangeZoneProperties cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_always_look_at_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysLookAtTopCardChecked());
|
cmd.set_always_look_at_top_card(player->getPlayerMenu()->getLibraryMenu()->isAlwaysLookAtTopCardChecked());
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -223,17 +222,17 @@ void PlayerActions::actOpenDeckInDeckEditor()
|
||||||
|
|
||||||
void PlayerActions::actViewGraveyard()
|
void PlayerActions::actViewGraveyard()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "grave", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::GRAVE, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actViewRfg()
|
void PlayerActions::actViewRfg()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "rfg", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::EXILE, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actViewSideboard()
|
void PlayerActions::actViewSideboard()
|
||||||
{
|
{
|
||||||
player->getGameScene()->toggleZoneView(player, "sb", -1);
|
player->getGameScene()->toggleZoneView(player, ZoneNames::SIDEBOARD, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actShuffle()
|
void PlayerActions::actShuffle()
|
||||||
|
|
@ -263,7 +262,7 @@ void PlayerActions::actShuffleTop()
|
||||||
defaultNumberTopCards = number;
|
defaultNumberTopCards = number;
|
||||||
|
|
||||||
Command_Shuffle cmd;
|
Command_Shuffle cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_start(0);
|
cmd.set_start(0);
|
||||||
cmd.set_end(number - 1); // inclusive, the indexed card at end will be shuffled
|
cmd.set_end(number - 1); // inclusive, the indexed card at end will be shuffled
|
||||||
|
|
||||||
|
|
@ -292,7 +291,7 @@ void PlayerActions::actShuffleBottom()
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
Command_Shuffle cmd;
|
Command_Shuffle cmd;
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_start(-number);
|
cmd.set_start(-number);
|
||||||
cmd.set_end(-1);
|
cmd.set_end(-1);
|
||||||
|
|
||||||
|
|
@ -376,7 +375,7 @@ void PlayerActions::actUndoDraw()
|
||||||
|
|
||||||
void PlayerActions::cmdSetTopCard(Command_MoveCard &cmd)
|
void PlayerActions::cmdSetTopCard(Command_MoveCard &cmd)
|
||||||
{
|
{
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(0);
|
cardToMove->set_card_id(0);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
|
|
@ -386,7 +385,7 @@ void PlayerActions::cmdSetBottomCard(Command_MoveCard &cmd)
|
||||||
{
|
{
|
||||||
CardZoneLogic *zone = player->getDeckZone();
|
CardZoneLogic *zone = player->getDeckZone();
|
||||||
int lastCard = zone->getCards().size() - 1;
|
int lastCard = zone->getCards().size() - 1;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(lastCard);
|
cardToMove->set_card_id(lastCard);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
|
|
@ -400,7 +399,7 @@ void PlayerActions::actMoveTopCardToGrave()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -415,7 +414,7 @@ void PlayerActions::actMoveTopCardToExile()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(ZoneNames::EXILE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -424,37 +423,25 @@ void PlayerActions::actMoveTopCardToExile()
|
||||||
|
|
||||||
void PlayerActions::actMoveTopCardsToGrave()
|
void PlayerActions::actMoveTopCardsToGrave()
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
moveTopCardsTo(ZoneNames::GRAVE, tr("grave"), false);
|
||||||
if (maxCards == 0) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok;
|
void PlayerActions::actMoveTopCardsToGraveFaceDown()
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to grave"),
|
{
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
moveTopCardsTo(ZoneNames::GRAVE, tr("grave"), true);
|
||||||
maxCards, 1, &ok);
|
|
||||||
if (!ok) {
|
|
||||||
return;
|
|
||||||
} else if (number > maxCards) {
|
|
||||||
number = maxCards;
|
|
||||||
}
|
|
||||||
defaultNumberTopCards = number;
|
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
|
||||||
cmd.set_start_zone("deck");
|
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
|
||||||
cmd.set_target_zone("grave");
|
|
||||||
cmd.set_x(0);
|
|
||||||
cmd.set_y(0);
|
|
||||||
|
|
||||||
for (int i = number - 1; i >= 0; --i) {
|
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actMoveTopCardsToExile()
|
void PlayerActions::actMoveTopCardsToExile()
|
||||||
|
{
|
||||||
|
moveTopCardsTo(ZoneNames::EXILE, tr("exile"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::actMoveTopCardsToExileFaceDown()
|
||||||
|
{
|
||||||
|
moveTopCardsTo(ZoneNames::EXILE, tr("exile"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown)
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
const int maxCards = player->getDeckZone()->getCards().size();
|
||||||
if (maxCards == 0) {
|
if (maxCards == 0) {
|
||||||
|
|
@ -462,25 +449,31 @@ void PlayerActions::actMoveTopCardsToExile()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to exile"),
|
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move top cards to %1").arg(zoneDisplayName),
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
||||||
maxCards, 1, &ok);
|
maxCards, 1, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
} else if (number > maxCards) {
|
}
|
||||||
|
|
||||||
|
if (number > maxCards) {
|
||||||
number = maxCards;
|
number = maxCards;
|
||||||
}
|
}
|
||||||
defaultNumberTopCards = number;
|
defaultNumberTopCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(targetZone.toStdString());
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
for (int i = number - 1; i >= 0; --i) {
|
for (int i = number - 1; i >= 0; --i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
auto card = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
card->set_card_id(i);
|
||||||
|
if (faceDown) {
|
||||||
|
card->set_face_down(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -490,22 +483,19 @@ void PlayerActions::actMoveTopCardsUntil()
|
||||||
{
|
{
|
||||||
stopMoveTopCardsUntil();
|
stopMoveTopCardsUntil();
|
||||||
|
|
||||||
DlgMoveTopCardsUntil dlg(player->getGame()->getTab(), movingCardsUntilExprs, movingCardsUntilNumberOfHits,
|
DlgMoveTopCardsUntil dlg(player->getGame()->getTab(), movingCardsUntilOptions);
|
||||||
movingCardsUntilAutoPlay);
|
|
||||||
if (!dlg.exec()) {
|
if (!dlg.exec()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto expr = dlg.getExpr();
|
auto expr = dlg.getExpr();
|
||||||
movingCardsUntilExprs = dlg.getExprs();
|
movingCardsUntilOptions = dlg.getOptions();
|
||||||
movingCardsUntilNumberOfHits = dlg.getNumberOfHits();
|
|
||||||
movingCardsUntilAutoPlay = dlg.isAutoPlay();
|
|
||||||
|
|
||||||
if (player->getDeckZone()->getCards().empty()) {
|
if (player->getDeckZone()->getCards().empty()) {
|
||||||
stopMoveTopCardsUntil();
|
stopMoveTopCardsUntil();
|
||||||
} else {
|
} else {
|
||||||
movingCardsUntilFilter = FilterString(expr);
|
movingCardsUntilFilter = FilterString(expr);
|
||||||
movingCardsUntilCounter = movingCardsUntilNumberOfHits;
|
movingCardsUntilCounter = movingCardsUntilOptions.numberOfHits;
|
||||||
movingCardsUntil = true;
|
movingCardsUntil = true;
|
||||||
actMoveTopCardToPlay();
|
actMoveTopCardToPlay();
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +507,7 @@ void PlayerActions::moveOneCardUntil(CardItem *card)
|
||||||
|
|
||||||
const bool isMatch = card && movingCardsUntilFilter.check(card->getCard().getCardPtr());
|
const bool isMatch = card && movingCardsUntilFilter.check(card->getCard().getCardPtr());
|
||||||
|
|
||||||
if (isMatch && movingCardsUntilAutoPlay) {
|
if (isMatch && movingCardsUntilOptions.autoPlay) {
|
||||||
// Directly calling playCard will deadlock, since we are already in the middle of processing an event.
|
// Directly calling playCard will deadlock, since we are already in the middle of processing an event.
|
||||||
// Use QTimer::singleShot to queue up the playCard on the event loop.
|
// Use QTimer::singleShot to queue up the playCard on the event loop.
|
||||||
QTimer::singleShot(0, this, [card, this] { playCard(card, false); });
|
QTimer::singleShot(0, this, [card, this] { playCard(card, false); });
|
||||||
|
|
@ -555,7 +545,7 @@ void PlayerActions::actMoveTopCardToBottom()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("deck");
|
cmd.set_target_zone(ZoneNames::DECK);
|
||||||
cmd.set_x(-1); // bottom of deck
|
cmd.set_x(-1); // bottom of deck
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -570,7 +560,7 @@ void PlayerActions::actMoveTopCardToPlay()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetTopCard(cmd);
|
cmdSetTopCard(cmd);
|
||||||
cmd.set_target_zone("stack");
|
cmd.set_target_zone(ZoneNames::STACK);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -584,12 +574,12 @@ void PlayerActions::actMoveTopCardToPlayFaceDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(0);
|
cardToMove->set_card_id(0);
|
||||||
cardToMove->set_face_down(true);
|
cardToMove->set_face_down(true);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -604,7 +594,7 @@ void PlayerActions::actMoveBottomCardToGrave()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -619,7 +609,7 @@ void PlayerActions::actMoveBottomCardToExile()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(ZoneNames::EXILE);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -628,37 +618,25 @@ void PlayerActions::actMoveBottomCardToExile()
|
||||||
|
|
||||||
void PlayerActions::actMoveBottomCardsToGrave()
|
void PlayerActions::actMoveBottomCardsToGrave()
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
moveBottomCardsTo(ZoneNames::GRAVE, tr("grave"), false);
|
||||||
if (maxCards == 0) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ok;
|
void PlayerActions::actMoveBottomCardsToGraveFaceDown()
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to grave"),
|
{
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
moveBottomCardsTo(ZoneNames::GRAVE, tr("grave"), true);
|
||||||
maxCards, 1, &ok);
|
|
||||||
if (!ok) {
|
|
||||||
return;
|
|
||||||
} else if (number > maxCards) {
|
|
||||||
number = maxCards;
|
|
||||||
}
|
|
||||||
defaultNumberBottomCards = number;
|
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
|
||||||
cmd.set_start_zone("deck");
|
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
|
||||||
cmd.set_target_zone("grave");
|
|
||||||
cmd.set_x(0);
|
|
||||||
cmd.set_y(0);
|
|
||||||
|
|
||||||
for (int i = maxCards - number; i < maxCards; ++i) {
|
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actMoveBottomCardsToExile()
|
void PlayerActions::actMoveBottomCardsToExile()
|
||||||
|
{
|
||||||
|
moveBottomCardsTo(ZoneNames::EXILE, tr("exile"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::actMoveBottomCardsToExileFaceDown()
|
||||||
|
{
|
||||||
|
moveBottomCardsTo(ZoneNames::EXILE, tr("exile"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerActions::moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown)
|
||||||
{
|
{
|
||||||
const int maxCards = player->getDeckZone()->getCards().size();
|
const int maxCards = player->getDeckZone()->getCards().size();
|
||||||
if (maxCards == 0) {
|
if (maxCards == 0) {
|
||||||
|
|
@ -666,25 +644,31 @@ void PlayerActions::actMoveBottomCardsToExile()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to exile"),
|
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Move bottom cards to %1").arg(zoneDisplayName),
|
||||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
||||||
maxCards, 1, &ok);
|
maxCards, 1, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
} else if (number > maxCards) {
|
}
|
||||||
|
|
||||||
|
if (number > maxCards) {
|
||||||
number = maxCards;
|
number = maxCards;
|
||||||
}
|
}
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone(targetZone.toStdString());
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
for (int i = maxCards - number; i < maxCards; ++i) {
|
for (int i = maxCards - number; i < maxCards; ++i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
auto card = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
card->set_card_id(i);
|
||||||
|
if (faceDown) {
|
||||||
|
card->set_face_down(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -698,7 +682,7 @@ void PlayerActions::actMoveBottomCardToTop()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("deck");
|
cmd.set_target_zone(ZoneNames::DECK);
|
||||||
cmd.set_x(0); // top of deck
|
cmd.set_x(0); // top of deck
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -768,7 +752,7 @@ void PlayerActions::actDrawBottomCard()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("hand");
|
cmd.set_target_zone(ZoneNames::HAND);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -794,9 +778,9 @@ void PlayerActions::actDrawBottomCards()
|
||||||
defaultNumberBottomCards = number;
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("hand");
|
cmd.set_target_zone(ZoneNames::HAND);
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -815,7 +799,7 @@ void PlayerActions::actMoveBottomCardToPlay()
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmdSetBottomCard(cmd);
|
cmdSetBottomCard(cmd);
|
||||||
cmd.set_target_zone("stack");
|
cmd.set_target_zone(ZoneNames::STACK);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -832,13 +816,13 @@ void PlayerActions::actMoveBottomCardToPlayFaceDown()
|
||||||
int lastCard = zone->getCards().size() - 1;
|
int lastCard = zone->getCards().size() - 1;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone(ZoneNames::DECK);
|
||||||
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
cardToMove->set_card_id(lastCard);
|
cardToMove->set_card_id(lastCard);
|
||||||
cardToMove->set_face_down(true);
|
cardToMove->set_face_down(true);
|
||||||
|
|
||||||
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
cmd.set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
|
@ -848,7 +832,7 @@ void PlayerActions::actMoveBottomCardToPlayFaceDown()
|
||||||
void PlayerActions::actUntapAll()
|
void PlayerActions::actUntapAll()
|
||||||
{
|
{
|
||||||
Command_SetCardAttr cmd;
|
Command_SetCardAttr cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_attribute(AttrTapped);
|
cmd.set_attribute(AttrTapped);
|
||||||
cmd.set_attr_value("0");
|
cmd.set_attr_value("0");
|
||||||
|
|
||||||
|
|
@ -880,7 +864,7 @@ void PlayerActions::actCreateToken()
|
||||||
ExactCard correctedCard = CardDatabaseManager::query()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId});
|
ExactCard correctedCard = CardDatabaseManager::query()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId});
|
||||||
if (correctedCard) {
|
if (correctedCard) {
|
||||||
lastTokenInfo.name = correctedCard.getName();
|
lastTokenInfo.name = correctedCard.getName();
|
||||||
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getUiAttributes().tableRow);
|
lastTokenTableRow = TableZone::tableRowToGridY(correctedCard.getInfo().getUiAttributes().tableRow);
|
||||||
if (lastTokenInfo.pt.isEmpty()) {
|
if (lastTokenInfo.pt.isEmpty()) {
|
||||||
lastTokenInfo.pt = correctedCard.getInfo().getPowTough();
|
lastTokenInfo.pt = correctedCard.getInfo().getPowTough();
|
||||||
}
|
}
|
||||||
|
|
@ -898,7 +882,7 @@ void PlayerActions::actCreateAnotherToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_CreateToken cmd;
|
Command_CreateToken cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_name(lastTokenInfo.name.toStdString());
|
cmd.set_card_name(lastTokenInfo.name.toStdString());
|
||||||
cmd.set_card_provider_id(lastTokenInfo.providerId.toStdString());
|
cmd.set_card_provider_id(lastTokenInfo.providerId.toStdString());
|
||||||
cmd.set_color(lastTokenInfo.color.toStdString());
|
cmd.set_color(lastTokenInfo.color.toStdString());
|
||||||
|
|
@ -931,7 +915,7 @@ void PlayerActions::setLastToken(CardInfoPtr cardInfo)
|
||||||
.providerId =
|
.providerId =
|
||||||
SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())};
|
SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())};
|
||||||
|
|
||||||
lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getUiAttributes().tableRow);
|
lastTokenTableRow = TableZone::tableRowToGridY(cardInfo->getUiAttributes().tableRow);
|
||||||
|
|
||||||
utilityMenu->setAndEnableCreateAnotherTokenAction(tr("C&reate another %1 token").arg(lastTokenInfo.name));
|
utilityMenu->setAndEnableCreateAnotherTokenAction(tr("C&reate another %1 token").arg(lastTokenInfo.name));
|
||||||
}
|
}
|
||||||
|
|
@ -1079,7 +1063,7 @@ bool PlayerActions::createRelatedFromRelation(const CardItem *sourceCard, const
|
||||||
|
|
||||||
// move card onto table first if attaching from some other zone
|
// move card onto table first if attaching from some other zone
|
||||||
// we only do this for AttachTo because cross-zone TransformInto is already handled server-side
|
// we only do this for AttachTo because cross-zone TransformInto is already handled server-side
|
||||||
if (attachType == CardRelationType::AttachTo && sourceCard->getZone()->getName() != "table") {
|
if (attachType == CardRelationType::AttachTo && sourceCard->getZone()->getName() != ZoneNames::TABLE) {
|
||||||
playCardToTable(sourceCard, false);
|
playCardToTable(sourceCard, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1099,13 +1083,11 @@ void PlayerActions::createCard(const CardItem *sourceCard,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the target token's location
|
QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(cardInfo->getUiAttributes().tableRow));
|
||||||
// TODO: Define this QPoint into its own function along with the one below
|
|
||||||
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - cardInfo->getUiAttributes().tableRow));
|
|
||||||
|
|
||||||
// create the token for the related card
|
// create the token for the related card
|
||||||
Command_CreateToken cmd;
|
Command_CreateToken cmd;
|
||||||
cmd.set_zone("table");
|
cmd.set_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_name(cardInfo->getName().toStdString());
|
cmd.set_card_name(cardInfo->getName().toStdString());
|
||||||
switch (cardInfo->getColors().size()) {
|
switch (cardInfo->getColors().size()) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -1134,12 +1116,12 @@ void PlayerActions::createCard(const CardItem *sourceCard,
|
||||||
|
|
||||||
switch (attachType) {
|
switch (attachType) {
|
||||||
case CardRelationType::DoesNotAttach:
|
case CardRelationType::DoesNotAttach:
|
||||||
cmd.set_target_zone("table");
|
cmd.set_target_zone(ZoneNames::TABLE);
|
||||||
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CardRelationType::AttachTo:
|
case CardRelationType::AttachTo:
|
||||||
cmd.set_target_zone("table"); // We currently only support creating tokens on the table
|
cmd.set_target_zone(ZoneNames::TABLE); // We currently only support creating tokens on the table
|
||||||
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
|
||||||
cmd.set_target_card_id(sourceCard->getId());
|
cmd.set_target_card_id(sourceCard->getId());
|
||||||
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
|
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
|
||||||
|
|
@ -1147,7 +1129,7 @@ void PlayerActions::createCard(const CardItem *sourceCard,
|
||||||
|
|
||||||
case CardRelationType::TransformInto:
|
case CardRelationType::TransformInto:
|
||||||
// allow cards to directly transform on stack
|
// allow cards to directly transform on stack
|
||||||
cmd.set_zone(sourceCard->getZone()->getName() == "stack" ? "stack" : "table");
|
cmd.set_zone(sourceCard->getZone()->getName() == ZoneNames::STACK ? ZoneNames::STACK : ZoneNames::TABLE);
|
||||||
// Transform card zone changes are handled server-side
|
// Transform card zone changes are handled server-side
|
||||||
cmd.set_target_zone(sourceCard->getZone()->getName().toStdString());
|
cmd.set_target_zone(sourceCard->getZone()->getName().toStdString());
|
||||||
cmd.set_target_card_id(sourceCard->getId());
|
cmd.set_target_card_id(sourceCard->getId());
|
||||||
|
|
@ -1262,7 +1244,7 @@ void PlayerActions::actMoveCardXCardsFromTop()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("deck");
|
cmd->set_target_zone(ZoneNames::DECK);
|
||||||
cmd->set_x(number);
|
cmd->set_x(number);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
|
|
@ -1593,23 +1575,34 @@ void PlayerActions::actCardCounterTrigger()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 11: { // set counter with dialog
|
case 11: { // set counter with dialog
|
||||||
bool ok;
|
|
||||||
player->setDialogSemaphore(true);
|
player->setDialogSemaphore(true);
|
||||||
|
|
||||||
int oldValue = 0;
|
// If a single card is selected, we show the old value in the dialog. Otherwise, we show "x"
|
||||||
if (player->getGameScene()->selectedItems().size() == 1) {
|
QList<QGraphicsItem *> sel = player->getGameScene()->selectedItems();
|
||||||
auto *card = static_cast<CardItem *>(player->getGameScene()->selectedItems().first());
|
QString oldValueForDlg = "x";
|
||||||
oldValue = card->getCounters().value(counterId, 0);
|
if (sel.size() == 1) {
|
||||||
|
auto *card = dynamic_cast<CardItem *>(sel.first());
|
||||||
|
oldValueForDlg = QString::number(card->getCounters().value(counterId, 0));
|
||||||
}
|
}
|
||||||
int number = QInputDialog::getInt(player->getGame()->getTab(), tr("Set counters"), tr("Number:"), oldValue,
|
|
||||||
0, MAX_COUNTERS_ON_CARD, 1, &ok);
|
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
|
||||||
|
QString counterName = cardCounterSettings.displayName(counterId);
|
||||||
|
|
||||||
|
AbstractCounterDialog dialog(counterName, oldValueForDlg, player->getGame()->getTab());
|
||||||
|
int ok = dialog.exec();
|
||||||
|
|
||||||
player->setDialogSemaphore(false);
|
player->setDialogSemaphore(false);
|
||||||
if (player->clearCardsToDelete() || !ok) {
|
if (player->clearCardsToDelete() || !ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &item : player->getGameScene()->selectedItems()) {
|
for (const auto &item : sel) {
|
||||||
auto *card = static_cast<CardItem *>(item);
|
auto *card = dynamic_cast<CardItem *>(item);
|
||||||
|
|
||||||
|
int oldValue = card->getCounters().value(counterId, 0);
|
||||||
|
Expression exp(oldValue);
|
||||||
|
int number = static_cast<int>(exp.parse(dialog.textValue()));
|
||||||
|
|
||||||
auto *cmd = new Command_SetCardCounter;
|
auto *cmd = new Command_SetCardCounter;
|
||||||
cmd->set_zone(card->getZone()->getName().toStdString());
|
cmd->set_zone(card->getZone()->getName().toStdString());
|
||||||
cmd->set_card_id(card->getId());
|
cmd->set_card_id(card->getId());
|
||||||
|
|
@ -1651,7 +1644,7 @@ void PlayerActions::playSelectedCards(const bool faceDown)
|
||||||
[](const auto &card1, const auto &card2) { return card1->getId() > card2->getId(); });
|
[](const auto &card1, const auto &card2) { return card1->getId() > card2->getId(); });
|
||||||
|
|
||||||
for (auto &card : selectedCards) {
|
for (auto &card : selectedCards) {
|
||||||
if (card && !isUnwritableRevealZone(card->getZone()) && card->getZone()->getName() != "table") {
|
if (card && !isUnwritableRevealZone(card->getZone()) && card->getZone()->getName() != ZoneNames::TABLE) {
|
||||||
playCard(card, faceDown);
|
playCard(card, faceDown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1704,7 +1697,7 @@ void PlayerActions::actRevealHand(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("hand");
|
cmd.set_zone_name(ZoneNames::HAND);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -1715,7 +1708,7 @@ void PlayerActions::actRevealRandomHandCard(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("hand");
|
cmd.set_zone_name(ZoneNames::HAND);
|
||||||
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -1727,7 +1720,7 @@ void PlayerActions::actRevealLibrary(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -1738,7 +1731,7 @@ void PlayerActions::actLendLibrary(int lendToPlayerId)
|
||||||
if (lendToPlayerId != -1) {
|
if (lendToPlayerId != -1) {
|
||||||
cmd.set_player_id(lendToPlayerId);
|
cmd.set_player_id(lendToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_grant_write_access(true);
|
cmd.set_grant_write_access(true);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -1751,7 +1744,7 @@ void PlayerActions::actRevealTopCards(int revealToPlayerId, int amount)
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name(ZoneNames::DECK);
|
||||||
cmd.set_top_cards(amount);
|
cmd.set_top_cards(amount);
|
||||||
// backward compatibility: servers before #1051 only permits to reveal the first card
|
// backward compatibility: servers before #1051 only permits to reveal the first card
|
||||||
cmd.add_card_id(0);
|
cmd.add_card_id(0);
|
||||||
|
|
@ -1765,7 +1758,7 @@ void PlayerActions::actRevealRandomGraveyardCard(int revealToPlayerId)
|
||||||
if (revealToPlayerId != -1) {
|
if (revealToPlayerId != -1) {
|
||||||
cmd.set_player_id(revealToPlayerId);
|
cmd.set_player_id(revealToPlayerId);
|
||||||
}
|
}
|
||||||
cmd.set_zone_name("grave");
|
cmd.set_zone_name(ZoneNames::GRAVE);
|
||||||
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
cmd.add_card_id(RANDOM_CARD_FROM_ZONE);
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -1828,7 +1821,7 @@ void PlayerActions::cardMenuAction()
|
||||||
}
|
}
|
||||||
case cmClone: {
|
case cmClone: {
|
||||||
auto *cmd = new Command_CreateToken;
|
auto *cmd = new Command_CreateToken;
|
||||||
cmd->set_zone("table");
|
cmd->set_zone(ZoneNames::TABLE);
|
||||||
cmd->set_card_name(card->getName().toStdString());
|
cmd->set_card_name(card->getName().toStdString());
|
||||||
cmd->set_card_provider_id(card->getProviderId().toStdString());
|
cmd->set_card_provider_id(card->getProviderId().toStdString());
|
||||||
cmd->set_color(card->getColor().toStdString());
|
cmd->set_color(card->getColor().toStdString());
|
||||||
|
|
@ -1870,13 +1863,13 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("deck");
|
cmd->set_target_zone(ZoneNames::DECK);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
|
|
||||||
if (idList.card_size() > 1) {
|
if (idList.card_size() > 1) {
|
||||||
auto *scmd = new Command_Shuffle;
|
auto *scmd = new Command_Shuffle;
|
||||||
scmd->set_zone_name("deck");
|
scmd->set_zone_name(ZoneNames::DECK);
|
||||||
scmd->set_start(0);
|
scmd->set_start(0);
|
||||||
scmd->set_end(idList.card_size() - 1); // inclusive, the indexed card at end will be shuffled
|
scmd->set_end(idList.card_size() - 1); // inclusive, the indexed card at end will be shuffled
|
||||||
// Server process events backwards, so...
|
// Server process events backwards, so...
|
||||||
|
|
@ -1892,13 +1885,13 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("deck");
|
cmd->set_target_zone(ZoneNames::DECK);
|
||||||
cmd->set_x(-1);
|
cmd->set_x(-1);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
|
|
||||||
if (idList.card_size() > 1) {
|
if (idList.card_size() > 1) {
|
||||||
auto *scmd = new Command_Shuffle;
|
auto *scmd = new Command_Shuffle;
|
||||||
scmd->set_zone_name("deck");
|
scmd->set_zone_name(ZoneNames::DECK);
|
||||||
scmd->set_start(-idList.card_size());
|
scmd->set_start(-idList.card_size());
|
||||||
scmd->set_end(-1);
|
scmd->set_end(-1);
|
||||||
// Server process events backwards, so...
|
// Server process events backwards, so...
|
||||||
|
|
@ -1914,7 +1907,7 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("hand");
|
cmd->set_target_zone(ZoneNames::HAND);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
|
|
@ -1926,7 +1919,7 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("grave");
|
cmd->set_target_zone(ZoneNames::GRAVE);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
|
|
@ -1938,12 +1931,40 @@ void PlayerActions::cardMenuAction()
|
||||||
cmd->set_start_zone(startZone.toStdString());
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
cmd->mutable_cards_to_move()->CopyFrom(idList);
|
||||||
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
cmd->set_target_zone("rfg");
|
cmd->set_target_zone(ZoneNames::EXILE);
|
||||||
cmd->set_x(0);
|
cmd->set_x(0);
|
||||||
cmd->set_y(0);
|
cmd->set_y(0);
|
||||||
commandList.append(cmd);
|
commandList.append(cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case cmMoveToTable: {
|
||||||
|
// Each card needs its own command because table row, pt, and cipt vary per card
|
||||||
|
for (const auto &card : cardList) {
|
||||||
|
auto *cmd = new Command_MoveCard;
|
||||||
|
cmd->set_start_player_id(startPlayerId);
|
||||||
|
cmd->set_start_zone(startZone.toStdString());
|
||||||
|
cmd->set_target_player_id(player->getPlayerInfo()->getId());
|
||||||
|
cmd->set_target_zone(ZoneNames::TABLE);
|
||||||
|
cmd->set_x(-1);
|
||||||
|
|
||||||
|
CardToMove *ctm = cmd->mutable_cards_to_move()->add_card();
|
||||||
|
ctm->set_card_id(card->getId());
|
||||||
|
ctm->set_face_down(false);
|
||||||
|
|
||||||
|
int tableRow = 0;
|
||||||
|
ExactCard exactCard = card->getCard();
|
||||||
|
if (exactCard) {
|
||||||
|
const CardInfo &info = exactCard.getInfo();
|
||||||
|
tableRow = info.getUiAttributes().tableRow;
|
||||||
|
ctm->set_pt(info.getPowTough().toStdString());
|
||||||
|
ctm->set_tapped(info.getUiAttributes().cipt);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->set_y(TableZone::tableRowToGridY(tableRow));
|
||||||
|
commandList.append(cmd);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#ifndef COCKATRICE_PLAYER_ACTIONS_H
|
#ifndef COCKATRICE_PLAYER_ACTIONS_H
|
||||||
#define COCKATRICE_PLAYER_ACTIONS_H
|
#define COCKATRICE_PLAYER_ACTIONS_H
|
||||||
#include "../dialogs/dlg_create_token.h"
|
#include "../dialogs/dlg_create_token.h"
|
||||||
|
#include "../dialogs/dlg_move_top_cards_until.h"
|
||||||
#include "event_processing_options.h"
|
#include "event_processing_options.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
|
||||||
|
|
@ -98,7 +99,9 @@ public slots:
|
||||||
void actMoveTopCardToGrave();
|
void actMoveTopCardToGrave();
|
||||||
void actMoveTopCardToExile();
|
void actMoveTopCardToExile();
|
||||||
void actMoveTopCardsToGrave();
|
void actMoveTopCardsToGrave();
|
||||||
|
void actMoveTopCardsToGraveFaceDown();
|
||||||
void actMoveTopCardsToExile();
|
void actMoveTopCardsToExile();
|
||||||
|
void actMoveTopCardsToExileFaceDown();
|
||||||
void actMoveTopCardsUntil();
|
void actMoveTopCardsUntil();
|
||||||
void actMoveTopCardToBottom();
|
void actMoveTopCardToBottom();
|
||||||
void actDrawBottomCard();
|
void actDrawBottomCard();
|
||||||
|
|
@ -108,7 +111,9 @@ public slots:
|
||||||
void actMoveBottomCardToGrave();
|
void actMoveBottomCardToGrave();
|
||||||
void actMoveBottomCardToExile();
|
void actMoveBottomCardToExile();
|
||||||
void actMoveBottomCardsToGrave();
|
void actMoveBottomCardsToGrave();
|
||||||
|
void actMoveBottomCardsToGraveFaceDown();
|
||||||
void actMoveBottomCardsToExile();
|
void actMoveBottomCardsToExile();
|
||||||
|
void actMoveBottomCardsToExileFaceDown();
|
||||||
void actMoveBottomCardToTop();
|
void actMoveBottomCardToTop();
|
||||||
|
|
||||||
void actSelectAll();
|
void actSelectAll();
|
||||||
|
|
@ -174,11 +179,12 @@ private:
|
||||||
|
|
||||||
bool movingCardsUntil;
|
bool movingCardsUntil;
|
||||||
QTimer *moveTopCardTimer;
|
QTimer *moveTopCardTimer;
|
||||||
QStringList movingCardsUntilExprs = {};
|
|
||||||
int movingCardsUntilNumberOfHits = 1;
|
|
||||||
bool movingCardsUntilAutoPlay = false;
|
|
||||||
FilterString movingCardsUntilFilter;
|
FilterString movingCardsUntilFilter;
|
||||||
int movingCardsUntilCounter = 0;
|
int movingCardsUntilCounter = 0;
|
||||||
|
MoveTopCardsUntilOptions movingCardsUntilOptions;
|
||||||
|
|
||||||
|
void moveTopCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
|
||||||
|
void moveBottomCardsTo(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
|
||||||
|
|
||||||
void createCard(const CardItem *sourceCard,
|
void createCard(const CardItem *sourceCard,
|
||||||
const QString &dbCardName,
|
const QString &dbCardName,
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,9 @@
|
||||||
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
|
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
|
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
PlayerEventHandler::PlayerEventHandler(Player *_player) : player(_player)
|
PlayerEventHandler::PlayerEventHandler(Player *_player) : QObject(_player), player(_player)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,7 +60,6 @@ void PlayerEventHandler::eventShuffle(const Event_Shuffle &event)
|
||||||
// we want to close empty views as well
|
// we want to close empty views as well
|
||||||
if (length == 0 || length > absStart) { // note this assumes views always start at the top of the library
|
if (length == 0 || length > absStart) { // note this assumes views always start at the top of the library
|
||||||
view->close();
|
view->close();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning() << zone->getName() << "of" << player->getPlayerInfo()->getName() << "holds empty zoneview!";
|
qWarning() << zone->getName() << "of" << player->getPlayerInfo()->getName() << "holds empty zoneview!";
|
||||||
|
|
@ -321,8 +321,8 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv
|
||||||
}
|
}
|
||||||
player->getPlayerMenu()->updateCardMenu(card);
|
player->getPlayerMenu()->updateCardMenu(card);
|
||||||
|
|
||||||
if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == "deck" &&
|
if (player->getPlayerActions()->isMovingCardsUntil() && startZoneString == ZoneNames::DECK &&
|
||||||
targetZone->getName() == "stack") {
|
targetZone->getName() == ZoneNames::STACK) {
|
||||||
player->getPlayerActions()->moveOneCardUntil(card);
|
player->getPlayerActions()->moveOneCardUntil(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -594,4 +594,4 @@ void PlayerEventHandler::processGameEvent(GameEvent::GameEventType type,
|
||||||
qWarning() << "unhandled game event" << type;
|
qWarning() << "unhandled game event" << type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ PlayerGraphicsItem::PlayerGraphicsItem(Player *_player) : player(_player)
|
||||||
playerArea = new PlayerArea(this);
|
playerArea = new PlayerArea(this);
|
||||||
|
|
||||||
playerTarget = new PlayerTarget(player, playerArea);
|
playerTarget = new PlayerTarget(player, playerArea);
|
||||||
qreal avatarMargin = (counterAreaWidth + CARD_HEIGHT + 15 - playerTarget->boundingRect().width()) / 2.0;
|
qreal avatarMargin =
|
||||||
|
(counterAreaWidth + CardDimensions::HEIGHT_F + 15 - playerTarget->boundingRect().width()) / 2.0;
|
||||||
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
|
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
|
||||||
|
|
||||||
initializeZones();
|
initializeZones();
|
||||||
|
|
@ -55,8 +56,9 @@ void PlayerGraphicsItem::onPlayerActiveChanged(bool _active)
|
||||||
void PlayerGraphicsItem::initializeZones()
|
void PlayerGraphicsItem::initializeZones()
|
||||||
{
|
{
|
||||||
deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this);
|
deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this);
|
||||||
auto base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0,
|
auto base = QPointF(counterAreaWidth + (CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F + 15) / 2.0,
|
||||||
10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0);
|
10 + playerTarget->boundingRect().height() + 5 -
|
||||||
|
(CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F) / 2.0);
|
||||||
deckZoneGraphicsItem->setPos(base);
|
deckZoneGraphicsItem->setPos(base);
|
||||||
|
|
||||||
qreal h = deckZoneGraphicsItem->boundingRect().width() + 5;
|
qreal h = deckZoneGraphicsItem->boundingRect().width() + 5;
|
||||||
|
|
@ -95,7 +97,7 @@ QRectF PlayerGraphicsItem::boundingRect() const
|
||||||
|
|
||||||
qreal PlayerGraphicsItem::getMinimumWidth() const
|
qreal PlayerGraphicsItem::getMinimumWidth() const
|
||||||
{
|
{
|
||||||
qreal result = tableZoneGraphicsItem->getMinimumWidth() + CARD_HEIGHT + 15 + counterAreaWidth +
|
qreal result = tableZoneGraphicsItem->getMinimumWidth() + CardDimensions::HEIGHT_F + 15 + counterAreaWidth +
|
||||||
stackZoneGraphicsItem->boundingRect().width();
|
stackZoneGraphicsItem->boundingRect().width();
|
||||||
if (!SettingsCache::instance().getHorizontalHand()) {
|
if (!SettingsCache::instance().getHorizontalHand()) {
|
||||||
result += handZoneGraphicsItem->boundingRect().width();
|
result += handZoneGraphicsItem->boundingRect().width();
|
||||||
|
|
@ -112,8 +114,8 @@ void PlayerGraphicsItem::paint(QPainter * /*painter*/,
|
||||||
void PlayerGraphicsItem::processSceneSizeChange(int newPlayerWidth)
|
void PlayerGraphicsItem::processSceneSizeChange(int newPlayerWidth)
|
||||||
{
|
{
|
||||||
// Extend table (and hand, if horizontal) to accommodate the new player width.
|
// Extend table (and hand, if horizontal) to accommodate the new player width.
|
||||||
qreal tableWidth =
|
qreal tableWidth = newPlayerWidth - CardDimensions::HEIGHT_F - 15 - counterAreaWidth -
|
||||||
newPlayerWidth - CARD_HEIGHT - 15 - counterAreaWidth - stackZoneGraphicsItem->boundingRect().width();
|
stackZoneGraphicsItem->boundingRect().width();
|
||||||
if (!SettingsCache::instance().getHorizontalHand()) {
|
if (!SettingsCache::instance().getHorizontalHand()) {
|
||||||
tableWidth -= handZoneGraphicsItem->boundingRect().width();
|
tableWidth -= handZoneGraphicsItem->boundingRect().width();
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +154,7 @@ void PlayerGraphicsItem::rearrangeCounters()
|
||||||
|
|
||||||
void PlayerGraphicsItem::rearrangeZones()
|
void PlayerGraphicsItem::rearrangeZones()
|
||||||
{
|
{
|
||||||
auto base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0);
|
auto base = QPointF(CardDimensions::HEIGHT_F + counterAreaWidth + 15, 0);
|
||||||
if (SettingsCache::instance().getHorizontalHand()) {
|
if (SettingsCache::instance().getHorizontalHand()) {
|
||||||
if (mirrored) {
|
if (mirrored) {
|
||||||
if (player->getHandZone()->contentsKnown()) {
|
if (player->getHandZone()->contentsKnown()) {
|
||||||
|
|
@ -203,7 +205,7 @@ void PlayerGraphicsItem::rearrangeZones()
|
||||||
void PlayerGraphicsItem::updateBoundingRect()
|
void PlayerGraphicsItem::updateBoundingRect()
|
||||||
{
|
{
|
||||||
prepareGeometryChange();
|
prepareGeometryChange();
|
||||||
qreal width = CARD_HEIGHT + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width();
|
qreal width = CardDimensions::HEIGHT_F + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width();
|
||||||
if (SettingsCache::instance().getHorizontalHand()) {
|
if (SettingsCache::instance().getHorizontalHand()) {
|
||||||
qreal handHeight =
|
qreal handHeight =
|
||||||
player->getPlayerInfo()->getHandVisible() ? handZoneGraphicsItem->boundingRect().height() : 0;
|
player->getPlayerInfo()->getHandVisible() ? handZoneGraphicsItem->boundingRect().height() : 0;
|
||||||
|
|
@ -214,7 +216,7 @@ void PlayerGraphicsItem::updateBoundingRect()
|
||||||
0, 0, width + handZoneGraphicsItem->boundingRect().width() + tableZoneGraphicsItem->boundingRect().width(),
|
0, 0, width + handZoneGraphicsItem->boundingRect().width() + tableZoneGraphicsItem->boundingRect().width(),
|
||||||
tableZoneGraphicsItem->boundingRect().height());
|
tableZoneGraphicsItem->boundingRect().height());
|
||||||
}
|
}
|
||||||
playerArea->setSize(CARD_HEIGHT + counterAreaWidth + 15, bRect.height());
|
playerArea->setSize(CardDimensions::HEIGHT_F + counterAreaWidth + 15, bRect.height());
|
||||||
|
|
||||||
emit sizeChanged();
|
emit sizeChanged();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
136
cockatrice/src/game/z_value_layer_manager.h
Normal file
136
cockatrice/src/game/z_value_layer_manager.h
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
/**
|
||||||
|
* @file z_value_layer_manager.h
|
||||||
|
* @ingroup GameGraphics
|
||||||
|
* @brief Semantic Z-value layer management for game scene rendering.
|
||||||
|
*
|
||||||
|
* This file provides a structured approach to Z-value allocation in the game scene.
|
||||||
|
* Z-values in Qt determine stacking order - higher values render on top of lower values.
|
||||||
|
*
|
||||||
|
* ## Layer Architecture
|
||||||
|
*
|
||||||
|
* The game scene is organized into three conceptual layers:
|
||||||
|
*
|
||||||
|
* 1. **Zone Layer (0-999)**: Zone backgrounds, containers, and static elements
|
||||||
|
* - Zone backgrounds (0.5-1.0)
|
||||||
|
* - Cards within zones (1.0 base + index)
|
||||||
|
*
|
||||||
|
* 2. **Card Layer (1-40,000,000)**: Dynamic card rendering on the table zone
|
||||||
|
* - Cards use formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100
|
||||||
|
* - Maximum card Z-value: ~40,000,000 (with 3 rows, actualY <= ~289)
|
||||||
|
*
|
||||||
|
* 3. **Overlay Layer (2,000,000,000+)**: UI elements that must appear above all cards
|
||||||
|
* - Hovered cards (+1)
|
||||||
|
* - Arrows (+3)
|
||||||
|
* - Zone views (+4)
|
||||||
|
* - Drag items (+5, +6)
|
||||||
|
* - Top UI elements (+7)
|
||||||
|
*
|
||||||
|
* ## Design Rationale
|
||||||
|
*
|
||||||
|
* The large gap between card Z-values (max ~40M) and overlay base (2B) provides
|
||||||
|
* safety margin for future table zone expansions while ensuring overlays always
|
||||||
|
* render above cards regardless of table position.
|
||||||
|
*
|
||||||
|
* ## Usage
|
||||||
|
*
|
||||||
|
* Prefer using the semantic constants from ZValues namespace:
|
||||||
|
* @code
|
||||||
|
* card->setZValue(ZValues::HOVERED_CARD);
|
||||||
|
* arrow->setZValue(ZValues::ARROWS);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* Use validation functions to verify card Z-values during development:
|
||||||
|
* @code
|
||||||
|
* Q_ASSERT(ZValueLayerManager::isValidCardZValue(cardZ));
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Z_VALUE_LAYER_MANAGER_H
|
||||||
|
#define Z_VALUE_LAYER_MANAGER_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @namespace ZValueLayerManager
|
||||||
|
* @brief Utilities for Z-value validation and layer management.
|
||||||
|
*/
|
||||||
|
namespace ZValueLayerManager
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum Layer
|
||||||
|
* @brief Semantic layer identifiers for Z-value allocation.
|
||||||
|
*
|
||||||
|
* These represent conceptual rendering layers, not actual Z-values.
|
||||||
|
* Use the corresponding ZValues constants for actual rendering.
|
||||||
|
*/
|
||||||
|
enum class Layer
|
||||||
|
{
|
||||||
|
/// Zone-level elements like backgrounds and containers
|
||||||
|
Zone,
|
||||||
|
/// Cards rendered in zones (uses sequential Z-values)
|
||||||
|
Card,
|
||||||
|
/// Temporary UI elements like hovered cards and drag items
|
||||||
|
Overlay
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximum Z-value a card can have on the table zone.
|
||||||
|
*
|
||||||
|
* Based on table zone formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100
|
||||||
|
* With maximum 3 rows and CardDimensions::HEIGHT = 102, actualY <= ~289.
|
||||||
|
* Maximum: (289 + 102) * 100000 + 100 * 100 = 39,110,000
|
||||||
|
*
|
||||||
|
* We use 40,000,000 as a safe upper bound with margin.
|
||||||
|
*/
|
||||||
|
constexpr qreal CARD_Z_VALUE_MAX = 40000000.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base Z-value for overlay elements.
|
||||||
|
*
|
||||||
|
* Must exceed CARD_Z_VALUE_MAX to ensure overlays render above all cards.
|
||||||
|
* The 50x margin (2B vs 40M) provides safety for future expansion.
|
||||||
|
*/
|
||||||
|
constexpr qreal OVERLAY_BASE = 2000000000.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates that a Z-value is within the valid card range.
|
||||||
|
*
|
||||||
|
* Cards should have Z-values between CARD_BASE (1.0) and CARD_Z_VALUE_MAX.
|
||||||
|
* Values outside this range may interfere with overlay rendering.
|
||||||
|
*
|
||||||
|
* @param zValue The Z-value to validate
|
||||||
|
* @return true if the Z-value is valid for a card
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr bool isValidCardZValue(qreal zValue)
|
||||||
|
{
|
||||||
|
return zValue >= 1.0 && zValue <= CARD_Z_VALUE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates that a Z-value is in the overlay layer.
|
||||||
|
*
|
||||||
|
* Overlay elements should have Z-values at or above OVERLAY_BASE.
|
||||||
|
*
|
||||||
|
* @param zValue The Z-value to validate
|
||||||
|
* @return true if the Z-value is valid for an overlay element
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr bool isOverlayZValue(qreal zValue)
|
||||||
|
{
|
||||||
|
return zValue >= OVERLAY_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the Z-value for a specific overlay element.
|
||||||
|
*
|
||||||
|
* @param offset Offset from OVERLAY_BASE (0-7 for current elements)
|
||||||
|
* @return The absolute Z-value for the overlay element
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr qreal overlayZValue(qreal offset)
|
||||||
|
{
|
||||||
|
return OVERLAY_BASE + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZValueLayerManager
|
||||||
|
|
||||||
|
#endif // Z_VALUE_LAYER_MANAGER_H
|
||||||
83
cockatrice/src/game/z_values.h
Normal file
83
cockatrice/src/game/z_values.h
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#ifndef Z_VALUES_H
|
||||||
|
#define Z_VALUES_H
|
||||||
|
|
||||||
|
#include "card_dimensions.h"
|
||||||
|
#include "z_value_layer_manager.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file z_values.h
|
||||||
|
* @ingroup GameGraphics
|
||||||
|
* @brief Centralized Z-value constants for rendering layer order.
|
||||||
|
*
|
||||||
|
* Z-values in Qt determine stacking order. Higher values render on top.
|
||||||
|
* These constants define the visual layering hierarchy for the game scene.
|
||||||
|
*
|
||||||
|
* ## Layer Architecture
|
||||||
|
*
|
||||||
|
* See z_value_layer_manager.h for detailed documentation on the three-layer
|
||||||
|
* architecture (Zone, Card, Overlay) and the rationale for Z-value choices.
|
||||||
|
*
|
||||||
|
* ## Quick Reference
|
||||||
|
*
|
||||||
|
* | Layer | Z-Value Range | Purpose |
|
||||||
|
* |----------|------------------|-----------------------------------|
|
||||||
|
* | Zone | 0.5 - 1.0 | Zone backgrounds, containers |
|
||||||
|
* | Card | 1.0 - 40,000,000 | Cards on table (position-based) |
|
||||||
|
* | Overlay | 2,000,000,000+ | UI elements above all cards |
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace ZValues
|
||||||
|
{
|
||||||
|
|
||||||
|
// Expose base for callers that need it
|
||||||
|
constexpr qreal OVERLAY_BASE = ZValueLayerManager::OVERLAY_BASE;
|
||||||
|
|
||||||
|
// Overlay layer Z-values for items that should appear above normal cards
|
||||||
|
constexpr qreal HOVERED_CARD = ZValueLayerManager::overlayZValue(1.0);
|
||||||
|
constexpr qreal ARROWS = ZValueLayerManager::overlayZValue(3.0);
|
||||||
|
constexpr qreal ZONE_VIEW_WIDGET = ZValueLayerManager::overlayZValue(4.0);
|
||||||
|
constexpr qreal DRAG_ITEM = ZValueLayerManager::overlayZValue(5.0);
|
||||||
|
constexpr qreal DRAG_ITEM_CHILD = ZValueLayerManager::overlayZValue(6.0);
|
||||||
|
constexpr qreal TOP_UI = ZValueLayerManager::overlayZValue(7.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute Z-value for child drag items based on hotspot position.
|
||||||
|
*
|
||||||
|
* When dragging multiple cards together, each child card needs a unique Z-value
|
||||||
|
* to prevent Z-fighting (flickering/flashing). The Z-values are derived from
|
||||||
|
* their position when grabbed to conserve original stacking. The formula encodes
|
||||||
|
* 2D coordinates into a single value where X has higher weight, ensuring
|
||||||
|
* deterministic visual stacking.
|
||||||
|
*
|
||||||
|
* @param hotSpotX The X coordinate of the grab position
|
||||||
|
* @param hotSpotY The Y coordinate of the grab position
|
||||||
|
* @return Unique Z-value for the child drag item
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr qreal childDragZValue(qreal hotSpotX, qreal hotSpotY)
|
||||||
|
{
|
||||||
|
return DRAG_ITEM_CHILD + hotSpotX * 1000000 + hotSpotY * 1000 + 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compute Z-value for cards on the table zone based on position.
|
||||||
|
*
|
||||||
|
* Cards lower on the table (higher Y) render above cards higher up,
|
||||||
|
* and cards to the right (higher X) render above cards to the left.
|
||||||
|
* This creates natural visual stacking for overlapping cards.
|
||||||
|
*
|
||||||
|
* @param x The X coordinate of the card position
|
||||||
|
* @param y The Y coordinate of the card position
|
||||||
|
* @return Z-value for the card's table position
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr qreal tableCardZValue(qreal x, qreal y)
|
||||||
|
{
|
||||||
|
return (y + CardDimensions::HEIGHT_F) * 100000.0 + (x + 1) * 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Card layering (general architecture, not command-zone specific)
|
||||||
|
constexpr qreal CARD_BASE = 1.0;
|
||||||
|
constexpr qreal CARD_MAX = ZValueLayerManager::CARD_Z_VALUE_MAX;
|
||||||
|
|
||||||
|
} // namespace ZValues
|
||||||
|
|
||||||
|
#endif // Z_VALUES_H
|
||||||
|
|
@ -56,7 +56,7 @@ void HandZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||||
QRectF HandZone::boundingRect() const
|
QRectF HandZone::boundingRect() const
|
||||||
{
|
{
|
||||||
if (SettingsCache::instance().getHorizontalHand())
|
if (SettingsCache::instance().getHorizontalHand())
|
||||||
return QRectF(0, 0, width, CARD_HEIGHT + 10);
|
return QRectF(0, 0, width, CardDimensions::HEIGHT_F + 10);
|
||||||
else
|
else
|
||||||
return QRectF(0, 0, 100, zoneHeight);
|
return QRectF(0, 0, 100, zoneHeight);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
cockatrice/src/game/zones/logic/card_zone_algorithms.h
Normal file
45
cockatrice/src/game/zones/logic/card_zone_algorithms.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef COCKATRICE_CARD_ZONE_ALGORITHMS_H
|
||||||
|
#define COCKATRICE_CARD_ZONE_ALGORITHMS_H
|
||||||
|
|
||||||
|
namespace CardZoneAlgorithms
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared insertion logic for zones where cards become visible on add and follow
|
||||||
|
* the standard pattern: clamp index, insert, clear identity if contents unknown,
|
||||||
|
* reset state, show card.
|
||||||
|
*
|
||||||
|
* Zones with different post-add behavior (signal connections, positional resets,
|
||||||
|
* hidden cards, or coordinate-based placement) should NOT use this — implement
|
||||||
|
* addCardImpl directly instead.
|
||||||
|
*
|
||||||
|
* Template parameters allow testing with lightweight mocks that avoid Qt graphics
|
||||||
|
* dependencies.
|
||||||
|
*
|
||||||
|
* @tparam CardList Must provide: size() -> int, insert(int, CardType*),
|
||||||
|
* getContentsKnown() -> bool
|
||||||
|
* @tparam CardType Must provide: setId(int), setCardRef(CardRefType),
|
||||||
|
* resetState(bool), setVisible(bool)
|
||||||
|
* @param keepAnnotations Forwarded to card->resetState(). Stack-like zones preserve
|
||||||
|
* annotations across zone transitions; hand-like zones clear them.
|
||||||
|
*/
|
||||||
|
template <typename CardList, typename CardType>
|
||||||
|
void addCardToList(CardList &cards, CardType *card, int x, bool keepAnnotations)
|
||||||
|
{
|
||||||
|
if (x < 0 || x >= cards.size()) {
|
||||||
|
x = static_cast<int>(cards.size());
|
||||||
|
}
|
||||||
|
cards.insert(x, card);
|
||||||
|
|
||||||
|
if (!cards.getContentsKnown()) {
|
||||||
|
card->setId(-1);
|
||||||
|
card->setCardRef({});
|
||||||
|
}
|
||||||
|
|
||||||
|
card->resetState(keepAnnotations);
|
||||||
|
card->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CardZoneAlgorithms
|
||||||
|
|
||||||
|
#endif // COCKATRICE_CARD_ZONE_ALGORITHMS_H
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param _player the player that the zone belongs to
|
* @param _player the player that the zone belongs to
|
||||||
|
|
@ -43,8 +44,10 @@ void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x,
|
||||||
|
|
||||||
for (auto *view : views) {
|
for (auto *view : views) {
|
||||||
if (qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->prepareAddCard(x)) {
|
if (qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->prepareAddCard(x)) {
|
||||||
view->getLogic()->addCard(new CardItem(player, nullptr, card->getCardRef(), card->getId()), reorganize, x,
|
auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId());
|
||||||
y);
|
copy->setFaceDown(card->getFaceDown());
|
||||||
|
|
||||||
|
view->getLogic()->addCard(copy, reorganize, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,9 +175,9 @@ void CardZoneLogic::clearContents()
|
||||||
QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
|
QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) const
|
||||||
{
|
{
|
||||||
QString ownerName = player->getPlayerInfo()->getName();
|
QString ownerName = player->getPlayerInfo()->getName();
|
||||||
if (name == "hand")
|
if (name == ZoneNames::HAND)
|
||||||
return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName));
|
||||||
else if (name == "deck")
|
else if (name == ZoneNames::DECK)
|
||||||
switch (gc) {
|
switch (gc) {
|
||||||
case CaseLookAtZone:
|
case CaseLookAtZone:
|
||||||
return (theirOwn ? tr("their library", "look at zone")
|
return (theirOwn ? tr("their library", "look at zone")
|
||||||
|
|
@ -190,11 +193,11 @@ QString CardZoneLogic::getTranslatedName(bool theirOwn, GrammaticalCase gc) cons
|
||||||
default:
|
default:
|
||||||
return (theirOwn ? tr("their library", "nominative") : tr("%1's library", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their library", "nominative") : tr("%1's library", "nominative").arg(ownerName));
|
||||||
}
|
}
|
||||||
else if (name == "grave")
|
else if (name == ZoneNames::GRAVE)
|
||||||
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName));
|
||||||
else if (name == "rfg")
|
else if (name == ZoneNames::EXILE)
|
||||||
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
|
return (theirOwn ? tr("their exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName));
|
||||||
else if (name == "sb")
|
else if (name == ZoneNames::SIDEBOARD)
|
||||||
switch (gc) {
|
switch (gc) {
|
||||||
case CaseLookAtZone:
|
case CaseLookAtZone:
|
||||||
return (theirOwn ? tr("their sideboard", "look at zone")
|
return (theirOwn ? tr("their sideboard", "look at zone")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "hand_zone_logic.h"
|
#include "hand_zone_logic.h"
|
||||||
|
|
||||||
#include "../../board/card_item.h"
|
#include "../../board/card_item.h"
|
||||||
|
#include "card_zone_algorithms.h"
|
||||||
|
|
||||||
HandZoneLogic::HandZoneLogic(Player *_player,
|
HandZoneLogic::HandZoneLogic(Player *_player,
|
||||||
const QString &_name,
|
const QString &_name,
|
||||||
|
|
@ -14,16 +15,5 @@ HandZoneLogic::HandZoneLogic(Player *_player,
|
||||||
|
|
||||||
void HandZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
void HandZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
||||||
{
|
{
|
||||||
// if x is negative set it to add at end
|
CardZoneAlgorithms::addCardToList(cards, card, x, false);
|
||||||
if (x < 0 || x >= cards.size()) {
|
}
|
||||||
x = cards.size();
|
|
||||||
}
|
|
||||||
cards.insert(x, card);
|
|
||||||
|
|
||||||
if (!cards.getContentsKnown()) {
|
|
||||||
card->setId(-1);
|
|
||||||
card->setCardRef({});
|
|
||||||
}
|
|
||||||
card->resetState();
|
|
||||||
card->setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "stack_zone_logic.h"
|
#include "stack_zone_logic.h"
|
||||||
|
|
||||||
#include "../../board/card_item.h"
|
#include "../../board/card_item.h"
|
||||||
|
#include "card_zone_algorithms.h"
|
||||||
|
|
||||||
StackZoneLogic::StackZoneLogic(Player *_player,
|
StackZoneLogic::StackZoneLogic(Player *_player,
|
||||||
const QString &_name,
|
const QString &_name,
|
||||||
|
|
@ -14,16 +15,5 @@ StackZoneLogic::StackZoneLogic(Player *_player,
|
||||||
|
|
||||||
void StackZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
void StackZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
||||||
{
|
{
|
||||||
// if x is negative set it to add at end
|
CardZoneAlgorithms::addCardToList(cards, card, x, true);
|
||||||
if (x < 0 || x >= cards.size()) {
|
}
|
||||||
x = static_cast<int>(cards.size());
|
|
||||||
}
|
|
||||||
cards.insert(x, card);
|
|
||||||
|
|
||||||
if (!cards.getContentsKnown()) {
|
|
||||||
card->setId(-1);
|
|
||||||
card->setCardRef({});
|
|
||||||
}
|
|
||||||
card->resetState(true);
|
|
||||||
card->setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ PileZone::PileZone(PileZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_log
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
|
|
||||||
setTransform(QTransform()
|
setTransform(QTransform()
|
||||||
.translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2)
|
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||||
.rotate(90)
|
.rotate(90)
|
||||||
.translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2));
|
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||||
|
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||||
Q_UNUSED(_roundCardCorners);
|
Q_UNUSED(_roundCardCorners);
|
||||||
|
|
@ -33,13 +33,13 @@ PileZone::PileZone(PileZoneLogic *_logic, QGraphicsItem *parent) : CardZone(_log
|
||||||
|
|
||||||
QRectF PileZone::boundingRect() const
|
QRectF PileZone::boundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT);
|
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPainterPath PileZone::shape() const
|
QPainterPath PileZone::shape() const
|
||||||
{
|
{
|
||||||
QPainterPath shape;
|
QPainterPath shape;
|
||||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
|
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
@ -52,9 +52,9 @@ void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*optio
|
||||||
getLogic()->getCards().at(0)->paintPicture(painter, getLogic()->getCards().at(0)->getTranslatedSize(painter),
|
getLogic()->getCards().at(0)->paintPicture(painter, getLogic()->getCards().at(0)->getTranslatedSize(painter),
|
||||||
90);
|
90);
|
||||||
|
|
||||||
painter->translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2);
|
painter->translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F);
|
||||||
painter->rotate(-90);
|
painter->rotate(-90);
|
||||||
painter->translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2);
|
painter->translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F);
|
||||||
paintNumberEllipse(getLogic()->getCards().size(), 28, Qt::white, -1, -1, painter);
|
paintNumberEllipse(getLogic()->getCards().size(), 28, Qt::white, -1, -1, painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,8 +68,13 @@ void PileZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZoneL
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
for (int i = 0; i < dragItems.size(); ++i)
|
for (int i = 0; i < dragItems.size(); ++i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId());
|
auto cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(dragItems[i]->getId());
|
||||||
|
if (dragItems[i]->isForceFaceDown()) {
|
||||||
|
cardToMove->set_face_down(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
@ -101,12 +106,12 @@ void PileZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
if (getLogic()->getCards().isEmpty())
|
if (getLogic()->getCards().isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool faceDown = event->modifiers().testFlag(Qt::ShiftModifier);
|
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||||
bool bottomCard = event->modifiers().testFlag(Qt::ControlModifier);
|
bool bottomCard = event->modifiers().testFlag(Qt::ControlModifier);
|
||||||
CardItem *card = bottomCard ? getLogic()->getCards().last() : getLogic()->getCards().first();
|
CardItem *card = bottomCard ? getLogic()->getCards().last() : getLogic()->getCards().first();
|
||||||
const int cardid =
|
const int cardid =
|
||||||
getLogic()->contentsKnown() ? card->getId() : (bottomCard ? getLogic()->getCards().size() - 1 : 0);
|
getLogic()->contentsKnown() ? card->getId() : (bottomCard ? getLogic()->getCards().size() - 1 : 0);
|
||||||
CardDragItem *drag = card->createDragItem(cardid, event->pos(), event->scenePos(), faceDown);
|
CardDragItem *drag = card->createDragItem(cardid, event->pos(), event->scenePos(), forceFaceDown);
|
||||||
drag->grabMouse();
|
drag->grabMouse();
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@ void SelectZone::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static_cast<GameScene *>(scene())->resizeRubberBand(
|
static_cast<GameScene *>(scene())->resizeRubberBand(
|
||||||
deviceTransform(static_cast<GameScene *>(scene())->getViewportTransform()).map(pos));
|
deviceTransform(static_cast<GameScene *>(scene())->getViewportTransform()).map(pos),
|
||||||
|
cardsInSelectionRect.size());
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,11 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||||
|
|
||||||
for (CardDragItem *item : dragItems) {
|
for (CardDragItem *item : dragItems) {
|
||||||
if (item) {
|
if (item) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(item->getId());
|
auto cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(item->getId());
|
||||||
|
if (item->isForceFaceDown()) {
|
||||||
|
cardToMove->set_face_down(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../board/card_item.h"
|
#include "../board/card_item.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../player/player_actions.h"
|
#include "../player/player_actions.h"
|
||||||
|
#include "../z_values.h"
|
||||||
#include "logic/table_zone_logic.h"
|
#include "logic/table_zone_logic.h"
|
||||||
|
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
|
|
@ -14,6 +15,7 @@
|
||||||
#include <libcockatrice/card/card_info.h>
|
#include <libcockatrice/card/card_info.h>
|
||||||
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||||
|
#include <libcockatrice/utility/zone_names.h>
|
||||||
|
|
||||||
const QColor TableZone::BACKGROUND_COLOR = QColor(100, 100, 100);
|
const QColor TableZone::BACKGROUND_COLOR = QColor(100, 100, 100);
|
||||||
const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
|
const QColor TableZone::FADE_MASK = QColor(0, 0, 0, 80);
|
||||||
|
|
@ -30,7 +32,7 @@ TableZone::TableZone(TableZoneLogic *_logic, QGraphicsItem *parent) : SelectZone
|
||||||
|
|
||||||
updateBg();
|
updateBg();
|
||||||
|
|
||||||
height = MARGIN_TOP + MARGIN_BOTTOM + TABLEROWS * CARD_HEIGHT + (TABLEROWS - 1) * PADDING_Y;
|
height = MARGIN_TOP + MARGIN_BOTTOM + TABLEROWS * CardDimensions::HEIGHT + (TABLEROWS - 1) * PADDING_Y;
|
||||||
width = MIN_WIDTH;
|
width = MIN_WIDTH;
|
||||||
currentMinimumWidth = width;
|
currentMinimumWidth = width;
|
||||||
|
|
||||||
|
|
@ -105,7 +107,7 @@ void TableZone::paintLandDivider(QPainter *painter)
|
||||||
{
|
{
|
||||||
// Place the line 2 grid heights down then back it off just enough to allow
|
// Place the line 2 grid heights down then back it off just enough to allow
|
||||||
// some space between a 3-card stack and the land area.
|
// some space between a 3-card stack and the land area.
|
||||||
qreal separatorY = MARGIN_TOP + 2 * (CARD_HEIGHT + PADDING_Y) - STACKED_CARD_OFFSET_Y / 2;
|
qreal separatorY = MARGIN_TOP + 2 * (CardDimensions::HEIGHT + PADDING_Y) - STACKED_CARD_OFFSET_Y / 2;
|
||||||
if (isInverted())
|
if (isInverted())
|
||||||
separatorY = height - separatorY;
|
separatorY = height - separatorY;
|
||||||
painter->setPen(QColor(255, 255, 255, 40));
|
painter->setPen(QColor(255, 255, 255, 40));
|
||||||
|
|
@ -134,8 +136,10 @@ void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
|
||||||
for (const auto &item : dragItems) {
|
for (const auto &item : dragItems) {
|
||||||
CardToMove *ctm = cmd.mutable_cards_to_move()->add_card();
|
CardToMove *ctm = cmd.mutable_cards_to_move()->add_card();
|
||||||
ctm->set_card_id(item->getId());
|
ctm->set_card_id(item->getId());
|
||||||
ctm->set_face_down(item->getFaceDown());
|
if (item->isForceFaceDown()) {
|
||||||
if (startZone->getName() != getLogic()->getName() && !item->getFaceDown()) {
|
ctm->set_face_down(true);
|
||||||
|
}
|
||||||
|
if (startZone->getName() != getLogic()->getName() && !item->isForceFaceDown()) {
|
||||||
const auto &card = item->getItem()->getCard();
|
const auto &card = item->getItem()->getCard();
|
||||||
if (card) {
|
if (card) {
|
||||||
ctm->set_pt(card.getInfo().getPowTough().toStdString());
|
ctm->set_pt(card.getInfo().getPowTough().toStdString());
|
||||||
|
|
@ -167,7 +171,7 @@ void TableZone::reorganizeCards()
|
||||||
actualY += 15;
|
actualY += 15;
|
||||||
|
|
||||||
getLogic()->getCards()[i]->setPos(actualX, actualY);
|
getLogic()->getCards()[i]->setPos(actualX, actualY);
|
||||||
getLogic()->getCards()[i]->setRealZValue((actualY + CARD_HEIGHT) * 100000 + (actualX + 1) * 100);
|
getLogic()->getCards()[i]->setRealZValue(ZValues::tableCardZValue(actualX, actualY));
|
||||||
|
|
||||||
QListIterator<CardItem *> attachedCardIterator(getLogic()->getCards()[i]->getAttachedCards());
|
QListIterator<CardItem *> attachedCardIterator(getLogic()->getCards()[i]->getAttachedCards());
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
@ -177,7 +181,7 @@ void TableZone::reorganizeCards()
|
||||||
qreal childX = actualX - j * STACKED_CARD_OFFSET_X;
|
qreal childX = actualX - j * STACKED_CARD_OFFSET_X;
|
||||||
qreal childY = y + 5;
|
qreal childY = y + 5;
|
||||||
attachedCard->setPos(childX, childY);
|
attachedCard->setPos(childX, childY);
|
||||||
attachedCard->setRealZValue((childY + CARD_HEIGHT) * 100000 + (childX + 1) * 100);
|
attachedCard->setRealZValue(ZValues::tableCardZValue(childX, childY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +196,7 @@ void TableZone::toggleTapped()
|
||||||
|
|
||||||
auto isCardOnTable = [](const QGraphicsItem *item) {
|
auto isCardOnTable = [](const QGraphicsItem *item) {
|
||||||
if (auto card = qgraphicsitem_cast<const CardItem *>(item)) {
|
if (auto card = qgraphicsitem_cast<const CardItem *>(item)) {
|
||||||
return card->getZone()->getName() == "table";
|
return card->getZone()->getName() == ZoneNames::TABLE;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
@ -229,7 +233,7 @@ void TableZone::resizeToContents()
|
||||||
|
|
||||||
// Minimum width is the rightmost card position plus enough room for
|
// Minimum width is the rightmost card position plus enough room for
|
||||||
// another card with padding, then margin.
|
// another card with padding, then margin.
|
||||||
currentMinimumWidth = xMax + (2 * CARD_WIDTH) + PADDING_X + MARGIN_RIGHT;
|
currentMinimumWidth = xMax + (2 * CardDimensions::WIDTH) + PADDING_X + MARGIN_RIGHT;
|
||||||
|
|
||||||
if (currentMinimumWidth < MIN_WIDTH)
|
if (currentMinimumWidth < MIN_WIDTH)
|
||||||
currentMinimumWidth = MIN_WIDTH;
|
currentMinimumWidth = MIN_WIDTH;
|
||||||
|
|
@ -279,10 +283,10 @@ void TableZone::computeCardStackWidths()
|
||||||
const int key = getCardStackMapKey(gridPoint.x() / 3, gridPoint.y());
|
const int key = getCardStackMapKey(gridPoint.x() / 3, gridPoint.y());
|
||||||
const int stackCount = cardStackCount.value(key, 0);
|
const int stackCount = cardStackCount.value(key, 0);
|
||||||
if (stackCount == 1)
|
if (stackCount == 1)
|
||||||
cardStackWidth.insert(key, CARD_WIDTH + getLogic()->getCards()[i]->getAttachedCards().size() *
|
cardStackWidth.insert(key, CardDimensions::WIDTH + getLogic()->getCards()[i]->getAttachedCards().size() *
|
||||||
STACKED_CARD_OFFSET_X);
|
STACKED_CARD_OFFSET_X);
|
||||||
else
|
else
|
||||||
cardStackWidth.insert(key, CARD_WIDTH + (stackCount - 1) * STACKED_CARD_OFFSET_X);
|
cardStackWidth.insert(key, CardDimensions::WIDTH + (stackCount - 1) * STACKED_CARD_OFFSET_X);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,7 +300,7 @@ QPointF TableZone::mapFromGrid(QPoint gridPoint) const
|
||||||
// Add in width of card stack plus padding for each column
|
// Add in width of card stack plus padding for each column
|
||||||
for (int i = 0; i < gridPoint.x() / 3; ++i) {
|
for (int i = 0; i < gridPoint.x() / 3; ++i) {
|
||||||
const int key = getCardStackMapKey(i, gridPoint.y());
|
const int key = getCardStackMapKey(i, gridPoint.y());
|
||||||
x += cardStackWidth.value(key, CARD_WIDTH) + PADDING_X;
|
x += cardStackWidth.value(key, CardDimensions::WIDTH) + PADDING_X;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInverted())
|
if (isInverted())
|
||||||
|
|
@ -307,7 +311,7 @@ QPointF TableZone::mapFromGrid(QPoint gridPoint) const
|
||||||
|
|
||||||
// Add in card size and padding for each row
|
// Add in card size and padding for each row
|
||||||
for (int i = 0; i < gridPoint.y(); ++i)
|
for (int i = 0; i < gridPoint.y(); ++i)
|
||||||
y += CARD_HEIGHT + PADDING_Y;
|
y += CardDimensions::HEIGHT + PADDING_Y;
|
||||||
|
|
||||||
return QPointF(x, y);
|
return QPointF(x, y);
|
||||||
}
|
}
|
||||||
|
|
@ -321,7 +325,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const
|
||||||
int y = mapPoint.y() - MARGIN_TOP;
|
int y = mapPoint.y() - MARGIN_TOP;
|
||||||
|
|
||||||
// Below calculation effectively rounds to the nearest grid point.
|
// Below calculation effectively rounds to the nearest grid point.
|
||||||
const int gridPointHeight = CARD_HEIGHT + PADDING_Y;
|
const int gridPointHeight = CardDimensions::HEIGHT + PADDING_Y;
|
||||||
int gridPointY = (y + PADDING_Y / 2) / gridPointHeight;
|
int gridPointY = (y + PADDING_Y / 2) / gridPointHeight;
|
||||||
|
|
||||||
gridPointY = clampValidTableRow(gridPointY);
|
gridPointY = clampValidTableRow(gridPointY);
|
||||||
|
|
@ -337,7 +341,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const
|
||||||
|
|
||||||
// Maximum value is a card width from the right margin, referenced to the
|
// Maximum value is a card width from the right margin, referenced to the
|
||||||
// grid area.
|
// grid area.
|
||||||
const int xMax = width - MARGIN_LEFT - MARGIN_RIGHT - CARD_WIDTH;
|
const int xMax = width - MARGIN_LEFT - MARGIN_RIGHT - CardDimensions::WIDTH;
|
||||||
|
|
||||||
int xStack = 0;
|
int xStack = 0;
|
||||||
int xNextStack = 0;
|
int xNextStack = 0;
|
||||||
|
|
@ -345,7 +349,7 @@ QPoint TableZone::mapToGrid(const QPointF &mapPoint) const
|
||||||
while ((xNextStack <= x) && (xNextStack <= xMax)) {
|
while ((xNextStack <= x) && (xNextStack <= xMax)) {
|
||||||
xStack = xNextStack;
|
xStack = xNextStack;
|
||||||
const int key = getCardStackMapKey(nextStackCol, gridPointY);
|
const int key = getCardStackMapKey(nextStackCol, gridPointY);
|
||||||
xNextStack += cardStackWidth.value(key, CARD_WIDTH) + PADDING_X;
|
xNextStack += cardStackWidth.value(key, CardDimensions::WIDTH) + PADDING_X;
|
||||||
nextStackCol++;
|
nextStackCol++;
|
||||||
}
|
}
|
||||||
int stackCol = qMax(nextStackCol - 1, 0);
|
int stackCol = qMax(nextStackCol - 1, 0);
|
||||||
|
|
@ -378,3 +382,11 @@ int TableZone::clampValidTableRow(const int row)
|
||||||
return TABLEROWS - 1;
|
return TABLEROWS - 1;
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TableZone::tableRowToGridY(int tableRow)
|
||||||
|
{
|
||||||
|
if (tableRow > 2) {
|
||||||
|
tableRow = 1;
|
||||||
|
}
|
||||||
|
return clampValidTableRow(2 - tableRow);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,12 @@ private:
|
||||||
/*
|
/*
|
||||||
Minimum width of the table zone including margins.
|
Minimum width of the table zone including margins.
|
||||||
*/
|
*/
|
||||||
static const int MIN_WIDTH = MARGIN_LEFT + (5 * CARD_WIDTH) + MARGIN_RIGHT;
|
static const int MIN_WIDTH = MARGIN_LEFT + (5 * CardDimensions::WIDTH) + MARGIN_RIGHT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Offset sizes when cards are stacked on each other in the grid
|
Offset sizes when cards are stacked on each other in the grid
|
||||||
*/
|
*/
|
||||||
static const int STACKED_CARD_OFFSET_X = CARD_WIDTH / 3;
|
static const int STACKED_CARD_OFFSET_X = CardDimensions::WIDTH / 3;
|
||||||
static const int STACKED_CARD_OFFSET_Y = PADDING_Y / 3;
|
static const int STACKED_CARD_OFFSET_Y = PADDING_Y / 3;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -151,6 +151,13 @@ public:
|
||||||
|
|
||||||
static int clampValidTableRow(const int row);
|
static int clampValidTableRow(const int row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a card's logical table row (0=creatures, 1=noncreatures, 2=lands)
|
||||||
|
* to the corresponding grid Y coordinate. Cards with tableRow > 2 (e.g.,
|
||||||
|
* instants/sorceries) default to the noncreatures row.
|
||||||
|
*/
|
||||||
|
static int tableRowToGridY(int tableRow);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Resizes the TableZone in case CardItems are within or
|
Resizes the TableZone in case CardItems are within or
|
||||||
outside of the TableZone constraints.
|
outside of the TableZone constraints.
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,10 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
|
||||||
for (int i = 0; i < cardList.size(); ++i) {
|
for (int i = 0; i < cardList.size(); ++i) {
|
||||||
auto card = cardList[i];
|
auto card = cardList[i];
|
||||||
CardRef cardRef = {QString::fromStdString(card->name()), QString::fromStdString(card->provider_id())};
|
CardRef cardRef = {QString::fromStdString(card->name()), QString::fromStdString(card->provider_id())};
|
||||||
getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, cardRef, card->id()), false, i);
|
auto copy = new CardItem(getLogic()->getPlayer(), this, cardRef, card->id());
|
||||||
|
copy->setFaceDown(card->face_down());
|
||||||
|
|
||||||
|
getLogic()->addCard(copy, false, i);
|
||||||
}
|
}
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
} else if (!qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->contentsKnown()) {
|
} else if (!qobject_cast<ZoneViewZoneLogic *>(getLogic())->getOriginalZone()->contentsKnown()) {
|
||||||
|
|
@ -91,8 +94,10 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
|
||||||
int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size());
|
int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size());
|
||||||
for (int i = 0; i < number; i++) {
|
for (int i = 0; i < number; i++) {
|
||||||
CardItem *card = c.at(i);
|
CardItem *card = c.at(i);
|
||||||
getLogic()->addCard(new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId()), false,
|
auto copy = new CardItem(getLogic()->getPlayer(), this, card->getCardRef(), card->getId());
|
||||||
i);
|
copy->setFaceDown(card->getFaceDown());
|
||||||
|
|
||||||
|
getLogic()->addCard(copy, false, i);
|
||||||
}
|
}
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
}
|
}
|
||||||
|
|
@ -107,12 +112,15 @@ void ZoneViewZone::zoneDumpReceived(const Response &r)
|
||||||
auto cardName = QString::fromStdString(cardInfo.name());
|
auto cardName = QString::fromStdString(cardInfo.name());
|
||||||
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
|
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
|
||||||
auto card = new CardItem(getLogic()->getPlayer(), this, {cardName, cardProviderId}, cardInfo.id(), getLogic());
|
auto card = new CardItem(getLogic()->getPlayer(), this, {cardName, cardProviderId}, cardInfo.id(), getLogic());
|
||||||
|
card->setFaceDown(cardInfo.face_down());
|
||||||
getLogic()->rawInsertCard(card, i);
|
getLogic()->rawInsertCard(card, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
qobject_cast<ZoneViewZoneLogic *>(getLogic())->updateCardIds(ZoneViewZoneLogic::INITIALIZE);
|
qobject_cast<ZoneViewZoneLogic *>(getLogic())->updateCardIds(ZoneViewZoneLogic::INITIALIZE);
|
||||||
reorganizeCards();
|
reorganizeCards();
|
||||||
emit getLogic()->cardCountChanged();
|
// clang-format off
|
||||||
|
emit getLogic()->cardCountChanged(); // emit keyword causes spurious spacing around ->
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because of boundingRect(), this function must not be called before the zone was added to a scene.
|
// Because of boundingRect(), this function must not be called before the zone was added to a scene.
|
||||||
|
|
@ -160,8 +168,8 @@ void ZoneViewZone::reorganizeCards()
|
||||||
// determine bounding rect
|
// determine bounding rect
|
||||||
qreal aleft = 0;
|
qreal aleft = 0;
|
||||||
qreal atop = 0;
|
qreal atop = 0;
|
||||||
qreal awidth = gridSize.cols * CARD_WIDTH + (CARD_WIDTH / 2) + HORIZONTAL_PADDING;
|
qreal awidth = gridSize.cols * CardDimensions::WIDTH_F + CardDimensions::WIDTH_HALF_F + HORIZONTAL_PADDING;
|
||||||
qreal aheight = (gridSize.rows * CARD_HEIGHT) / 3 + CARD_HEIGHT * 1.3;
|
qreal aheight = (gridSize.rows * CardDimensions::HEIGHT_F) / 3 + CardDimensions::HEIGHT_F * 1.3;
|
||||||
optimumRect = QRectF(aleft, atop, awidth, aheight);
|
optimumRect = QRectF(aleft, atop, awidth, aheight);
|
||||||
|
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
|
|
@ -204,8 +212,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca
|
||||||
}
|
}
|
||||||
|
|
||||||
lastColumnProp = columnProp;
|
lastColumnProp = columnProp;
|
||||||
qreal x = col * CARD_WIDTH;
|
qreal x = col * CardDimensions::WIDTH_F;
|
||||||
qreal y = row * CARD_HEIGHT / 3;
|
qreal y = row * CardDimensions::HEIGHT_F / 3;
|
||||||
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
||||||
c->setRealZValue(i);
|
c->setRealZValue(i);
|
||||||
longestRow = qMax(row, longestRow);
|
longestRow = qMax(row, longestRow);
|
||||||
|
|
@ -232,8 +240,8 @@ ZoneViewZone::GridSize ZoneViewZone::positionCardsForDisplay(CardList &cards, Ca
|
||||||
|
|
||||||
for (int i = 0; i < cardCount; i++) {
|
for (int i = 0; i < cardCount; i++) {
|
||||||
CardItem *c = cards.at(i);
|
CardItem *c = cards.at(i);
|
||||||
qreal x = (i / rows) * CARD_WIDTH;
|
qreal x = (i / rows) * CardDimensions::WIDTH_F;
|
||||||
qreal y = (i % rows) * CARD_HEIGHT / 3;
|
qreal y = (i % rows) * CardDimensions::HEIGHT_F / 3;
|
||||||
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
c->setPos(HORIZONTAL_PADDING + x, VERTICAL_PADDING + y);
|
||||||
c->setRealZValue(i);
|
c->setRealZValue(i);
|
||||||
}
|
}
|
||||||
|
|
@ -279,8 +287,13 @@ void ZoneViewZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
cmd.set_is_reversed(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getIsReversed());
|
cmd.set_is_reversed(qobject_cast<ZoneViewZoneLogic *>(getLogic())->getIsReversed());
|
||||||
|
|
||||||
for (int i = 0; i < dragItems.size(); ++i)
|
for (int i = 0; i < dragItems.size(); ++i) {
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId());
|
auto cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(dragItems[i]->getId());
|
||||||
|
if (dragItems[i]->isForceFaceDown()) {
|
||||||
|
cardToMove->set_face_down(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../game_scene.h"
|
#include "../game_scene.h"
|
||||||
#include "../player/player.h"
|
#include "../player/player.h"
|
||||||
#include "../player/player_actions.h"
|
#include "../player/player_actions.h"
|
||||||
|
#include "../z_values.h"
|
||||||
#include "view_zone.h"
|
#include "view_zone.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
|
@ -47,7 +48,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
|
||||||
{
|
{
|
||||||
setAcceptHoverEvents(true);
|
setAcceptHoverEvents(true);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
setZValue(2000000006);
|
setZValue(ZValues::ZONE_VIEW_WIDGET);
|
||||||
setFlag(ItemIgnoresTransformations);
|
setFlag(ItemIgnoresTransformations);
|
||||||
|
|
||||||
QGraphicsLinearLayout *vbox = new QGraphicsLinearLayout(Qt::Vertical);
|
QGraphicsLinearLayout *vbox = new QGraphicsLinearLayout(Qt::Vertical);
|
||||||
|
|
@ -71,7 +72,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
|
||||||
|
|
||||||
QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
|
QGraphicsProxyWidget *searchEditProxy = new QGraphicsProxyWidget;
|
||||||
searchEditProxy->setWidget(&searchEdit);
|
searchEditProxy->setWidget(&searchEdit);
|
||||||
searchEditProxy->setZValue(2000000007);
|
searchEditProxy->setZValue(ZValues::DRAG_ITEM);
|
||||||
vbox->addItem(searchEditProxy);
|
vbox->addItem(searchEditProxy);
|
||||||
|
|
||||||
// top row
|
// top row
|
||||||
|
|
@ -80,13 +81,13 @@ ZoneViewWidget::ZoneViewWidget(Player *_player,
|
||||||
// groupBy options
|
// groupBy options
|
||||||
QGraphicsProxyWidget *groupBySelectorProxy = new QGraphicsProxyWidget;
|
QGraphicsProxyWidget *groupBySelectorProxy = new QGraphicsProxyWidget;
|
||||||
groupBySelectorProxy->setWidget(&groupBySelector);
|
groupBySelectorProxy->setWidget(&groupBySelector);
|
||||||
groupBySelectorProxy->setZValue(2000000008);
|
groupBySelectorProxy->setZValue(ZValues::TOP_UI);
|
||||||
hTopRow->addItem(groupBySelectorProxy);
|
hTopRow->addItem(groupBySelectorProxy);
|
||||||
|
|
||||||
// sortBy options
|
// sortBy options
|
||||||
QGraphicsProxyWidget *sortBySelectorProxy = new QGraphicsProxyWidget;
|
QGraphicsProxyWidget *sortBySelectorProxy = new QGraphicsProxyWidget;
|
||||||
sortBySelectorProxy->setWidget(&sortBySelector);
|
sortBySelectorProxy->setWidget(&sortBySelector);
|
||||||
sortBySelectorProxy->setZValue(2000000007);
|
sortBySelectorProxy->setZValue(ZValues::DRAG_ITEM);
|
||||||
hTopRow->addItem(sortBySelectorProxy);
|
hTopRow->addItem(sortBySelectorProxy);
|
||||||
|
|
||||||
vbox->addItem(hTopRow);
|
vbox->addItem(hTopRow);
|
||||||
|
|
@ -457,7 +458,7 @@ void ZoneViewWidget::resizeScrollbar(const qreal newZoneHeight)
|
||||||
*/
|
*/
|
||||||
static qreal rowsToHeight(int rows)
|
static qreal rowsToHeight(int rows)
|
||||||
{
|
{
|
||||||
const qreal cardsHeight = (rows + 1) * (CARD_HEIGHT / 3);
|
const qreal cardsHeight = (rows + 1) * (CardDimensions::HEIGHT_F / 3);
|
||||||
return cardsHeight + 5; // +5 padding to make the cutoff look nicer
|
return cardsHeight + 5; // +5 padding to make the cutoff look nicer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -573,4 +574,4 @@ void ZoneViewWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||||
if (event->pos().y() <= 0) {
|
if (event->pos().y() <= 0) {
|
||||||
expandWindow();
|
expandWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ CardPictureLoader::CardPictureLoader() : QObject(nullptr)
|
||||||
connect(&SettingsCache::instance(), &SettingsCache::picDownloadChanged, this,
|
connect(&SettingsCache::instance(), &SettingsCache::picDownloadChanged, this,
|
||||||
&CardPictureLoader::picDownloadChanged);
|
&CardPictureLoader::picDownloadChanged);
|
||||||
|
|
||||||
|
qRegisterMetaType<ExactCard>();
|
||||||
connect(worker, &CardPictureLoaderWorker::imageLoaded, this, &CardPictureLoader::imageLoaded);
|
connect(worker, &CardPictureLoaderWorker::imageLoaded, this, &CardPictureLoader::imageLoaded);
|
||||||
|
|
||||||
statusBar = new CardPictureLoaderStatusBar(nullptr);
|
statusBar = new CardPictureLoaderStatusBar(nullptr);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
#include <libcockatrice/card/database/card_database.h>
|
#include <libcockatrice/card/database/card_database.h>
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
#include <libcockatrice/card/import/card_name_normalizer.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>
|
||||||
|
|
||||||
|
|
@ -42,7 +43,7 @@ DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bo
|
||||||
DeckList deckList;
|
DeckList deckList;
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = deckList.loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file, CardNameNormalizer());
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice: {
|
case DeckFileFormat::Cockatrice: {
|
||||||
result = deckList.loadFromFile_Native(&file);
|
result = deckList.loadFromFile_Native(&file);
|
||||||
|
|
@ -50,7 +51,7 @@ DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bo
|
||||||
qCInfo(DeckLoaderLog) << "Failed to load " << fileName
|
qCInfo(DeckLoaderLog) << "Failed to load " << fileName
|
||||||
<< "as cockatrice format; retrying as plain format";
|
<< "as cockatrice format; retrying as plain format";
|
||||||
file.seek(0);
|
file.seek(0);
|
||||||
result = deckList.loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file, CardNameNormalizer());
|
||||||
fmt = DeckFileFormat::PlainText;
|
fmt = DeckFileFormat::PlainText;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <QPrinter>
|
#include <QPrinter>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
#include <libcockatrice/deck_list/deck_list.h>
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(DeckLoaderLog, "deck_loader");
|
inline Q_LOGGING_CATEGORY(DeckLoaderLog, "deck_loader");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <libcockatrice/network/server/remote/user_level.h>
|
#include <libcockatrice/network/server/remote/user_level.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(PixelMapGeneratorLog, "pixel_map_generator");
|
inline Q_LOGGING_CATEGORY(PixelMapGeneratorLog, "pixel_map_generator");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QStyle>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QStyleHints>
|
#include <QStyleHints>
|
||||||
#include <Qt>
|
#include <Qt>
|
||||||
|
|
@ -89,6 +90,11 @@ struct PaletteColorInfo
|
||||||
|
|
||||||
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
|
defaultStyleName = qApp->style()->objectName();
|
||||||
|
// FIXME workaround for windows11 style being broken
|
||||||
|
if (defaultStyleName == "windows11") {
|
||||||
|
defaultStyleName = "windowsvista";
|
||||||
|
}
|
||||||
ensureThemeDirectoryExists();
|
ensureThemeDirectoryExists();
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||||
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &ThemeManager::themeChangedSlot);
|
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &ThemeManager::themeChangedSlot);
|
||||||
|
|
@ -177,7 +183,7 @@ QBrush ThemeManager::loadExtraBrush(QString fileName, QBrush &fallbackBrush)
|
||||||
|
|
||||||
static inline QPalette createDarkGreenFusionPalette()
|
static inline QPalette createDarkGreenFusionPalette()
|
||||||
{
|
{
|
||||||
QPalette p;
|
QPalette p = QStyleFactory::create("Fusion")->standardPalette();
|
||||||
|
|
||||||
// ---------- Core backgrounds ----------
|
// ---------- Core backgrounds ----------
|
||||||
p.setColor(QPalette::Window, QColor(30, 30, 30)); // #ff1e1e1e
|
p.setColor(QPalette::Window, QColor(30, 30, 30)); // #ff1e1e1e
|
||||||
|
|
@ -246,7 +252,7 @@ static inline QPalette createDarkGreenFusionPalette()
|
||||||
|
|
||||||
static inline QPalette createLightGreenFusionPalette()
|
static inline QPalette createLightGreenFusionPalette()
|
||||||
{
|
{
|
||||||
QPalette p;
|
QPalette p = QStyleFactory::create("Fusion")->standardPalette();
|
||||||
|
|
||||||
// ---------- Core backgrounds ----------
|
// ---------- Core backgrounds ----------
|
||||||
p.setColor(QPalette::Window, QColor(240, 240, 240)); // #fff0f0f0
|
p.setColor(QPalette::Window, QColor(240, 240, 240)); // #fff0f0f0
|
||||||
|
|
@ -330,13 +336,15 @@ void ThemeManager::themeChangedSlot()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (themeName == FUSION_THEME_NAME) {
|
if (themeName == FUSION_THEME_NAME) {
|
||||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
QStyle *fusionStyle = QStyleFactory::create("Fusion");
|
||||||
|
qApp->setStyle(fusionStyle);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||||
QPalette palette;
|
// Start from Fusion's own palette so dark mode is handled correctly,
|
||||||
|
// then apply any tweaks on top of it.
|
||||||
|
QPalette palette = fusionStyle->standardPalette();
|
||||||
if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
|
if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
|
||||||
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
||||||
}
|
}
|
||||||
|
|
||||||
qApp->setPalette(palette);
|
qApp->setPalette(palette);
|
||||||
#endif
|
#endif
|
||||||
} else if (themeName == FUSION_THEME_NAME_LIGHT) {
|
} else if (themeName == FUSION_THEME_NAME_LIGHT) {
|
||||||
|
|
@ -346,7 +354,7 @@ void ThemeManager::themeChangedSlot()
|
||||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||||
qApp->setPalette(createDarkGreenFusionPalette());
|
qApp->setPalette(createDarkGreenFusionPalette());
|
||||||
} else {
|
} else {
|
||||||
qApp->setStyle("");
|
qApp->setStyle(QStyleFactory::create(defaultStyleName)); // setting the style also sets the palette
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dirPath.isEmpty()) {
|
if (dirPath.isEmpty()) {
|
||||||
|
|
|
||||||
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