Compare commits

..

6 commits

Author SHA1 Message Date
BruebachL
b3450a78cd [Oracle] Change basic lands exception to regex to deal with snow basics. (#6931)
* [Oracle] Change basic lands exception to regex to deal with snow basics.

Took 45 minutes

* Update oracle/src/oracleimporter.cpp

Co-authored-by: ebbit1q <ebbit1q@gmail.com>

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2026-05-23 00:19:40 +02:00
RickyRister
a5384933c6 [VDE] Disable filter dock widget (#6924) 2026-05-23 00:19:40 +02:00
github-actions[bot]
482bb78527 Update translation files (#6920)
Co-authored-by: github-actions <github-actions@github.com>
2026-05-23 00:19:40 +02:00
RickyRister
cb2ca152b7 Make undo draw failure visible in chat (#6889)
* [Server][Game] Make undo draw failure visible in chat

* genericize the proto
2026-05-22 01:00:57 +02:00
ebbit1q
762f36335e fix cards attaching/transforming to the wrong card across players (#6909)
* fix cards attaching/transforming to the wrong card across players

* move comment
2026-05-22 00:49:38 +02:00
ebbit1q
bd80528e7b fix resizing the visual card database loading more pages forever (#6884)
* fix resizing the vde loading more pages forever

* make near end of page const
2026-05-22 00:49:27 +02:00
628 changed files with 48830 additions and 74748 deletions

View file

@ -13,9 +13,17 @@ fi
# Check formatting using format.sh
echo "Checking your code using format.sh..."
./format.sh --color-diff --cmake --shell --print-version --branch origin/master
diff="$(./format.sh --diff --cmake --shell --print-version --branch origin/master)"
err=$?
sep="
----------
"
used_version="${diff%%"$sep"*}"
diff="${diff#*"$sep"}"
changes_to_make="${diff%%"$sep"*}"
files_to_edit="${diff#*"$sep"}"
case $err in
1)
cat <<EOM
@ -28,10 +36,19 @@ case $err in
*** Then commit and push those changes to this branch. ***
*** Check our CONTRIBUTING.md file for more details. ***
*** ***
*** Thank you ❤️ ***
*** Thank you ❤️ ***
*** ***
***********************************************************
Used version:
$used_version
Affected files:
$files_to_edit
The following changes should be made:
$changes_to_make
Exiting...
EOM
exit 2
@ -48,6 +65,9 @@ EOM
*** ***
***********************************************************
Used version:
$used_version
Exiting...
EOM
exit 0

View file

@ -89,8 +89,6 @@ else
echo "'$previous' to '$TAG' ($count commits)"
# --> is the markdown comment escape sequence, emojis are way better
generated_list="${generated_list//-->/→}"
# Escape & to preserve it from commit message into markdown output
generated_list="${generated_list//&/\\&}"
body="${body//--REPLACE-WITH-GENERATED-LIST--/$generated_list}"
body="${body//--REPLACE-WITH-COMMIT-COUNT--/$count}"
body="${body//--REPLACE-WITH-PREVIOUS-RELEASE-TAG--/$previous}"

View file

@ -3,9 +3,7 @@ AccessModifierOffset: -4
ColumnLimit: 120
---
Language: Cpp
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortFunctionsOnASingleLine: None
BinPackParameters: false
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: false
@ -20,14 +18,18 @@ BraceWrapping:
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBraces: Custom
IncludeBlocks: Regroup
AllowShortFunctionsOnASingleLine: None
BinPackParameters: false
AllowAllParametersOfDeclarationOnNextLine: false
IndentCaseLabels: true
InsertBraces: true
PointerAlignment: Right
RemoveSemicolon: true
SortIncludes: true
IncludeBlocks: Regroup
StatementAttributeLikeMacros: [emit]
# requires clang-format 15
InsertBraces: true
# requires clang-format 16
# RemoveSemicolon: true
---
Language: Proto
AllowShortFunctionsOnASingleLine: None

5
.codacy.yml Normal file
View file

@ -0,0 +1,5 @@
---
exclude_paths:
- '**/translations/*.ts'
# codacy config documentation: https://support.codacy.com/hc/en-us/articles/115002130625-Codacy-Configuration-File

View file

@ -209,16 +209,6 @@ nowadays and clean it up for you.
Lines should be 120 characters or less. Please break up lines that are too long
into smaller parts, for example at spaces or after opening a brace.
### Documentation Comments ###
Use [Doxygen](https://www.doxygen.nl/) for code documentation:
- **Doc blocks**: Use `/** @brief Description */` (Javadoc-style), not `///`
- **Member comments**: Use trailing `///<` for inline member documentation
- **TODOs**: Use `//! \todo Description` (Qt-style), Doxygen collects them into a Todo List
(uses [Qt-style comments](https://www.doxygen.nl/manual/docblocks.html) with
Doxygen's [\todo command](https://www.doxygen.nl/manual/commands.html#cmdtodo))
### Memory Management ###
New code should be written using references over pointers and stack allocation

View file

@ -1,10 +1,10 @@
name: Build Desktop
permissions:
actions: write # needed to delete entries in GHA cache (update ccache)
attestations: write # needed to persist the attestation.
contents: write
id-token: write # needed for signing certificate in attestation
id-token: write
attestations: write
actions: write # needed for ccache action to be able to delete gha caches
on:
push:
@ -19,7 +19,7 @@ on:
- '.github/workflows/desktop-build.yml'
- 'CMakeLists.txt'
- 'vcpkg.json'
- 'vcpkg' # needed to match submodule bumps (gitlink)
- 'vcpkg'
tags:
- '*'
pull_request:
@ -32,7 +32,7 @@ on:
- '.github/workflows/desktop-build.yml'
- 'CMakeLists.txt'
- 'vcpkg.json'
- 'vcpkg' # needed to match submodule bumps (gitlink)
- 'vcpkg'
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on release)
concurrency:
@ -44,217 +44,216 @@ jobs:
name: Configure
runs-on: ubuntu-slim
outputs:
tag: ${{ steps.configure.outputs.tag }}
sha: ${{ steps.configure.outputs.sha }}
tag: ${{steps.configure.outputs.tag}}
sha: ${{steps.configure.outputs.sha}}
steps:
- name: "Configure"
env:
RESOLVED_SHA: ${{ case(github.event_name == 'pull_request', github.event.pull_request.head.sha, github.sha) }}
steps:
- name: Configure
id: configure
shell: bash
run: |
if [[ "$GITHUB_REF_TYPE" == 'tag' ]]; then # release
echo "tag=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
tag_regex='^refs/tags/'
if [[ $GITHUB_EVENT_NAME == pull-request ]]; then # pull request
sha="${{github.event.pull_request.head.sha}}"
elif [[ $GITHUB_REF =~ $tag_regex ]]; then # release
sha="$GITHUB_SHA"
tag="${GITHUB_REF/refs\/tags\//}"
echo "tag=$tag" >>"$GITHUB_OUTPUT"
else # push to branch
sha="$GITHUB_SHA"
fi
echo "sha=$RESOLVED_SHA" >> "$GITHUB_OUTPUT"
echo "sha=$sha" >>"$GITHUB_OUTPUT"
- name: "Checkout"
- name: Checkout
if: steps.configure.outputs.tag != null
uses: actions/checkout@v7
uses: actions/checkout@v6
with:
fetch-depth: 0 # fetch all history for all branches and tags
fetch-depth: 0
- name: "Prepare release parameters"
- name: Prepare release parameters
id: prepare
if: steps.configure.outputs.tag != null
shell: bash
env:
TAG: ${{ steps.configure.outputs.tag }}
TAG: ${{steps.configure.outputs.tag}}
run: .ci/prep_release.sh
- name: "Create release"
- name: Create release
if: steps.configure.outputs.tag != null
id: create_release
shell: bash
env:
GH_TOKEN: ${{ github.token }}
tag_name: ${{ steps.configure.outputs.tag }}
target: ${{ steps.configure.outputs.sha }}
release_name: ${{ steps.prepare.outputs.title }}
body_path: ${{ steps.prepare.outputs.body_path }}
prerelease: ${{ steps.prepare.outputs.is_beta }}
GH_TOKEN: ${{github.token}}
tag_name: ${{steps.configure.outputs.tag}}
target: ${{steps.configure.outputs.sha}}
release_name: ${{steps.prepare.outputs.title}}
body_path: ${{steps.prepare.outputs.body_path}}
prerelease: ${{steps.prepare.outputs.is_beta}}
run: |
args=()
[[ $prerelease == yes ]] && args+=(--prerelease)
gh release create "$tag_name" --verify-tag --draft "${args[@]}" \
--target "$target" \
--title "$release_name" \
--notes-file "$body_path"
if [[ $prerelease == yes ]]; then
args="--prerelease"
fi
gh release create "$tag_name" --draft --verify-tag $args \
--target "$target" --title "$release_name" \
--notes-file "$body_path"
build-linux:
strategy:
fail-fast: false
matrix:
# The files in ".ci/$distro$version" correspond to the values given here
# These names correspond to the files in ".ci/$distro$version"
include:
- distro: Arch
allow-failure: yes
package: skip # We are packaged in Arch already
allow-failure: yes
- distro: Servatrice_Debian
version: 12
package: DEB
server_only: yes
test: skip
server_only: yes
- distro: Debian
version: 12
package: DEB
test: skip # Running tests on all distros is superfluous
- distro: Debian
version: 13
package: DEB
- distro: Fedora
version: 43
package: RPM
test: skip # Running tests on all distros is superfluous
- distro: Fedora
version: 44
package: RPM
- distro: Ubuntu
version: 24.04
package: DEB
test: skip # Running tests on all distros is superfluous
- distro: Ubuntu
version: 26.04
package: DEB
name: ${{ matrix.distro }} ${{ matrix.version }}
name: ${{matrix.distro}} ${{matrix.version}}
needs: configure
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.allow-failure == 'yes' }}
continue-on-error: ${{matrix.allow-failure == 'yes'}}
timeout-minutes: 70
env:
CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }} # directory for caching docker image and ccache
NAME: ${{matrix.distro}}${{matrix.version}}
CACHE: ${{github.workspace}}/.cache/${{matrix.distro}}${{matrix.version}} # directory for caching docker image and ccache
# Cache size over the entire repo is 10Gi:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CCACHE_SIZE: 550M
CCACHE_EVICTION_AGE: 7d
CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CMAKE_GENERATOR: 'Ninja'
NAME: ${{ matrix.distro }}${{ matrix.version }}
steps:
- name: "Checkout"
uses: actions/checkout@v7
- name: Checkout
uses: actions/checkout@v6
- name: "Restore compiler cache (ccache)"
- name: Restore compiler cache (ccache)
id: ccache_restore
uses: actions/cache/restore@v6
uses: actions/cache/restore@v5
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
with:
key: ccache-${{ matrix.distro }}${{ matrix.version }}-${{ env.BRANCH_NAME }}
path: ${{ env.CACHE }}
restore-keys: ccache-${{ matrix.distro }}${{ matrix.version }}-
path: ${{env.CACHE}}
key: ccache-${{matrix.distro}}${{matrix.version}}-${{env.BRANCH_NAME}}
restore-keys: ccache-${{matrix.distro}}${{matrix.version}}-
- name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image"
- name: Build ${{matrix.distro}} ${{matrix.version}} Docker image
shell: bash
run: source .ci/docker.sh --build
- name: "Build debug and test"
- name: Build debug and test
if: matrix.test != 'skip'
shell: bash
run: |
source .ci/docker.sh
RUN --server --debug --test --ccache "$CCACHE_SIZE" \
--cmake-generator "$CMAKE_GENERATOR"
--cmake-generator "$CMAKE_GENERATOR"
- name: "Build release package"
- name: Build release package
id: build
if: matrix.package != 'skip'
shell: bash
env:
SUFFIX: '-${{ matrix.distro }}${{ matrix.version }}'
package: '${{ matrix.package }}'
server_only: '${{ matrix.server_only }}'
SUFFIX: '-${{matrix.distro}}${{matrix.version}}'
package: '${{matrix.package}}'
server_only: '${{matrix.server_only}}'
run: |
source .ci/docker.sh
args=()
[[ $server_only == yes ]] && args+=(--no-client)
[[ $GITHUB_REF == "refs/heads/master" ]] && args+=(--evict-ccache "$CCACHE_EVICTION_AGE")
if [[ $server_only == yes ]]; then
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[@]}"
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
- name: "Delete remote compiler cache (ccache)"
- name: Delete remote compiler cache (ccache)
if: github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
continue-on-error: true
env:
CACHE_PRIMARY_KEY: ${{ steps.ccache_restore.outputs.cache-primary-key }}
GH_TOKEN: ${{ github.token }}
run: |
if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then
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)"
- name: Save updated compiler cache (ccache)
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@v6
uses: actions/cache/save@v5
with:
path: ${{env.CACHE}}
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
path: ${{ env.CACHE }}
- name: "Upload artifact"
- name: Upload artifact
id: upload_artifact
if: matrix.package != 'skip'
uses: actions/upload-artifact@v7
with:
path: ${{steps.build.outputs.path}}
archive: false
if-no-files-found: error
path: ${{ steps.build.outputs.path }}
- name: "Upload to release"
- name: Upload to release
id: upload_release
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
shell: bash
env:
asset_name: ${{ steps.build.outputs.fullname }}
asset_path: ${{ steps.build.outputs.path }}
GH_TOKEN: ${{ github.token }}
tag_name: ${{ needs.configure.outputs.tag }}
GH_TOKEN: ${{github.token}}
tag_name: ${{needs.configure.outputs.tag}}
asset_name: ${{steps.build.outputs.fullname}}
asset_path: ${{steps.build.outputs.path}}
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'
uses: actions/attest@v4
with:
subject-path: ${{steps.build.outputs.path}}
show-summary: false
subject-path: ${{ steps.build.outputs.path }}
- name: "Verify binary attestation"
- name: Verify binary attestation
if: steps.attestation.outcome == 'success'
shell: bash
env:
BUILD_PATH: ${{ steps.build.outputs.path }}
GH_TOKEN: ${{ github.token }}
run: gh attestation verify "$BUILD_PATH" --repo Cockatrice/Cockatrice
GH_TOKEN: ${{github.token}}
run: gh attestation verify "${{steps.build.outputs.path}}" --repo Cockatrice/Cockatrice
build-vcpkg:
strategy:
@ -264,234 +263,234 @@ jobs:
- os: macOS
target: 13
runner: macos-15-intel
ccache_eviction_age: 7d
cmake_generator: Ninja
make_package: 1
soc: Intel
xcode: "16.4"
type: Release
override_target: 13
make_package: 1
package_suffix: "-macOS13_Intel"
qt_version: 6.11.0
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Intel
type: Release
cmake_generator: Ninja
use_ccache: 1
xcode: "16.4"
ccache_eviction_age: 7d
- os: macOS
target: 14
runner: macos-14
ccache_eviction_age: 7d
cmake_generator: Ninja
soc: Apple
xcode: "15.4"
type: Release
make_package: 1
package_suffix: "-macOS14"
qt_version: 6.11.0
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Apple
type: Release
cmake_generator: Ninja
use_ccache: 1
xcode: "15.4"
ccache_eviction_age: 7d
- os: macOS
target: 15
runner: macos-15
ccache_eviction_age: 7d
cmake_generator: Ninja
soc: Apple
xcode: "16.4"
type: Release
make_package: 1
package_suffix: "-macOS15"
qt_version: 6.11.0
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Apple
type: Release
cmake_generator: Ninja
use_ccache: 1
xcode: "16.4"
ccache_eviction_age: 7d
- os: macOS
target: 15
runner: macos-15
ccache_eviction_age: 7d
cmake_generator: Ninja
qt_version: 6.11.0
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Apple
type: Debug
use_ccache: 1
xcode: "16.4"
type: Debug
qt_version: 6.11.0
qt_arch: clang_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
cmake_generator: Ninja
use_ccache: 1
ccache_eviction_age: 7d
- os: Windows
target: 10
runner: windows-2025
cmake_generator: "Visual Studio 18 2026"
cmake_generator_platform: x64
type: Release
make_package: 1
package_suffix: "-Win10"
qt_version: 6.11.0
qt_arch: win64_msvc2022_64
qt_modules: qtimageformats qtmultimedia qtwebsockets
type: Release
cmake_generator: "Visual Studio 17 2022"
cmake_generator_platform: x64
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
runs-on: ${{ matrix.runner }}
runs-on: ${{matrix.runner}}
timeout-minutes: 100
env:
CCACHE_DIR: ${{ github.workspace }}/.cache/
CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CCACHE_DIR: ${{github.workspace}}/.cache/
# Cache size over the entire repo is 10Gi:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CCACHE_SIZE: 550M
steps:
- name: "Checkout"
uses: actions/checkout@v7
- name: Checkout
uses: actions/checkout@v6
with:
submodules: recursive
- name: "[Windows] Add msbuild to PATH"
- name: Add msbuild to PATH
if: matrix.os == 'Windows'
id: add-msbuild
uses: microsoft/setup-msbuild@v3
with:
msbuild-architecture: x64
- name: "[macOS] Setup ccache"
if: matrix.os == 'macOS' && matrix.use_ccache == 1
- name: Setup ccache
if: matrix.use_ccache == 1 && matrix.os == 'macOS'
run: brew install ccache
- name: "[macOS] Restore compiler cache (ccache)"
if: matrix.os == 'macOS' && matrix.use_ccache == 1
- name: Restore compiler cache (ccache)
if: matrix.use_ccache == 1
id: ccache_restore
uses: actions/cache/restore@v6
uses: actions/cache/restore@v5
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
with:
key: ccache-${{ matrix.runner }}-${{ matrix.soc }}-${{ matrix.type }}-${{ env.BRANCH_NAME }}
path: ${{ env.CCACHE_DIR }}
restore-keys: ccache-${{ matrix.runner }}-${{ matrix.soc }}-${{ matrix.type }}-
path: ${{env.CCACHE_DIR}}
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
restore-keys: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-
- name: "Install aqtinstall"
- name: Install aqtinstall
run: pipx install 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"
env:
QT_VERSION: ${{ matrix.qt_version }}
- name: Resolve latest Qt patch version
id: resolve_qt_version
shell: bash
run: .ci/resolve_latest_aqt_qt_version.sh "$QT_VERSION"
run: .ci/resolve_latest_aqt_qt_version.sh "${{matrix.qt_version}}"
- name: "[macOS] Restore thin Qt ${{ steps.resolve_qt_version.outputs.version }} libraries"
- name: Restore thin Qt ${{ steps.resolve_qt_version.outputs.version }} libraries (${{ matrix.soc }} macOS)
if: matrix.os == 'macOS'
id: restore_qt
uses: actions/cache/restore@v6
uses: actions/cache/restore@v5
with:
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
path: ${{ github.workspace }}/Qt
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
# Using jurplel/install-qt-action to install Qt without using brew
# Qt build using vcpkg either just fails or takes too long to build
- name: "[macOS] Install fat Qt ${{ steps.resolve_qt_version.outputs.version }}"
# qt build using vcpkg either just fails or takes too long to build
- name: Install fat Qt ${{ steps.resolve_qt_version.outputs.version }} (${{ matrix.soc }} macOS)
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
uses: jurplel/install-qt-action@v4
with:
cache: false
dir: ${{ github.workspace }}
modules: ${{ matrix.qt_modules }}
version: ${{ steps.resolve_qt_version.outputs.version }}
arch: ${{matrix.qt_arch}}
modules: ${{matrix.qt_modules}}
cache: false
dir: ${{github.workspace}}
- name: "[macOS] Create thin Qt libraries"
- name: Thin Qt libraries (${{ matrix.soc }} macOS)
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
run: .ci/thin_macos_qtlib.sh
- name: "[macOS] Cache thin Qt libraries"
- name: Cache thin Qt libraries (${{ matrix.soc }} macOS)
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
uses: actions/cache/save@v6
uses: actions/cache/save@v5
with:
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
path: ${{ github.workspace }}/Qt
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
- name: "[Windows] Install Qt ${{ matrix.qt_version }}"
- name: Install Qt ${{matrix.qt_version}} (Windows)
if: matrix.os == 'Windows'
uses: jurplel/install-qt-action@v4
with:
# Qt 6.11.0 only works with aqtinstall directly from git until aqtinstall 3.4 is released
# 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
cache: true
modules: ${{ matrix.qt_modules }}
version: ${{ steps.resolve_qt_version.outputs.version }}
arch: ${{matrix.qt_arch}}
modules: ${{matrix.qt_modules}}
cache: true
- name: "[Windows] Install NSIS"
- name: Install NSIS
if: matrix.os == 'Windows'
shell: bash
run: choco install nsis
- name: "Setup vcpkg cache"
- name: Setup vcpkg cache
id: vcpkg-cache
uses: TAServers/vcpkg-cache@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Uses environment variables, see compile.sh for more details
- name: "Build Cockatrice"
# uses environment variables, see compile.sh for more details
- name: Build Cockatrice
id: build
shell: bash
env:
BUILDTYPE: '${{ matrix.type }}'
CCACHE_EVICTION_AGE: ${{ matrix.ccache_eviction_age }}
CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
CMAKE_GENERATOR_PLATFORM: ${{ matrix.cmake_generator_platform }}
DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer'
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
MAKE_PACKAGE: '${{ matrix.make_package }}'
PACKAGE_SUFFIX: '${{ matrix.package_suffix }}'
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
USE_CCACHE: ${{ matrix.use_ccache }}
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
BUILDTYPE: '${{matrix.type}}'
MAKE_PACKAGE: '${{matrix.make_package}}'
PACKAGE_SUFFIX: '${{matrix.package_suffix}}'
CMAKE_GENERATOR: ${{matrix.cmake_generator}}
CMAKE_GENERATOR_PLATFORM: ${{matrix.cmake_generator_platform}}
USE_CCACHE: ${{matrix.use_ccache}}
VCPKG_DISABLE_METRICS: 1
VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite'
# macOS-specific environment variables, will be ignored on Windows
MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }}
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
DEVELOPER_DIR: '/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer'
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
CCACHE_EVICTION_AGE: ${{ matrix.ccache_eviction_age }}
run: .ci/compile.sh --server --test --vcpkg
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
- name: "[macOS] Delete remote compiler cache (ccache)"
if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
- 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:
CACHE_PRIMARY_KEY: ${{ steps.ccache_restore.outputs.cache-primary-key }}
GH_TOKEN: ${{ github.token }}
run: |
if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then
if gh cache delete --repo ${{ github.repository }} ${{ steps.ccache_restore.outputs.cache-primary-key }}; then
echo "Cache deleted successfully"
fi
- name: "[macOS] Save updated compiler cache (ccache)"
if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master'
uses: actions/cache/save@v6
- name: Save updated compiler cache (ccache)
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
uses: actions/cache/save@v5
with:
path: ${{env.CCACHE_DIR}}
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
path: ${{ env.CCACHE_DIR }}
- name: "[macOS] Sign app bundle"
- name: Sign app bundle
if: matrix.os == 'macOS' && matrix.make_package && needs.configure.outputs.tag != null
id: sign_macos
env:
BUILD_PATH: ${{ steps.build.outputs.path }}
MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }}
MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }}
run: |
if [[ -n "$MACOS_CERTIFICATE_NAME" ]]
then
security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain
/usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose "$BUILD_PATH"
/usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose "${{steps.build.outputs.path}}"
fi
- name: "[macOS] Notarize app bundle"
if: matrix.os == 'macOS' && steps.sign_macos.outcome == 'success'
- name: Notarize app bundle
if: steps.sign_macos.outcome == 'success'
env:
BUILD_PATH: ${{ steps.build.outputs.path }}
MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
run: |
if [[ -n "$MACOS_NOTARIZATION_APPLE_ID" ]]
then
@ -503,7 +502,7 @@ jobs:
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
# notarization service
echo "Creating temp notarization archive"
ditto -c -k --keepParent "$BUILD_PATH" "notarization.zip"
ditto -c -k --keepParent "${{steps.build.outputs.path}}" "notarization.zip"
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
@ -515,52 +514,51 @@ jobs:
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple "$BUILD_PATH"
xcrun stapler staple "${{steps.build.outputs.path}}"
fi
- name: "Upload artifact"
- name: Upload artifact
if: matrix.make_package
id: upload_artifact
uses: actions/upload-artifact@v7
with:
path: ${{steps.build.outputs.path}}
archive: false
if-no-files-found: error
path: ${{ steps.build.outputs.path }}
- name: "[Windows] Upload PDBs (Program Databases)"
- name: Upload PDBs (Program Databases)
if: matrix.os == 'Windows' && github.ref_type != 'tag'
uses: actions/upload-artifact@v7
with:
if-no-files-found: error
name: ${{ steps.build.outputs.name }}-PDBs
name: ${{steps.build.outputs.name}}-PDBs
path: |
build/cockatrice/Release/*.pdb
build/oracle/Release/*.pdb
build/servatrice/Release/*.pdb
if-no-files-found: error
- name: "Upload to release"
- name: Upload to release
if: needs.configure.outputs.tag != null && matrix.make_package == '1'
id: upload_release
shell: bash
env:
asset_name: ${{ steps.build.outputs.fullname }}
asset_path: ${{ steps.build.outputs.path }}
GH_TOKEN: ${{ github.token }}
tag_name: ${{ needs.configure.outputs.tag }}
GH_TOKEN: ${{github.token}}
tag_name: ${{needs.configure.outputs.tag}}
asset_name: ${{steps.build.outputs.fullname}}
asset_path: ${{steps.build.outputs.path}}
run: gh release upload "$tag_name" "$asset_path#$asset_name"
- name: "Attest binary provenance"
- name: Attest binary provenance
if: steps.upload_release.outcome == 'success'
id: attestation
uses: actions/attest@v4
with:
subject-path: ${{steps.build.outputs.path}}
show-summary: false
subject-path: ${{ steps.build.outputs.path }}
- name: "Verify binary attestation"
- name: Verify binary attestation
if: steps.attestation.outcome == 'success'
shell: bash
env:
BUILD_PATH: ${{ steps.build.outputs.path }}
GH_TOKEN: ${{ github.token }}
run: gh attestation verify "$BUILD_PATH" --repo Cockatrice/Cockatrice
GH_TOKEN: ${{github.token}}
run: gh attestation verify "${{steps.build.outputs.path}}" --repo Cockatrice/Cockatrice

View file

@ -1,7 +1,7 @@
name: Code Style (C++)
on:
# Push trigger not needed for linting, we do not allow direct pushes to master
# push trigger not needed for linting, we do not allow direct pushes to master
pull_request:
paths:
- '*/**' # matches all files not in root
@ -21,20 +21,17 @@ jobs:
runs-on: ubuntu-slim
steps:
- name: "Checkout"
uses: actions/checkout@v7
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 20 # should be enough to find merge base
- name: "Install dependencies"
- name: Install dependencies
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
clang-format \
cmake-format \
shellcheck
sudo apt-get install -y --no-install-recommends clang-format cmake-format shellcheck
- name: "Check code formatting"
- name: Check code formatting
shell: bash
run: ./.ci/lint_cpp.sh

View file

@ -1,10 +1,9 @@
name: Build Docker Image
permissions:
contents: read
packages: write
on:
release:
types:
- released # publishing of stable releases
push:
branches:
- master
@ -14,9 +13,6 @@ on:
paths:
- '.github/workflows/docker-release.yml'
- 'Dockerfile'
release:
types:
- released # publishing of stable releases
# Cancel earlier, unfinished runs of this workflow on the same branch (unless on release)
concurrency:
@ -28,51 +24,54 @@ jobs:
name: amd64 & arm64
if: ${{ github.repository_owner == 'Cockatrice' }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: "Checkout"
uses: actions/checkout@v7
- name: Checkout
uses: actions/checkout@v6
- name: "Docker metadata"
- name: Docker metadata
id: metadata
uses: docker/metadata-action@v6
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index # needed for GHCR
with:
annotations: |
org.opencontainers.image.title=Servatrice
org.opencontainers.image.url=https://cockatrice.github.io/
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
images: |
ghcr.io/cockatrice/servatrice
labels: |
org.opencontainers.image.title=Servatrice
org.opencontainers.image.url=https://cockatrice.github.io/
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
annotations: |
org.opencontainers.image.title=Servatrice
org.opencontainers.image.url=https://cockatrice.github.io/
org.opencontainers.image.description=Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games
- name: "Set up QEMU"
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: "Set up Docker buildx"
- name: Set up Docker buildx
uses: docker/setup-buildx-action@v4
- name: "Login to GitHub Container Registry (GHCR)"
if: github.event_name == 'release' && github.event.release.prerelease == false
id: login
- name: Login to GitHub Container Registry
if: contains(github.event.release.tag_name, 'Release') && github.event.release.target_commitish == 'master'
uses: docker/login-action@v4
with:
password: ${{ github.token }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: "Build and push Docker image"
- name: Build and push Docker image
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.ref_type == 'tag' }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
annotations: ${{ steps.metadata.outputs.annotations }}
cache-from: type=gha,scope=servatrice
cache-to: type=gha,mode=max,scope=servatrice
context: .
labels: ${{ steps.metadata.outputs.labels }}
platforms: linux/amd64,linux/arm64
push: ${{ steps.login.outcome == 'success' }}
tags: ${{ steps.metadata.outputs.tags }}

View file

@ -1,18 +1,18 @@
name: Generate Docs
on:
release:
types:
- published # publishing of stable releases and pre-releases
pull_request:
paths:
- 'doc/doxygen/**'
- '.github/workflows/documentation-build.yml'
- 'Doxyfile'
release:
types:
- published # publishing of stable releases and pre-releases
workflow_dispatch:
env:
COCKATRICE_REF: ${{ github.ref_name }} # tag name if the commit is tagged, otherwise branch name
COCKATRICE_REF: ${{ github.ref_name }} # Tag name if the commit is tagged, otherwise branch name
jobs:
docs:
@ -20,22 +20,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: "Checkout code"
uses: actions/checkout@v7
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
- name: "Install Graphviz"
- name: Install Graphviz
run: |
sudo apt-get install -y graphviz
dot -V
- name: "Install Doxygen"
- name: Install Doxygen
uses: ssciwr/doxygen-install@v2
with:
version: "1.16.1"
- name: "Update Doxygen Configuration"
- name: Update Doxygen Configuration
run: |
git diff Doxyfile
doxygen -u Doxyfile
@ -48,16 +48,16 @@ jobs:
exit 1
fi
- name: "Generate Documentation"
- name: Generate Documentation
if: always()
run: doxygen Doxyfile
- name: "Deploy to cockatrice.github.io"
- name: Deploy to cockatrice.github.io
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
uses: peaceiris/actions-gh-pages@v4
with:
deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
destination_dir: docs # docs will be available at https://cockatrice.github.io/docs/
external_repository: Cockatrice/cockatrice.github.io
publish_branch: master
publish_dir: ./docs/html
destination_dir: docs # Docs will live under https://cockatrice.github.io/docs/

View file

@ -1,14 +1,14 @@
name: Update Translations
on:
workflow_dispatch:
schedule:
# runs in the middle of each month starting a quarter (UTC) = two weeks after new strings are built
- cron: '0 0 15 1,4,7,10 *'
pull_request:
paths:
- '.tx/**'
- '.github/workflows/translations-pull.yml'
schedule:
# Runs in the middle of each month starting a quarter (UTC) = two weeks after new strings are built
- cron: '0 0 15 1,4,7,10 *'
workflow_dispatch:
jobs:
translations:
@ -19,20 +19,18 @@ jobs:
runs-on: ubuntu-slim
steps:
- name: "Checkout repo"
uses: actions/checkout@v7
- name: Checkout repo
uses: actions/checkout@v6
- name: "Pull translated strings from Transifex"
# Do not run this step for PR's from forks, they don't have access to the secret
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false
- name: Pull translated strings from Transifex
uses: transifex/cli-action@v2
with:
# Used config file: https://github.com/Cockatrice/Cockatrice/blob/master/.tx/config
# Docs: https://github.com/transifex/cli#pulling-files-from-transifex
args: pull --force --all
# used config file: https://github.com/Cockatrice/Cockatrice/blob/master/.tx/config
# https://github.com/transifex/cli#pulling-files-from-transifex
token: ${{ secrets.TX_TOKEN }}
args: pull --force --all
- name: "Create pull request"
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v8
@ -40,32 +38,35 @@ jobs:
add-paths: |
cockatrice/translations/*.ts
oracle/translations/*.ts
author: github-actions <github-actions@github.com> # owner of the commit
commit-message: Update translation files
# author is the owner of the commit
author: github-actions <github-actions@github.com>
branch: ci-update_translations
delete-branch: true
title: 'Update translations'
body: |
Pulled all translated strings from [Transifex][1].
---
*This PR is automatically generated and updated by the workflow at `.github/workflows/translations-pull.yml`. Review [action runs][2].*<br>
*After merging, all new languages and translations are available in the next build.*
[1]: https://explore.transifex.com/cockatrice/cockatrice/
[2]: https://github.com/Cockatrice/Cockatrice/actions/workflows/translations-pull.yml?query=branch%3Amaster
branch: ci-update_translations
commit-message: Update translation files
delete-branch: true
draft: false
labels: |
CI
Translation
title: 'Update translations'
draft: false
- name: "PR Status"
- name: PR Status
if: github.event_name != 'pull_request'
shell: bash
env:
PR_NUMBER: ${{ steps.create_pr.outputs.pull-request-number }}
PR_URL: ${{ steps.create_pr.outputs.pull-request-url }}
STATUS: ${{ case(steps.create_pr.outputs.pull-request-operation == 'none', 'unchanged', steps.create_pr.outputs.pull-request-operation) }}
STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: |
echo "PR #$PR_NUMBER $STATUS!" >> "$GITHUB_STEP_SUMMARY"
echo "URL: $PR_URL" >> "$GITHUB_STEP_SUMMARY"
if [[ "$STATUS" == "none" ]]; then
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!" >> $GITHUB_STEP_SUMMARY
else
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!" >> $GITHUB_STEP_SUMMARY
fi
echo "URL: ${{ steps.create_pr.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY

View file

@ -1,14 +1,14 @@
name: Update Translation Source
on:
workflow_dispatch:
schedule:
# runs at the start of each quarter (UTC)
- cron: '0 0 1 1,4,7,10 *'
pull_request:
paths:
- '.ci/update_translation_source_strings.sh'
- '.github/workflows/translations-push.yml'
schedule:
# Runs at the start of each quarter (UTC)
- cron: '0 0 1 1,4,7,10 *'
workflow_dispatch:
jobs:
translations:
@ -19,33 +19,32 @@ jobs:
runs-on: ubuntu-slim
steps:
- name: "Checkout repo"
uses: actions/checkout@v7
- name: Checkout repo
uses: actions/checkout@v6
- name: "Install lupdate"
- name: Install lupdate
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends qttools5-dev-tools
- name: "Update Cockatrice translation source"
env:
FILE: cockatrice/cockatrice_en@source.ts
- name: Update Cockatrice translation source
id: cockatrice
shell: bash
run: >
DIRS="cockatrice/src $(find . -maxdepth 1 -type d -name 'libcockatrice_*')"
.ci/update_translation_source_strings.sh
run: |
FILE="cockatrice/cockatrice_en@source.ts"
export DIRS="cockatrice/src $(find . -maxdepth 1 -type d -name 'libcockatrice_*')"
FILE="$FILE" DIRS="$DIRS" .ci/update_translation_source_strings.sh
- name: "Update Oracle translation source"
- name: Update Oracle translation source
id: oracle
shell: bash
env:
DIRS: 'oracle/src'
FILE: 'oracle/oracle_en@source.ts'
DIRS: 'oracle/src'
run: .ci/update_translation_source_strings.sh
- name: "Render template"
- name: Render template
id: template
uses: chuhlomin/render-template/binary@v1
with:
@ -55,7 +54,7 @@ jobs:
oracle_output: ${{ steps.oracle.outputs.output }}
commit: ${{ github.sha }}
- name: "Create pull request"
- name: Create pull request
if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v8
@ -63,24 +62,27 @@ jobs:
add-paths: |
cockatrice/cockatrice_en@source.ts
oracle/oracle_en@source.ts
author: github-actions <github-actions@github.com> # owner of the commit
body: ${{ steps.template.outputs.result }}
branch: ci-update_translation_source
commit-message: Update translation source strings
# author is the owner of the commit
author: github-actions <github-actions@github.com>
branch: ci-update_translation_source
delete-branch: true
draft: false
title: 'Update source strings'
body: ${{ steps.template.outputs.result }}
labels: |
CI
Translation
title: 'Update source strings'
draft: false
- name: "PR Status"
- name: PR Status
if: github.event_name != 'pull_request'
shell: bash
env:
PR_NUMBER: ${{ steps.create_pr.outputs.pull-request-number }}
PR_URL: ${{ steps.create_pr.outputs.pull-request-url }}
STATUS: ${{ case(steps.create_pr.outputs.pull-request-operation == 'none', 'unchanged', steps.create_pr.outputs.pull-request-operation) }}
STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: |
echo "PR #$PR_NUMBER $STATUS!" >> "$GITHUB_STEP_SUMMARY"
echo "URL: $PR_URL" >> "$GITHUB_STEP_SUMMARY"
if [[ "$STATUS" == "none" ]]; then
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!" >> $GITHUB_STEP_SUMMARY
else
echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!" >> $GITHUB_STEP_SUMMARY
fi
echo "URL: ${{ steps.create_pr.outputs.pull-request-url }}" >> $GITHUB_STEP_SUMMARY

View file

@ -74,7 +74,7 @@ endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
project("Cockatrice" VERSION 3.1.0)
project("Cockatrice" VERSION 3.0.1)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)

View file

@ -117,22 +117,21 @@ ${If} $InstDir == ""
; we need to set a default based on the install mode
StrCpy $InstDir $0
${EndIf}
Call SetModeDestinationFromInstdir
; --- Detect portable install when using /R (must come BEFORE 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}
; Now that $PortableMode reflects reality, commit InstDir into the correct slot
Call SetModeDestinationFromInstdir
${If} $ReinstallMode = 1
${AndIf} $PortableMode = 0
Call AutoUninstallIfNeeded
${EndIf}

View file

@ -56,75 +56,68 @@ set(cockatrice_SOURCES
src/filters/filter_tree_model.cpp
src/filters/syntax_help.cpp
src/game/abstract_game.cpp
src/game/arrow_registry.cpp
src/game_graphics/board/abstract_card_drag_item.cpp
src/game_graphics/board/abstract_card_item.cpp
src/game_graphics/board/abstract_counter.cpp
src/game/board/arrow_data.cpp
src/game_graphics/board/arrow_item.cpp
src/game_graphics/board/arrow_target.cpp
src/game_graphics/board/card_drag_item.cpp
src/game_graphics/board/card_item.cpp
src/game/board/abstract_card_drag_item.cpp
src/game/board/abstract_card_item.cpp
src/game/board/abstract_counter.cpp
src/game/board/arrow_item.cpp
src/game/board/arrow_target.cpp
src/game/board/card_drag_item.cpp
src/game/board/card_item.cpp
src/game/board/card_list.cpp
src/game/board/card_state.cpp
src/game_graphics/board/counter_general.cpp
src/game/board/counter_state.cpp
src/game_graphics/board/translate_counter_name.cpp
src/game_graphics/deckview/deck_view.cpp
src/game_graphics/deckview/deck_view_container.cpp
src/game_graphics/deckview/tabbed_deck_view_container.cpp
src/game_graphics/dialogs/dlg_create_token.cpp
src/game_graphics/dialogs/dlg_move_top_cards_until.cpp
src/game_graphics/dialogs/dlg_roll_dice.cpp
src/game/board/counter_general.cpp
src/game/board/translate_counter_name.cpp
src/game/deckview/deck_view.cpp
src/game/deckview/deck_view_container.cpp
src/game/deckview/tabbed_deck_view_container.cpp
src/game/dialogs/dlg_create_token.cpp
src/game/dialogs/dlg_move_top_cards_until.cpp
src/game/dialogs/dlg_roll_dice.cpp
src/game/game.cpp
src/game/game_event_handler.cpp
src/game/game_meta_info.cpp
src/game_graphics/game_scene.cpp
src/game/game_scene.cpp
src/game/game_state.cpp
src/game_graphics/game_view.cpp
src/game_graphics/hand_counter.cpp
src/game_graphics/log/message_log_widget.cpp
src/game/game_view.cpp
src/game/hand_counter.cpp
src/game/log/message_log_widget.cpp
src/game/phase.cpp
src/game_graphics/phases_toolbar.cpp
src/game_graphics/player/menu/card_menu.cpp
src/game_graphics/player/menu/custom_zone_menu.cpp
src/game_graphics/player/menu/grave_menu.cpp
src/game_graphics/player/menu/hand_menu.cpp
src/game_graphics/player/menu/library_menu.cpp
src/game_graphics/player/menu/move_menu.cpp
src/game_graphics/player/menu/player_menu.cpp
src/game_graphics/player/menu/pt_menu.cpp
src/game_graphics/player/menu/rfg_menu.cpp
src/game_graphics/player/menu/say_menu.cpp
src/game_graphics/player/menu/sideboard_menu.cpp
src/game_graphics/player/menu/utility_menu.cpp
src/game_graphics/tally/subtype_tally.cpp
src/game_graphics/tally/tally.cpp
src/game/phases_toolbar.cpp
src/game/player/menu/card_menu.cpp
src/game/player/menu/custom_zone_menu.cpp
src/game/player/menu/grave_menu.cpp
src/game/player/menu/hand_menu.cpp
src/game/player/menu/library_menu.cpp
src/game/player/menu/move_menu.cpp
src/game/player/menu/player_menu.cpp
src/game/player/menu/pt_menu.cpp
src/game/player/menu/rfg_menu.cpp
src/game/player/menu/say_menu.cpp
src/game/player/menu/sideboard_menu.cpp
src/game/player/menu/utility_menu.cpp
src/game/player/player.cpp
src/game/player/player_actions.cpp
src/game_graphics/player/player_area.cpp
src/game_graphics/player/player_dialogs.cpp
src/game/player/player_area.cpp
src/game/player/player_event_handler.cpp
src/game_graphics/player/player_graphics_item.cpp
src/game/player/player_graphics_item.cpp
src/game/player/player_info.cpp
src/game_graphics/player/player_list_widget.cpp
src/game/player/player_logic.cpp
src/game/player/player_list_widget.cpp
src/game/player/player_manager.cpp
src/game_graphics/player/player_target.cpp
src/game/player/player_target.cpp
src/game/replay.cpp
src/game/zones/card_zone_logic.cpp
src/game/zones/hand_zone_logic.cpp
src/game/zones/pile_zone_logic.cpp
src/game/zones/stack_zone_logic.cpp
src/game/zones/table_zone_logic.cpp
src/game/zones/view_zone_logic.cpp
src/game_graphics/zones/card_zone.cpp
src/game_graphics/zones/hand_zone.cpp
src/game_graphics/zones/pile_zone.cpp
src/game_graphics/zones/select_zone.cpp
src/game_graphics/zones/stack_zone.cpp
src/game_graphics/zones/table_zone.cpp
src/game_graphics/zones/view_zone.cpp
src/game_graphics/zones/view_zone_widget.cpp
src/game/zones/card_zone.cpp
src/game/zones/hand_zone.cpp
src/game/zones/logic/card_zone_logic.cpp
src/game/zones/logic/hand_zone_logic.cpp
src/game/zones/logic/pile_zone_logic.cpp
src/game/zones/logic/stack_zone_logic.cpp
src/game/zones/logic/table_zone_logic.cpp
src/game/zones/logic/view_zone_logic.cpp
src/game/zones/pile_zone.cpp
src/game/zones/select_zone.cpp
src/game/zones/stack_zone.cpp
src/game/zones/table_zone.cpp
src/game/zones/view_zone.cpp
src/game/zones/view_zone_widget.cpp
src/game_graphics/board/abstract_graphics_item.cpp
src/interface/card_picture_loader/card_picture_loader.cpp
src/interface/card_picture_loader/card_picture_loader_local.cpp
@ -137,13 +130,7 @@ set(cockatrice_SOURCES
src/interface/layouts/overlap_layout.cpp
src/interface/widgets/utility/line_edit_completer.cpp
src/interface/pixel_map_generator.cpp
src/interface/theme_config.cpp
src/interface/theme_manager.cpp
src/interface/palette_editor/color_button.cpp
src/interface/palette_editor/palette_generator.cpp
src/interface/palette_editor/quick_setup_panel.cpp
src/interface/palette_editor/palette_grid_widget.cpp
src/interface/palette_editor/palette_editor_dialog.cpp
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
src/interface/widgets/cards/additional_info/mana_cost_widget.cpp
src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp
@ -185,7 +172,6 @@ set(cockatrice_SOURCES
src/interface/widgets/deck_analytics/analyzer_modules/mana_distribution/mana_distribution_single_display_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_total_widget.cpp
src/interface/widgets/deck_analytics/analyzer_modules/mana_curve/mana_curve_category_widget.cpp
src/interface/widgets/deck_editor/card_database_view.cpp
src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
src/interface/widgets/deck_editor/deck_editor_card_database_dock_widget.cpp
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
@ -238,23 +224,11 @@ set(cockatrice_SOURCES
src/interface/widgets/server/handle_public_servers.cpp
src/interface/widgets/server/remote/remote_decklist_tree_widget.cpp
src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp
src/interface/widgets/server/user/user_avatar_provider.cpp
src/interface/widgets/server/user/user_card_art_provider.cpp
src/interface/widgets/server/user/user_card_settings_dialog.cpp
src/interface/widgets/server/user/user_context_menu.cpp
src/interface/widgets/server/user/user_info_box.cpp
src/interface/widgets/server/user/user_info_connection.cpp
src/interface/widgets/server/user/user_list_manager.cpp
src/interface/widgets/server/user/user_list_painter.cpp
src/interface/widgets/server/user/user_list_widget.cpp
src/interface/widgets/settings_page/appearance_settings_page.cpp
src/interface/widgets/settings_page/deck_editor_settings_page.cpp
src/interface/widgets/settings_page/general_settings_page.cpp
src/interface/widgets/settings_page/messages_settings_page.cpp
src/interface/widgets/settings_page/shortcut_settings_page.cpp
src/interface/widgets/settings_page/sound_settings_page.cpp
src/interface/widgets/settings_page/storage_settings_page.cpp
src/interface/widgets/settings_page/user_interface_settings_page.cpp
src/interface/widgets/utility/custom_line_edit.cpp
src/interface/widgets/utility/get_text_with_max.cpp
src/interface/widgets/utility/sequence_edit.cpp
@ -333,7 +307,6 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/tab.cpp
src/interface/widgets/tabs/tab_account.cpp
src/interface/widgets/tabs/tab_admin.cpp
src/interface/widgets/tabs/tab_card_art_rules.cpp
src/interface/widgets/tabs/tab_deck_editor.cpp
src/interface/widgets/tabs/tab_deck_storage.cpp
src/interface/widgets/tabs/tab_game.cpp
@ -356,8 +329,6 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
src/interface/widgets/utility/compact_push_button.cpp
src/interface/widgets/utility/compact_push_button.h
src/interface/widgets/server/user/user_info_popup.cpp
src/interface/widgets/server/user/user_info_popup.h
)
add_subdirectory(sounds)

View file

@ -55,7 +55,6 @@
<file>resources/icons/view.svg</file>
<file>resources/icons/mana/B.svg</file>
<file>resources/icons/mana/C.svg</file>
<file>resources/icons/mana/G.svg</file>
<file>resources/icons/mana/R.svg</file>
<file>resources/icons/mana/U.svg</file>
@ -70,7 +69,6 @@
<file>resources/config/interface.svg</file>
<file>resources/config/messages.svg</file>
<file>resources/config/deckeditor.svg</file>
<file>resources/config/storage.svg</file>
<file>resources/config/shorcuts.svg</file>
<file>resources/config/sound.svg</file>
<file>resources/config/debug.ini</file>

File diff suppressed because it is too large Load diff

View file

@ -28,8 +28,6 @@
#dlg_tip_of_the_day = true
#dlg_update = true
#general_settings_page = true
#settings_cache = true
#servers_settings = true
#shortcuts_settings = true

View file

@ -1,799 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
width="62.636364"
height="62.090908"
id="svg2"
sodipodi:version="0.32"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
sodipodi:docname="storage.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.0"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"><defs
id="defs4"><linearGradient
id="linearGradient3169"><stop
style="stop-color:#0000ff;stop-opacity:1;"
offset="0"
id="stop3171" /><stop
style="stop-color:#000067;stop-opacity:1;"
offset="1"
id="stop3173" /></linearGradient><linearGradient
id="linearGradient4766"><stop
style="stop-color:#784421;stop-opacity:1;"
offset="0"
id="stop4768" /><stop
style="stop-color:#3d2210;stop-opacity:0;"
offset="1"
id="stop4770" /></linearGradient><linearGradient
id="linearGradient4758"><stop
style="stop-color:#a05a2c;stop-opacity:1;"
offset="0"
id="stop4760" /><stop
style="stop-color:#3d2210;stop-opacity:1;"
offset="1"
id="stop4762" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" /><inkscape:perspective
id="perspective2484"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 526.18109 : 1"
sodipodi:type="inkscape:persp3d" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4758"
id="linearGradient4764"
x1="466.09601"
y1="485.96021"
x2="715.14801"
y2="485.96021"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4766"
id="linearGradient4772"
x1="496.548"
y1="485.26816"
x2="683.31201"
y2="485.26816"
gradientUnits="userSpaceOnUse" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3169"
id="radialGradient3175"
cx="120.07376"
cy="56.138123"
fx="120.07376"
fy="56.138123"
r="82.790039"
gradientTransform="matrix(1,0,0,0.2116376,0,44.257186)"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6482"
id="linearGradient6488"
x1="32.18182"
y1="3.2835093"
x2="32.18182"
y2="13.02554"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0281354,0,0,1.0429299,85.21874,131.0326)" /><linearGradient
id="linearGradient6482"><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop6484" /><stop
style="stop-color:#00ff00;stop-opacity:0;"
offset="1"
id="stop6486" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6464"
id="linearGradient6470"
x1="32.090908"
y1="1.8181819"
x2="31.09091"
y2="62.909088"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,-0.1818182)" /><linearGradient
id="linearGradient6464"><stop
style="stop-color:#0061ff;stop-opacity:1;"
offset="0"
id="stop6466" /><stop
style="stop-color:#001c4c;stop-opacity:1;"
offset="1"
id="stop6468" /></linearGradient><linearGradient
y2="62.909088"
x2="31.09091"
y1="1.8181819"
x1="32.090908"
gradientTransform="translate(86.2151,131.5372)"
gradientUnits="userSpaceOnUse"
id="linearGradient4477"
xlink:href="#linearGradient6464"
inkscape:collect="always" /><linearGradient
inkscape:collect="always"
id="linearGradient2916"><stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop2918" /><stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop2920" /></linearGradient><linearGradient
inkscape:collect="always"
id="linearGradient2902"><stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop2905" /><stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop2907" /></linearGradient><linearGradient
id="linearGradient2064"><stop
id="stop2066"
offset="0"
style="stop-color:white;stop-opacity:1;" /><stop
style="stop-color:#555753;stop-opacity:0.60000002;"
offset="0.5"
id="stop2070" /><stop
id="stop2068"
offset="1"
style="stop-color:#555753;stop-opacity:0;" /></linearGradient><linearGradient
id="linearGradient9641"><stop
style="stop-color:white;stop-opacity:1"
offset="0"
id="stop9643" /><stop
style="stop-color:#888a85;stop-opacity:1"
offset="1"
id="stop9645" /></linearGradient><linearGradient
id="linearGradient9633"><stop
style="stop-color:#eeeeec;stop-opacity:1"
offset="0"
id="stop9635" /><stop
style="stop-color:#888a85;stop-opacity:1"
offset="1"
id="stop9639" /></linearGradient><linearGradient
id="linearGradient9613"><stop
style="stop-color:white;stop-opacity:1"
offset="0"
id="stop9615" /><stop
id="stop9619"
offset="0.5"
style="stop-color:white;stop-opacity:1;" /><stop
style="stop-color:#cccfca;stop-opacity:1"
offset="1"
id="stop9617" /></linearGradient><linearGradient
id="linearGradient8710"><stop
style="stop-color:black;stop-opacity:1;"
offset="0"
id="stop8712" /><stop
style="stop-color:white;stop-opacity:1;"
offset="1"
id="stop8714" /></linearGradient><linearGradient
id="linearGradient8631"><stop
id="stop8633"
offset="0"
style="stop-color:#eeeeec;stop-opacity:1" /><stop
style="stop-color:#eeeeec;stop-opacity:1;"
offset="0.2"
id="stop8637" /><stop
id="stop8635"
offset="1"
style="stop-color:#babdb6;stop-opacity:1" /></linearGradient><linearGradient
id="linearGradient8625"><stop
id="stop8627"
offset="0"
style="stop-color:white;stop-opacity:1" /><stop
id="stop8629"
offset="1"
style="stop-color:#babdb6;stop-opacity:1" /></linearGradient><linearGradient
id="linearGradient8613"><stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop8615" /><stop
style="stop-color:#2e3436;stop-opacity:1"
offset="1"
id="stop8617" /></linearGradient><linearGradient
id="linearGradient5740"><stop
style="stop-color:#d0d0cb;stop-opacity:1;"
offset="0"
id="stop5742" /><stop
style="stop-color:#babdb6;stop-opacity:1"
offset="1"
id="stop5744" /></linearGradient><linearGradient
id="linearGradient5690"><stop
style="stop-color:white;stop-opacity:1;"
offset="0"
id="stop5692" /><stop
style="stop-color:#888a85;stop-opacity:0.59848487"
offset="1"
id="stop5694" /></linearGradient><linearGradient
id="linearGradient2899"><stop
id="stop2901"
offset="0"
style="stop-color:#555753;stop-opacity:1" /><stop
id="stop2903"
offset="1"
style="stop-color:#2e3436;stop-opacity:1" /></linearGradient><linearGradient
id="linearGradient3468"><stop
style="stop-color:#fdfdfc;stop-opacity:1"
offset="0"
id="stop3470" /><stop
style="stop-color:white;stop-opacity:0.37121212"
offset="1"
id="stop3472" /></linearGradient><linearGradient
id="linearGradient2909"><stop
style="stop-color:white;stop-opacity:0;"
offset="0"
id="stop2911" /><stop
id="stop2917"
offset="0.5"
style="stop-color:white;stop-opacity:1;" /><stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop2913" /></linearGradient><linearGradient
id="linearGradient2839"><stop
style="stop-color:white;stop-opacity:0.25773194;"
offset="0"
id="stop2841" /><stop
id="stop2847"
offset="0.5472973"
style="stop-color:white;stop-opacity:1;" /><stop
style="stop-color:white;stop-opacity:0.24705882;"
offset="0.66243607"
id="stop2849" /><stop
id="stop2851"
offset="0.875"
style="stop-color:white;stop-opacity:0.83505154;" /><stop
style="stop-color:white;stop-opacity:0;"
offset="1"
id="stop2843" /></linearGradient><linearGradient
id="linearGradient2900"><stop
style="stop-color:black;stop-opacity:0;"
offset="0"
id="stop2902" /><stop
id="stop2908"
offset="0.5"
style="stop-color:black;stop-opacity:1;" /><stop
style="stop-color:black;stop-opacity:0;"
offset="1"
id="stop2904" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3468"
id="linearGradient3474"
x1="24.748737"
y1="35.354588"
x2="24.998737"
y2="14.997767"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.995556,0,-3.931113)" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2902"
id="radialGradient4700"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(4.095822,0,0,3.101282,-9.53921,-94.5433)"
cx="0"
cy="17"
fx="0"
fy="17"
r="2" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2902"
id="radialGradient4702"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(4.095822,0,0,3.101282,38.20996,-10.90025)"
cx="0"
cy="17"
fx="0"
fy="17"
r="2" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2900"
id="linearGradient4704"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.047911,0,0,2.067521,1.347566,6.673675)"
x1="9.8994951"
y1="20"
x2="9.8994951"
y2="13.979153" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2909"
id="linearGradient4711"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1.42294,10.5,-14.95703)"
x1="15.335379"
y1="33.06237"
x2="20.329321"
y2="36.37693" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2909"
id="linearGradient4713"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1.42294,-0.875,-15.04578)"
x1="15.335379"
y1="33.06237"
x2="20.329321"
y2="36.37693" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2909"
id="linearGradient4715"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.459833,0,-0.391165,1.370105,40.62503,-13.29892)"
x1="15.335379"
y1="33.06237"
x2="20.329321"
y2="36.37693" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5740"
id="radialGradient5748"
cx="25.251999"
cy="16.47991"
fx="25.251999"
fy="16.47991"
r="21.980215"
gradientTransform="matrix(1.032991,-0.596398,0.575121,0.99614,-12.23456,11.55448)"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2064"
id="linearGradient5790"
gradientUnits="userSpaceOnUse"
x1="18.048874"
y1="25.461344"
x2="22.211937"
y2="12.143078"
gradientTransform="matrix(0.940224,0,0,0.931632,1.331811,1.401537)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8631"
id="linearGradient5865"
x1="24"
y1="36.638382"
x2="25.818018"
y2="6.8314762"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2839"
id="linearGradient7658"
gradientUnits="userSpaceOnUse"
x1="27.057796"
y1="12.669416"
x2="32.042896"
y2="31.219666" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5690"
id="linearGradient8603"
x1="20.304037"
y1="24.035707"
x2="18.498415"
y2="40.647167"
gradientUnits="userSpaceOnUse" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient8613"
id="radialGradient8619"
cx="7.5177727"
cy="30.573555"
fx="7.5177727"
fy="30.573555"
r="0.53125"
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
gradientUnits="userSpaceOnUse" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient9613"
id="radialGradient8623"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.389748,0,0,1.348872,-2.91982,-10.63815)"
cx="7.5191436"
cy="30.304251"
fx="7.5191436"
fy="30.304251"
r="0.53125" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient9633"
id="radialGradient8664"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.569487,0,0,1.523325,-4.288627,-15.92107)"
cx="7.5336008"
cy="30.307562"
fx="7.5336008"
fy="30.307562"
r="0.53125" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient8613"
id="radialGradient8666"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
cx="7.5177727"
cy="30.573555"
fx="7.5177727"
fy="30.573555"
r="0.53125" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient8625"
id="radialGradient8676"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
cx="7.4792061"
cy="30.36071"
fx="7.4792061"
fy="30.36071"
r="0.53125" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient8613"
id="radialGradient8678"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
cx="7.5177727"
cy="30.573555"
fx="7.5177727"
fy="30.573555"
r="0.53125" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient9641"
id="radialGradient8680"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
cx="7.4893188"
cy="30.337601"
fx="7.4893188"
fy="30.337601"
r="0.53125" /><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient8613"
id="radialGradient8682"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.662477,0,0,1.61358,-4.989175,-18.65647)"
cx="7.5177727"
cy="30.573555"
fx="7.5177727"
fy="30.573555"
r="0.53125" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8710"
id="linearGradient8716"
x1="40.617188"
y1="30.554688"
x2="40.710938"
y2="30.359375"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8710"
id="linearGradient9605"
gradientUnits="userSpaceOnUse"
x1="40.617188"
y1="30.554688"
x2="40.710938"
y2="30.359375"
gradientTransform="matrix(0.602867,-0.797841,0.797841,0.602867,-41.12611,44.62773)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8710"
id="linearGradient9649"
gradientUnits="userSpaceOnUse"
x1="40.617188"
y1="30.554688"
x2="40.710938"
y2="30.359375"
gradientTransform="rotate(-30.000012,-5.5813167,76.089146)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient8710"
id="linearGradient9654"
gradientUnits="userSpaceOnUse"
x1="40.617188"
y1="30.554688"
x2="40.710938"
y2="30.359375"
gradientTransform="matrix(0.707107,0.527555,-0.707107,0.527555,29.0058,-24.09196)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2916"
id="linearGradient2973"
x1="12.5"
y1="43.1875"
x2="12.5"
y2="34.045513"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2899"
id="linearGradient5655"
gradientUnits="userSpaceOnUse"
x1="53.812813"
y1="43.573235"
x2="-2.8138931"
y2="35.500015"
gradientTransform="translate(0,50)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2902"
id="linearGradient2992"
x1="21.9375"
y1="39"
x2="21.9375"
y2="37.995617"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2902"
id="linearGradient2910"
x1="22.101398"
y1="27.658131"
x2="22.971142"
y2="20.903238"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,2)" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2916"
id="linearGradient2922"
x1="24.847851"
y1="28.908398"
x2="24.847851"
y2="25.757175"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,2)" /></defs><sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.8830488"
inkscape:cx="-3.9945275"
inkscape:cy="-14.363301"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1408"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050" /><metadata
id="metadata7"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-86.987816,-132.85536)"><rect
style="fill:url(#linearGradient4477);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-opacity:1"
id="rect6462"
width="61.636364"
height="61.090908"
x="87.487816"
y="133.35536"
ry="5.6363635" /><rect
style="fill:url(#linearGradient6488);fill-opacity:1;fill-rule:nonzero;stroke:none"
id="rect6472"
width="59.796619"
height="13.251164"
x="88.407707"
y="134.45705"
ry="4.7325583" /><g
inkscape:label="Livello 1"
id="layer1-3"
style="display:inline"
transform="matrix(1.1537183,0,0,1.1537183,91.003924,136.40297)"><g
id="g3519"
style="opacity:0.7"
transform="matrix(1.030831,0,0,1.151147,-0.73609,-12.57431)"
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><rect
transform="scale(-1)"
y="-48.024086"
x="-9.5392103"
height="12.405126"
width="8.1916437"
id="rect2884"
style="opacity:1;fill:url(#radialGradient4700);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /><rect
y="35.618961"
x="38.209965"
height="12.405126"
width="8.1916437"
id="rect2894"
style="opacity:1;fill:url(#radialGradient4702);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /><rect
y="35.618961"
x="9.5392103"
height="12.405126"
width="28.670753"
id="rect2898"
style="opacity:1;fill:url(#linearGradient4704);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /></g><g
id="g5672"
transform="translate(0,-48.99747)"><path
sodipodi:nodetypes="ccccccccccccc"
id="rect2010"
d="M 4.5182287,80.500013 H 43.481768 c 0.564099,0 1.018229,0.45413 1.018229,1.018229 v 2.963543 c 0,1.315584 -0.450231,3.018228 -2.455729,3.018228 L 40.5,87.5 v 1 h -33 v -1 l -1.8567713,1.3e-5 c -1.2712053,0 -2.1432282,-0.884627 -2.1432282,-2.255665 v -3.726106 c 0,-0.564099 0.4541297,-1.018229 1.0182282,-1.018229 z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient5655);fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><path
transform="translate(0,50)"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2973);stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
d="m 4.59375,31.59375 v 3.729743 c 0,0.599619 0.3756505,1.104854 0.8863276,1.104854 H 42.426407 c 0.512469,0 0.979843,-0.507235 0.979843,-1.016466 V 31.59375 Z"
id="path2076"
sodipodi:nodetypes="ccccccc" /><g
transform="translate(0,50)"
style="opacity:0.5"
id="g4706"><path
style="opacity:0.109524;fill:url(#linearGradient4711);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 26.144738,32.088747 c 0,0 -1.502602,5.533939 -3.226175,5.911253 0,0 6.231378,-0.125771 6.231378,-0.125771 1.387072,-0.317461 3.358758,-5.785482 3.358758,-5.785482 z"
id="path2907"
sodipodi:nodetypes="ccccc"
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" /><path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
sodipodi:nodetypes="ccccc"
id="path2892"
d="m 14.769738,32 c 0,0 -1.502602,5.533939 -3.226175,5.911253 0,0 6.231378,-0.125771 6.231378,-0.125771 C 19.162013,37.468021 21.133699,32 21.133699,32 Z"
style="opacity:0.109524;fill:url(#linearGradient4713);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
sodipodi:nodetypes="ccccc"
id="path2896"
d="m 34.886139,32 c 0,0 -2.212224,5.328458 -3.108503,5.691761 0,0 2.899969,-0.121101 2.899969,-0.121101 C 35.402697,37.264987 37.8125,32 37.8125,32 Z"
style="opacity:0.109524;fill:url(#linearGradient4715);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /></g></g><path
style="fill:url(#radialGradient5748);fill-opacity:1;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
d="m 11.693127,10.498788 h 24.572566 c 1.68417,0 2.396517,0.117479 3.040019,2.385005 l 5.074491,17.881119 c 0.501024,1.765471 -1.355848,2.735101 -3.040018,2.735101 H 6.6186312 c -1.868408,0 -3.4893833,-1.181417 -3.0400182,-2.735101 L 8.8290448,12.611497 c 0.5683008,-1.964905 1.1799122,-2.112709 2.8640822,-2.112709 z"
id="rect1879"
sodipodi:nodetypes="cczzcczzc"
inkscape:export-filename="/home/lapo/Desktop/uhm.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" /><path
sodipodi:type="inkscape:offset"
inkscape:radius="-0.5"
inkscape:original="M 11.6875 10.5 C 10.00333 10.5 9.4120513 10.660095 8.84375 12.625 L 3.59375 30.75 C 3.1443849 32.303684 4.7565918 33.500002 6.625 33.5 L 41.34375 33.5 C 43.02792 33.5 44.876024 32.515471 44.375 30.75 L 39.3125 12.875 C 38.668998 10.607474 37.965419 10.5 36.28125 10.5 L 11.6875 10.5 z "
style="display:inline;opacity:0.462406;fill:url(#linearGradient7658);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
id="path5806"
d="m 11.6875,11 c -0.826242,0 -1.28475,0.05742 -1.5625,0.242188 -0.2777497,0.184768 -0.5284825,0.580009 -0.8007812,1.521484 l -5.2500001,18.125 c -0.1708248,0.590628 0.021709,1.039316 0.4902344,1.4375 C 5.0329784,32.724356 5.7975106,33.000001 6.625,33 h 34.71875 c 0.744655,0 1.538941,-0.232575 2.03125,-0.609375 0.492309,-0.3768 0.719298,-0.799984 0.519531,-1.503906 l -5.0625,-17.875 C 38.52278,11.922001 38.224454,11.462814 37.910156,11.253906 37.595859,11.044998 37.112699,11 36.28125,11 Z" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8623);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8621"
transform="matrix(-2.628602,0,0,1.777765,27.79309,-23.77739)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><path
style="fill:none;fill-opacity:1;stroke:url(#linearGradient5790);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 16.110953,12.552805 c -0.573581,0 -1.02837,0.431821 -1.02837,0.989859 l -0.940223,3.230801 c -2.859962,1.276514 -4.6423552,3.099073 -4.6423552,5.123976 0,3.856957 6.4790242,6.987239 14.4853222,6.98724 8.006296,0 14.514705,-3.130284 14.514704,-6.98724 0,-2.039034 -1.835591,-3.875388 -4.730501,-5.153089 l -0.940224,-3.201688 c 0,-0.558038 -0.454788,-0.989859 -1.02837,-0.989859 z"
id="path2784"
sodipodi:nodetypes="cccssscccc" /><path
style="display:inline;fill:none;fill-opacity:1;stroke:url(#linearGradient3474);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1"
d="m 11.6875,11.500005 c -0.803124,0 -1.097168,0.07051 -1.21875,0.155556 -0.121582,0.08504 -0.357707,0.40212 -0.6875,1.306667 l -5.25,18.137786 c -0.1337204,0.366765 -0.054827,0.533865 0.3125,0.84 0.3673267,0.306136 1.066693,0.56 1.78125,0.560001 h 34.71875 c 0.639793,0 1.393345,-0.237954 1.78125,-0.52889 0.387905,-0.290935 0.488311,-0.382809 0.3125,-0.871111 L 38.375,13.242228 c -0.377206,-1.04766 -0.68208,-1.439297 -0.84375,-1.555556 -0.16167,-0.116259 -0.443711,-0.186667 -1.25,-0.186667 z"
id="path3394"
sodipodi:nodetypes="csccsccsccscc" /><g
id="g5657"
transform="translate(7,-1)"
style="opacity:0.302857"><rect
ry="0.74712253"
rx="0.75130093"
y="35.500008"
x="18.499996"
height="1.9999924"
width="14.000004"
id="rect5641"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
y="36"
x="19"
height="1"
width="1"
id="rect5645"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
y="36"
x="22"
height="1"
width="1"
id="rect5647"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
y="36"
x="24"
height="1"
width="1"
id="rect5649"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
y="36"
x="26"
height="1"
width="1"
id="rect5651"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /><rect
y="36"
x="29"
height="1"
width="2"
id="rect5653"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /></g><path
sodipodi:type="inkscape:offset"
inkscape:radius="-0.44194174"
inkscape:original="M 16.125 12.5625 C 15.55142 12.5625 15.09375 12.973212 15.09375 13.53125 L 14.15625 16.78125 C 11.296288 18.057765 9.5 19.881347 9.5 21.90625 C 9.5 25.763206 15.993702 28.874999 24 28.875 C 32.006296 28.874999 38.500001 25.763206 38.5 21.90625 C 38.5 19.867215 36.67616 18.027701 33.78125 16.75 L 32.84375 13.53125 C 32.843748 12.973212 32.386082 12.5625 31.8125 12.5625 L 16.125 12.5625 z "
style="display:inline;fill:url(#linearGradient5865);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path5857"
d="m 16.125,13.003906 c -0.362612,0 -0.589844,0.210942 -0.589844,0.527344 a 0.44198593,0.44198593 0 0 1 -0.01758,0.123047 l -0.9375,3.25 a 0.44198593,0.44198593 0 0 1 -0.24414,0.28125 c -1.389903,0.620369 -2.504368,1.368471 -3.25586,2.177734 -0.751491,0.809263 -1.1386718,1.661199 -1.1386717,2.542969 0,1.680455 1.4530107,3.311153 3.9980467,4.533203 2.545037,1.22205 6.114654,1.99414 10.060547,1.994141 3.945892,-1e-6 7.51551,-0.772091 10.060547,-1.994141 2.545037,-1.22205 3.998047,-2.852748 3.998047,-4.533203 0,-0.887751 -0.391823,-1.747213 -1.154297,-2.5625 -0.762474,-0.815287 -1.893636,-1.568394 -3.300781,-2.189453 a 0.44198593,0.44198593 0 0 1 -0.246094,-0.28125 l -0.9375,-3.21875 a 0.44198593,0.44198593 0 0 1 -0.01758,-0.123047 c -10e-7,-0.316404 -0.22723,-0.527344 -0.589844,-0.527344 z" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:0.0530303;fill-rule:nonzero;stroke:url(#linearGradient8603);stroke-width:2.52015;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8595"
transform="matrix(0.449978,0,0,0.349909,16.36363,12.21469)"
cx="16.970562"
cy="25.107418"
rx="7.7781744"
ry="4.2868347" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8619);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8611"
transform="matrix(1.411772,0,0,0.969697,-3.014767,0.848485)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8664);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.462594;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8660"
transform="matrix(-2.628602,0,0,1.777765,60.79309,-23.77739)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8666);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8662"
transform="matrix(1.411772,0,0,0.969697,29.98523,0.848485)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8676);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8668"
transform="matrix(-2.628602,0,0,1.777765,31.79309,-40.77739)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8678);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8670"
transform="matrix(1.411772,0,0,0.969697,0.985233,-16.15152)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8680);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8672"
transform="matrix(-2.628602,0,0,1.777765,56.3029,-40.77739)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><ellipse
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient8682);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="path8674"
transform="matrix(1.411772,0,0,0.969697,25.49504,-16.15152)"
cx="7.625"
cy="30.578125"
rx="0.53125"
ry="0.515625" /><path
style="opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient8716);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 40.328109,30.261401 0.874999,0.430332"
id="path8700" /><path
style="display:inline;opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9605);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 7.330186,30.695906 8.201031,30.257228"
id="path9603" /><path
style="display:inline;opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9649);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 11.263531,13.446473 0.972937,-0.06482"
id="path9647" /><path
style="display:inline;opacity:0.4;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9654);stroke-width:0.3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 36.124038,13.147874 0.314427,0.688634"
id="path9652" /><rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.12;fill:url(#linearGradient2992);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.681836;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
id="rect2984"
width="32.03125"
height="1"
x="8"
y="38" /><path
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.12;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2910);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
d="M 10.460155,15.082355 6.8513979,27.675762 C 8.2982685,28.375511 10.625,29.167061 10.429825,31.533131 H 37.299883 C 37.869398,29.640915 39.875,28.375 41.34614,28.25 L 37.498106,15.082355 32.350135,12.523347 H 14.318912 Z"
id="path1997"
sodipodi:nodetypes="ccccccccc" /><path
sodipodi:nodetypes="ccccc"
id="path2912"
d="m 7.9763979,27.050762 c 1.4468706,0.699749 3.1789321,1.433241 3.4256991,3.357369 H 36.857941 C 37.427456,28.515915 38.875,27.5 40.34614,27.375 Z"
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.834286;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2922);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 40 KiB

View file

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="169.33115mm"
height="169.59981mm"
viewBox="0 0 169.33115 169.59981"
version="1.1"
id="svg1"
inkscape:export-filename="C.svg"
inkscape:export-xdpi="96.000015"
inkscape:export-ydpi="96.000015"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
sodipodi:docname="colorless.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.71535494"
inkscape:cx="397.00572"
inkscape:cy="536.09751"
inkscape:window-width="1853"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:page
x="0"
y="0"
width="169.33115"
height="169.59981"
id="page2"
margin="0"
bleed="0" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-20.334425,-63.700102)">
<ellipse
style="fill:#cccccc;stroke:#000000;stroke-width:0.165333;stroke-linecap:round"
id="path1"
cx="-30.617094"
cy="179.22736"
transform="matrix(0.70654605,-0.70766707,0.70654608,0.70766704,0,0)"
rx="84.650612"
ry="84.65062" />
<rect
style="fill:none;stroke:#000000;stroke-width:14.5003;stroke-linecap:round;stroke-linejoin:bevel;stroke-dasharray:none"
id="rect1"
width="84.683701"
height="84.683769"
x="-221.60611"
y="-73.174698"
ry="0.084683768"
transform="matrix(-0.7073973,-0.70681615,0.7073973,-0.70681615,0,0)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -6,12 +6,12 @@
#include <QNetworkRequest>
#include <QRegularExpression>
#include <QUrlQuery>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
#include <version_string.h>
DeckStatsInterface::DeckStatsInterface(QObject *parent) : QObject(parent)
DeckStatsInterface::DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent)
: QObject(parent), cardDatabase(_cardDatabase)
{
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &DeckStatsInterface::queryFinished);
@ -70,8 +70,8 @@ void DeckStatsInterface::analyzeDeck(const DeckList &deck)
void DeckStatsInterface::copyDeckWithoutTokens(const DeckList &source, DeckList &destination)
{
auto copyIfNotAToken = [&destination](const auto node, const auto card) {
CardInfoPtr dbCard = CardDatabaseManager::query()->getCardInfo(card->getName());
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
if (dbCard && !dbCard->getIsToken()) {
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1);
addedCard->setNumber(card->getNumber());

View file

@ -1,12 +1,13 @@
/**
* @file deck_stats_interface.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECKSTATS_INTERFACE_H
#define DECKSTATS_INTERFACE_H
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/deck_list/deck_list.h>
class QByteArray;
@ -20,6 +21,8 @@ class DeckStatsInterface : public QObject
private:
QNetworkAccessManager *manager;
CardDatabase &cardDatabase;
/**
* Deckstats doesn't recognize token cards, and instead tries to find the
* closest non-token card instead. So we construct a new deck which has no
@ -32,7 +35,7 @@ private slots:
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
public:
explicit DeckStatsInterface(QObject *parent = nullptr);
explicit DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
void analyzeDeck(const DeckList &deck);
};

View file

@ -6,12 +6,12 @@
#include <QNetworkRequest>
#include <QRegularExpression>
#include <QUrlQuery>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
#include <version_string.h>
TappedOutInterface::TappedOutInterface(QObject *parent) : QObject(parent)
TappedOutInterface::TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent)
: QObject(parent), cardDatabase(_cardDatabase)
{
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &TappedOutInterface::queryFinished);
@ -97,8 +97,8 @@ void TappedOutInterface::analyzeDeck(const DeckList &deck)
void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard)
{
auto copyMainOrSide = [&mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = CardDatabaseManager::query()->getCardInfo(card->getName());
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
if (!dbCard || dbCard->getIsToken()) {
return;
}

View file

@ -1,14 +1,14 @@
/**
* @file tapped_out_interface.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef TAPPEDOUT_INTERFACE_H
#define TAPPEDOUT_INTERFACE_H
#include <QLoggingCategory>
#include <QObject>
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/deck_list/deck_list.h>
inline Q_LOGGING_CATEGORY(TappedOutInterfaceLog, "tapped_out_interface");
@ -29,13 +29,14 @@ class TappedOutInterface : public QObject
private:
QNetworkAccessManager *manager;
CardDatabase &cardDatabase;
void copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard);
private slots:
void queryFinished(QNetworkReply *reply);
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
public:
explicit TappedOutInterface(QObject *parent = nullptr);
explicit TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
void analyzeDeck(const DeckList &deck);
};

View file

@ -1,8 +1,8 @@
/**
* @file deck_link_to_api_transformer.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECK_LINK_TO_API_TRANSFORMER_H
#define DECK_LINK_TO_API_TRANSFORMER_H

View file

@ -1,8 +1,8 @@
/**
* @file interface_json_deck_parser.h
* @ingroup ApiInterfaces
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef INTERFACE_JSON_DECK_PARSER_H
#define INTERFACE_JSON_DECK_PARSER_H

View file

@ -1,8 +1,8 @@
/**
* @file spoiler_background_updater.h
* @ingroup Client
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
#define COCKATRICE_SPOILER_DOWNLOADER_H

View file

@ -1,8 +1,8 @@
/**
* @file client_update_checker.h
* @ingroup ClientUpdate
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CLIENT_UPDATE_CHECKER_H
#define CLIENT_UPDATE_CHECKER_H

View file

@ -1,8 +1,8 @@
/**
* @file release_channel.h
* @ingroup ClientUpdate
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef RELEASECHANNEL_H
#define RELEASECHANNEL_H

View file

@ -1,8 +1,8 @@
/**
* @file update_downloader.h
* @ingroup ClientUpdate
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_UPDATEDOWNLOADER_H
#define COCKATRICE_UPDATEDOWNLOADER_H

View file

@ -1,7 +1,5 @@
#include "cache_settings.h"
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
#include "../network/update/client/release_channel.h"
#include "card_counter_settings.h"
#include "version_string.h"
@ -280,16 +278,6 @@ SettingsCache::SettingsCache()
networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt();
cardPictureLoaderCacheMethod =
settings
->value("personal/cardPictureLoaderCacheMethod",
static_cast<int>(CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE))
.toInt();
localCardImageStorageNamingScheme =
settings
->value("personal/localCardImageStorageNamingScheme",
static_cast<int>(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_Set_Collector))
.toInt();
picDownload = settings->value("personal/picturedownload", true).toBool();
showStatusBar = settings->value("personal/showStatusBar", false).toBool();
@ -309,11 +297,9 @@ SettingsCache::SettingsCache()
cardViewExpandedRowsMax = settings->value("interface/cardViewExpandedRowsMax", 20).toInt();
closeEmptyCardView = settings->value("interface/closeEmptyCardView", true).toBool();
focusCardViewSearchBar = settings->value("interface/focusCardViewSearchBar", true).toBool();
keepGameChatFocus = settings->value("interface/keepGameChatFocus", false).toBool();
showDragSelectionCount = settings->value("interface/showlassoselectioncount", true).toBool();
showTotalSelectionCount = settings->value("interface/showpersistentselectioncount", true).toBool();
showSubtypeSelectionTally = settings->value("interface/showsubtypeselectiontally", true).toBool();
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
showGameSelectorFilterToolbar = settings->value("menu/showgameselectorfiltertoolbar", true).toBool();
@ -372,7 +358,6 @@ SettingsCache::SettingsCache()
openDeckInNewTab = settings->value("editor/openDeckInNewTab", false).toBool();
rewindBufferingMs = settings->value("replay/rewindBufferingMs", 200).toInt();
styleUserList = settings->value("appearance/styleUserList", true).toBool();
chatMention = settings->value("chat/mention", true).toBool();
chatMentionCompleter = settings->value("chat/mentioncompleter", true).toBool();
chatMentionForeground = settings->value("chat/mentionforeground", true).toBool();
@ -391,7 +376,6 @@ SettingsCache::SettingsCache()
ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool();
ignoreUnregisteredUserMessages = settings->value("chat/ignore_unregistered_messages", false).toBool();
ignoreNonBuddyUserMessages = settings->value("chat/ignore_nonbuddy_messages", false).toBool();
scaleCards = settings->value("cards/scaleCards", true).toBool();
verticalCardOverlapPercent = settings->value("cards/verticalCardOverlapPercent", 33).toInt();
@ -460,13 +444,6 @@ void SettingsCache::setFocusCardViewSearchBar(QT_STATE_CHANGED_T value)
settings->setValue("interface/focusCardViewSearchBar", focusCardViewSearchBar);
}
void SettingsCache::setKeepGameChatFocus(QT_STATE_CHANGED_T value)
{
keepGameChatFocus = value;
settings->setValue("interface/keepGameChatFocus", keepGameChatFocus);
emit keepGameChatFocusChanged(keepGameChatFocus);
}
void SettingsCache::setKnownMissingFeatures(const QString &_knownMissingFeatures)
{
knownMissingFeatures = _knownMissingFeatures;
@ -1047,13 +1024,6 @@ void SettingsCache::setRewindBufferingMs(int _rewindBufferingMs)
settings->setValue("replay/rewindBufferingMs", rewindBufferingMs);
}
void SettingsCache::setStyleUserList(QT_STATE_CHANGED_T _styleUserList)
{
styleUserList = static_cast<bool>(_styleUserList);
settings->setValue("appearance/styleUserList", styleUserList);
emit styleUserListChanged();
}
void SettingsCache::setChatMention(QT_STATE_CHANGED_T _chatMention)
{
chatMention = static_cast<bool>(_chatMention);
@ -1135,12 +1105,6 @@ void SettingsCache::setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignore
settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages);
}
void SettingsCache::setIgnoreNonBuddyUserMessages(QT_STATE_CHANGED_T _ignoreNonBuddyUserMessages)
{
ignoreNonBuddyUserMessages = static_cast<bool>(_ignoreNonBuddyUserMessages);
settings->setValue("chat/ignore_nonbuddy_messages", ignoreNonBuddyUserMessages);
}
void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
{
pixmapCacheSize = _pixmapCacheSize;
@ -1148,13 +1112,6 @@ void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
emit pixmapCacheSizeChanged(pixmapCacheSize);
}
void SettingsCache::setCardImageCacheMethod(const CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod)
{
cardPictureLoaderCacheMethod = static_cast<int>(_cardImageCachingMethod);
settings->setValue("personal/cardPictureLoaderCacheMethod", cardPictureLoaderCacheMethod);
emit cardPictureLoaderCacheMethodChanged(cardPictureLoaderCacheMethod);
}
void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
{
networkCacheSize = _networkCacheSize;
@ -1169,14 +1126,6 @@ void SettingsCache::setNetworkRedirectCacheTtl(const int _redirectCacheTtl)
emit redirectCacheTtlChanged(redirectCacheTtl);
}
void SettingsCache::setLocalCardImageStorageNamingScheme(
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme)
{
localCardImageStorageNamingScheme = static_cast<int>(_localCardImageStorageNamingScheme);
settings->setValue("personal/localCardImageStorageNamingScheme", localCardImageStorageNamingScheme);
emit localCardImageStorageNamingSchemeChanged(localCardImageStorageNamingScheme);
}
void SettingsCache::setClientID(const QString &_clientID)
{
clientID = _clientID;
@ -1396,12 +1345,6 @@ void SettingsCache::setShowTotalSelectionCount(QT_STATE_CHANGED_T _showTotalSele
settings->setValue("interface/showpersistentselectioncount", showTotalSelectionCount);
}
void SettingsCache::setShowSubtypeSelectionTally(QT_STATE_CHANGED_T _showSubtypeSelectionTally)
{
showSubtypeSelectionTally = static_cast<bool>(_showSubtypeSelectionTally);
settings->setValue("interface/showsubtypeselectiontally", showSubtypeSelectionTally);
}
void SettingsCache::loadPaths()
{
QString dataPath = getDataPath();

View file

@ -1,14 +1,12 @@
/**
* @file cache_settings.h
* @ingroup Settings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SETTINGSCACHE_H
#define SETTINGSCACHE_H
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
#include "shortcuts_settings.h"
#include <QDate>
@ -183,20 +181,15 @@ signals:
void soundThemeChanged();
void ignoreUnregisteredUsersChanged();
void ignoreUnregisteredUserMessagesChanged();
void ignoreNonBuddyUserMessagesChanged();
void pixmapCacheSizeChanged(int newSizeInMBs);
void networkCacheSizeChanged(int newSizeInMBs);
void redirectCacheTtlChanged(int newTtl);
void cardPictureLoaderCacheMethodChanged(int cardPictureLoaderCacheMethod);
void localCardImageStorageNamingSchemeChanged(int localCardImageStorageNamingScheme);
void masterVolumeChanged(int value);
void styleUserListChanged();
void chatMentionCompleterChanged();
void downloadSpoilerTimeIndexChanged();
void downloadSpoilerStatusChanged();
void useTearOffMenusChanged(bool state);
void roundCardCornersChanged(bool roundCardCorners);
void keepGameChatFocusChanged(bool value);
private:
QSettings *settings;
@ -285,7 +278,6 @@ private:
bool autoRotateSidewaysLayoutCards;
bool openDeckInNewTab;
int rewindBufferingMs;
bool styleUserList;
bool chatMention;
bool chatMentionCompleter;
QString chatMentionColor;
@ -298,7 +290,6 @@ private:
QString soundThemeName;
bool ignoreUnregisteredUsers;
bool ignoreUnregisteredUserMessages;
bool ignoreNonBuddyUserMessages;
QString picUrl;
QString picUrlFallback;
QString clientID;
@ -309,12 +300,9 @@ private:
int cardViewExpandedRowsMax;
bool closeEmptyCardView;
bool focusCardViewSearchBar;
bool keepGameChatFocus;
int pixmapCacheSize;
int networkCacheSize;
int redirectCacheTtl;
int cardPictureLoaderCacheMethod;
int localCardImageStorageNamingScheme;
bool scaleCards;
int verticalCardOverlapPercent;
bool showMessagePopups;
@ -355,7 +343,6 @@ private:
bool showStatusBar;
bool showDragSelectionCount;
bool showTotalSelectionCount;
bool showSubtypeSelectionTally;
public:
SettingsCache();
@ -479,10 +466,6 @@ public:
{
return showTotalSelectionCount;
}
[[nodiscard]] bool getShowSubtypeSelectionTally() const
{
return showSubtypeSelectionTally;
}
[[nodiscard]] bool getNotificationsEnabled() const
{
return notificationsEnabled;
@ -745,10 +728,6 @@ public:
{
return rewindBufferingMs;
}
[[nodiscard]] bool getStyleUserList() const
{
return styleUserList;
}
[[nodiscard]] bool getChatMention() const
{
return chatMention;
@ -803,18 +782,10 @@ public:
{
return ignoreUnregisteredUserMessages;
}
[[nodiscard]] bool getIgnoreNonBuddyUserMessages() const
{
return ignoreNonBuddyUserMessages;
}
[[nodiscard]] int getPixmapCacheSize() const
{
return pixmapCacheSize;
}
[[nodiscard]] CardPictureLoaderCacheMethod::CacheMethod getCardPictureLoaderCacheMethod() const
{
return static_cast<CardPictureLoaderCacheMethod::CacheMethod>(cardPictureLoaderCacheMethod);
}
[[nodiscard]] int getNetworkCacheSizeInMB() const
{
return networkCacheSize;
@ -823,10 +794,6 @@ public:
{
return redirectCacheTtl;
}
[[nodiscard]] CardPictureLoaderLocalSchemes::NamingScheme getLocalCardImageStorageNamingScheme() const
{
return static_cast<CardPictureLoaderLocalSchemes::NamingScheme>(localCardImageStorageNamingScheme);
}
[[nodiscard]] bool getScaleCards() const
{
return scaleCards;
@ -948,7 +915,6 @@ public:
void setCardViewExpandedRowsMax(int value);
void setCloseEmptyCardView(QT_STATE_CHANGED_T value);
void setFocusCardViewSearchBar(QT_STATE_CHANGED_T value);
void setKeepGameChatFocus(QT_STATE_CHANGED_T value);
QString getClientID() override
{
return clientID;
@ -981,10 +947,6 @@ public:
{
return focusCardViewSearchBar;
}
[[nodiscard]] bool getKeepGameChatFocus() const
{
return keepGameChatFocus;
}
[[nodiscard]] ShortcutsSettings &shortcuts() const
{
return *shortcutsSettings;
@ -1124,7 +1086,6 @@ public slots:
void setAutoRotateSidewaysLayoutCards(QT_STATE_CHANGED_T _autoRotateSidewaysLayoutCards);
void setOpenDeckInNewTab(QT_STATE_CHANGED_T _openDeckInNewTab);
void setRewindBufferingMs(int _rewindBufferingMs);
void setStyleUserList(QT_STATE_CHANGED_T _styleUserList);
void setChatMention(QT_STATE_CHANGED_T _chatMention);
void setChatMentionCompleter(QT_STATE_CHANGED_T _chatMentionCompleter);
void setChatMentionForeground(QT_STATE_CHANGED_T _chatMentionForeground);
@ -1136,13 +1097,9 @@ public slots:
void setSoundThemeName(const QString &_soundThemeName);
void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers);
void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages);
void setIgnoreNonBuddyUserMessages(QT_STATE_CHANGED_T _ignoreNonBuddyUserMessages);
void setPixmapCacheSize(const int _pixmapCacheSize);
void setCardImageCacheMethod(CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod);
void setNetworkCacheSizeInMB(const int _networkCacheSize);
void setNetworkRedirectCacheTtl(const int _redirectCacheTtl);
void setLocalCardImageStorageNamingScheme(
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme);
void setCardScaling(const QT_STATE_CHANGED_T _scaleCards);
void setStackCardOverlapPercent(const int _verticalCardOverlapPercent);
void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups);
@ -1181,6 +1138,5 @@ public slots:
void setRoundCardCorners(bool _roundCardCorners);
void setShowDragSelectionCount(QT_STATE_CHANGED_T _showDragSelectionCount);
void setShowTotalSelectionCount(QT_STATE_CHANGED_T _showTotalSelectionCount);
void setShowSubtypeSelectionTally(QT_STATE_CHANGED_T _showSubtypeSelectionTally);
};
#endif

View file

@ -1,8 +1,8 @@
/**
* @file card_counter_settings.h
* @ingroup GameSettings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARD_COUNTER_SETTINGS_H
#define CARD_COUNTER_SETTINGS_H

View file

@ -1,8 +1,8 @@
/**
* @file shortcut_treeview.h
* @ingroup CoreSettings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SHORTCUT_TREEVIEW_H
#define SHORTCUT_TREEVIEW_H

View file

@ -64,13 +64,8 @@ ShortcutsSettings::ShortcutsSettings(const QString &settingsPath, QObject *paren
}
}
/**
* @brief Migrates legacy shortcut key names to current naming scheme.
*
* PR 5079 changed Textbox/unfocusTextBox to Player/unfocusTextBox and
* tab_game/aFocusChat to Player/aFocusChat. This migration allows players
* to keep their already configured shortcuts.
*/
/// PR 5079 changes Textbox/unfocusTextBox to Player/unfocusTextBox and tab_game/aFocusChat to Player/aFocusChat.
/// A migration is necessary to let players keep their already configured shortcuts.
void ShortcutsSettings::migrateShortcuts()
{
if (QFile(settingsFilePath).exists()) {
@ -241,7 +236,9 @@ bool ShortcutsSettings::isValid(const QString &name, const QString &sequences) c
return findOverlaps(name, sequences).isEmpty();
}
/** @brief Checks if the shortcut is a shortcut that is active in all windows. */
/**
* Checks if the shortcut is a shortcut that is active in all windows
*/
static bool isAlwaysActiveShortcut(const QString &shortcutName)
{
return shortcutName.startsWith("MainWindow") || shortcutName.startsWith("Tabs");

View file

@ -1,8 +1,8 @@
/**
* @file shortcuts_settings.h
* @ingroup CoreSettings
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SHORTCUTSSETTINGS_H
#define SHORTCUTSSETTINGS_H
@ -223,10 +223,6 @@ private:
{"TabDeckEditor/aLoadDeck", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load Deck..."),
parseSequenceString("Ctrl+O"),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aLoadDeckFromWebsite",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load deck from online service..."),
parseSequenceString("Ctrl+Shift+O"),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aLoadDeckFromClipboard",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load Deck from Clipboard..."),
parseSequenceString("Ctrl+Shift+V"),
@ -287,10 +283,6 @@ private:
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load Deck from Clipboard..."),
parseSequenceString("Ctrl+Shift+V"),
ShortcutGroup::Game_Lobby)},
{"DeckViewContainer/loadFromWebsiteButton",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load from website..."),
parseSequenceString("Ctrl+Shift+O"),
ShortcutGroup::Game_Lobby)},
{"DeckViewContainer/unloadDeckButton", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Unload Deck"),
parseSequenceString("Ctrl+Alt+U"),
ShortcutGroup::Game_Lobby)},

View file

@ -1,8 +1,8 @@
/**
* @file sound_engine.h
* @ingroup Core
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SOUNDENGINE_H
#define SOUNDENGINE_H

View file

@ -1,8 +1,8 @@
/**
* @file deck_filter_string.h
* @ingroup DeckStorageWidgets
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECK_FILTER_STRING_H
#define DECK_FILTER_STRING_H

View file

@ -1,8 +1,8 @@
/**
* @file filter_builder.h
* @ingroup CardDatabaseModelFilters
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef FILTERBUILDER_H
#define FILTERBUILDER_H

View file

@ -1,8 +1,8 @@
/**
* @file filter_tree_model.h
* @ingroup CardDatabaseModelFilters
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef FILTERTREEMODEL_H
#define FILTERTREEMODEL_H

View file

@ -2,8 +2,8 @@
* @file syntax_help.h
* @ingroup CardDatabaseModelFilters
* @ingroup DeckStorageWidgets
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef SEARCH_SYNTAX_HELP_H
#define SEARCH_SYNTAX_HELP_H

View file

@ -1,9 +1,9 @@
#include "abstract_game.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "player/player_logic.h"
#include "player/player.h"
AbstractGame::AbstractGame(QObject *_parent) : QObject(_parent)
AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab)
{
gameMetaInfo = new GameMetaInfo(this);
gameEventHandler = new GameEventHandler(this);
@ -44,7 +44,7 @@ void AbstractGame::setActiveCard(CardItem *card)
CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const
{
PlayerLogic *player = playerManager->getPlayer(playerId);
Player *player = playerManager->getPlayer(playerId);
if (!player) {
return nullptr;
}

View file

@ -1,8 +1,8 @@
/**
* @file abstract_game.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_ABSTRACT_GAME_H
#define COCKATRICE_ABSTRACT_GAME_H
@ -16,19 +16,26 @@
#include <libcockatrice/protocol/pb/game_replay.pb.h>
class CardItem;
class TabGame;
class AbstractGame : public QObject
{
Q_OBJECT
public:
explicit AbstractGame(QObject *parent);
explicit AbstractGame(TabGame *tab);
TabGame *tab;
GameMetaInfo *gameMetaInfo;
GameState *gameState;
GameEventHandler *gameEventHandler;
PlayerManager *playerManager;
CardItem *activeCard;
TabGame *getTab() const
{
return tab;
}
GameMetaInfo *getGameMetaInfo()
{
return gameMetaInfo;

View file

@ -1,48 +0,0 @@
#include "arrow_registry.h"
#include "../game_graphics/board/arrow_item.h"
void ArrowRegistry::insert(QSharedPointer<ArrowData> data, ArrowItem *arrow)
{
const ArrowKey key{data->creatorId, data->id};
if (auto *existing = take(data->creatorId, data->id)) {
existing->delArrow();
}
dataStore.insert(key, data);
items.insert(key, arrow);
byPlayer[data->creatorId].insert(data->id);
}
ArrowItem *ArrowRegistry::take(int creatorId, int arrowId)
{
const ArrowKey key{creatorId, arrowId};
dataStore.remove(key);
auto &playerSet = byPlayer[creatorId];
playerSet.remove(arrowId);
if (playerSet.isEmpty()) {
byPlayer.remove(creatorId);
}
return items.take(key);
}
ArrowItem *ArrowRegistry::get(int creatorId, int arrowId) const
{
return items.value(ArrowKey{creatorId, arrowId}, nullptr);
}
bool ArrowRegistry::contains(int creatorId, int arrowId) const
{
return items.contains(ArrowKey{creatorId, arrowId});
}
QSet<int> ArrowRegistry::idsForPlayer(int playerId) const
{
return byPlayer.value(playerId);
}
QList<ArrowItem *> ArrowRegistry::all() const
{
return items.values();
}

View file

@ -1,43 +0,0 @@
#ifndef COCKATRICE_ARROW_REGISTRY_H
#define COCKATRICE_ARROW_REGISTRY_H
#include "board/arrow_data.h"
#include <QMap>
#include <QSet>
#include <QSharedPointer>
class ArrowItem;
struct ArrowKey
{
int creatorId;
int arrowId;
bool operator<(const ArrowKey &other) const
{
if (creatorId != other.creatorId) {
return creatorId < other.creatorId;
}
return arrowId < other.arrowId;
}
};
class ArrowRegistry
{
public:
void insert(QSharedPointer<ArrowData> data, ArrowItem *arrow);
ArrowItem *take(int creatorId, int arrowId);
[[nodiscard]] ArrowItem *get(int creatorId, int arrowId) const;
[[nodiscard]] bool contains(int creatorId, int arrowId) const;
[[nodiscard]] QSet<int> idsForPlayer(int playerId) const;
[[nodiscard]] QList<ArrowItem *> all() const;
private:
QMap<ArrowKey, QSharedPointer<ArrowData>> dataStore;
QMap<ArrowKey, ArrowItem *> items;
QMap<int, QSet<int>> byPlayer;
};
#endif

View file

@ -1,8 +1,8 @@
/**
* @file abstract_card_drag_item.h
* @ingroup GameGraphicsCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef ABSTRACTCARDDRAGITEM_H
#define ABSTRACTCARDDRAGITEM_H

View file

@ -13,7 +13,7 @@
#include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h>
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, PlayerLogic *_owner, int _id)
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, Player *_owner, int _id)
: ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0),
bgColor(Qt::transparent), isHovered(false), realZValue(0)
{

View file

@ -7,14 +7,14 @@
#ifndef ABSTRACTCARDITEM_H
#define ABSTRACTCARDITEM_H
#include "../../game_graphics/board/graphics_item_type.h"
#include "../card_dimensions.h"
#include "arrow_target.h"
#include "graphics_item_type.h"
#include <libcockatrice/card/printing/exact_card.h>
#include <libcockatrice/utility/card_ref.h>
class PlayerLogic;
class Player;
class AbstractCardItem : public ArrowTarget
{
@ -44,11 +44,6 @@ signals:
void deleteCardInfoPopup(QString cardName);
void sigPixmapUpdated();
void cardShiftClicked(QString cardName);
void rightClicked(AbstractCardItem *card, QPoint screenPos);
void playSelected(AbstractCardItem *card);
void playSelectedFaceDown(AbstractCardItem *card);
void hideSelected(AbstractCardItem *card);
void selectionChanged(AbstractCardItem *card, bool selected);
public:
enum
@ -61,7 +56,7 @@ public:
}
explicit AbstractCardItem(QGraphicsItem *parent = nullptr,
const CardRef &cardRef = {},
PlayerLogic *_owner = nullptr,
Player *_owner = nullptr,
int _id = -1);
~AbstractCardItem() override;
QRectF boundingRect() const override;

View file

@ -1,15 +1,14 @@
#include "abstract_counter.h"
#include "../../client/settings/cache_settings.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../../game_graphics/board/translate_counter_name.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "translate_counter_name.h"
#include <QAction>
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QKeyEvent>
#include <QMenu>
#include <QString>
@ -17,24 +16,24 @@
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
#include <libcockatrice/utility/expression.h>
AbstractCounter::AbstractCounter(CounterState *state,
PlayerLogic *_player,
AbstractCounter::AbstractCounter(Player *_player,
int _id,
const QString &_name,
bool _shownInCounterArea,
int _value,
bool _useNameForShortcut,
QGraphicsItem *parent)
: QGraphicsItem(parent), player(_player), id(state->getId()), name(state->getName()), value(state->getValue()),
color(state->getColor()), radius(state->getRadius()), useNameForShortcut(_useNameForShortcut),
shownInCounterArea(_shownInCounterArea)
: QGraphicsItem(parent), player(_player), id(_id), name(_name), value(_value),
useNameForShortcut(_useNameForShortcut), hovered(false), aDec(nullptr), aInc(nullptr), dialogSemaphore(false),
deleteAfterDialog(false), shownInCounterArea(_shownInCounterArea)
{
setAcceptHoverEvents(true);
connect(state, &CounterState::valueChanged, this, [this](int, int newValue) {
value = newValue;
update();
});
shortcutActive = false;
if (player->getPlayerInfo()->getLocalOrJudge()) {
menu = new TearOffMenu(TranslateCounterName::getDisplayName(state->getName()));
QString displayName = TranslateCounterName::getDisplayName(_name);
menu = new TearOffMenu(displayName);
aSet = new QAction(this);
connect(aSet, &QAction::triggered, this, &AbstractCounter::setCounter);
menu->addAction(aSet);
@ -42,18 +41,17 @@ AbstractCounter::AbstractCounter(CounterState *state,
for (int i = 10; i >= -10; --i) {
if (i == 0) {
menu->addSeparator();
continue;
} else {
QAction *aIncrement = new QAction(QString(i < 0 ? "%1" : "+%1").arg(i), this);
if (i == -1) {
aDec = aIncrement;
} else if (i == 1) {
aInc = aIncrement;
}
aIncrement->setData(i);
connect(aIncrement, &QAction::triggered, this, &AbstractCounter::incrementCounter);
menu->addAction(aIncrement);
}
auto *a = new QAction(QString(i < 0 ? "%1" : "+%1").arg(i), this);
if (i == -1) {
aDec = a;
}
if (i == 1) {
aInc = a;
}
a->setData(i);
connect(a, &QAction::triggered, this, &AbstractCounter::incrementCounter);
menu->addAction(a);
}
} else {
menu = nullptr;
@ -81,26 +79,31 @@ void AbstractCounter::delCounter()
void AbstractCounter::retranslateUi()
{
if (aSet) {
if (menu) {
aSet->setText(tr("&Set counter..."));
}
}
void AbstractCounter::setShortcutsActive()
{
if (!menu || !player->getPlayerInfo()->getLocal()) {
if (!menu) {
return;
}
ShortcutsSettings &sc = SettingsCache::instance().shortcuts();
shortcutActive = true;
if (!player->getPlayerInfo()->getLocal()) {
return;
}
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
if (name == "life") {
aSet->setShortcuts(sc.getShortcut("Player/aSet"));
aDec->setShortcuts(sc.getShortcut("Player/aDec"));
aInc->setShortcuts(sc.getShortcut("Player/aInc"));
shortcutActive = true;
aSet->setShortcuts(shortcuts.getShortcut("Player/aSet"));
aDec->setShortcuts(shortcuts.getShortcut("Player/aDec"));
aInc->setShortcuts(shortcuts.getShortcut("Player/aInc"));
} else if (useNameForShortcut) {
aSet->setShortcuts(sc.getShortcut("Player/aSetCounter_" + name));
aDec->setShortcuts(sc.getShortcut("Player/aDecCounter_" + name));
aInc->setShortcuts(sc.getShortcut("Player/aIncCounter_" + name));
shortcutActive = true;
aSet->setShortcuts(shortcuts.getShortcut("Player/aSetCounter_" + name));
aDec->setShortcuts(shortcuts.getShortcut("Player/aDecCounter_" + name));
aInc->setShortcuts(shortcuts.getShortcut("Player/aIncCounter_" + name));
}
}
@ -125,32 +128,45 @@ void AbstractCounter::refreshShortcuts()
}
}
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
void AbstractCounter::setValue(int _value)
{
if (!isUnderMouse() || !player->getPlayerInfo()->getLocalOrJudge()) {
event->ignore();
return;
}
if (event->button() == Qt::MiddleButton || QApplication::keyboardModifiers() & Qt::ShiftModifier) {
if (menu) {
menu->exec(event->screenPos());
}
} else {
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(event->button() == Qt::LeftButton ? 1 : -1);
player->getPlayerActions()->sendGameCommand(cmd);
}
event->accept();
value = _value;
update();
}
void AbstractCounter::hoverEnterEvent(QGraphicsSceneHoverEvent *)
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (isUnderMouse() && player->getPlayerInfo()->getLocalOrJudge()) {
if (event->button() == Qt::MiddleButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
if (menu) {
menu->exec(event->screenPos());
}
event->accept();
} else if (event->button() == Qt::LeftButton) {
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(1);
player->getPlayerActions()->sendGameCommand(cmd);
event->accept();
} else if (event->button() == Qt::RightButton) {
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(-1);
player->getPlayerActions()->sendGameCommand(cmd);
event->accept();
}
} else {
event->ignore();
}
}
void AbstractCounter::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
{
hovered = true;
update();
}
void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
{
hovered = false;
update();
@ -158,36 +174,35 @@ void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
void AbstractCounter::incrementCounter()
{
const int delta = static_cast<QAction *>(sender())->data().toInt();
Command_IncCounter cmd;
cmd.set_counter_id(id);
cmd.set_delta(static_cast<QAction *>(sender())->data().toInt());
cmd.set_delta(delta);
player->getPlayerActions()->sendGameCommand(cmd);
}
void AbstractCounter::setCounter()
{
QWidget *parent = nullptr;
if (auto *view = scene() ? scene()->views().value(0) : nullptr) {
parent = view->window();
}
dialogSemaphore = true;
AbstractCounterDialog dlg(name, QString::number(value), parent);
const int ok = dlg.exec();
dialogSemaphore = false;
AbstractCounterDialog dialog(name, QString::number(value), player->getGame()->getTab());
const int ok = dialog.exec();
if (deleteAfterDialog) {
deleteLater();
return;
}
dialogSemaphore = false;
if (!ok) {
return;
}
Expression exp(value);
int newValue = static_cast<int>(exp.parse(dialog.textValue()));
Command_SetCounter cmd;
cmd.set_counter_id(id);
cmd.set_value(static_cast<int>(exp.parse(dlg.textValue())));
cmd.set_value(newValue);
player->getPlayerActions()->sendGameCommand(cmd);
}

View file

@ -1,20 +1,19 @@
/**
* @file abstract_counter.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COUNTER_H
#define COUNTER_H
#include "../../game/board/counter_state.h"
#include "../../interface/widgets/menus/tearoff_menu.h"
#include "../player/menu/abstract_player_component.h"
#include <QGraphicsItem>
#include <QInputDialog>
class PlayerLogic;
class Player;
class QAction;
class QKeyEvent;
class QMenu;
@ -26,26 +25,22 @@ class AbstractCounter : public QObject, public QGraphicsItem, public AbstractPla
Q_INTERFACES(QGraphicsItem)
protected:
PlayerLogic *player;
Player *player;
int id;
QString name;
int value;
QColor color;
int radius;
bool hovered = false;
bool useNameForShortcut;
bool useNameForShortcut, hovered;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
private:
QAction *aSet = nullptr, *aDec = nullptr, *aInc = nullptr;
TearOffMenu *menu = nullptr;
bool dialogSemaphore = false;
bool deleteAfterDialog = false;
QAction *aSet, *aDec, *aInc;
TearOffMenu *menu;
bool dialogSemaphore, deleteAfterDialog;
bool shownInCounterArea;
bool shortcutActive = false;
bool shortcutActive;
private slots:
void refreshShortcuts();
@ -53,14 +48,17 @@ private slots:
void setCounter();
public:
AbstractCounter(CounterState *state,
PlayerLogic *player,
bool shownInCounterArea,
bool useNameForShortcut = false,
AbstractCounter(Player *_player,
int _id,
const QString &_name,
bool _shownInCounterArea,
int _value,
bool _useNameForShortcut = false,
QGraphicsItem *parent = nullptr);
~AbstractCounter() override;
void retranslateUi() override;
void setValue(int _value);
void setShortcutsActive() override;
void setShortcutsInactive() override;
void delCounter();
@ -69,6 +67,7 @@ public:
{
return menu;
}
int getId() const
{
return id;
@ -77,22 +76,14 @@ public:
{
return name;
}
QColor getColor() const
bool getShownInCounterArea() const
{
return color;
}
int getRadius() const
{
return radius;
return shownInCounterArea;
}
int getValue() const
{
return value;
}
bool getShownInCounterArea() const
{
return shownInCounterArea;
}
};
class AbstractCounterDialog : public QInputDialog

View file

@ -1,21 +0,0 @@
#include "arrow_data.h"
ArrowData ArrowData::fromProto(const ServerInfo_Arrow &arrow, int creatorId, bool isLocalCreator)
{
ArrowData data;
data.creatorId = creatorId;
data.isLocalCreator = isLocalCreator;
data.id = arrow.id();
data.startPlayerId = arrow.start_player_id();
data.startZone = QString::fromStdString(arrow.start_zone());
data.startCardId = arrow.start_card_id();
data.targetPlayerId = arrow.target_player_id();
data.color = convertColorToQColor(arrow.arrow_color());
if (arrow.has_target_zone()) {
data.targetZone = QString::fromStdString(arrow.target_zone());
data.targetCardId = arrow.target_card_id();
}
return data;
}

View file

@ -1,30 +0,0 @@
#ifndef COCKATRICE_ARROW_DATA_H
#define COCKATRICE_ARROW_DATA_H
#include <QColor>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_arrow.pb.h>
#include <libcockatrice/utility/color.h>
struct ArrowData
{
int creatorId = -1;
bool isLocalCreator = false;
int id = -1;
int startPlayerId = -1;
QString startZone = "";
int startCardId = -1;
int targetPlayerId = -1;
QString targetZone = "";
int targetCardId = -1;
QColor color = "";
static ArrowData fromProto(const ServerInfo_Arrow &arrow, int creatorId, bool isLocalCreator);
bool isPlayerTargeted() const
{
return targetZone.isEmpty();
}
};
#endif // COCKATRICE_ARROW_DATA_H

View file

@ -2,8 +2,8 @@
#include "arrow_item.h"
#include "../../client/settings/cache_settings.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "../player/player_target.h"
#include "../z_values.h"
#include "../zones/card_zone.h"
@ -21,24 +21,17 @@
#include <libcockatrice/utility/color.h>
#include <libcockatrice/utility/zone_names.h>
ArrowItem::ArrowItem(QSharedPointer<const ArrowData> _data, ArrowTarget *_startItem, ArrowTarget *_targetItem)
: data(std::move(_data)), startItem(_startItem), targetItem(_targetItem)
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false),
color(_color), fullColor(true)
{
setZValue(ZValues::ARROWS);
auto doUpdate = [this]() {
if (startItem && targetItem) {
updatePath();
}
};
if (startItem) {
connect(startItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
connect(startItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
startItem->addArrowFrom(this);
}
if (targetItem) {
connect(targetItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
connect(targetItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
targetItem->addArrowTo(this);
}
if (startItem && targetItem) {
@ -46,16 +39,24 @@ ArrowItem::ArrowItem(QSharedPointer<const ArrowData> _data, ArrowTarget *_startI
}
}
void ArrowItem::onTargetDestroyed()
ArrowItem::~ArrowItem()
{
emit requestDeletion(data->creatorId, data->id);
}
void ArrowItem::delArrow()
{
if (startItem) {
startItem->removeArrowFrom(this);
startItem = 0;
}
if (targetItem) {
targetItem->setBeingPointedAt(false);
targetItem->removeArrowTo(this);
targetItem = 0;
}
player->removeArrow(this);
deleteLater();
}
@ -126,7 +127,7 @@ void ArrowItem::updatePath(const QPointF &endPoint)
void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QColor paintColor(data->color);
QColor paintColor(color);
if (fullColor) {
paintColor.setAlpha(200);
} else {
@ -138,12 +139,13 @@ void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*opti
void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (!data->isLocalCreator) {
if (!player->getPlayerInfo()->getLocal()) {
event->ignore();
return;
}
for (auto *item : scene()->items(event->scenePos())) {
QList<QGraphicsItem *> colliding = scene()->items(event->scenePos());
for (QGraphicsItem *item : colliding) {
if (qgraphicsitem_cast<CardItem *>(item)) {
event->ignore();
return;
@ -152,72 +154,66 @@ void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
event->accept();
if (event->button() == Qt::RightButton) {
emit requestDeletion(data->creatorId, data->id);
Command_DeleteArrow cmd;
cmd.set_arrow_id(id);
player->getPlayerActions()->sendGameCommand(cmd);
}
}
// ArrowDragItem
ArrowDragItem::ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase)
: ArrowItem(QSharedPointer<ArrowData>::create(ArrowData{.creatorId = _owner->getPlayerInfo()->getId(),
.isLocalCreator = true,
.id = -1,
.color = _color}),
_startItem,
nullptr),
player(_owner), deleteInPhase(_deleteInPhase)
ArrowDragItem::ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase)
: ArrowItem(_owner, -1, _startItem, 0, _color), deleteInPhase(_deleteInPhase)
{
}
void ArrowDragItem::addChildArrow(ArrowDragItem *child)
void ArrowDragItem::addChildArrow(ArrowDragItem *childArrow)
{
childArrows.append(child);
childArrows.append(childArrow);
}
void ArrowDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
// This ensures that if a mouse move event happens after a call to delArrow(),
// the event will be discarded as it would create some stray pointers.
if (targetLocked || !startItem) {
return;
}
const QPointF endPos = event->scenePos();
QPointF endPos = event->scenePos();
ArrowTarget *cursorItem = nullptr;
QList<QGraphicsItem *> colliding = scene()->items(endPos);
ArrowTarget *cursorItem = 0;
qreal cursorItemZ = -1;
for (auto *item : scene()->items(endPos)) {
ArrowTarget *candidate = nullptr;
if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
candidate = card;
} else if (auto *pt = qgraphicsitem_cast<PlayerTarget *>(item)) {
candidate = pt;
}
if (candidate && candidate->zValue() > cursorItemZ) {
cursorItem = candidate;
cursorItemZ = candidate->zValue();
for (int i = colliding.size() - 1; i >= 0; i--) {
if (qgraphicsitem_cast<PlayerTarget *>(colliding.at(i)) || qgraphicsitem_cast<CardItem *>(colliding.at(i))) {
if (colliding.at(i)->zValue() > cursorItemZ) {
cursorItem = static_cast<ArrowTarget *>(colliding.at(i));
cursorItemZ = cursorItem->zValue();
}
}
}
if (cursorItem != targetItem) {
if (targetItem) {
disconnect(positionConnection);
targetItem->setBeingPointedAt(false);
}
targetItem = cursorItem;
fullColor = (cursorItem != nullptr);
if (cursorItem && cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
positionConnection =
connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
}
if ((cursorItem != targetItem) && targetItem) {
targetItem->setBeingPointedAt(false);
targetItem->removeArrowTo(this);
}
if (!cursorItem) {
fullColor = false;
targetItem = 0;
updatePath(endPos);
} else {
if (cursorItem != targetItem) {
fullColor = true;
if (cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
cursorItem->addArrowTo(this);
}
targetItem = cursorItem;
}
updatePath();
}
targetItem ? updatePath() : updatePath(endPos);
update();
for (auto *child : childArrows) {
for (ArrowDragItem *child : childArrows) {
child->mouseMoveEvent(event);
}
}
@ -228,33 +224,27 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
return;
}
if (targetItem && targetItem != startItem) {
CardItem *startCard = qgraphicsitem_cast<CardItem *>(startItem);
if (targetItem && (targetItem != startItem)) {
CardZoneLogic *startZone = static_cast<CardItem *>(startItem)->getZone();
// For now, we can safely assume that the start item is always a card.
// The target item can be a player as well.
if (!startCard) {
delArrow();
return;
}
CardZoneLogic *startZone = startCard->getZone();
CardItem *startCard = qgraphicsitem_cast<CardItem *>(startItem);
CardItem *targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
Command_CreateArrow cmd;
cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(data->color));
cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(color));
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_start_card_id(startCard->getId());
if (auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem)) {
if (targetCard) {
CardZoneLogic *targetZone = targetCard->getZone();
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
} else if (auto *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem)) {
} else { // failed to cast target to card, this means it's a player
PlayerTarget *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem);
cmd.set_target_player_id(targetPlayer->getOwner()->getPlayerInfo()->getId());
} else {
delArrow();
return;
}
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
@ -277,29 +267,21 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
player->getPlayerActions()->sendGameCommand(cmd);
}
delArrow();
for (auto *child : childArrows) {
for (ArrowDragItem *child : childArrows) {
child->mouseReleaseEvent(event);
}
}
// ArrowAttachItem
ArrowAttachItem::ArrowAttachItem(ArrowTarget *_startItem)
: ArrowItem(
QSharedPointer<ArrowData>::create(ArrowData{.creatorId = _startItem->getOwner()->getPlayerInfo()->getId(),
.isLocalCreator = true,
.id = -1,
.color = Qt::green}),
_startItem,
nullptr),
player(_startItem->getOwner())
: ArrowItem(_startItem->getOwner(), -1, _startItem, 0, Qt::green)
{
}
void ArrowAttachItem::addChildArrow(ArrowAttachItem *child)
void ArrowAttachItem::addChildArrow(ArrowAttachItem *childArrow)
{
childArrows.append(child);
childArrows.append(childArrow);
}
void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
@ -308,43 +290,67 @@ void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
return;
}
const QPointF endPos = event->scenePos();
QPointF endPos = event->scenePos();
ArrowTarget *cursorItem = nullptr;
QList<QGraphicsItem *> colliding = scene()->items(endPos);
ArrowTarget *cursorItem = 0;
qreal cursorItemZ = -1;
for (auto *item : scene()->items(endPos)) {
if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
if (card->zValue() > cursorItemZ) {
cursorItem = card;
cursorItemZ = card->zValue();
for (int i = colliding.size() - 1; i >= 0; i--) {
if (qgraphicsitem_cast<CardItem *>(colliding.at(i))) {
if (colliding.at(i)->zValue() > cursorItemZ) {
cursorItem = static_cast<ArrowTarget *>(colliding.at(i));
cursorItemZ = cursorItem->zValue();
}
}
}
if (cursorItem != targetItem) {
if (targetItem) {
disconnect(positionConnection);
targetItem->setBeingPointedAt(false);
}
targetItem = cursorItem;
fullColor = (cursorItem != nullptr);
if (cursorItem && cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
positionConnection =
connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
}
if ((cursorItem != targetItem) && targetItem) {
targetItem->setBeingPointedAt(false);
}
if (!cursorItem) {
fullColor = false;
targetItem = 0;
updatePath(endPos);
} else {
fullColor = true;
if (cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
}
targetItem = cursorItem;
updatePath();
}
targetItem ? updatePath() : updatePath(endPos);
update();
for (auto *child : childArrows) {
for (ArrowAttachItem *child : childArrows) {
child->mouseMoveEvent(event);
}
}
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
{
// do nothing if target is already attached to another card or is not in play
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
return;
}
CardZoneLogic *startZone = startCard->getZone();
CardZoneLogic *targetZone = targetCard->getZone();
// move card onto table first if attaching from some other zone
if (startZone->getName() != ZoneNames::TABLE) {
player->getPlayerActions()->playCardToTable(startCard, false);
}
Command_AttachCard cmd;
cmd.set_start_zone(ZoneNames::TABLE);
cmd.set_card_id(startCard->getId());
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
player->getPlayerActions()->sendGameCommand(cmd);
}
void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!startItem) {
@ -353,40 +359,21 @@ void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
// Attaching could move startItem under the current cursor position, causing all children to retarget to it right
// before they are processed. Prevent that.
for (auto *child : childArrows) {
for (ArrowAttachItem *child : childArrows) {
child->setTargetLocked(true);
}
if (targetItem && targetItem != startItem) {
auto *startCard = qgraphicsitem_cast<CardItem *>(startItem);
auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
if (targetItem && (targetItem != startItem)) {
auto startCard = qgraphicsitem_cast<CardItem *>(startItem);
auto targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
if (startCard && targetCard) {
attachCards(startCard, targetCard);
}
}
delArrow();
for (auto *child : childArrows) {
for (ArrowAttachItem *child : childArrows) {
child->mouseReleaseEvent(event);
}
}
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
{
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
return;
}
// move card onto table first if attaching from some other zone
if (startCard->getZone()->getName() != ZoneNames::TABLE) {
player->getPlayerActions()->playCardToTable(startCard, false);
}
Command_AttachCard cmd;
cmd.set_start_zone(ZoneNames::TABLE);
cmd.set_card_id(startCard->getId());
cmd.set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetCard->getZone()->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
player->getPlayerActions()->sendGameCommand(cmd);
}

View file

@ -1,44 +1,40 @@
/**
* @file arrow_item.h
* @ingroup GameGraphics
* @brief TODO: Document this.
*/
#ifndef ARROWITEM_H
#define ARROWITEM_H
#include "../../game/board/arrow_data.h"
#include "arrow_target.h"
#include <QGraphicsItem>
#include <QPointer>
#include <QSharedPointer>
class CardItem;
class QGraphicsSceneMouseEvent;
class PlayerLogic;
class QMenu;
class Player;
class ArrowTarget;
class ArrowItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
signals:
void requestDeletion(int creatorId, int id);
private:
QPainterPath path;
QMenu *menu;
protected:
QSharedPointer<const ArrowData> data;
QPointer<ArrowTarget> startItem;
QPointer<ArrowTarget> targetItem;
bool targetLocked = false;
bool fullColor = true;
Player *player;
int id;
ArrowTarget *startItem, *targetItem;
bool targetLocked;
QColor color;
bool fullColor;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
public:
ArrowItem(QSharedPointer<const ArrowData> _data, ArrowTarget *_startItem, ArrowTarget *_targetItem);
void onTargetDestroyed();
void delArrow();
void updatePath();
void updatePath(const QPointF &endPoint);
ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &color);
~ArrowItem() override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
[[nodiscard]] QRectF boundingRect() const override
{
@ -48,13 +44,24 @@ public:
{
return path;
}
void updatePath();
void updatePath(const QPointF &endPoint);
[[nodiscard]] int getId() const
{
return data->id;
return id;
}
[[nodiscard]] int getCreatorId() const
[[nodiscard]] Player *getPlayer() const
{
return data->creatorId;
return player;
}
void setStartItem(ArrowTarget *_item)
{
startItem = _item;
}
void setTargetItem(ArrowTarget *_item)
{
targetItem = _item;
}
[[nodiscard]] ArrowTarget *getStartItem() const
{
@ -68,20 +75,19 @@ public:
{
targetLocked = _targetLocked;
}
void delArrow();
};
class ArrowDragItem : public ArrowItem
{
Q_OBJECT
private:
PlayerLogic *player;
int deleteInPhase;
QList<ArrowDragItem *> childArrows;
QMetaObject::Connection positionConnection;
public:
ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase);
void addChildArrow(ArrowDragItem *child);
ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase);
void addChildArrow(ArrowDragItem *childArrow);
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
@ -92,18 +98,17 @@ class ArrowAttachItem : public ArrowItem
{
Q_OBJECT
private:
PlayerLogic *player;
QList<ArrowAttachItem *> childArrows;
QMetaObject::Connection positionConnection;
void attachCards(CardItem *startCard, const CardItem *targetCard);
public:
explicit ArrowAttachItem(ArrowTarget *_startItem);
void addChildArrow(ArrowAttachItem *child);
void addChildArrow(ArrowAttachItem *childArrow);
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
};
#endif
#endif // ARROWITEM_H

View file

@ -0,0 +1,43 @@
#include "arrow_target.h"
#include "../player/player.h"
#include "arrow_item.h"
ArrowTarget::ArrowTarget(Player *_owner, QGraphicsItem *parent)
: AbstractGraphicsItem(parent), owner(_owner), beingPointedAt(false)
{
setFlag(ItemSendsScenePositionChanges);
}
ArrowTarget::~ArrowTarget()
{
for (int i = 0; i < arrowsFrom.size(); ++i) {
arrowsFrom[i]->setStartItem(0);
arrowsFrom[i]->delArrow();
}
for (int i = 0; i < arrowsTo.size(); ++i) {
arrowsTo[i]->setTargetItem(0);
arrowsTo[i]->delArrow();
}
}
void ArrowTarget::setBeingPointedAt(bool _beingPointedAt)
{
beingPointedAt = _beingPointedAt;
update();
}
QVariant ArrowTarget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemScenePositionHasChanged && scene()) {
for (auto *arrow : arrowsFrom) {
arrow->updatePath();
}
for (auto *arrow : arrowsTo) {
arrow->updatePath();
}
}
return QGraphicsItem::itemChange(change, value);
}

View file

@ -0,0 +1,70 @@
/**
* @file arrow_target.h
* @ingroup GameGraphics
* @brief TODO: Document this.
*/
#ifndef ARROWTARGET_H
#define ARROWTARGET_H
#include "../../game_graphics/board/abstract_graphics_item.h"
#include <QList>
class Player;
class ArrowItem;
class ArrowTarget : public AbstractGraphicsItem
{
Q_OBJECT
protected:
Player *owner;
private:
bool beingPointedAt;
QList<ArrowItem *> arrowsFrom, arrowsTo;
public:
explicit ArrowTarget(Player *_owner, QGraphicsItem *parent = nullptr);
~ArrowTarget() override;
[[nodiscard]] Player *getOwner() const
{
return owner;
}
void setBeingPointedAt(bool _beingPointedAt);
[[nodiscard]] bool getBeingPointedAt() const
{
return beingPointedAt;
}
[[nodiscard]] const QList<ArrowItem *> &getArrowsFrom() const
{
return arrowsFrom;
}
void addArrowFrom(ArrowItem *arrow)
{
arrowsFrom.append(arrow);
}
void removeArrowFrom(ArrowItem *arrow)
{
arrowsFrom.removeOne(arrow);
}
[[nodiscard]] const QList<ArrowItem *> &getArrowsTo() const
{
return arrowsTo;
}
void addArrowTo(ArrowItem *arrow)
{
arrowsTo.append(arrow);
}
void removeArrowTo(ArrowItem *arrow)
{
arrowsTo.removeOne(arrow);
}
protected:
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
};
#endif

View file

@ -1,8 +1,8 @@
/**
* @file card_drag_item.h
* @ingroup GameGraphicsCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARDDRAGITEM_H
#define CARDDRAGITEM_H

View file

@ -1,12 +1,12 @@
#include "card_item.h"
#include "../../client/settings/cache_settings.h"
#include "../../game/phase.h"
#include "../../game/player/player_actions.h"
#include "../../game/player/player_logic.h"
#include "../../game/zones/view_zone_logic.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../game_scene.h"
#include "../phase.h"
#include "../player/player.h"
#include "../player/player_actions.h"
#include "../zones/logic/view_zone_logic.h"
#include "../zones/table_zone.h"
#include "../zones/view_zone.h"
#include "arrow_item.h"
@ -20,17 +20,14 @@
#include <libcockatrice/card/card_info.h>
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
CardItem::CardItem(PlayerLogic *_owner,
QGraphicsItem *parent,
const CardRef &cardRef,
int _cardid,
CardZoneLogic *_zone)
: AbstractCardItem(parent, cardRef, _owner, _cardid), state(new CardState(this, _zone)), dragItem(nullptr)
CardItem::CardItem(Player *_owner, QGraphicsItem *parent, const CardRef &cardRef, int _cardid, CardZoneLogic *_zone)
: AbstractCardItem(parent, cardRef, _owner, _cardid), zone(_zone), attacking(false), destroyOnZoneChange(false),
doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
{
owner->addCard(this);
connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) {
if (state->getCounters().contains(counterId)) {
if (counters.contains(counterId)) {
update();
}
});
@ -40,7 +37,7 @@ void CardItem::prepareDelete()
{
if (owner != nullptr) {
if (owner->getGame()->getActiveCard() == this) {
emit owner->requestCardMenuUpdate(nullptr);
owner->getPlayerMenu()->updateCardMenu(nullptr);
owner->getGame()->setActiveCard(nullptr);
}
owner = nullptr;
@ -51,9 +48,9 @@ void CardItem::prepareDelete()
attachedCards.first()->setAttachedTo(nullptr);
}
if (state->getAttachedTo() != nullptr) {
state->getAttachedTo()->removeAttachedCard(this);
state->setAttachedTo(nullptr);
if (attachedTo != nullptr) {
attachedTo->removeAttachedCard(this);
attachedTo = nullptr;
}
}
@ -68,7 +65,7 @@ void CardItem::deleteLater()
void CardItem::setZone(CardZoneLogic *_zone)
{
state->setZone(_zone);
zone = _zone;
}
void CardItem::retranslateUi()
@ -83,23 +80,23 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
AbstractCardItem::paint(painter, option, widget);
int i = 0;
QMapIterator<int, int> counterIterator(state->getCounters());
QMapIterator<int, int> counterIterator(counters);
while (counterIterator.hasNext()) {
counterIterator.next();
QColor _color = cardCounterSettings.color(counterIterator.key());
paintNumberEllipse(counterIterator.value(), 14, _color, i, state->getCounters().size(), painter);
paintNumberEllipse(counterIterator.value(), 14, _color, i, counters.size(), painter);
++i;
}
QSizeF translatedSize = getTranslatedSize(painter);
qreal scaleFactor = translatedSize.width() / boundingRect().width();
if (!state->getPT().isEmpty()) {
if (!pt.isEmpty()) {
painter->save();
transformPainter(painter, translatedSize, tapAngle);
if (!getFaceDown() && state->getPT() == exactCard.getInfo().getPowTough()) {
if (!getFaceDown() && pt == exactCard.getInfo().getPowTough()) {
painter->setPen(Qt::white);
} else {
painter->setPen(QColor(255, 150, 0)); // dark orange
@ -110,11 +107,11 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 10 * scaleFactor,
translatedSize.height() - 8 * scaleFactor),
Qt::AlignRight | Qt::AlignBottom, state->getPT());
Qt::AlignRight | Qt::AlignBottom, pt);
painter->restore();
}
if (!state->getAnnotation().isEmpty()) {
if (!annotation.isEmpty()) {
painter->save();
transformPainter(painter, translatedSize, tapAngle);
@ -124,7 +121,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 8 * scaleFactor,
translatedSize.height() - 8 * scaleFactor),
Qt::AlignCenter | Qt::TextWrapAnywhere, state->getAnnotation());
Qt::AlignCenter | Qt::TextWrapAnywhere, annotation);
painter->restore();
}
@ -132,7 +129,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->fillPath(shape(), QBrush(QColor(255, 0, 0, 100)));
}
if (state->getDoesntUntap()) {
if (doesntUntap) {
painter->save();
painter->setRenderHint(QPainter::Antialiasing, false);
@ -151,66 +148,70 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
void CardItem::setAttacking(bool _attacking)
{
state->setAttacking(_attacking);
attacking = _attacking;
update();
}
void CardItem::setCounter(int _id, int _value)
{
state->setCounter(_id, _value);
if (_value) {
counters.insert(_id, _value);
} else {
counters.remove(_id);
}
update();
}
void CardItem::setAnnotation(const QString &_annotation)
{
state->setAnnotation(_annotation);
annotation = _annotation;
update();
}
void CardItem::setDoesntUntap(bool _doesntUntap)
{
state->setDoesntUntap(_doesntUntap);
doesntUntap = _doesntUntap;
update();
}
void CardItem::setPT(const QString &_pt)
{
state->setPT(_pt);
pt = _pt;
update();
}
void CardItem::setAttachedTo(CardItem *_attachedTo)
{
if (state->getAttachedTo() != nullptr) {
state->getAttachedTo()->removeAttachedCard(this);
if (attachedTo != nullptr) {
attachedTo->removeAttachedCard(this);
}
gridPoint.setX(-1);
state->setAttachedTo(_attachedTo);
if (state->getAttachedTo() != nullptr) {
attachedTo = _attachedTo;
if (attachedTo != nullptr) {
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
// attached cards
if (state->getAttachedTo()->getZone() == nullptr) {
if (attachedTo->zone == nullptr) {
deleteLater();
} else {
emit state->getAttachedTo()->getZone()->cardAdded(this);
state->getAttachedTo()->addAttachedCard(this);
if (state->getZone() != state->getAttachedTo()->getZone()) {
state->getAttachedTo()->getZone()->reorganizeCards();
emit attachedTo->zone->cardAdded(this);
attachedTo->addAttachedCard(this);
if (zone != attachedTo->getZone()) {
attachedTo->getZone()->reorganizeCards();
}
}
} else {
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
// attached cards
if (state->getZone() == nullptr) {
if (zone == nullptr) {
deleteLater();
} else {
emit state->getZone()->cardAdded(this);
emit zone->cardAdded(this);
}
}
if (state->getZone() != nullptr) {
state->getZone()->reorganizeCards();
if (zone != nullptr) {
zone->reorganizeCards();
}
}
@ -219,7 +220,13 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
*/
void CardItem::resetState(bool keepAnnotations)
{
state->resetState(keepAnnotations);
attacking = false;
counters.clear();
pt.clear();
if (!keepAnnotations) {
annotation.clear();
}
attachedTo = 0;
attachedCards.clear();
setTapped(false, false);
setDoesntUntap(false);
@ -231,11 +238,11 @@ void CardItem::resetState(bool keepAnnotations)
void CardItem::processCardInfo(const ServerInfo_Card &_info)
{
state->clearCounters();
counters.clear();
const int counterListSize = _info.counter_list_size();
for (int i = 0; i < counterListSize; ++i) {
const ServerInfo_CardCounter &counterInfo = _info.counter_list(i);
state->insertCounter(counterInfo.id(), counterInfo.value());
counters.insert(counterInfo.id(), counterInfo.value());
}
setId(_info.id());
@ -277,7 +284,7 @@ void CardItem::drawArrow(const QColor &arrowColor)
}
auto *game = owner->getGame();
PlayerLogic *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
Player *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
int phase = 0; // 0 means to not set the phase
if (SettingsCache::instance().getDoNotDeleteArrowsInSubPhases()) {
int currentPhase = game->getGameState()->getCurrentPhase();
@ -292,7 +299,7 @@ void CardItem::drawArrow(const QColor &arrowColor)
if (card == nullptr || card == this) {
continue;
}
if (card->getZone() != state->getZone()) {
if (card->getZone() != zone) {
continue;
}
@ -317,7 +324,7 @@ void CardItem::drawAttachArrow()
if (card == nullptr) {
continue;
}
if (card->getZone() != state->getZone()) {
if (card->getZone() != zone) {
continue;
}
@ -350,7 +357,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
2 * QApplication::startDragDistance()) {
return;
}
if (const ZoneViewZoneLogic *view = qobject_cast<const ZoneViewZoneLogic *>(state->getZone())) {
if (const ZoneViewZoneLogic *view = qobject_cast<const ZoneViewZoneLogic *>(zone)) {
if (view->getRevealZone() && !view->getWriteableRevealZone()) {
return;
}
@ -368,12 +375,12 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
int childIndex = 0;
for (const auto &item : scene()->selectedItems()) {
CardItem *card = static_cast<CardItem *>(item);
if ((card == this) || (card->getZone() != state->getZone())) {
if ((card == this) || (card->getZone() != zone)) {
continue;
}
++childIndex;
QPointF childPos;
if (state->getZone()->getHasCardAttr()) {
if (zone->getHasCardAttr()) {
childPos = card->pos() - pos();
} else {
childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0);
@ -394,18 +401,15 @@ void CardItem::playCard(bool faceDown)
return;
}
TableZoneLogic *tz = qobject_cast<TableZoneLogic *>(state->getZone());
TableZoneLogic *tz = qobject_cast<TableZoneLogic *>(zone);
if (tz) {
emit tz->toggleTapped();
} else {
if (SettingsCache::instance().getClickPlaysAllSelected()) {
if (faceDown) {
emit playSelectedFaceDown(this);
} else {
emit playSelected(this);
}
faceDown ? zone->getPlayer()->getPlayerActions()->actPlayFacedown()
: zone->getPlayer()->getPlayerActions()->actPlay();
} else {
state->getZone()->getPlayer()->getPlayerActions()->playCard(this, faceDown);
zone->getPlayer()->getPlayerActions()->playCard(this, faceDown);
}
}
}
@ -461,11 +465,11 @@ static bool isUnwritableRevealZone(CardZoneLogic *zone)
*/
void CardItem::handleClickedToPlay(bool shiftHeld)
{
if (isUnwritableRevealZone(state->getZone())) {
if (isUnwritableRevealZone(zone)) {
if (SettingsCache::instance().getClickPlaysAllSelected()) {
emit hideSelected(this);
zone->getPlayer()->getPlayerActions()->actHide();
} else {
state->getZone()->removeCard(this);
zone->removeCard(this);
}
} else {
playCard(shiftHeld);
@ -474,15 +478,21 @@ void CardItem::handleClickedToPlay(bool shiftHeld)
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::RightButton && owner != nullptr) {
emit rightClicked(this, event->screenPos());
return;
}
if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) &&
(!SettingsCache::instance().getDoubleClickToPlay())) {
if (event->button() == Qt::RightButton) {
if (owner != nullptr) {
owner->getGame()->setActiveCard(this);
if (QMenu *cardMenu = owner->getPlayerMenu()->updateCardMenu(this)) {
cardMenu->popup(event->screenPos());
return;
}
}
} else if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) &&
(!SettingsCache::instance().getDoubleClickToPlay())) {
handleClickedToPlay(event->modifiers().testFlag(Qt::ShiftModifier));
}
if (owner != nullptr) {
if (owner != nullptr) { // cards without owner will be deleted
setCursor(Qt::OpenHandCursor);
}
AbstractCardItem::mouseReleaseEvent(event);
@ -528,14 +538,14 @@ bool CardItem::animationEvent()
QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
if ((change == ItemSelectedHasChanged) && owner != nullptr) {
bool selected = value.toBool();
if (selected) {
if (value == true) {
owner->getGame()->setActiveCard(this);
owner->getPlayerMenu()->updateCardMenu(this);
} else if (owner->getGameScene()->selectedItems().isEmpty()) {
owner->getGame()->setActiveCard(nullptr);
owner->getPlayerMenu()->updateCardMenu(nullptr);
}
emit selectionChanged(this, selected);
}
return AbstractCardItem::itemChange(change, value);
}
}

View file

@ -1,14 +1,13 @@
/**
* @file card_item.h
* @ingroup GameGraphicsCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARDITEM_H
#define CARDITEM_H
#include "../../game/board/card_state.h"
#include "../../game/zones/card_zone_logic.h"
#include "../zones/logic/card_zone_logic.h"
#include "abstract_card_item.h"
#include <libcockatrice/network/server/remote/game/server_card.h>
@ -17,20 +16,27 @@ class CardDatabase;
class CardDragItem;
class CardZone;
class ServerInfo_Card;
class PlayerLogic;
class Player;
class QAction;
class QColor;
const int MAX_COUNTERS_ON_CARD = 999;
const int ROTATION_DEGREES_PER_FRAME = 10;
class CardItem : public AbstractCardItem
{
Q_OBJECT
private:
CardState *state;
CardZoneLogic *zone;
bool attacking;
QMap<int, int> counters;
QString annotation;
QString pt;
bool destroyOnZoneChange;
bool doesntUntap;
QPoint gridPoint;
CardDragItem *dragItem;
CardItem *attachedTo;
QList<CardItem *> attachedCards;
void prepareDelete();
@ -47,20 +53,16 @@ public:
{
return Type;
}
explicit CardItem(PlayerLogic *_owner,
explicit CardItem(Player *_owner,
QGraphicsItem *parent = nullptr,
const CardRef &cardRef = {},
int _cardid = -1,
CardZoneLogic *_zone = nullptr);
void retranslateUi();
[[nodiscard]] CardState *getState() const
{
return state;
}
[[nodiscard]] CardZoneLogic *getZone() const
{
return state->getZone();
return zone;
}
void setZone(CardZoneLogic *_zone);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
@ -76,50 +78,50 @@ public:
{
return gridPoint;
}
[[nodiscard]] PlayerLogic *getOwner() const
[[nodiscard]] Player *getOwner() const
{
return owner;
}
void setOwner(PlayerLogic *_owner)
void setOwner(Player *_owner)
{
owner = _owner;
}
[[nodiscard]] bool getAttacking() const
{
return state->getAttacking();
return attacking;
}
void setAttacking(bool _attacking);
[[nodiscard]] const QMap<int, int> &getCounters() const
{
return state->getCounters();
return counters;
}
void setCounter(int _id, int _value);
[[nodiscard]] QString getAnnotation() const
{
return state->getAnnotation();
return annotation;
}
void setAnnotation(const QString &_annotation);
[[nodiscard]] bool getDoesntUntap() const
{
return state->getDoesntUntap();
return doesntUntap;
}
void setDoesntUntap(bool _doesntUntap);
[[nodiscard]] QString getPT() const
{
return state->getPT();
return pt;
}
void setPT(const QString &_pt);
[[nodiscard]] bool getDestroyOnZoneChange() const
{
return state->getDestroyOnZoneChange();
return destroyOnZoneChange;
}
void setDestroyOnZoneChange(bool _destroy)
{
state->setDestroyOnZoneChange(_destroy);
destroyOnZoneChange = _destroy;
}
[[nodiscard]] CardItem *getAttachedTo() const
{
return state->getAttachedTo();
return attachedTo;
}
void setAttachedTo(CardItem *_attachedTo);
void addAttachedCard(CardItem *card)

View file

@ -1,6 +1,6 @@
#include "card_list.h"
#include "../../game_graphics/board/card_item.h"
#include "card_item.h"
#include <QDebug>
#include <algorithm>

View file

@ -1,8 +1,8 @@
/**
* @file card_list.h
* @ingroup GameLogicCards
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef CARDLIST_H
#define CARDLIST_H

View file

@ -1,111 +0,0 @@
#include "card_state.h"
void CardState::resetState(bool keepAnnotations)
{
attacking = false;
counters.clear();
pt.clear();
if (!keepAnnotations) {
annotation.clear();
}
attachedTo = nullptr;
}
void CardState::setZone(CardZoneLogic *_zone)
{
if (zone == _zone) {
return;
}
zone = _zone;
emit zoneChanged(this, zone);
emit stateChanged();
}
void CardState::setAttacking(bool _attacking)
{
if (attacking == _attacking) {
return;
}
attacking = _attacking;
emit attackingChanged(_attacking);
emit stateChanged();
}
void CardState::insertCounter(int id, int value)
{
counters.insert(id, value);
emit countersChanged(counters);
emit stateChanged();
}
void CardState::setCounter(int id, int value)
{
if (value) {
counters[id] = value;
} else {
counters.remove(id);
}
emit countersChanged(counters);
emit stateChanged();
}
void CardState::clearCounters()
{
counters.clear();
emit countersChanged(counters);
emit stateChanged();
}
void CardState::setAnnotation(const QString &_annotation)
{
if (annotation == _annotation) {
return;
}
annotation = _annotation;
emit annotationChanged(annotation);
emit stateChanged();
}
void CardState::setPT(const QString &_pt)
{
if (pt == _pt) {
return;
}
pt = _pt;
emit ptChanged(pt);
emit stateChanged();
}
void CardState::setDoesntUntap(bool _doesntUntap)
{
if (doesntUntap == _doesntUntap) {
return;
}
doesntUntap = _doesntUntap;
emit doesntUntapChanged(_doesntUntap);
emit stateChanged();
}
void CardState::setDestroyOnZoneChange(bool _destroyOnZoneChange)
{
if (destroyOnZoneChange == _destroyOnZoneChange) {
return;
}
destroyOnZoneChange = _destroyOnZoneChange;
emit destroyOnZoneChangeChanged(_destroyOnZoneChange);
emit stateChanged();
}
void CardState::setAttachedTo(CardItem *_attachedTo)
{
if (attachedTo == _attachedTo) {
return;
}
attachedTo = _attachedTo;
emit attachedToChanged(_attachedTo);
emit stateChanged();
}

View file

@ -1,103 +0,0 @@
#ifndef COCKATRICE_CARD_STATE_H
#define COCKATRICE_CARD_STATE_H
#include <QMap>
#include <QObject>
class CardZoneLogic;
class CardItem;
class CardState : public QObject
{
Q_OBJECT
private:
bool attacking = false;
QMap<int, int> counters;
QString annotation;
QString pt;
bool doesntUntap = false;
bool destroyOnZoneChange = false;
CardItem *attachedTo = nullptr;
CardZoneLogic *zone = nullptr;
signals:
void stateChanged();
void attackingChanged(bool newValue);
void countersChanged(const QMap<int, int> &newCounters);
void annotationChanged(const QString &newAnnotation);
void ptChanged(const QString &newPt);
void doesntUntapChanged(bool newValue);
void destroyOnZoneChangeChanged(bool newValue);
void attachedToChanged(CardItem *newAttachedTo);
void zoneChanged(CardState *changedCard, CardZoneLogic *newZone);
public:
explicit CardState(QObject *parent, CardZoneLogic *_zone) : QObject(parent), zone(_zone)
{
}
void resetState(bool keepAnnotations);
CardZoneLogic *getZone() const
{
return zone;
}
void setZone(CardZoneLogic *_zone);
bool getAttacking() const
{
return attacking;
}
void setAttacking(bool _attacking);
const QMap<int, int> &getCounters() const
{
return counters;
}
void insertCounter(int id, int value);
void setCounter(int id, int value);
void clearCounters();
QString getAnnotation() const
{
return annotation;
}
void setAnnotation(const QString &_annotation);
QString getPT() const
{
return pt;
}
void setPT(const QString &_pt);
bool getDoesntUntap() const
{
return doesntUntap;
}
void setDoesntUntap(bool _doesntUntap);
bool getDestroyOnZoneChange() const
{
return destroyOnZoneChange;
}
void setDestroyOnZoneChange(bool _destroyOnZoneChange);
CardItem *getAttachedTo() const
{
return attachedTo;
}
void setAttachedTo(CardItem *_attachedTo);
};
#endif // COCKATRICE_CARD_STATE_H

View file

@ -1,12 +1,19 @@
#include "counter_general.h"
#include "../../game_graphics/board/abstract_graphics_item.h"
#include "../../interface/pixel_map_generator.h"
#include "abstract_graphics_item.h"
#include <QPainter>
GeneralCounter::GeneralCounter(CounterState *state, PlayerLogic *player, bool useNameForShortcut, QGraphicsItem *parent)
: AbstractCounter(state, player, true, useNameForShortcut, parent)
GeneralCounter::GeneralCounter(Player *_player,
int _id,
const QString &_name,
const QColor &_color,
int _radius,
int _value,
bool useNameForShortcut,
QGraphicsItem *parent)
: AbstractCounter(_player, _id, _name, true, _value, useNameForShortcut, parent), color(_color), radius(_radius)
{
setCacheMode(DeviceCoordinateCache);
}

View file

@ -1,8 +1,8 @@
/**
* @file counter_general.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COUNTER_GENERAL_H
#define COUNTER_GENERAL_H
@ -12,10 +12,17 @@
class GeneralCounter : public AbstractCounter
{
Q_OBJECT
private:
QColor color;
int radius;
public:
GeneralCounter(CounterState *state,
PlayerLogic *player,
GeneralCounter(Player *_player,
int _id,
const QString &_name,
const QColor &_color,
int _radius,
int _value,
bool useNameForShortcut = false,
QGraphicsItem *parent = nullptr);
QRectF boundingRect() const override;

View file

@ -1,24 +0,0 @@
#include "counter_state.h"
#include <libcockatrice/utility/color.h>
CounterState::CounterState(int id, const QString &name, const QColor &color, int radius, int value, QObject *parent)
: QObject(parent), id(id), name(name), color(color), radius(radius), value(value)
{
}
CounterState *CounterState::fromProto(const ServerInfo_Counter &counter, QObject *parent)
{
return new CounterState(counter.id(), QString::fromStdString(counter.name()),
convertColorToQColor(counter.counter_color()), counter.radius(), counter.count(), parent);
}
void CounterState::setValue(int newValue)
{
if (newValue == value) {
return;
}
int old = value;
value = newValue;
emit valueChanged(old, newValue);
}

View file

@ -1,51 +0,0 @@
#ifndef COCKATRICE_COUNTER_STATE_H
#define COCKATRICE_COUNTER_STATE_H
#include <QColor>
#include <QObject>
#include <QString>
#include <libcockatrice/protocol/pb/serverinfo_counter.pb.h>
class CounterState : public QObject
{
Q_OBJECT
public:
CounterState(int id, const QString &name, const QColor &color, int radius, int value, QObject *parent = nullptr);
static CounterState *fromProto(const ServerInfo_Counter &counter, QObject *parent = nullptr);
int getId() const
{
return id;
}
QString getName() const
{
return name;
}
QColor getColor() const
{
return color;
}
int getRadius() const
{
return radius;
}
int getValue() const
{
return value;
}
void setValue(int newValue);
signals:
void valueChanged(int oldValue, int newValue);
private:
int id;
QString name;
QColor color;
int radius;
int value;
};
#endif // COCKATRICE_COUNTER_STATE_H

View file

@ -1,8 +1,8 @@
/**
* @file translate_counter_name.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef TRANSLATECOUNTERNAME_H
#define TRANSLATECOUNTERNAME_H

View file

@ -12,16 +12,16 @@
*/
namespace CardDimensions
{
/** @brief Card width in pixels. */
/// Card width in pixels
constexpr int WIDTH = 72;
/** @brief Card height in pixels. */
/// Card height in pixels
constexpr int HEIGHT = 102;
/** @brief Pre-converted for floating-point contexts (Z-value calculations). */
/// 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);
/** @brief Half-dimensions for centering and rotation transforms. */
/// 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

View file

@ -360,16 +360,6 @@ void DeckViewScene::rebuildTree()
return;
}
QStringList requiredZones = {DECK_ZONE_MAIN, DECK_ZONE_SIDE};
for (const QString &zoneName : requiredZones) {
if (!cardContainers.contains(zoneName)) {
auto *container = new DeckViewCardContainer(zoneName);
cardContainers.insert(zoneName, container);
addItem(container);
}
}
for (auto *currentZone : deck->getZoneNodes()) {
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
if (!container) {

View file

@ -1,8 +1,8 @@
/**
* @file deck_view.h
* @ingroup Lobby
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECKVIEW_H
#define DECKVIEW_H

View file

@ -19,7 +19,7 @@
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
#include <libcockatrice/protocol/pb/response_deck_download.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/string_limits.h>
#include <libcockatrice/utility/trice_limits.h>
ToggleButton::ToggleButton(QWidget *parent) : QPushButton(parent), state(false)
{
@ -209,7 +209,6 @@ void DeckViewContainer::refreshShortcuts()
loadLocalButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadLocalButton"));
loadRemoteButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadRemoteButton"));
loadFromClipboardButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadFromClipboardButton"));
loadFromWebsiteButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadFromWebsiteButton"));
unloadDeckButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/unloadDeckButton"));
readyStartButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/readyStartButton"));
sideboardLockButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/sideboardLockButton"));

View file

@ -1,8 +1,8 @@
/**
* @file deck_view_container.h
* @ingroup Lobby
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DECK_VIEW_CONTAINER_H
#define DECK_VIEW_CONTAINER_H

View file

@ -1,8 +1,8 @@
/**
* @file tabbed_deck_view_container.h
* @ingroup Lobby
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef TABBED_DECK_VIEW_CONTAINER_H
#define TABBED_DECK_VIEW_CONTAINER_H

View file

@ -20,7 +20,7 @@
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/models/database/card_database_model.h>
#include <libcockatrice/models/database/token/token_display_model.h>
#include <libcockatrice/utility/string_limits.h>
#include <libcockatrice/utility/trice_limits.h>
DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent)
: QDialog(parent), predefinedTokens(_predefinedTokens)

View file

@ -1,8 +1,8 @@
/**
* @file dlg_create_token.h
* @ingroup GameDialogs
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DLG_CREATETOKEN_H
#define DLG_CREATETOKEN_H

View file

@ -1,8 +1,8 @@
/**
* @file dlg_move_top_cards_until.h
* @ingroup GameDialogs
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DLG_MOVE_TOP_CARDS_UNTIL_H
#define DLG_MOVE_TOP_CARDS_UNTIL_H

View file

@ -5,7 +5,7 @@
#include <QSpinBox>
#include <QVBoxLayout>
#include <QWidget>
#include <libcockatrice/utility/dice_limits.h>
#include <libcockatrice/utility/trice_limits.h>
DlgRollDice::DlgRollDice(QWidget *parent) : QDialog(parent)
{

View file

@ -1,8 +1,8 @@
/**
* @file dlg_roll_dice.h
* @ingroup GameDialogs
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef DLG_ROLL_DICE_H
#define DLG_ROLL_DICE_H

View file

@ -4,16 +4,16 @@
#include <libcockatrice/protocol/pb/event_game_joined.pb.h>
Game::Game(QObject *_parent,
bool isLocalGame,
Game::Game(TabGame *_tab,
QList<AbstractClient *> &_clients,
const Event_GameJoined &event,
const QMap<int, QString> &_roomGameTypes)
: AbstractGame(_parent)
: AbstractGame(_tab)
{
gameMetaInfo->setFromProto(event.game_info());
gameMetaInfo->setRoomGameTypes(_roomGameTypes);
gameState = new GameState(this, 0, event.host_id(), isLocalGame, _clients, false, event.resuming(), -1, false);
gameState = new GameState(this, 0, event.host_id(), tab->getTabSupervisor()->getIsLocalGame(), _clients, false,
event.resuming(), -1, false);
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
playerManager = new PlayerManager(this, event.player_id(), event.judge(), event.spectator());
gameMetaInfo->setStarted(false);

View file

@ -1,8 +1,8 @@
/**
* @file game.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_GAME_H
#define COCKATRICE_GAME_H
@ -16,8 +16,7 @@ class Game : public AbstractGame
Q_OBJECT
public:
Game(QObject *parent,
bool isLocalGame,
Game(TabGame *tab,
QList<AbstractClient *> &_clients,
const Event_GameJoined &event,
const QMap<int, QString> &_roomGameTypes);

View file

@ -1,8 +1,8 @@
#include "game_event_handler.h"
#include "../game_graphics/log/message_log_widget.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "abstract_game.h"
#include "log/message_log_widget.h"
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <libcockatrice/protocol/get_pb_extension.h>
@ -99,7 +99,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
if (cont.has_forced_by_judge()) {
auto id = cont.forced_by_judge();
PlayerLogic *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr);
Player *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr);
if (judgep) {
emit setContextJudgeName(judgep->getPlayerInfo()->getName());
} else if (game->getPlayerManager()->getSpectators().contains(id)) {
@ -160,7 +160,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
break;
default: {
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
if (!player) {
qCWarning(GameEventHandlerLog) << "unhandled game event: invalid player id";
break;
@ -213,25 +213,11 @@ void GameEventHandler::handleChatMessageSent(const QString &chatMessage)
sendGameCommand(cmd);
}
void GameEventHandler::handleArrowDeletion(int creatorId, int arrowId)
void GameEventHandler::handleArrowDeletion(int arrowId)
{
Command_DeleteArrow cmd;
cmd.set_arrow_id(arrowId);
auto preparedCommand = prepareGameCommand(cmd);
connect(preparedCommand, &PendingCommand::finished, this, [creatorId, arrowId, this](const Response &response) {
handleArrowDeletionFinished(response, creatorId, arrowId);
});
sendGameCommand(preparedCommand);
}
void GameEventHandler::handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId)
{
if (response.response_code() == Response::RespNameNotFound) {
emit arrowDeleted(creatorId, arrowId);
}
sendGameCommand(cmd);
}
void GameEventHandler::eventSpectatorSay(const Event_GameSay &event,
@ -275,7 +261,7 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
emit spectatorJoined(prop);
}
} else {
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
if (!player) {
player = game->getPlayerManager()->addPlayer(playerId, prop.user_info());
emit playerJoined(prop);
@ -324,7 +310,7 @@ void GameEventHandler::processCardAttachmentsForPlayers(const Event_GameStateCha
const ServerInfo_Player &playerInfo = event.player_list(i);
const ServerInfo_PlayerProperties &prop = playerInfo.properties();
if (!prop.spectator()) {
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0);
Player *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0);
if (!player) {
continue;
}
@ -337,7 +323,7 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
int eventPlayerId,
const GameEventContext &context)
{
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) {
return;
}
@ -361,7 +347,7 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
case GameEventContext::CONCEDE: {
player->setConceded(true);
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones();
}
@ -373,7 +359,7 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
case GameEventContext::UNCONCEDE: {
player->setConceded(false);
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones();
}
@ -423,7 +409,7 @@ void GameEventHandler::eventJoin(const Event_Join &event, int /*eventPlayerId*/,
emit logJoinSpectator(playerName);
emit spectatorJoined(playerInfo);
} else {
PlayerLogic *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info());
Player *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info());
emit logJoinPlayer(newPlayer);
emit playerJoined(playerInfo);
}
@ -451,7 +437,7 @@ QString GameEventHandler::getLeaveReason(Event_Leave::LeaveReason reason)
}
void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext & /*context*/)
{
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) {
return;
}
@ -466,7 +452,7 @@ void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, c
player->deleteLater();
// Rearrange all remaining zones so that attachment relationship updates take place
QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones();
}
@ -488,7 +474,7 @@ void GameEventHandler::eventReverseTurn(const Event_ReverseTurn &event,
int eventPlayerId,
const GameEventContext & /*context*/)
{
PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) {
return;
}
@ -519,7 +505,7 @@ void GameEventHandler::eventSetActivePlayer(const Event_SetActivePlayer &event,
const GameEventContext & /*context*/)
{
game->getGameState()->setActivePlayer(event.active_player_id());
PlayerLogic *player = game->getPlayerManager()->getPlayer(event.active_player_id());
Player *player = game->getPlayerManager()->getPlayer(event.active_player_id());
if (!player) {
return;
}

View file

@ -1,8 +1,8 @@
/**
* @file game_event_handler.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_GAME_EVENT_HANDLER_H
#define COCKATRICE_GAME_EVENT_HANDLER_H
@ -38,7 +38,7 @@ class Event_Kicked;
class Event_ReverseTurn;
class AbstractGame;
class PendingCommand;
class PlayerLogic;
class Player;
inline Q_LOGGING_CATEGORY(GameEventHandlerLog, "game_event_handler");
@ -60,8 +60,7 @@ public:
void handleActivePhaseChanged(int phase);
void handleGameLeft();
void handleChatMessageSent(const QString &chatMessage);
void handleArrowDeletion(int creatorId, int arrowId);
void handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId);
void handleArrowDeletion(int arrowId);
void eventSpectatorSay(const Event_GameSay &event, int eventPlayerId, const GameEventContext &context);
void eventSpectatorLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext &context);
@ -96,7 +95,7 @@ public slots:
signals:
void emitUserEvent();
void addPlayerToAutoCompleteList(QString playerName);
void localPlayerDeckSelected(PlayerLogic *localPlayer, int playerId, ServerInfo_Player playerInfo);
void localPlayerDeckSelected(Player *localPlayer, int playerId, ServerInfo_Player playerInfo);
void remotePlayerDeckSelected(QString deckList, int playerId, QString playerName);
void remotePlayersDecksSelected(QVector<QPair<int, QPair<QString, QString>>> opponentDecks);
void localPlayerSideboardLocked(int playerId, bool sideboardLocked);
@ -113,22 +112,21 @@ signals:
void containerProcessingStarted(GameEventContext context);
void setContextJudgeName(QString judgeName);
void containerProcessingDone();
void arrowDeleted(int creatorId, int arrowId);
void logSpectatorSay(ServerInfo_User userInfo, QString message);
void logSpectatorLeave(QString name, QString reason);
void logGameStart();
void logReadyStart(PlayerLogic *player);
void logNotReadyStart(PlayerLogic *player);
void logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize);
void logSideboardLockSet(PlayerLogic *player, bool sideboardLocked);
void logConnectionStateChanged(PlayerLogic *player, bool connected);
void logReadyStart(Player *player);
void logNotReadyStart(Player *player);
void logDeckSelect(Player *player, QString deckHash, int sideboardSize);
void logSideboardLockSet(Player *player, bool sideboardLocked);
void logConnectionStateChanged(Player *player, bool connected);
void logJoinSpectator(QString spectatorName);
void logJoinPlayer(PlayerLogic *player);
void logLeave(PlayerLogic *player, QString reason);
void logJoinPlayer(Player *player);
void logLeave(Player *player, QString reason);
void logKicked();
void logTurnReversed(PlayerLogic *player, bool reversed);
void logTurnReversed(Player *player, bool reversed);
void logGameClosed();
void logActivePlayer(PlayerLogic *activePlayer);
void logActivePlayer(Player *activePlayer);
void logActivePhaseChanged(int activePhase);
void logConcede(int playerId);
void logUnconcede(int playerId);

View file

@ -1,8 +1,8 @@
/**
* @file game_meta_info.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef GAME_META_INFO_H
#define GAME_META_INFO_H

View file

@ -1,13 +1,9 @@
#include "game_scene.h"
#include "../client/settings/cache_settings.h"
#include "../game/abstract_game.h"
#include "../game/player/player_actions.h"
#include "../game/player/player_logic.h"
#include "../game_graphics/player/player_graphics_item.h"
#include "board/card_item.h"
#include "phases_toolbar.h"
#include "player/menu/player_menu.h"
#include "player/player.h"
#include "player/player_graphics_item.h"
#include "zones/select_zone.h"
#include "zones/view_zone.h"
@ -76,114 +72,19 @@ QList<CardItem *> GameScene::selectedCards() const
return selectedCards;
}
void GameScene::onCardSelectionChanged(AbstractCardItem *abstractCard, bool selected)
{
CardItem *card = qobject_cast<CardItem *>(abstractCard);
if (!card || !card->getOwner()) {
return;
}
auto *owner = card->getOwner();
if (selected) {
owner->requestCardMenuUpdate(card);
return;
}
if (selectedItems().isEmpty()) {
owner->getGame()->setActiveCard(nullptr);
owner->requestCardMenuUpdate(nullptr);
}
}
void GameScene::onCardRightClicked(AbstractCardItem *abstractCard, QPoint screenPos)
{
auto *card = qobject_cast<CardItem *>(abstractCard);
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
auto *view = playerViews.value(card->getOwner()->getPlayerInfo()->getId());
if (!view) {
return;
}
card->getOwner()->getGame()->setActiveCard(card);
if (auto *menu = view->getPlayerMenu()->updateCardMenu(card)) {
menu->popup(screenPos);
}
}
void GameScene::playSelected(AbstractCardItem *card)
{
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
card->getOwner()->getPlayerActions()->actPlay(selectedCards());
}
void GameScene::playSelectedFaceDown(AbstractCardItem *card)
{
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
card->getOwner()->getPlayerActions()->actPlayFacedown(selectedCards());
}
void GameScene::hideSelected(AbstractCardItem *card)
{
if (!card) {
return;
}
if (!card->getOwner()) {
return;
}
card->getOwner()->getPlayerActions()->actHide(selectedCards());
}
/**
* @brief Adds a player to the scene and stores their graphics item.
* @param player Player to add.
*
* Connects to the player's sizeChanged signal to recompute layout on resize.
*/
void GameScene::addPlayer(PlayerLogic *player)
void GameScene::addPlayer(Player *player)
{
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::addPlayer name=" << player->getPlayerInfo()->getName();
auto *view = new PlayerGraphicsItem(player);
playerViews.insert(player->getPlayerInfo()->getId(), view);
addItem(view);
connect(view, &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange);
connect(player, &PlayerLogic::concededChanged, this, [this](int id, bool conceded) {
if (conceded) {
clearArrowsForPlayer(id);
}
rearrange();
});
connect(player, &PlayerLogic::requestZoneViewToggle, this, &GameScene::toggleZoneView);
connect(player, &PlayerLogic::requestRevealedZoneView, this, &GameScene::addRevealedZoneView);
connect(player, &PlayerLogic::arrowDeleted, this, &GameScene::deleteArrow);
connect(player, &PlayerLogic::arrowCreateRequested, this, &GameScene::addArrow);
connect(player, &PlayerLogic::arrowDeleteRequested, this, &GameScene::requestArrowDeletion);
connect(player, &PlayerLogic::arrowsClearedLocally, this,
[this, id = player->getPlayerInfo()->getId()]() { clearArrowsForPlayerLocally(id); });
connect(player->getPlayerEventHandler(), &PlayerEventHandler::cardZoneChanged, this, &GameScene::onCardZoneChanged);
rearrange();
players << player->getGraphicsItem();
addItem(player->getGraphicsItem());
connect(player->getGraphicsItem(), &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange);
}
/**
@ -192,20 +93,17 @@ void GameScene::addPlayer(PlayerLogic *player)
*
* Closes any zone views associated with the player and recomputes layout.
*/
void GameScene::removePlayer(PlayerLogic *player)
void GameScene::removePlayer(Player *player)
{
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::removePlayer name=" << player->getPlayerInfo()->getName();
clearArrowsForPlayer(player->getPlayerInfo()->getId());
for (ZoneViewWidget *zone : zoneViews) {
if (zone->getPlayer() == player) {
zone->close();
}
}
auto *view = playerViews.take(player->getPlayerInfo()->getId());
removeItem(view);
view->deleteLater();
players.removeOne(player->getGraphicsItem());
removeItem(player->getGraphicsItem());
rearrange();
}
@ -280,14 +178,14 @@ void GameScene::processViewSizeChange(const QSize &newSize)
*
* Used to determine rotation and layout order.
*/
QList<PlayerLogic *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
QList<Player *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
{
QList<PlayerLogic *> activePlayers;
QList<Player *> activePlayers;
firstPlayerIndex = 0;
bool firstPlayerFound = false;
for (auto *pgItem : playerViews.values()) {
PlayerLogic *p = pgItem->getLogic();
for (auto *pgItem : players) {
Player *p = pgItem->getPlayer();
if (p && !p->getConceded()) {
activePlayers.append(p);
if (!firstPlayerFound && p->getPlayerInfo()->getLocal()) {
@ -307,9 +205,9 @@ QList<PlayerLogic *> GameScene::collectActivePlayers(int &firstPlayerIndex) cons
*
* Applies rotation offset and ensures the list wraps correctly.
*/
QList<PlayerLogic *> GameScene::rotatePlayers(const QList<PlayerLogic *> &activePlayers, int firstPlayerIndex) const
QList<Player *> GameScene::rotatePlayers(const QList<Player *> &activePlayers, int firstPlayerIndex) const
{
QList<PlayerLogic *> rotated = activePlayers;
QList<Player *> rotated = activePlayers;
if (!rotated.isEmpty()) {
int totalRotation = firstPlayerIndex + playerRotation;
while (totalRotation < 0) {
@ -340,7 +238,7 @@ int GameScene::determineColumnCount(int playerCount)
* - Position players in columns with spacing.
* - Mirror graphics for visual balance.
*/
QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &playersPlaying, int columns)
QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<Player *> &playersPlaying, int columns)
{
playersByColumn.clear();
@ -348,7 +246,7 @@ QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &pl
qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing;
QList<int> columnWidth;
QListIterator<PlayerLogic *> playersIter(playersPlaying);
QListIterator<Player *> playersIter(playersPlaying);
for (int col = 0; col < columns; ++col) {
playersByColumn.append(QList<PlayerGraphicsItem *>());
columnWidth.append(0);
@ -356,14 +254,14 @@ QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &pl
int rowsInColumn = rows - (playersPlaying.size() % columns) * col; // Adjust rows for uneven columns
for (int j = 0; j < rowsInColumn; ++j) {
PlayerLogic *player = playersIter.next();
Player *player = playersIter.next();
if (col == 0) {
playersByColumn[col].prepend(playerViews.value(player->getPlayerInfo()->getId()));
playersByColumn[col].prepend(player->getGraphicsItem());
} else {
playersByColumn[col].append(playerViews.value(player->getPlayerInfo()->getId()));
playersByColumn[col].append(player->getGraphicsItem());
}
auto *pgItem = playerViews.value(player->getPlayerInfo()->getId());
auto *pgItem = player->getGraphicsItem();
thisColumnHeight += pgItem->boundingRect().height() + playerAreaSpacing;
columnWidth[col] = std::max(columnWidth[col], (int)pgItem->boundingRect().width());
}
@ -450,89 +348,6 @@ void GameScene::resizeColumnsAndPlayers(const QList<qreal> &minWidthByColumn, qr
}
}
void GameScene::addArrow(QSharedPointer<ArrowData> data)
{
auto *startView = playerViews.value(data->startPlayerId);
auto *targetView = playerViews.value(data->targetPlayerId);
if (!startView || !targetView) {
return;
}
PlayerLogic *startLogic = startView->getLogic();
auto *startZone = startLogic->getZones().value(data->startZone);
if (!startZone) {
return;
}
CardItem *startCard = startZone->getCard(data->startCardId);
if (!startCard) {
return;
}
ArrowTarget *targetItem = nullptr;
if (data->isPlayerTargeted()) {
targetItem = targetView->getPlayerTarget();
} else {
auto *zone = targetView->getLogic()->getZones().value(data->targetZone);
if (zone) {
targetItem = zone->getCard(data->targetCardId);
}
}
if (!targetItem) {
return;
}
auto *arrow = new ArrowItem(data, startCard, targetItem);
addItem(arrow);
arrowRegistry.insert(data, arrow);
connect(arrow, &ArrowItem::requestDeletion, this, &GameScene::requestArrowDeletion);
}
void GameScene::deleteArrow(int playerId, int arrowId)
{
if (auto *arrow = arrowRegistry.take(playerId, arrowId)) {
arrow->delArrow();
}
}
void GameScene::requestArrowDeletion(int playerId, int arrowId)
{
if (arrowRegistry.contains(playerId, arrowId)) {
emit arrowDeletionRequested(playerId, arrowId);
}
}
void GameScene::onCardZoneChanged(CardItem *card, bool sameZone)
{
QList<ArrowItem *> toDelete;
for (auto *arrow : arrowRegistry.all()) {
if (arrow->getStartItem() == card || arrow->getTargetItem() == card) {
if (sameZone) {
arrow->updatePath();
} else {
toDelete.append(arrow);
}
}
}
for (auto *arrow : toDelete) {
deleteArrow(arrow->getCreatorId(), arrow->getId());
}
}
void GameScene::clearArrowsForPlayer(int playerId)
{
for (int arrowId : arrowRegistry.idsForPlayer(playerId)) {
emit requestArrowDeletion(playerId, arrowId);
}
}
void GameScene::clearArrowsForPlayerLocally(int playerId)
{
for (int arrowId : arrowRegistry.idsForPlayer(playerId)) {
arrowRegistry.take(playerId, arrowId)->delArrow();
}
}
// ---------- Hover Handling ----------
void GameScene::updateHover(const QPointF &scenePos)
@ -620,7 +435,7 @@ CardItem *GameScene::findTopmostCardInZone(const QList<QGraphicsItem *> &items,
* If an identical view exists, it is closed. Otherwise, a new ZoneViewWidget is created
* and positioned based on zone type.
*/
void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed)
void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numberCards, bool isReversed)
{
for (auto &view : zoneViews) {
ZoneViewZone *temp = view->getZone();
@ -653,7 +468,7 @@ void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int
* @param cardList List of cards to show.
* @param withWritePermission Whether edits are allowed.
*/
void GameScene::addRevealedZoneView(PlayerLogic *player,
void GameScene::addRevealedZoneView(Player *player,
CardZoneLogic *zone,
const QList<const ServerInfo_Card *> &cardList,
bool withWritePermission)

View file

@ -1,10 +1,7 @@
#ifndef GAMESCENE_H
#define GAMESCENE_H
#include "../game/arrow_registry.h"
#include "../game/board/arrow_data.h"
#include "../game/zones/card_zone_logic.h"
#include "board/arrow_item.h"
#include "zones/logic/card_zone_logic.h"
#include <QGraphicsScene>
#include <QList>
@ -15,7 +12,7 @@
inline Q_LOGGING_CATEGORY(GameSceneLog, "game_scene");
inline Q_LOGGING_CATEGORY(GameScenePlayerAdditionRemovalLog, "game_scene.player_addition_removal");
class PlayerLogic;
class Player;
class PlayerGraphicsItem;
class ZoneViewWidget;
class CardZone;
@ -44,9 +41,8 @@ private:
static const int playerAreaSpacing = 5; ///< Space between player areas
PhasesToolbar *phasesToolbar; ///< Toolbar showing game phases
QMap<int, PlayerGraphicsItem *> playerViews; ///< ID lookup for player graphics items
QList<PlayerGraphicsItem *> players; ///< All player graphics items
QList<QList<PlayerGraphicsItem *>> playersByColumn; ///< Players organized by column
ArrowRegistry arrowRegistry; ///< ID registry for arrow graphics items
QList<ZoneViewWidget *> zoneViews; ///< Active zone view widgets
QSize viewSize; ///< Current view size
QPointer<CardItem> hoveredCard; ///< Currently hovered card
@ -60,12 +56,10 @@ private:
*/
void updateHover(const QPointF &scenePos);
/**
* @brief Activates hover state and escapes the card from its clip container
* so hover scaling is visible beyond zone bounds.
*/
/// Activates hover state and escapes the card from its clip container so hover scaling is visible beyond zone
/// bounds.
void beginCardHover(CardItem *card);
/** @brief Deactivates hover state and restores the card to its clip container. */
/// Deactivates hover state and restores the card to its clip container.
void endCardHover(CardItem *card);
public:
@ -76,36 +70,26 @@ public:
*/
explicit GameScene(PhasesToolbar *_phasesToolbar, QObject *parent = nullptr);
/** @brief Destructor, cleans up timer and zone views. */
/** Destructor, cleans up timer and zone views. */
~GameScene() override;
/** @brief Updates UI text for all zone views. */
/** Updates UI text for all zone views. */
void retranslateUi();
/** @brief Gets all selected CardItems. */
/** Gets all selected CardItems */
QList<CardItem *> selectedCards() const;
/**
* @brief Adds a player to the scene and stores their graphics item.
* @param player Player to add.
*/
void addPlayer(PlayerLogic *player);
void addPlayer(Player *player);
/**
* @brief Removes a player from the scene.
* @param player Player to remove.
*/
void removePlayer(PlayerLogic *player);
QMap<int, PlayerGraphicsItem *> getPlayers() const
{
return playerViews;
}
PlayerGraphicsItem *viewForPlayer(int playerId)
{
return playerViews.value(playerId);
}
void removePlayer(Player *player);
/**
* @brief Adjusts the global rotation offset for player layout.
@ -113,7 +97,7 @@ public:
*/
void adjustPlayerRotation(int rotationAdjustment);
/** @brief Recomputes the layout of players and the scene size. */
/** Recomputes the layout of players and the scene size. */
void rearrange();
/**
@ -127,7 +111,7 @@ public:
* @param firstPlayerIndex Output index of first local player.
* @return List of active players.
*/
QList<PlayerLogic *> collectActivePlayers(int &firstPlayerIndex) const;
QList<Player *> collectActivePlayers(int &firstPlayerIndex) const;
/**
* @brief Rotates the list of players for layout.
@ -135,7 +119,7 @@ public:
* @param firstPlayerIndex Index of first local player.
* @return Rotated list.
*/
QList<PlayerLogic *> rotatePlayers(const QList<PlayerLogic *> &players, int firstPlayerIndex) const;
QList<Player *> rotatePlayers(const QList<Player *> &players, int firstPlayerIndex) const;
/**
* @brief Determines the number of columns to display players in.
@ -150,7 +134,7 @@ public:
* @param columns Number of columns to split into.
* @return Calculated scene size.
*/
QSizeF computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &playersPlaying, int columns);
QSizeF computeSceneSizeAndPlayerLayout(const QList<Player *> &playersPlaying, int columns);
/**
* @brief Computes the minimum width for each column based on player minimum widths.
@ -173,73 +157,56 @@ public:
*/
void resizeColumnsAndPlayers(const QList<qreal> &minWidthByColumn, qreal newWidth);
/** @brief Finds the topmost card zone under the cursor. */
/** Finds the topmost card zone under the cursor. */
static CardZone *findTopmostZone(const QList<QGraphicsItem *> &items);
/** @brief Finds the topmost card in a given zone, considering attachments and Z-order. */
/** Finds the topmost card in a given zone, considering attachments and Z-order. */
static CardItem *findTopmostCardInZone(const QList<QGraphicsItem *> &items, CardZone *zone);
/** @brief Updates hovered card highlighting. */
/** Updates hovered card highlighting. */
void updateHoveredCard(CardItem *newCard);
/** @brief Registers a card for animation updates. */
/** Registers a card for animation updates. */
void registerAnimationItem(AbstractCardItem *card);
/** @brief Unregisters a card from animation updates. */
/** Unregisters a card from animation updates. */
void unregisterAnimationItem(AbstractCardItem *card);
void startRubberBand(const QPointF &selectionOrigin);
void resizeRubberBand(const QPointF &cursorPoint, int selectedCount);
void stopRubberBand();
public slots:
void onCardSelectionChanged(AbstractCardItem *card, bool selected);
void onCardRightClicked(AbstractCardItem *card, QPoint screenPos);
void playSelected(AbstractCardItem *card);
void playSelectedFaceDown(AbstractCardItem *card);
void hideSelected(AbstractCardItem *card);
/** @brief Toggles a zone view for a player. */
void toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed = false);
/** Toggles a zone view for a player. */
void toggleZoneView(Player *player, const QString &zoneName, int numberCards, bool isReversed = false);
/** @brief Adds a revealed zone view (for shown cards). */
void addRevealedZoneView(PlayerLogic *player,
/** Adds a revealed zone view (for shown cards). */
void addRevealedZoneView(Player *player,
CardZoneLogic *zone,
const QList<const ServerInfo_Card *> &cardList,
bool withWritePermission);
/** @brief Removes a zone view widget from the scene. */
/** Removes a zone view widget from the scene. */
void removeZoneView(ZoneViewWidget *item);
/** @brief Closes all zone views. */
/** Closes all zone views. */
void clearViews();
/** @brief Closes the most recently added zone view. */
/** Closes the most recently added zone view. */
void closeMostRecentZoneView();
QTransform getViewTransform() const;
QTransform getViewportTransform() const;
/// Directly modifies the scene
void addArrow(QSharedPointer<ArrowData> data);
void deleteArrow(int playerId, int arrowId);
void clearArrowsForPlayer(int playerId);
void clearArrowsForPlayerLocally(int playerId);
/// Queues up arrow deletion but doesn't directly modify the scene
void requestArrowDeletion(int playerId, int arrowId);
void onCardZoneChanged(CardItem *card, bool sameZone);
protected:
/** @brief Handles hover updates. */
/** Handles hover updates. */
bool event(QEvent *event) override;
/** @brief Handles animation timer updates. */
/** Handles animation timer updates. */
void timerEvent(QTimerEvent *event) override;
signals:
void sigStartRubberBand(const QPointF &selectionOrigin);
void sigResizeRubberBand(const QPointF &cursorPoint, int selectedCount);
void sigStopRubberBand();
void arrowDeletionRequested(int creatorId, int arrowId);
};
#endif

View file

@ -1,8 +1,8 @@
/**
* @file game_state.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef COCKATRICE_GAME_STATE_H
#define COCKATRICE_GAME_STATE_H

View file

@ -4,12 +4,9 @@
#include "game_scene.h"
#include <QAction>
#include <QGridLayout>
#include <QLabel>
#include <QLayout>
#include <QResizeEvent>
#include <QRubberBand>
#include <libcockatrice/utility/qt_utils.h>
// QRubberBand calls raise() in showEvent() and changeEvent() to stay on top of siblings.
// This subclass disables that behavior so dragCountLabel can appear above it.
@ -37,6 +34,7 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
{
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
setFocusPolicy(Qt::ClickFocus);
setViewportUpdateMode(BoundingRectViewportUpdate);
connect(scene, &GameScene::sceneRectChanged, this, &GameView::updateSceneRect);
@ -46,9 +44,6 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
connect(scene, &GameScene::sigStopRubberBand, this, &GameView::stopRubberBand);
connect(scene, &QGraphicsScene::selectionChanged, this, [this]() { updateTotalSelectionCount(); });
setFocusDisabled(SettingsCache::instance().getKeepGameChatFocus());
connect(&SettingsCache::instance(), &SettingsCache::keepGameChatFocusChanged, this, &GameView::setFocusDisabled);
aCloseMostRecentZoneView = new QAction(this);
connect(aCloseMostRecentZoneView, &QAction::triggered, scene, &GameScene::closeMostRecentZoneView);
@ -58,40 +53,31 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
refreshShortcuts();
rubberBand = new SelectionRubberBand(QRubberBand::Rectangle, this);
const QString baseProperties = "color: white; "
"font-family: monospace; "
"background-color: rgba(0, 0, 0, 160); "
"border-radius: 3px; "
"padding: 1px 2px; "
"white-space: pre;";
const QString dragCountLabelStyle = baseProperties + "font-size: 14px; font-weight: bold;";
const QString totalCountLabelStyle = baseProperties + "font-size: 16px; font-weight: bold;";
const QString subtypeTallyLabelStyle = baseProperties + "font-size: 12px;";
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(dragCountLabelStyle);
dragCountLabel->setStyleSheet(countLabelStyle);
dragCountLabel->hide();
dragCountLabel->raise();
totalCountLabel = new QLabel(this);
totalCountLabel->setStyleSheet(totalCountLabelStyle);
totalCountLabel->setStyleSheet(countLabelStyle);
totalCountLabel->hide();
tallyContainer = new QWidget(this);
tallyContainer->setStyleSheet(subtypeTallyLabelStyle);
tallyLayout = new QGridLayout(tallyContainer);
tallyLayout->setContentsMargins(2, 2, 2, 2);
tallyLayout->setSpacing(2);
tallyContainer->hide();
}
void GameView::resizeEvent(QResizeEvent *event)
{
QGraphicsView::resizeEvent(event);
GameScene *s = static_cast<GameScene *>(scene());
s->processViewSizeChange(event->size());
GameScene *s = dynamic_cast<GameScene *>(scene());
if (s) {
s->processViewSizeChange(event->size());
}
updateSceneRect(scene()->sceneRect());
updateTotalSelectionCount(event->size());
@ -176,118 +162,27 @@ void GameView::refreshShortcuts()
SettingsCache::instance().shortcuts().getShortcut("Player/aCloseMostRecentZoneView"));
}
void GameView::clearTallyLabels()
{
QtUtils::clearLayoutRec(tallyLayout);
}
QSize GameView::rebuildTallyLabels(const QList<TallyRow> &entries)
{
clearTallyLabels();
const QString nameStyle = QStringLiteral("color: white; font-size: 12px; background: transparent;");
const QString countStyle =
QStringLiteral("color: white; font-size: 14px; font-weight: bold; background: transparent;");
int totalHeight = 0;
int maxNameWidth = 0;
int maxCountWidth = 0;
int row = 0;
for (const TallyRow &entry : entries) {
auto *nameLabel = new QLabel(entry.name, tallyContainer);
nameLabel->setStyleSheet(nameStyle);
nameLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
tallyLayout->addWidget(nameLabel, row, 0);
auto *countLabel = new QLabel(entry.value, tallyContainer);
countLabel->setStyleSheet(countStyle);
countLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
tallyLayout->addWidget(countLabel, row, 1);
QSize nameSize = nameLabel->sizeHint();
QSize countSize = countLabel->sizeHint();
maxNameWidth = qMax(maxNameWidth, nameSize.width());
maxCountWidth = qMax(maxCountWidth, countSize.width());
totalHeight += qMax(nameSize.height(), countSize.height());
++row;
}
int spacing = tallyLayout->spacing();
int margins = tallyLayout->contentsMargins().left() + tallyLayout->contentsMargins().right();
int verticalMargins = tallyLayout->contentsMargins().top() + tallyLayout->contentsMargins().bottom();
int width = maxNameWidth + spacing + maxCountWidth + margins;
int height = totalHeight + (row - 1) * spacing + verticalMargins;
return QSize(width, height);
}
void GameView::updateTotalSelectionCount(const QSize &viewSize)
{
constexpr int kMarginInPixels = 10;
constexpr int kSpacingBetweenLabels = 4;
int availableWidth = viewSize.isValid() ? viewSize.width() : viewport()->width();
int availableHeight = viewSize.isValid() ? viewSize.height() : viewport()->height();
if (!SettingsCache::instance().getShowTotalSelectionCount()) {
totalCountLabel->hide();
return;
}
int count = scene()->selectedItems().count();
if (!SettingsCache::instance().getShowTotalSelectionCount() || count <= 1) {
totalCountLabel->hide();
} else {
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();
}
TallyType tallyType =
SettingsCache::instance().getShowSubtypeSelectionTally() ? TallyType::Subtypes : TallyType::None;
GameScene *gameScene = static_cast<GameScene *>(scene());
QList<TallyRow> entries = Tally::compute(gameScene->selectedCards(), tallyType);
if (entries.isEmpty() || count <= 1) {
tallyContainer->hide();
cachedTallyRows.clear();
return;
}
// Only rebuild labels if entries changed
QSize containerSize;
if (entries != cachedTallyRows) {
cachedTallyRows = entries;
containerSize = rebuildTallyLabels(entries);
tallyContainer->resize(containerSize);
} else {
containerSize = tallyContainer->size();
totalCountLabel->hide();
}
int x = availableWidth - containerSize.width() - kMarginInPixels;
int y;
if (totalCountLabel->isVisible()) {
y = totalCountLabel->y() - containerSize.height() - kSpacingBetweenLabels;
} else {
y = availableHeight - containerSize.height() - kMarginInPixels;
}
y = qMax(kMarginInPixels, y);
tallyContainer->move(x, y);
tallyContainer->show();
}
/**
* Disabling focus on the game view will allow chat to maintain the autofocusing behavior of pre 2.10.3,
* at the cost of disabling the zone view search bar.
*/
void GameView::setFocusDisabled(bool disabled)
{
setFocusPolicy(disabled ? Qt::NoFocus : Qt::ClickFocus);
}

View file

@ -1,18 +1,15 @@
/**
* @file game_view.h
* @ingroup GameGraphics
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef GAMEVIEW_H
#define GAMEVIEW_H
#include "tally/tally.h"
#include <QGraphicsView>
class GameScene;
class QGridLayout;
class QLabel;
class QRubberBand;
@ -24,13 +21,7 @@ private:
QRubberBand *rubberBand;
QLabel *dragCountLabel;
QLabel *totalCountLabel;
QWidget *tallyContainer;
QGridLayout *tallyLayout;
QPointF selectionOrigin;
QList<TallyRow> cachedTallyRows; ///< Cached entries to avoid redundant rebuilds
QSize rebuildTallyLabels(const QList<TallyRow> &entries);
void clearTallyLabels();
protected:
void resizeEvent(QResizeEvent *event) override;
@ -40,7 +31,6 @@ private slots:
void stopRubberBand();
void refreshShortcuts();
void updateTotalSelectionCount(const QSize &viewSize = QSize());
void setFocusDisabled(bool disabled);
public slots:
void updateSceneRect(const QRectF &rect);

View file

@ -1,14 +1,14 @@
/**
* @file hand_counter.h
* @ingroup GameGraphicsPlayers
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef HANDCOUNTER_H
#define HANDCOUNTER_H
#include "board/abstract_graphics_item.h"
#include "board/graphics_item_type.h"
#include "../game_graphics/board/abstract_graphics_item.h"
#include "../game_graphics/board/graphics_item_type.h"
#include <QString>

View file

@ -1,13 +1,13 @@
#include "message_log_widget.h"
#include "../../client/settings/card_counter_settings.h"
#include "../../client/sound_engine.h"
#include "../../game/phase.h"
#include "../../game/player/player_logic.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../board/card_item.h"
#include "../board/translate_counter_name.h"
#include "../phase.h"
#include "../player/player.h"
#include <../../client/settings/card_counter_settings.h>
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
#include <libcockatrice/utility/zone_names.h>
@ -105,7 +105,7 @@ void MessageLogWidget::containerProcessingStarted(const GameEventContext &contex
}
}
void MessageLogWidget::logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal)
void MessageLogWidget::logAlwaysRevealTopCard(Player *player, CardZoneLogic *zone, bool reveal)
{
appendHtmlServerMessage((reveal ? tr("%1 is now keeping the top card %2 revealed.")
: tr("%1 is not revealing the top card %2 any longer."))
@ -113,7 +113,7 @@ void MessageLogWidget::logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
}
void MessageLogWidget::logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal)
void MessageLogWidget::logAlwaysLookAtTopCard(Player *player, CardZoneLogic *zone, bool reveal)
{
appendHtmlServerMessage((reveal ? tr("%1 can now look at top card %2 at any time.")
: tr("%1 no longer can look at top card %2 at any time."))
@ -121,10 +121,7 @@ void MessageLogWidget::logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
}
void MessageLogWidget::logAttachCard(PlayerLogic *player,
QString cardName,
PlayerLogic *targetPlayer,
QString targetCardName)
void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName)
{
appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.")
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
@ -151,7 +148,7 @@ void MessageLogWidget::logUnconcede(int playerId)
true);
}
void MessageLogWidget::logConnectionStateChanged(PlayerLogic *player, bool connectionState)
void MessageLogWidget::logConnectionStateChanged(Player *player, bool connectionState)
{
if (connectionState) {
soundEngine->playSound("player_reconnect");
@ -164,10 +161,10 @@ void MessageLogWidget::logConnectionStateChanged(PlayerLogic *player, bool conne
}
}
void MessageLogWidget::logCreateArrow(PlayerLogic *player,
PlayerLogic *startPlayer,
void MessageLogWidget::logCreateArrow(Player *player,
Player *startPlayer,
QString startCard,
PlayerLogic *targetPlayer,
Player *targetPlayer,
QString targetCard,
bool playerTarget)
{
@ -223,7 +220,7 @@ void MessageLogWidget::logCreateArrow(PlayerLogic *player,
}
}
void MessageLogWidget::logCreateToken(PlayerLogic *player, QString cardName, QString pt, bool faceDown)
void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString pt, bool faceDown)
{
if (faceDown) {
appendHtmlServerMessage(
@ -236,7 +233,7 @@ void MessageLogWidget::logCreateToken(PlayerLogic *player, QString cardName, QSt
}
}
void MessageLogWidget::logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize)
void MessageLogWidget::logDeckSelect(Player *player, QString deckHash, int sideboardSize)
{
if (sideboardSize < 0) {
appendHtmlServerMessage(
@ -249,13 +246,13 @@ void MessageLogWidget::logDeckSelect(PlayerLogic *player, QString deckHash, int
}
}
void MessageLogWidget::logDestroyCard(PlayerLogic *player, QString cardName)
void MessageLogWidget::logDestroyCard(Player *player, QString cardName)
{
appendHtmlServerMessage(
tr("%1 destroys %2.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(std::move(cardName))));
}
void MessageLogWidget::logMoveCard(PlayerLogic *player,
void MessageLogWidget::logMoveCard(Player *player,
CardItem *card,
CardZoneLogic *startZone,
int oldX,
@ -362,7 +359,7 @@ void MessageLogWidget::logMoveCard(PlayerLogic *player,
appendHtmlServerMessage(message);
}
void MessageLogWidget::logDrawCards(PlayerLogic *player, int number, bool deckIsEmpty)
void MessageLogWidget::logDrawCards(Player *player, int number, bool deckIsEmpty)
{
soundEngine->playSound("draw_card");
if (currentContext == MessageContext_Mulligan) {
@ -379,7 +376,7 @@ void MessageLogWidget::logDrawCards(PlayerLogic *player, int number, bool deckIs
}
}
void MessageLogWidget::logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed)
void MessageLogWidget::logDumpZone(Player *player, CardZoneLogic *zone, int numberCards, bool isReversed)
{
if (numberCards == -1) {
appendHtmlServerMessage(tr("%1 is looking at %2.")
@ -395,7 +392,7 @@ void MessageLogWidget::logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int
}
}
void MessageLogWidget::logFlipCard(PlayerLogic *player, QString cardName, bool faceDown)
void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown)
{
if (faceDown) {
appendHtmlServerMessage(
@ -421,7 +418,7 @@ void MessageLogWidget::logGameFlooded()
appendMessage(tr("You are flooding the game. Please wait a couple of seconds."));
}
void MessageLogWidget::logJoin(PlayerLogic *player)
void MessageLogWidget::logJoin(Player *player)
{
soundEngine->playSound("player_join");
appendHtmlServerMessage(tr("%1 has joined the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
@ -438,7 +435,7 @@ void MessageLogWidget::logKicked()
appendHtmlServerMessage(tr("You have been kicked out of the game."), true);
}
void MessageLogWidget::logLeave(PlayerLogic *player, QString reason)
void MessageLogWidget::logLeave(Player *player, QString reason)
{
soundEngine->playSound("player_leave");
appendHtmlServerMessage(tr("%1 has left the game (%2).")
@ -453,13 +450,13 @@ void MessageLogWidget::logLeaveSpectator(QString name, QString reason)
.arg(sanitizeHtml(std::move(name)), sanitizeHtml(std::move(reason))));
}
void MessageLogWidget::logNotReadyStart(PlayerLogic *player)
void MessageLogWidget::logNotReadyStart(Player *player)
{
appendHtmlServerMessage(
tr("%1 is not ready to start the game any more.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
}
void MessageLogWidget::logMulligan(PlayerLogic *player, int number)
void MessageLogWidget::logMulligan(Player *player, int number)
{
if (!player) {
return;
@ -479,16 +476,16 @@ void MessageLogWidget::logReplayStarted(int gameId)
appendHtmlServerMessage(tr("You are watching a replay of game #%1.").arg(gameId));
}
void MessageLogWidget::logReadyStart(PlayerLogic *player)
void MessageLogWidget::logReadyStart(Player *player)
{
appendHtmlServerMessage(tr("%1 is ready to start the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
}
void MessageLogWidget::logRevealCards(PlayerLogic *player,
void MessageLogWidget::logRevealCards(Player *player,
CardZoneLogic *zone,
int cardId,
QString cardName,
PlayerLogic *otherPlayer,
Player *otherPlayer,
bool faceDown,
int amount,
bool isLentToAnotherPlayer)
@ -571,14 +568,14 @@ void MessageLogWidget::logRevealCards(PlayerLogic *player,
}
}
void MessageLogWidget::logReverseTurn(PlayerLogic *player, bool reversed)
void MessageLogWidget::logReverseTurn(Player *player, bool reversed)
{
appendHtmlServerMessage(tr("%1 reversed turn order, now it's %2.")
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
.arg(reversed ? tr("reversed") : tr("normal")));
}
void MessageLogWidget::logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls)
void MessageLogWidget::logRollDie(Player *player, int sides, const QList<uint> &rolls)
{
if (rolls.length() == 1) {
const auto roll = rolls.at(0);
@ -615,7 +612,7 @@ void MessageLogWidget::logRollDie(PlayerLogic *player, int sides, const QList<ui
soundEngine->playSound("roll_dice");
}
void MessageLogWidget::logSay(PlayerLogic *player, QString message)
void MessageLogWidget::logSay(Player *player, QString message)
{
appendMessage(std::move(message), {}, *player->getPlayerInfo()->getUserInfo(), true);
}
@ -630,13 +627,13 @@ void MessageLogWidget::logSetActivePhase(int phaseNumber)
phase.getName() + "</b></font>");
}
void MessageLogWidget::logSetActivePlayer(PlayerLogic *player)
void MessageLogWidget::logSetActivePlayer(Player *player)
{
appendHtml("<br><font color=\"green\"><b>" + QDateTime::currentDateTime().toString("[hh:mm:ss] ") +
QString(tr("%1's turn.")).arg(player->getPlayerInfo()->getName()) + "</b></font><br>");
}
void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation)
void MessageLogWidget::logSetAnnotation(Player *player, CardItem *card, QString newAnnotation)
{
appendHtmlServerMessage(
QString(tr("%1 sets annotation of %2 to %3."))
@ -645,27 +642,25 @@ void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardItem *card, QSt
.arg(QString("&quot;<font class=\"blue\">%1</font>&quot;").arg(sanitizeHtml(std::move(newAnnotation)))));
}
void MessageLogWidget::logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue)
void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int counterId, int value, int oldValue)
{
QString finalStr;
int delta = abs(oldValue - value);
if (value > oldValue) {
finalStr = tr("%1 places %2 %3%4 counter(s) on %5 (now %6).", "", delta);
finalStr = tr("%1 places %2 \"%3\" counter(s) on %4 (now %5).", "", delta);
} else {
finalStr = tr("%1 removes %2 %3%4 counter(s) from %5 (now %6).", "", delta);
finalStr = tr("%1 removes %2 \"%3\" counter(s) from %4 (now %5).", "", delta);
}
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
QString hex = cardCounterSettings.color(counterId).name();
appendHtmlServerMessage(finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
.arg("<font class=\"blue\">" + QString::number(delta) + "</font>")
.arg("<font color=\"" + hex + "\">●</font>")
.arg(cardCounterSettings.displayName(counterId))
.arg(cardLink(std::move(cardName)))
.arg(value));
}
void MessageLogWidget::logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue)
void MessageLogWidget::logSetCounter(Player *player, QString counterName, int value, int oldValue)
{
if (counterName == "life") {
soundEngine->playSound("life_change");
@ -680,7 +675,7 @@ void MessageLogWidget::logSetCounter(PlayerLogic *player, QString counterName, i
.arg(value - oldValue));
}
void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap)
void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap)
{
QString str;
if (doesntUntap) {
@ -691,7 +686,7 @@ void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bo
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName())));
}
void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString newPT)
void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT)
{
if (currentContext == MessageContext_MoveCard) {
return;
@ -718,7 +713,7 @@ void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString new
}
}
void MessageLogWidget::logSetSideboardLock(PlayerLogic *player, bool locked)
void MessageLogWidget::logSetSideboardLock(Player *player, bool locked)
{
if (locked) {
appendHtmlServerMessage(
@ -729,7 +724,7 @@ void MessageLogWidget::logSetSideboardLock(PlayerLogic *player, bool locked)
}
}
void MessageLogWidget::logSetTapped(PlayerLogic *player, CardItem *card, bool tapped)
void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped)
{
if (currentContext == MessageContext_MoveCard) {
return;
@ -752,7 +747,7 @@ void MessageLogWidget::logSetTapped(PlayerLogic *player, CardItem *card, bool ta
}
}
void MessageLogWidget::logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end)
void MessageLogWidget::logShuffle(Player *player, CardZoneLogic *zone, int start, int end)
{
if (currentContext == MessageContext_Mulligan) {
return;
@ -789,14 +784,14 @@ void MessageLogWidget::logSpectatorSay(const ServerInfo_User &spectator, QString
appendMessage(std::move(message), {}, spectator, false);
}
void MessageLogWidget::logUnattachCard(PlayerLogic *player, QString cardName)
void MessageLogWidget::logUnattachCard(Player *player, QString cardName)
{
appendHtmlServerMessage(tr("%1 unattaches %2.")
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
.arg(cardLink(std::move(cardName))));
}
void MessageLogWidget::logUndoDraw(PlayerLogic *player, QString cardName)
void MessageLogWidget::logUndoDraw(Player *player, QString cardName)
{
if (cardName.isEmpty()) {
appendHtmlServerMessage(tr("%1 undoes their last draw.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
@ -808,7 +803,7 @@ void MessageLogWidget::logUndoDraw(PlayerLogic *player, QString cardName)
}
}
void MessageLogWidget::logUndoDrawFailed(PlayerLogic *player)
void MessageLogWidget::logUndoDrawFailed(Player *player)
{
appendHtmlServerMessage(
tr("%1 failed to undo their last draw.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));

View file

@ -0,0 +1,109 @@
/**
* @file message_log_widget.h
* @ingroup GameWidgets
* @brief TODO: Document this.
*/
#ifndef MESSAGELOGWIDGET_H
#define MESSAGELOGWIDGET_H
#include "../../interface/widgets/server/chat_view/chat_view.h"
#include "../zones/logic/card_zone_logic.h"
class AbstractGame;
class CardItem;
class GameEventContext;
class Player;
class PlayerEventHandler;
class MessageLogWidget : public ChatView
{
Q_OBJECT
private:
enum MessageContext
{
MessageContext_None,
MessageContext_MoveCard,
MessageContext_Mulligan
};
MessageContext currentContext;
QString messagePrefix, messageSuffix;
static QPair<QString, QString> getFromStr(CardZoneLogic *zone, QString cardName, int position, bool ownerChange);
public:
void connectToPlayerEventHandler(PlayerEventHandler *player);
MessageLogWidget(TabSupervisor *_tabSupervisor, AbstractGame *_game, QWidget *parent = nullptr);
public slots:
void containerProcessingDone();
void containerProcessingStarted(const GameEventContext &context);
void logAlwaysRevealTopCard(Player *player, CardZoneLogic *zone, bool reveal);
void logAlwaysLookAtTopCard(Player *player, CardZoneLogic *zone, bool reveal);
void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName);
void logConcede(int playerId);
void logUnconcede(int playerId);
void logConnectionStateChanged(Player *player, bool connectionState);
void logCreateArrow(Player *player,
Player *startPlayer,
QString startCard,
Player *targetPlayer,
QString targetCard,
bool playerTarget);
void logCreateToken(Player *player, QString cardName, QString pt, bool faceDown);
void logDeckSelect(Player *player, QString deckHash, int sideboardSize);
void logDestroyCard(Player *player, QString cardName);
void logDrawCards(Player *player, int number, bool deckIsEmpty);
void logDumpZone(Player *player, CardZoneLogic *zone, int numberCards, bool isReversed = false);
void logFlipCard(Player *player, QString cardName, bool faceDown);
void logGameClosed();
void logGameStart();
void logGameFlooded();
void logJoin(Player *player);
void logJoinSpectator(QString name);
void logKicked();
void logLeave(Player *player, QString reason);
void logLeaveSpectator(QString name, QString reason);
void logNotReadyStart(Player *player);
void logMoveCard(Player *player,
CardItem *card,
CardZoneLogic *startZone,
int oldX,
CardZoneLogic *targetZone,
int newX);
void logMulligan(Player *player, int number);
void logReplayStarted(int gameId);
void logReadyStart(Player *player);
void logRevealCards(Player *player,
CardZoneLogic *zone,
int cardId,
QString cardName,
Player *otherPlayer,
bool faceDown,
int amount,
bool isLentToAnotherPlayer);
void logReverseTurn(Player *player, bool reversed);
void logRollDie(Player *player, int sides, const QList<uint> &rolls);
void logSay(Player *player, QString message);
void logSetActivePhase(int phase);
void logSetActivePlayer(Player *player);
void logSetAnnotation(Player *player, CardItem *card, QString newAnnotation);
void logSetCardCounter(Player *player, QString cardName, int counterId, int value, int oldValue);
void logSetCounter(Player *player, QString counterName, int value, int oldValue);
void logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap);
void logSetPT(Player *player, CardItem *card, QString newPT);
void logSetSideboardLock(Player *player, bool locked);
void logSetTapped(Player *player, CardItem *card, bool tapped);
void logShuffle(Player *player, CardZoneLogic *zone, int start, int end);
void logSpectatorSay(const ServerInfo_User &spectator, QString message);
void logUnattachCard(Player *player, QString cardName);
void logUndoDraw(Player *player, QString cardName);
void logUndoDrawFailed(Player *player);
void setContextJudgeName(QString player);
void appendHtmlServerMessage(const QString &html,
bool optionalIsBold = false,
QString optionalFontColor = QString()) override;
};
#endif

View file

@ -1,8 +1,8 @@
/**
* @file phase.h
* @ingroup GameLogic
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef PHASE_H
#define PHASE_H

View file

@ -2,13 +2,13 @@
* @file phases_toolbar.h
* @ingroup GameGraphics
* @ingroup GameWidgets
* @brief TODO: Document this.
*/
//! \todo Document this file.
#ifndef PHASESTOOLBAR_H
#define PHASESTOOLBAR_H
#include "board/abstract_graphics_item.h"
#include "../game_graphics/board/abstract_graphics_item.h"
#include <QFrame>
#include <QGraphicsObject>
@ -21,7 +21,7 @@ namespace protobuf
class Message;
}
} // namespace google
class PlayerLogic;
class Player;
class GameCommand;
class PhaseButton : public QObject, public QGraphicsItem

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