mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 09:33:25 -08:00
Compare commits
10 commits
8fcf04d42d
...
9b2abac9af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b2abac9af | ||
|
|
8a8372e0d7 | ||
|
|
c9bbc2d831 | ||
|
|
b6b6f1ea5d | ||
|
|
51e42a50ca | ||
|
|
31fb173881 | ||
|
|
c2ecd58e99 | ||
|
|
7e71d424f1 | ||
|
|
95e5cda296 | ||
|
|
42a0352477 |
459 changed files with 4434 additions and 14623 deletions
218
.ci/compile.sh
218
.ci/compile.sh
|
|
@ -311,24 +311,16 @@ if [[ $RUNNER_OS == macOS ]]; then
|
|||
|
||||
if [[ $MAKE_PACKAGE ]]; then
|
||||
# Workaround https://github.com/actions/runner-images/issues/7522
|
||||
# have hdiutil repeat the command 10 times in hope of success.
|
||||
# The wrapper has to exit non-zero once it gives up: CPack reads that status to
|
||||
# decide whether the disk image was created, so a zero exit turns a failed hdiutil
|
||||
# into a much later, misleading "Problem copying the package" error that hides
|
||||
# hdiutil's own message.
|
||||
# have hdiutil repeat the command 10 times in hope of success
|
||||
hdiutil_script="/tmp/hdiutil.sh"
|
||||
# shellcheck disable=SC2016
|
||||
echo '#!/bin/bash
|
||||
attempts=10
|
||||
i=0
|
||||
while true; do
|
||||
hdiutil "$@" && exit 0
|
||||
rc=$?
|
||||
if (( ++i >= attempts )); then
|
||||
echo "::error::hdiutil $1 failed $i times (last status $rc), giving up" >&2
|
||||
exit "$rc"
|
||||
while ! hdiutil "$@"; do
|
||||
if (( ++i >= 10 )); then
|
||||
echo "Error: hdiutil failed $i times!" >&2
|
||||
break
|
||||
fi
|
||||
echo "hdiutil $1 attempt $i/$attempts failed (status $rc), retrying" >&2
|
||||
sleep 1
|
||||
done' >"$hdiutil_script"
|
||||
chmod +x "$hdiutil_script"
|
||||
|
|
@ -467,206 +459,6 @@ if [[ $MAKE_COVERAGE ]]; then
|
|||
echo "::endgroup::"
|
||||
fi
|
||||
|
||||
if [[ $RUNNER_OS == Windows && ! $MAKE_NO_CLIENT ]]; then
|
||||
echo "::group::Probe the installer's holder lookup"
|
||||
# The working directory is still the build dir here: the package steps below are what
|
||||
# leave and re-enter it, and that is what made a $BUILD_DIR-prefixed path name
|
||||
# build/build. Both paths are relative to the dir the probe was built into.
|
||||
probe="./installer-holder-probe.exe"
|
||||
if [[ ! -f $probe ]]; then
|
||||
echo "::error file=$0::installer-holder-probe.exe was not built"
|
||||
exit 1
|
||||
fi
|
||||
# The probe exists to name a holder that a process-and-module scan cannot see: one
|
||||
# that has a file open without having loaded it. Holding a temporary DLL with
|
||||
# FileShare.None is exactly that case, so this asserts the reason the probe was
|
||||
# added instead of only that the Restart Manager answers at all. It needs no NSIS
|
||||
# and no packaging, so it runs on every Windows build that gets this far.
|
||||
# The holder is a process of its own: the probe never names the process that started it,
|
||||
# which is what keeps an in-place uninstaller from being named as a holder of the
|
||||
# directory it is emptying. The same DLL held by the script that starts the probe
|
||||
# therefore has to come back as nothing, and that is the second case below.
|
||||
probe_check="./holder-probe-check.ps1"
|
||||
cat >"$probe_check" <<'POWERSHELL'
|
||||
$ErrorActionPreference = "Stop"
|
||||
$dir = Join-Path ([IO.Path]::GetTempPath()) "cockatrice-holder-probe-$PID"
|
||||
Remove-Item -Recurse -Force $dir -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force $dir | Out-Null
|
||||
$probe = (Resolve-Path -LiteralPath $env:PROBE_EXE).Path
|
||||
|
||||
function Invoke-Probe([string] $guardDir) {
|
||||
$start = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$start.FileName = $probe
|
||||
$start.UseShellExecute = $false
|
||||
$start.RedirectStandardOutput = $true
|
||||
$start.EnvironmentVariables["COCKATRICE_GUARD_DIR"] = $guardDir
|
||||
$process = [System.Diagnostics.Process]::Start($start)
|
||||
$read = $process.StandardOutput.ReadToEndAsync()
|
||||
if (-not $process.WaitForExit(20000)) {
|
||||
try { $process.Kill() } catch { }
|
||||
throw "the holder probe did not finish within 20 s for $guardDir"
|
||||
}
|
||||
$output = $read.Result
|
||||
$code = $process.ExitCode
|
||||
$process.Dispose()
|
||||
return @{ Code = $code; Output = $output }
|
||||
}
|
||||
|
||||
function Wait-UntilLocked([string] $path) {
|
||||
$deadline = (Get-Date).AddSeconds(15)
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
try {
|
||||
$open = [IO.File]::Open($path, "Open", "ReadWrite", "None")
|
||||
$open.Dispose()
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
throw "the holder never locked $path"
|
||||
}
|
||||
|
||||
try {
|
||||
$file = Join-Path $dir "locked.dll"
|
||||
[IO.File]::WriteAllText($file, "x")
|
||||
|
||||
# The holder is a process of its own, not this script: the probe never names the process
|
||||
# that started it (the case below asserts that), so a file held here would be left out on
|
||||
# purpose and the check would pass for the wrong reason.
|
||||
$holderScript = Join-Path $dir "hold.ps1"
|
||||
Set-Content -LiteralPath $holderScript -Value @'
|
||||
param([string] $Path)
|
||||
$handle = [IO.File]::Open($Path, "Open", "ReadWrite", "None")
|
||||
Start-Sleep -Seconds 120
|
||||
'@
|
||||
$powershell = Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||
$holder = Start-Process -FilePath $powershell -PassThru -ArgumentList @(
|
||||
"-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "`"$holderScript`"", "-Path", "`"$file`"")
|
||||
try {
|
||||
Wait-UntilLocked $file
|
||||
$locked = Invoke-Probe $dir
|
||||
if ($locked.Code -ne 1) { throw "expected exit 1 for a locked file, got $($locked.Code) : $($locked.Output)" }
|
||||
if ($locked.Output -notmatch "pid\s+$($holder.Id)\b") {
|
||||
throw "the lookup did not name the process holding the file: $($locked.Output)"
|
||||
}
|
||||
} finally {
|
||||
try { $holder.Kill() } catch { }
|
||||
try { $holder.WaitForExit(5000) | Out-Null } catch { }
|
||||
}
|
||||
|
||||
# The probe is started by the installer, or by an uninstaller that runs in place from the
|
||||
# directory it is emptying, so the asking process holds files there itself. Naming it would
|
||||
# ask the user to close the program that is asking - a question neither the close nor the
|
||||
# end offer can answer, so the guard repeated it until the update was cancelled. A holder
|
||||
# that is only the asking process has to come back as nothing.
|
||||
$handle = [IO.File]::Open($file, "Open", "ReadWrite", "None")
|
||||
try {
|
||||
$self = Invoke-Probe $dir
|
||||
} finally {
|
||||
$handle.Dispose()
|
||||
}
|
||||
if ($self.Code -ne 0) { throw "expected exit 0 when the asking process is the only holder, got $($self.Code) : $($self.Output)" }
|
||||
if ($self.Output -match "pid\s+$PID\b") { throw "the lookup named the process that started it: $($self.Output)" }
|
||||
|
||||
# A payload executable that refuses to be replaced is running, whether or not this probe
|
||||
# may name it: the Restart Manager does not report every mapping, and the image path of a
|
||||
# process under another account cannot be read from here, so both process lookups can
|
||||
# come back empty while the program is still there. Held here by the asking process, so
|
||||
# that it cannot be named - the answer has to be "could not name it", never "nothing is
|
||||
# holding it", which is what sent an update into an uninstall that could only fail
|
||||
# halfway. Exit 3 is the code the guard answers by asking the user to close it and retry.
|
||||
$image = Join-Path $dir "oracle.exe"
|
||||
[IO.File]::WriteAllText($image, "x")
|
||||
$handle = [IO.File]::Open($image, "Open", "ReadWrite", "None")
|
||||
try {
|
||||
$unnameable = Invoke-Probe $dir
|
||||
} finally {
|
||||
$handle.Dispose()
|
||||
}
|
||||
if ($unnameable.Code -ne 3) {
|
||||
throw "expected exit 3 for a payload executable that is in use but cannot be named, got $($unnameable.Code) : $($unnameable.Output)"
|
||||
}
|
||||
if ($unnameable.Output -notmatch "oracle\.exe is in use") {
|
||||
throw "the answer did not name the executable it could not replace: $($unnameable.Output)"
|
||||
}
|
||||
|
||||
$empty = Join-Path $dir "empty"
|
||||
New-Item -ItemType Directory -Force $empty | Out-Null
|
||||
$nothing = Invoke-Probe $empty
|
||||
if ($nothing.Code -ne 0) { throw "expected exit 0 for a directory with nothing open, got $($nothing.Code) : $($nothing.Output)" }
|
||||
# A process running from the directory is a holder even when it has no file open: an
|
||||
# instance holds its payload as mapped images, not as handles, and that is the state
|
||||
# the guard used to miss - it passed, the purge failed, and the install ended in a
|
||||
# warning with no offer to close and try again. The image is a copy of a native
|
||||
# Windows program, so it starts without its usual directory next to it, and it carries
|
||||
# one of the payload's own names because that is what the lookup names.
|
||||
$copy = Join-Path $dir "cockatrice.exe"
|
||||
Copy-Item -LiteralPath (Join-Path $env:SystemRoot "System32\cmd.exe") -Destination $copy
|
||||
$running = Start-Process -FilePath $copy -ArgumentList "/c", "ping -n 20 127.0.0.1 >nul" -PassThru
|
||||
try {
|
||||
Start-Sleep -Milliseconds 1500
|
||||
$byImage = Invoke-Probe $dir
|
||||
} finally {
|
||||
try { $running.Kill() } catch { }
|
||||
# Wait for the image to be released, or the cleanup below leaves the copy behind.
|
||||
try { $running.WaitForExit(5000) | Out-Null } catch { }
|
||||
}
|
||||
if ($byImage.Code -ne 1) { throw "expected exit 1 for a process running from the directory, got $($byImage.Code) : $($byImage.Output)" }
|
||||
if ($byImage.Output -notmatch "cockatrice\.exe \(pid\s+$($running.Id)") {
|
||||
throw "the lookup did not name the process running from the directory: $($byImage.Output)"
|
||||
}
|
||||
|
||||
# A program in a folder below the directory is not an instance of the installation, even
|
||||
# when it carries a payload program's name: the install directory can be a folder the
|
||||
# user keeps other applications in, each in its own subfolder, and naming one of those
|
||||
# asked for a close the probe never sends and an end it refuses to perform, so the guard
|
||||
# could only abort the update. A program that really does hold a payload file is still
|
||||
# named, by the Restart Manager lookup exercised above.
|
||||
$nested = Join-Path $dir "other"
|
||||
New-Item -ItemType Directory -Force $nested | Out-Null
|
||||
$nestedImage = Join-Path $nested "cockatrice.exe"
|
||||
Copy-Item -LiteralPath (Join-Path $env:SystemRoot "System32\cmd.exe") -Destination $nestedImage
|
||||
$nestedRunning = Start-Process -FilePath $nestedImage -ArgumentList "/c", "ping -n 20 127.0.0.1 >nul" -PassThru
|
||||
try {
|
||||
Start-Sleep -Milliseconds 1500
|
||||
$inSubfolder = Invoke-Probe $dir
|
||||
} finally {
|
||||
try { $nestedRunning.Kill() } catch { }
|
||||
try { $nestedRunning.WaitForExit(5000) | Out-Null } catch { }
|
||||
}
|
||||
if ($inSubfolder.Code -ne 0) {
|
||||
throw "expected exit 0 for a program in a folder below the directory, got $($inSubfolder.Code) : $($inSubfolder.Output)"
|
||||
}
|
||||
|
||||
# A program the user keeps in the directory itself is not a payload program either: the
|
||||
# guard ends only what the payload installs, and naming anything else asks for an answer
|
||||
# that cannot free a single file.
|
||||
$foreign = Join-Path $dir "tool.exe"
|
||||
Copy-Item -LiteralPath (Join-Path $env:SystemRoot "System32\cmd.exe") -Destination $foreign
|
||||
$foreignRunning = Start-Process -FilePath $foreign -ArgumentList "/c", "ping -n 20 127.0.0.1 >nul" -PassThru
|
||||
try {
|
||||
Start-Sleep -Milliseconds 1500
|
||||
$ignored = Invoke-Probe $dir
|
||||
} finally {
|
||||
try { $foreignRunning.Kill() } catch { }
|
||||
try { $foreignRunning.WaitForExit(5000) | Out-Null } catch { }
|
||||
}
|
||||
if ($ignored.Code -ne 0) {
|
||||
throw "expected exit 0 for a program the payload does not install, got $($ignored.Code) : $($ignored.Output)"
|
||||
}
|
||||
Write-Host "holder lookup named pid $($holder.Id) for a file another process holds, named nothing for a file only the asking process holds, reported a payload executable it could not name as in use instead of free, named nothing for an empty directory, named pid $($running.Id) for a payload program running from the directory, and named nothing for a payload program in a folder below it or for a program the payload does not install"
|
||||
} finally {
|
||||
Remove-Item -Recurse -Force $dir -ErrorAction SilentlyContinue
|
||||
}
|
||||
POWERSHELL
|
||||
if ! PROBE_EXE="$probe" powershell -NoProfile -File "$probe_check"; then
|
||||
rm -f "$probe_check"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$probe_check"
|
||||
echo "::endgroup::"
|
||||
fi
|
||||
|
||||
if [[ $MAKE_INSTALL ]]; then
|
||||
echo "::group::Install"
|
||||
cmake --build . --target install --config "$BUILDTYPE"
|
||||
|
|
|
|||
40
.github/workflows/desktop-build.yml
vendored
40
.github/workflows/desktop-build.yml
vendored
|
|
@ -101,36 +101,6 @@ jobs:
|
|||
--title "$release_name" \
|
||||
--notes-file "$body_path"
|
||||
|
||||
vcpkg-baseline:
|
||||
name: vcpkg baseline
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v7
|
||||
|
||||
# vcpkg-tool reads versions/baseline.json out of the commit named by
|
||||
# `builtin-baseline`, through the `vcpkg` submodule's git history. A submodule
|
||||
# pointer that lags the manifest - e.g. a stale `vcpkg/` worktree captured by
|
||||
# `git add` in a PR - makes every vcpkg leg fail in configure with "failed to
|
||||
# `git show` versions/baseline.json". That reads like a baseline or network
|
||||
# problem, when the pointer is what has to move. Check the two agree here in
|
||||
# seconds instead of on five build legs.
|
||||
- name: "Check the submodule pointer against the manifest baseline"
|
||||
shell: bash
|
||||
run: |
|
||||
pointer="$(git rev-parse HEAD:vcpkg 2>/dev/null || true)"
|
||||
baseline="$(sed -nE 's/.*"builtin-baseline"[[:space:]]*:[[:space:]]*"([0-9a-f]{40})".*/\1/p' vcpkg.json)"
|
||||
if [[ -z "$pointer" || -z "$baseline" ]]; then
|
||||
echo "::error file=vcpkg.json::could not read the vcpkg submodule pointer or the builtin-baseline"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$pointer" != "$baseline" ]]; then
|
||||
echo "::error file=vcpkg.json::vcpkg submodule is at $pointer but builtin-baseline is $baseline"
|
||||
echo "Move them together: git -C vcpkg checkout $baseline && git add vcpkg"
|
||||
exit 1
|
||||
fi
|
||||
echo "vcpkg submodule and builtin-baseline agree on $baseline"
|
||||
|
||||
build-linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
|
@ -496,7 +466,7 @@ jobs:
|
|||
vcpkg_upload: 1 # only one leg per vcpkg_scope hands its archives over
|
||||
|
||||
name: ${{ matrix.os }} ${{ matrix.target }}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
||||
needs: [configure, vcpkg-baseline]
|
||||
needs: configure
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 100
|
||||
env:
|
||||
|
|
@ -614,17 +584,11 @@ jobs:
|
|||
# job. A scope nobody has written to yet therefore leaves the directory missing
|
||||
# and fails the job, which is exactly the state every scope starts in. Make the
|
||||
# directory up front so an empty scope is a cache miss instead of an error.
|
||||
# always() covers the cache step itself failing: the action's post save still runs
|
||||
# then, and it should report the real error instead of ENOENT. It cannot rescue a
|
||||
# failure before the cache step, since a post step only runs for an action whose
|
||||
# main step did. The fallback keeps this guard from failing when the cache step was
|
||||
# skipped and left no path output.
|
||||
- name: "Create vcpkg cache directory"
|
||||
if: always()
|
||||
shell: bash
|
||||
env:
|
||||
CACHE_DIR: '${{ steps.vcpkg-cache.outputs.path }}'
|
||||
run: mkdir -p "${CACHE_DIR:-$GITHUB_WORKSPACE/.vcpkg-cache}"
|
||||
run: mkdir -p "$CACHE_DIR"
|
||||
|
||||
# Uses environment variables, see compile.sh for more details
|
||||
- name: "Build Cockatrice"
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ endif()
|
|||
|
||||
# A project name is needed for CPack
|
||||
# Version can be overriden by git tags, see cmake/getversion.cmake
|
||||
project("Cockatrice" VERSION 3.2.0)
|
||||
project("Cockatrice" VERSION 3.1.2)
|
||||
|
||||
# Set release name if not provided via env/cmake var
|
||||
if(NOT DEFINED GIT_TAG_RELEASENAME)
|
||||
|
|
@ -250,22 +250,7 @@ message(STATUS "Update Translations: ${UPDATE_TRANSLATIONS}")
|
|||
|
||||
include(FindQtRuntime)
|
||||
|
||||
# Reject APIs that were deprecated before the oldest Qt release we support
|
||||
# (6.4). Qt 6.5 renamed the switch, so use whichever spelling the found
|
||||
# version understands while still compiling everywhere.
|
||||
if(Qt6_VERSION VERSION_GREATER_EQUAL 6.5)
|
||||
add_compile_definitions(QT_DISABLE_DEPRECATED_UP_TO=0x060400)
|
||||
else()
|
||||
add_compile_definitions(QT_DISABLE_DEPRECATED_BEFORE=0x060400)
|
||||
endif()
|
||||
|
||||
# Set once here for every target: these variables are inherited by the
|
||||
# subdirectories, so the per-directory copies were redundant. Only the
|
||||
# variables are set; qt_standard_project_setup would also change the runtime
|
||||
# output directories and the install RPATH.
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
set(CMAKE_AUTOUIC TRUE)
|
||||
set(CMAKE_AUTORCC TRUE)
|
||||
|
||||
# Find other needed libraries
|
||||
find_package(Protobuf CONFIG)
|
||||
|
|
@ -435,9 +420,6 @@ if(WITH_ORACLE OR WITH_CLIENT)
|
|||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_models ${CMAKE_BINARY_DIR}/libcockatrice_models)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_filters ${CMAKE_BINARY_DIR}/libcockatrice_filters)
|
||||
endif()
|
||||
if(WITH_CLIENT)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/libcockatrice_game ${CMAKE_BINARY_DIR}/libcockatrice_game)
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER)
|
||||
add_subdirectory(servatrice)
|
||||
|
|
@ -449,13 +431,6 @@ if(WITH_CLIENT)
|
|||
set(CPACK_INSTALL_CMAKE_PROJECTS "Cockatrice;Cockatrice;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND WITH_CLIENT)
|
||||
# Runs from the installer's $PLUGINSDIR when a purge fails, and is never installed
|
||||
# (see LogProcessesUsingInstallDir in cmake/NSIS.template.in), so it has no install
|
||||
# rules and is not part of the client's staged tree.
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/tools/installer-holder-probe ${CMAKE_BINARY_DIR}/tools/installer-holder-probe)
|
||||
endif()
|
||||
|
||||
if(WITH_ORACLE)
|
||||
add_subdirectory(oracle)
|
||||
set(CPACK_INSTALL_CMAKE_PROJECTS "Oracle;Oracle;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
||||
|
|
@ -468,5 +443,5 @@ endif()
|
|||
|
||||
if(Qt6_FOUND AND Qt6_VERSION_MINOR GREATER_EQUAL 3)
|
||||
# Qt6.3+ requires project finalization to support translations
|
||||
qt_finalize_project()
|
||||
qt6_finalize_project()
|
||||
endif()
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -15,10 +15,9 @@
|
|||
---
|
||||
|
||||
<br><pre><p align='center'>
|
||||
<b>To get started with Cockatrice ⇢ [view our webpage](https://cockatrice.github.io/)</b>
|
||||
<b>To get support, or suggest changes to the app ⇢ [file an issue](https://github.com/Cockatrice/Cockatrice/issues) ([How?](https://github.com/Cockatrice/Cockatrice/wiki/How-to-Create-a-GitHub-Ticket-Regarding-Cockatrice))</b><br>
|
||||
<b>To learn about the app and its code ⇢ [read our code documentation](https://cockatrice.github.io/docs/)</b>
|
||||
<b>To help with development ⇢ learn [how to contribute](#contribute)</b>
|
||||
<b>To get started with Cockatrice ⇢ [view our webpage](https://cockatrice.github.io/)</b><br>
|
||||
<b>To get support, or suggest changes to the app ⇢ [file an issue](https://github.com/Cockatrice/Cockatrice/issues) ([How?](https://github.com/Cockatrice/Cockatrice/wiki/How-to-Create-a-GitHub-Ticket-Regarding-Cockatrice))</b>
|
||||
<b>To help with development ⇢ learn [how to contribute](#contribute-)</b>
|
||||
</pre><p><br>
|
||||
|
||||
|
||||
|
|
@ -84,7 +83,7 @@ Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other p
|
|||
|
||||
### Code
|
||||
|
||||
To commit code to the project, please review our [Contribution Guidelines](https://github.com/Cockatrice/Cockatrice/blob/master/.github/CONTRIBUTING.md) first.<br>
|
||||
To contribute code to the project, please review our [guidelines](https://github.com/Cockatrice/Cockatrice/blob/master/.github/CONTRIBUTING.md) first.<br>
|
||||
We maintain two tags for contributors to easier find issues to potentially work on:
|
||||
- [](https://github.com/Cockatrice/Cockatrice/issues?utf8=%E2%9C%93&q=is%3Aopen%20is%3Aissue%20label%3A%22Good%20first%20issue%22%20)<br>
|
||||
Issues tagged in this way provide a simple way to get started. They don't require much experience to be worked on.
|
||||
|
|
@ -96,7 +95,7 @@ We'll happily advice on how best to implement a feature, or we can show you wher
|
|||
|
||||
You can also have a look at our `Todo List` in our [Code Documentation](https://cockatrice.github.io/docs) or search the repo for [`\todo` comments](https://github.com/search?q=repo%3ACockatrice%2FCockatrice%20%5Ctodo&type=code).
|
||||
|
||||
### Documentation [](https://github.com/Cockatrice/Cockatrice/actions/workflows/documentation-build.yml?query=event%3Arelease+event%3Aworkflow_dispatch)
|
||||
### Documentation [](https://github.com/Cockatrice/Cockatrice/actions/workflows/documentation-build.yml?query=event%3Apush)
|
||||
|
||||
There are various places where useful information for different needs are maintained:
|
||||
- [Official Code Documentation](https://cockatrice.github.io/docs/)
|
||||
|
|
@ -105,8 +104,7 @@ There are various places where useful information for different needs are mainta
|
|||
- [Official README](https://github.com/Cockatrice/Cockatrice/blob/master/README.md) `This file`
|
||||
- [Official CONTRIBUTING](https://github.com/Cockatrice/Cockatrice/blob/master/.github/CONTRIBUTING.md)
|
||||
|
||||
Cockatrice tries to use the [Google Developer Documentation Style Guide](https://developers.google.com/style/) to ensure consistent documentation.
|
||||
We encourage everybody to improve the documentation by suggesting edits based on this guide.
|
||||
Cockatrice tries to use the [Google Developer Documentation Style Guide](https://developers.google.com/style/) to ensure consistent documentation. We encourage you to improve the documentation by suggesting edits based on this guide.
|
||||
|
||||
### Translation [](https://explore.transifex.com/cockatrice/cockatrice/)
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -57,29 +57,6 @@ try {
|
|||
}
|
||||
}
|
||||
|
||||
# --- What was holding the files, read from the log as well -------------------
|
||||
# The guard and the close attempt each log one line naming every holder and what
|
||||
# happened to it. Carrying the last of each as event data keeps an abort caused by
|
||||
# a running instance actionable without opening the attachment. Kept out of the
|
||||
# message so the issue still groups on the reason alone.
|
||||
$Holders = ''
|
||||
$CloseResult = ''
|
||||
$EndResult = ''
|
||||
if (Test-Path -LiteralPath $LogPath) {
|
||||
$holderLine = Select-String -LiteralPath $LogPath -Pattern 'guard: still in use by (.*)$' | Select-Object -Last 1
|
||||
if ($holderLine) {
|
||||
$Holders = $holderLine.Matches[0].Groups[1].Value
|
||||
}
|
||||
$closeLine = Select-String -LiteralPath $LogPath -Pattern '(close-holders: .*)$' | Select-Object -Last 1
|
||||
if ($closeLine) {
|
||||
$CloseResult = $closeLine.Matches[0].Groups[1].Value
|
||||
}
|
||||
$endLine = Select-String -LiteralPath $LogPath -Pattern '(end-holders: .*)$' | Select-Object -Last 1
|
||||
if ($endLine) {
|
||||
$EndResult = $endLine.Matches[0].Groups[1].Value
|
||||
}
|
||||
}
|
||||
|
||||
# --- Event ---------------------------------------------------------------
|
||||
$eventId = [guid]::NewGuid().ToString('N')
|
||||
$now = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
|
||||
|
|
@ -98,9 +75,6 @@ try {
|
|||
extra = @{
|
||||
reason = $Reason
|
||||
os = [System.Environment]::OSVersion.VersionString
|
||||
holders = $Holders
|
||||
close_result = $CloseResult
|
||||
end_result = $EndResult
|
||||
}
|
||||
}
|
||||
$eventJson = $sentryEvent | ConvertTo-Json -Compress -Depth 6
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ set(cockatrice_SOURCES
|
|||
src/client/settings/shortcut_treeview.cpp
|
||||
src/client/settings/shortcuts_settings.cpp
|
||||
src/interface/deck_loader/card_node_function.cpp
|
||||
src/interface/deck_loader/deck_file_format.cpp
|
||||
src/interface/deck_loader/deck_loader.cpp
|
||||
src/interface/deck_loader/loaded_deck.cpp
|
||||
src/interface/widgets/dialogs/dlg_connect.cpp
|
||||
src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp
|
||||
src/interface/widgets/dialogs/dlg_create_game.cpp
|
||||
|
|
@ -69,27 +71,36 @@ set(cockatrice_SOURCES
|
|||
src/filters/filter_builder.cpp
|
||||
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_registry.cpp
|
||||
src/game_graphics/board/arrow_target.cpp
|
||||
src/game_graphics/board/card_drag_item.cpp
|
||||
src/game_graphics/board/card_item.cpp
|
||||
src/game/board/card_list.cpp
|
||||
src/game/board/card_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_annotation.cpp
|
||||
src/game_graphics/dialogs/dlg_create_token.cpp
|
||||
src/game_graphics/dialogs/dlg_move_top_cards_until.cpp
|
||||
src/game_graphics/dialogs/dlg_roll_dice.cpp
|
||||
src/game/game.cpp
|
||||
src/game/game_event_handler.cpp
|
||||
src/game/game_meta_info.cpp
|
||||
src/game_graphics/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/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
|
||||
|
|
@ -107,11 +118,23 @@ set(cockatrice_SOURCES
|
|||
src/game_graphics/tally/stats_tally.cpp
|
||||
src/game_graphics/tally/subtype_tally.cpp
|
||||
src/game_graphics/tally/tally.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_event_handler.cpp
|
||||
src/game_graphics/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_manager.cpp
|
||||
src/game_graphics/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
|
||||
|
|
@ -172,7 +195,6 @@ set(cockatrice_SOURCES
|
|||
src/interface/widgets/cards/card_info_picture_widget.cpp
|
||||
src/interface/widgets/cards/card_info_picture_with_text_overlay_widget.cpp
|
||||
src/interface/widgets/cards/card_info_text_widget.cpp
|
||||
src/interface/widgets/cards/card_picture_delegate.cpp
|
||||
src/interface/widgets/cards/card_size_widget.cpp
|
||||
src/interface/widgets/cards/deck_card_zone_display_widget.cpp
|
||||
src/interface/widgets/cards/deck_preview_card_picture_widget.cpp
|
||||
|
|
@ -292,7 +314,6 @@ set(cockatrice_SOURCES
|
|||
src/interface/widgets/utility/sequence_edit.cpp
|
||||
src/interface/widgets/utility/visibility_change_listener.cpp
|
||||
src/interface/widgets/utility/visibility_change_listener.h
|
||||
src/interface/widgets/visual_database_display/card_database_visual_view.cpp
|
||||
src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp
|
||||
src/interface/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
||||
src/interface/widgets/visual_database_display/visual_database_display_filter_toolbar_widget.cpp
|
||||
|
|
@ -325,7 +346,6 @@ set(cockatrice_SOURCES
|
|||
src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.cpp
|
||||
src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.cpp
|
||||
src/interface/window_main.cpp
|
||||
src/installer_close_server.cpp
|
||||
src/main.cpp
|
||||
src/single_instance_manager.cpp
|
||||
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
|
||||
|
|
@ -431,7 +451,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/installer_close_server.h
|
||||
src/single_instance_manager.h
|
||||
src/client/url_scheme_event_filter.h
|
||||
src/interface/intents/intent_connect_to_server.cpp
|
||||
|
|
@ -493,7 +512,7 @@ if(APPLE)
|
|||
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
|
||||
endif(APPLE)
|
||||
|
||||
qt_add_resources(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
|
||||
qt6_add_resources(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
|
||||
|
||||
# Declare path variables
|
||||
set(ICONDIR
|
||||
|
|
@ -514,7 +533,7 @@ set(COCKATRICE_MAC_QM_INSTALL_DIR "cockatrice.app/Contents/Resources/translation
|
|||
set(COCKATRICE_UNIX_QM_INSTALL_DIR "share/cockatrice/translations")
|
||||
set(COCKATRICE_WIN32_QM_INSTALL_DIR "translations")
|
||||
|
||||
qt_add_executable(
|
||||
qt6_add_executable(
|
||||
cockatrice
|
||||
WIN32
|
||||
MACOSX_BUNDLE
|
||||
|
|
@ -526,7 +545,7 @@ qt_add_executable(
|
|||
|
||||
target_precompile_headers(cockatrice PRIVATE "${CMAKE_SOURCE_DIR}/cmake/pch/qtwidgets_pch.h")
|
||||
|
||||
qt_add_shaders(
|
||||
qt6_add_shaders(
|
||||
cockatrice
|
||||
"onboarding_shaders"
|
||||
PREFIX
|
||||
|
|
@ -538,7 +557,7 @@ qt_add_shaders(
|
|||
src/interface/widgets/onboarding/shaders/brand_plate.frag
|
||||
)
|
||||
|
||||
qt_add_resources(
|
||||
qt6_add_resources(
|
||||
cockatrice
|
||||
"onboarding_qml"
|
||||
PREFIX
|
||||
|
|
@ -554,7 +573,6 @@ target_link_libraries(
|
|||
PUBLIC libcockatrice_card
|
||||
libcockatrice_deck_list
|
||||
libcockatrice_filters
|
||||
libcockatrice_game
|
||||
libcockatrice_utility
|
||||
libcockatrice_network
|
||||
libcockatrice_models
|
||||
|
|
@ -771,7 +789,7 @@ endif()
|
|||
if(Qt6LinguistTools_FOUND)
|
||||
#Qt6 Translations happen after the executable is built up
|
||||
if(UPDATE_TRANSLATIONS)
|
||||
qt_add_translations(
|
||||
qt6_add_translations(
|
||||
cockatrice
|
||||
TS_FILES
|
||||
${cockatrice_TS}
|
||||
|
|
@ -781,7 +799,7 @@ if(Qt6LinguistTools_FOUND)
|
|||
cockatrice_QM
|
||||
)
|
||||
else()
|
||||
qt_add_translations(cockatrice TS_FILES ${cockatrice_TS} QM_FILES_OUTPUT_VARIABLE cockatrice_QM)
|
||||
qt6_add_translations(cockatrice TS_FILES ${cockatrice_TS} QM_FILES_OUTPUT_VARIABLE cockatrice_QM)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
|
|
@ -807,4 +825,4 @@ if(Qt6LinguistTools_FOUND)
|
|||
endforeach()
|
||||
endif()
|
||||
|
||||
qt_finalize_target(cockatrice)
|
||||
qt6_finalize_target(cockatrice)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QVBoxLayout>
|
||||
#include <libcockatrice/utility/qt_utils.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
LatencyStatusWidget::LatencyStatusWidget(QWidget *parent) : QWidget(parent)
|
||||
|
|
@ -25,7 +24,9 @@ LatencyStatusWidget::LatencyStatusWidget(QWidget *parent) : QWidget(parent)
|
|||
latencyGraph = new LatencyGraphWidget(this);
|
||||
latencyGraph->setFixedSize(90, 14);
|
||||
|
||||
auto *layout = QtUtils::makeLayout<QHBoxLayout>(this, 4);
|
||||
auto *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(4);
|
||||
layout->addWidget(latencyGraph);
|
||||
layout->addWidget(pingLabel);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include "../../../interface/pixel_map_generator.h"
|
||||
#include "../../settings/cache_settings.h"
|
||||
#include "../interface/widgets/dialogs/dlg_connect.h"
|
||||
#include "../interface/widgets/dialogs/dlg_edit_password.h"
|
||||
#include "../interface/widgets/dialogs/dlg_forgot_password_challenge.h"
|
||||
#include "../interface/widgets/dialogs/dlg_forgot_password_request.h"
|
||||
#include "../interface/widgets/dialogs/dlg_forgot_password_reset.h"
|
||||
|
|
@ -25,7 +24,6 @@
|
|||
#include <libcockatrice/network/client/remote/remote_client.h>
|
||||
#include <libcockatrice/protocol/pb/response.pb.h>
|
||||
#include <libcockatrice/settings/servers_settings.h>
|
||||
#include <libcockatrice/utility/qt_utils.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
class QWidget;
|
||||
|
|
@ -100,10 +98,6 @@ void ConnectionController::wireClientSignals()
|
|||
|
||||
connect(remoteClient, &RemoteClient::sigPasswordVerifierReady, this,
|
||||
&ConnectionController::onPasswordVerifierReady);
|
||||
|
||||
connect(remoteClient, &RemoteClient::sigPasswordChangeSuccess, this,
|
||||
&ConnectionController::onPasswordChangeSuccess);
|
||||
connect(remoteClient, &RemoteClient::sigPasswordChangeError, this, &ConnectionController::onPasswordChangeError);
|
||||
}
|
||||
|
||||
void ConnectionController::connectToServer()
|
||||
|
|
@ -249,27 +243,17 @@ void ConnectionController::onLoginError(int r,
|
|||
{
|
||||
switch (static_cast<Response::ResponseCode>(r)) {
|
||||
case Response::RespClientUpdateRequired: {
|
||||
QString formatted = "Missing Features: ";
|
||||
for (int i = 0; i < missingFeatures.size(); ++i) {
|
||||
formatted.append(QString("\n %1").arg(QChar(0x2022)) + " " + missingFeatures.value(i));
|
||||
}
|
||||
|
||||
QMessageBox msgBox(dialogParent);
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setWindowTitle(tr("Failed Login"));
|
||||
|
||||
if (missingFeatures.isEmpty()) {
|
||||
// Without a feature list this is either a login the client stopped itself or a
|
||||
// strict server asking for a password; the reason string already says which and
|
||||
// what to do. No client update can fix any of those causes, so show it instead of
|
||||
// the update advice.
|
||||
msgBox.setText(reasonStr.isEmpty() ? tr("The login did not complete.") : reasonStr);
|
||||
} else {
|
||||
QString formatted = tr("Missing Features:");
|
||||
for (const QString &feature : missingFeatures) {
|
||||
formatted.append(QString("\n %1 ").arg(QChar(0x2022)) + feature);
|
||||
}
|
||||
|
||||
msgBox.setText(tr("Your client seems to be missing features this server requires for connection.") +
|
||||
"\n\n" + tr("To update your client, go to 'Help -> Check for Client Updates'."));
|
||||
msgBox.setDetailedText(formatted);
|
||||
}
|
||||
|
||||
msgBox.setText(tr("Your client seems to be missing features this server requires for connection.") +
|
||||
"\n\n" + tr("To update your client, go to 'Help -> Check for Client Updates'."));
|
||||
msgBox.setDetailedText(formatted);
|
||||
msgBox.exec();
|
||||
break;
|
||||
}
|
||||
|
|
@ -316,8 +300,9 @@ void ConnectionController::onLoginError(int r,
|
|||
}
|
||||
|
||||
case Response::RespRegistrationRequired: {
|
||||
if (QtUtils::confirm(dialogParent, tr("Error"),
|
||||
tr("This server requires user registration. Do you want to register now?"))) {
|
||||
if (QMessageBox::question(dialogParent, tr("Error"),
|
||||
tr("This server requires user registration. Do you want to register now?"),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
registerToServer();
|
||||
}
|
||||
return; // don't re-prompt connect
|
||||
|
|
@ -356,16 +341,10 @@ void ConnectionController::onLoginError(int r,
|
|||
}
|
||||
|
||||
case Response::RespPasswordChangeRequired: {
|
||||
// The credentials were right, but the account may not be used until a new password
|
||||
// is chosen. Let the user complete the change here: sending them off to "ask the
|
||||
// administrator for your temporary password" sends them in circles, since they just
|
||||
// logged in with it and the session ends without a way to comply.
|
||||
DlgEditPassword dlg(dialogParent);
|
||||
dlg.setWindowTitle(tr("Password Change Required"));
|
||||
if (dlg.exec()) {
|
||||
remoteClient->changePasswordToServer(dlg.getOldPassword(), dlg.getNewPassword());
|
||||
return; // onPasswordChangeSuccess/onPasswordChangeError decides the next step
|
||||
}
|
||||
QMessageBox::information(
|
||||
dialogParent, tr("Password Change Required"),
|
||||
tr("An administrator has reset your password. Please contact your server administrator to obtain "
|
||||
"your temporary password, then log in and change it via Account -> Change Password."));
|
||||
remoteClient->disconnectFromServer();
|
||||
return;
|
||||
}
|
||||
|
|
@ -528,43 +507,6 @@ void ConnectionController::onNotifyUserAboutUpdate()
|
|||
"To update your client, go to Help -> Check for Updates."));
|
||||
}
|
||||
|
||||
void ConnectionController::onPasswordChangeSuccess()
|
||||
{
|
||||
// The credential saved for this profile is stale now: drop it so the next login asks for
|
||||
// the new password instead of replaying the old verifier.
|
||||
if (!pendingSaveName.isEmpty()) {
|
||||
SettingsCache::instance().servers().setServerPassword(pendingSaveName, "");
|
||||
}
|
||||
|
||||
QMessageBox::information(dialogParent, tr("Password Changed"),
|
||||
tr("Your password has been changed. Please log in again with your new password."));
|
||||
remoteClient->disconnectFromServer();
|
||||
connectToServer();
|
||||
}
|
||||
|
||||
void ConnectionController::onPasswordChangeError(int responseCode)
|
||||
{
|
||||
QString reason;
|
||||
switch (static_cast<Response::ResponseCode>(responseCode)) {
|
||||
case Response::RespWrongPassword:
|
||||
reason = tr("The current password is incorrect.");
|
||||
break;
|
||||
case Response::RespPasswordTooShort:
|
||||
reason = tr("The new password is too short.");
|
||||
break;
|
||||
case Response::RespClientUpdateRequired:
|
||||
reason = tr("The server does not accept the new password format.");
|
||||
break;
|
||||
default:
|
||||
reason = tr("The password could not be changed (error %1).").arg(responseCode);
|
||||
break;
|
||||
}
|
||||
|
||||
QMessageBox::critical(dialogParent, tr("Password Change Failed"), reason);
|
||||
remoteClient->disconnectFromServer();
|
||||
connectToServer();
|
||||
}
|
||||
|
||||
void ConnectionController::onForgotPasswordSuccess()
|
||||
{
|
||||
QMessageBox::information(
|
||||
|
|
@ -575,38 +517,14 @@ void ConnectionController::onForgotPasswordSuccess()
|
|||
SettingsCache::instance().servers().setFPPlayerName("");
|
||||
}
|
||||
|
||||
void ConnectionController::onForgotPasswordError(int responseCode)
|
||||
void ConnectionController::onForgotPasswordError()
|
||||
{
|
||||
// Rate limiting is retryable, so it must not clear the prefill.
|
||||
bool keepPrefill = false;
|
||||
QString message;
|
||||
switch (static_cast<Response::ResponseCode>(responseCode)) {
|
||||
case Response::RespTooManyRequests:
|
||||
// Retryable: keep the host/port/user prefill so the user can try again. The window
|
||||
// is server-configured (an hour by default), so do not promise a shorter wait.
|
||||
keepPrefill = true;
|
||||
message = tr("Too many password reset attempts from your address. Please wait before "
|
||||
"requesting a new reset.");
|
||||
break;
|
||||
case Response::RespFunctionNotAllowed:
|
||||
// Also returned for an unknown user, a banned user, and an expired token or
|
||||
// challenge, so the message must not claim a single cause.
|
||||
message = tr("The server did not accept the reset request. Check the user name, or contact "
|
||||
"the server operator to reset your password.");
|
||||
break;
|
||||
default:
|
||||
message = tr("Failed to reset user account password, please contact the server operator to reset your "
|
||||
"password.");
|
||||
break;
|
||||
}
|
||||
|
||||
QMessageBox::warning(dialogParent, tr("Reset Password"), message);
|
||||
|
||||
if (!keepPrefill) {
|
||||
SettingsCache::instance().servers().setFPHostName("");
|
||||
SettingsCache::instance().servers().setFPPort("");
|
||||
SettingsCache::instance().servers().setFPPlayerName("");
|
||||
}
|
||||
QMessageBox::warning(
|
||||
dialogParent, tr("Reset Password"),
|
||||
tr("Failed to reset user account password, please contact the server operator to reset your password."));
|
||||
SettingsCache::instance().servers().setFPHostName("");
|
||||
SettingsCache::instance().servers().setFPPort("");
|
||||
SettingsCache::instance().servers().setFPPlayerName("");
|
||||
}
|
||||
|
||||
void ConnectionController::onPromptForgotPasswordReset()
|
||||
|
|
|
|||
|
|
@ -87,17 +87,13 @@ private slots:
|
|||
|
||||
// Forgot-password flow
|
||||
void onForgotPasswordSuccess();
|
||||
void onForgotPasswordError(int responseCode);
|
||||
void onForgotPasswordError();
|
||||
void onPromptForgotPasswordReset();
|
||||
void onPromptForgotPasswordChallenge();
|
||||
|
||||
// Persists the derived scrypt verifier after a successful challenge-response login
|
||||
void onPasswordVerifierReady(const QString &verifier);
|
||||
|
||||
// Completes the forced password change the server demanded at login
|
||||
void onPasswordChangeSuccess();
|
||||
void onPasswordChangeError(int responseCode);
|
||||
|
||||
private:
|
||||
void wireClientSignals();
|
||||
void updateWindowTitle();
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@
|
|||
#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 <libcockatrice/network/network_manager.h>
|
||||
#include <version_string.h>
|
||||
|
||||
DeckStatsInterface::DeckStatsInterface(QObject *parent) : QObject(parent)
|
||||
{
|
||||
manager = NetworkManagerFactory::create(this);
|
||||
manager = new QNetworkAccessManager(this);
|
||||
connect(manager, &QNetworkAccessManager::finished, this, &DeckStatsInterface::queryFinished);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,12 +26,11 @@
|
|||
#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 <libcockatrice/network/network_manager.h>
|
||||
#include <version_string.h>
|
||||
|
||||
TappedOutInterface::TappedOutInterface(QObject *parent) : QObject(parent)
|
||||
{
|
||||
manager = NetworkManagerFactory::create(this);
|
||||
manager = new QNetworkAccessManager(this);
|
||||
connect(manager, &QNetworkAccessManager::finished, this, &TappedOutInterface::queryFinished);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include <functional>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/network/network_manager.h>
|
||||
#include <libcockatrice/settings/download_settings.h>
|
||||
#include <libcockatrice/settings/paths_settings.h>
|
||||
#include <tuple>
|
||||
|
|
@ -57,7 +56,7 @@ void SpoilerBackgroundUpdater::startSpoilerDownloadProcess(QString url, bool sav
|
|||
|
||||
void SpoilerBackgroundUpdater::downloadFromURL(QUrl url, bool saveResults)
|
||||
{
|
||||
auto *nam = NetworkManagerFactory::create(this);
|
||||
auto *nam = new QNetworkAccessManager(this);
|
||||
auto request = QNetworkRequest(url);
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
|
||||
QNetworkReply *reply = nam->get(request);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include <QVariant>
|
||||
#include <QVariantMap>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/network/network_manager.h>
|
||||
#include <optional>
|
||||
#include <qnamespace.h>
|
||||
#include <qprocessordetection.h>
|
||||
|
|
@ -63,7 +62,7 @@ std::optional<int> getProductVersionMajor()
|
|||
|
||||
} // namespace
|
||||
|
||||
ReleaseChannel::ReleaseChannel() : netMan(NetworkManagerFactory::create(this)), response(nullptr), lastRelease(nullptr)
|
||||
ReleaseChannel::ReleaseChannel() : netMan(new QNetworkAccessManager(this)), response(nullptr), lastRelease(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@
|
|||
#include <QNetworkRequest>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <libcockatrice/network/network_manager.h>
|
||||
|
||||
UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(nullptr)
|
||||
{
|
||||
netMan = NetworkManagerFactory::create(this);
|
||||
netMan = new QNetworkAccessManager(this);
|
||||
}
|
||||
|
||||
void UpdateDownloader::beginDownload(QUrl downloadUrl)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ inline Q_LOGGING_CATEGORY(SettingsCacheLog, "settings_cache");
|
|||
|
||||
class ReleaseChannel;
|
||||
|
||||
#define DEFAULT_LANG_NAME "English"
|
||||
#define CLIENT_INFO_NOT_SET "notset"
|
||||
|
||||
#define DEFAULT_FONT_SIZE 12
|
||||
|
|
|
|||
|
|
@ -2,18 +2,13 @@
|
|||
#define COCKATRICE_SETTINGS_CARD_PREFERENCE_PROVIDER_H
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <libcockatrice/interfaces/interface_card_preference_provider.h>
|
||||
#include <libcockatrice/settings/card_override_settings.h>
|
||||
#include <libcockatrice/settings/cards_display_settings.h>
|
||||
|
||||
class SettingsCardPreferenceProvider : public QObject, public ICardPreferenceProvider
|
||||
class SettingsCardPreferenceProvider : public ICardPreferenceProvider
|
||||
{
|
||||
public:
|
||||
explicit SettingsCardPreferenceProvider(QObject *parent = nullptr) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] QString getCardPreferenceOverride(const QString &cardName) const override
|
||||
{
|
||||
return SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardName);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "deck_filter_string.h"
|
||||
|
||||
#include "../interface/deck_loader/loaded_deck.h"
|
||||
#include "libcockatrice/card/card_localization.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
#include "libcockatrice/deck_list/deck_list.h"
|
||||
|
|
@ -14,7 +15,6 @@
|
|||
#include <algorithm>
|
||||
#include <any>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/deck_list/loaded_deck.h>
|
||||
#include <libcockatrice/filters/filter_string.h>
|
||||
#include <libcockatrice/utility/peglib.h>
|
||||
#include <mutex>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <QString>
|
||||
#include <functional>
|
||||
#include <libcockatrice/card/card_localization.h>
|
||||
#include <libcockatrice/deck_list/loaded_deck.h>
|
||||
|
||||
struct CardSearchLanguage;
|
||||
struct LoadedDeck;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/filters/filter_card.h>
|
||||
#include <libcockatrice/utility/qt_utils.h>
|
||||
#include <stddef.h>
|
||||
|
||||
FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
||||
|
|
@ -40,8 +39,9 @@ FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
|||
edit->setClearButtonEnabled(true);
|
||||
edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
QGridLayout *layout = QtUtils::makeLayout<QGridLayout>();
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->setObjectName("layout");
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
layout->addWidget(typeCombo, 0, 0, 1, 2);
|
||||
layout->addWidget(filterCombo, 0, 2, 1, 2);
|
||||
|
|
|
|||
|
|
@ -11,27 +11,6 @@
|
|||
|
||||
class QObject;
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @brief Visits every filter item below @p node, depth first.
|
||||
*/
|
||||
template <typename Callback> void forEachFilter(const FilterTreeNode *node, const Callback &callback)
|
||||
{
|
||||
if (node == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto *filterItem = dynamic_cast<const FilterItem *>(node)) {
|
||||
callback(filterItem);
|
||||
}
|
||||
|
||||
for (int i = 0; i < node->childCount(); ++i) {
|
||||
forEachFilter(node->nodeAt(i), callback);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FilterTreeModel::FilterTreeModel(QObject *parent) : QAbstractItemModel(parent)
|
||||
{
|
||||
fTree = new FilterTree;
|
||||
|
|
@ -131,31 +110,46 @@ void FilterTreeModel::clearFiltersOfType(CardFilter::Attr filterType)
|
|||
QList<const CardFilter *> FilterTreeModel::getFiltersOfType(CardFilter::Attr filterType) const
|
||||
{
|
||||
QList<const CardFilter *> filters;
|
||||
forEachFilter(fTree, [&](const FilterItem *filterItem) {
|
||||
if (filterItem->attr() == filterType) {
|
||||
filters.append(new CardFilter(filterItem->text(), filterItem->type(), filterItem->attr()));
|
||||
}
|
||||
});
|
||||
return filters;
|
||||
}
|
||||
if (!fTree) {
|
||||
return filters;
|
||||
}
|
||||
|
||||
QStringList FilterTreeModel::getFilterTermsOfType(CardFilter::Attr filterType) const
|
||||
{
|
||||
QStringList terms;
|
||||
forEachFilter(fTree, [&](const FilterItem *filterItem) {
|
||||
if (filterItem->attr() == filterType) {
|
||||
terms.append(filterItem->text());
|
||||
std::function<void(const FilterTreeNode *)> traverse;
|
||||
traverse = [&](const FilterTreeNode *node) {
|
||||
if (const auto *filterItem = dynamic_cast<const FilterItem *>(node)) {
|
||||
if (filterItem->attr() == filterType) {
|
||||
QString text = filterItem->text();
|
||||
filters.append(new CardFilter(text, filterItem->type(), filterItem->attr()));
|
||||
}
|
||||
}
|
||||
});
|
||||
return terms;
|
||||
for (int i = 0; i < node->childCount(); ++i) {
|
||||
traverse(node->nodeAt(i));
|
||||
}
|
||||
};
|
||||
|
||||
traverse(fTree);
|
||||
return filters;
|
||||
}
|
||||
|
||||
QList<const CardFilter *> FilterTreeModel::allFilters() const
|
||||
{
|
||||
QList<const CardFilter *> filters;
|
||||
forEachFilter(fTree, [&](const FilterItem *filterItem) {
|
||||
filters.append(new CardFilter(filterItem->text(), filterItem->type(), filterItem->attr()));
|
||||
});
|
||||
if (!fTree) {
|
||||
return filters;
|
||||
}
|
||||
|
||||
std::function<void(const FilterTreeNode *)> traverse;
|
||||
traverse = [&](const FilterTreeNode *node) {
|
||||
if (const auto *filterItem = dynamic_cast<const FilterItem *>(node)) {
|
||||
QString text = filterItem->text();
|
||||
filters.append(new CardFilter(text, filterItem->type(), filterItem->attr()));
|
||||
}
|
||||
for (int i = 0; i < node->childCount(); ++i) {
|
||||
traverse(node->nodeAt(i));
|
||||
}
|
||||
};
|
||||
|
||||
traverse(fTree);
|
||||
return filters;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,14 +28,7 @@ public slots:
|
|||
void addFilter(const CardFilter *f);
|
||||
void removeFilter(const CardFilter *f);
|
||||
void clearFiltersOfType(CardFilter::Attr filterType);
|
||||
/**
|
||||
* @brief Copies every active filter of one attribute into new CardFilter objects.
|
||||
*
|
||||
* The caller owns the returned filters. Prefer getFilterTermsOfType() when only
|
||||
* the terms are needed.
|
||||
*/
|
||||
[[nodiscard]] QList<const CardFilter *> getFiltersOfType(CardFilter::Attr filterType) const;
|
||||
/// @brief Copies every active filter into new CardFilter objects. The caller owns them.
|
||||
[[nodiscard]] QList<const CardFilter *> allFilters() const;
|
||||
|
||||
private slots:
|
||||
|
|
@ -55,13 +48,6 @@ public:
|
|||
{
|
||||
return fTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The texts of every active filter of one attribute, without allocating filters.
|
||||
*
|
||||
* Prefer this over getFiltersOfType() when only the filter terms are needed.
|
||||
*/
|
||||
[[nodiscard]] QStringList getFilterTermsOfType(CardFilter::Attr filterType) const;
|
||||
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
[[nodiscard]] int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ AbstractGame::AbstractGame(QObject *_parent) : QObject(_parent)
|
|||
{
|
||||
gameMetaInfo = new GameMetaInfo(this);
|
||||
gameEventHandler = new GameEventHandler(this);
|
||||
|
||||
activeCard = nullptr;
|
||||
}
|
||||
|
||||
bool AbstractGame::isHost() const
|
||||
|
|
@ -46,7 +48,12 @@ void AbstractGame::loadReplay(const GameReplay *replay)
|
|||
gameMetaInfo->setSpectatorsOmniscient(true);
|
||||
}
|
||||
|
||||
CardState *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const
|
||||
void AbstractGame::setActiveCard(CardItem *card)
|
||||
{
|
||||
activeCard = card;
|
||||
}
|
||||
|
||||
CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const
|
||||
{
|
||||
PlayerLogic *player = playerManager->getPlayer(playerId);
|
||||
if (!player) {
|
||||
|
|
@ -11,14 +11,14 @@
|
|||
#include <QString>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardItem;
|
||||
class AbstractClient;
|
||||
class CardState;
|
||||
class GameEventHandler;
|
||||
class GameMetaInfo;
|
||||
class GameReplay;
|
||||
class GameState;
|
||||
class PlayerManager;
|
||||
class CardState;
|
||||
|
||||
class AbstractGame : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -30,6 +30,7 @@ public:
|
|||
GameState *gameState;
|
||||
GameEventHandler *gameEventHandler;
|
||||
PlayerManager *playerManager;
|
||||
CardItem *activeCard;
|
||||
|
||||
GameMetaInfo *getGameMetaInfo()
|
||||
{
|
||||
|
|
@ -57,7 +58,13 @@ public:
|
|||
|
||||
void loadReplay(const GameReplay *replay);
|
||||
|
||||
CardState *getCard(int playerId, const QString &zoneName, int cardId) const;
|
||||
CardItem *getCard(int playerId, const QString &zoneName, int cardId) const;
|
||||
|
||||
void setActiveCard(CardItem *card);
|
||||
CardItem *getActiveCard() const
|
||||
{
|
||||
return activeCard;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_ABSTRACT_GAME_H
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
#include "arrow_registry.h"
|
||||
|
||||
#include "arrow_item.h"
|
||||
#include "../game_graphics/board/arrow_item.h"
|
||||
#include "board/arrow_data.h"
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <libcockatrice/game/board/arrow_data.h>
|
||||
|
||||
void ArrowRegistry::insert(QSharedPointer<ArrowData> data, ArrowItem *arrow)
|
||||
{
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <libcockatrice/game/board/arrow_data.h>
|
||||
|
||||
class ArrowItem;
|
||||
struct ArrowData;
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include "card_list.h"
|
||||
|
||||
#include "card_state.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "libcockatrice/card/printing/exact_card.h"
|
||||
|
||||
#include <QChar>
|
||||
#include <QDebug>
|
||||
|
|
@ -10,26 +11,26 @@
|
|||
#include <compare>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
|
||||
CardList::CardList(bool _contentsKnown) : QList<CardState *>(), contentsKnown(_contentsKnown)
|
||||
CardList::CardList(bool _contentsKnown) : QList<CardItem *>(), contentsKnown(_contentsKnown)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds the CardState with the given id in the list.
|
||||
* @brief Finds the CardItem with the given id in the list.
|
||||
* If contentsKnown is false, then this just returns the first element of the list.
|
||||
*
|
||||
* @param cardId The id of the card to find.
|
||||
*
|
||||
* @returns A pointer to the CardState, or a nullptr if not found.
|
||||
* @returns A pointer to the CardItem, or a nullptr if not found.
|
||||
*/
|
||||
CardState *CardList::findCard(const int cardId) const
|
||||
CardItem *CardList::findCard(const int cardId) const
|
||||
{
|
||||
if (!contentsKnown && !empty()) {
|
||||
return at(0);
|
||||
} else {
|
||||
for (auto *cardState : *this) {
|
||||
if (cardState->getId() == cardId) {
|
||||
return cardState;
|
||||
for (auto *cardItem : *this) {
|
||||
if (cardItem->getId() == cardId) {
|
||||
return cardItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +38,7 @@ CardState *CardList::findCard(const int cardId) const
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief sorts the list by using string comparison on properties extracted from the CardState
|
||||
* @brief sorts the list by using string comparison on properties extracted from the CardItem
|
||||
* The cards are compared using each property in order.
|
||||
* If two cards have the same value for a property, then the next property in the list is used.
|
||||
*
|
||||
|
|
@ -50,7 +51,7 @@ void CardList::sortBy(const QList<SortOption> &option)
|
|||
return;
|
||||
}
|
||||
|
||||
auto comparator = [&option](CardState *a, CardState *b) {
|
||||
auto comparator = [&option](CardItem *a, CardItem *b) {
|
||||
for (auto prop : option) {
|
||||
auto extractor = getExtractorFor(prop);
|
||||
QString t1 = extractor(a);
|
||||
|
|
@ -115,26 +116,26 @@ static QString getColorSortString(const CardInfo &c, bool appendAtEnd)
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief returns the function that extracts the given property from the CardState.
|
||||
* @brief returns the function that extracts the given property from the CardItem.
|
||||
*/
|
||||
std::function<QString(CardState *)> CardList::getExtractorFor(SortOption option)
|
||||
std::function<QString(CardItem *)> CardList::getExtractorFor(SortOption option)
|
||||
{
|
||||
switch (option) {
|
||||
case NoSort:
|
||||
return [](CardState *) { return ""; };
|
||||
return [](CardItem *) { return ""; };
|
||||
case SortByMainType:
|
||||
return [](CardState *c) { return c->getCardInfo().getMainCardType(); };
|
||||
return [](CardItem *c) { return c->getCardInfo().getMainCardType(); };
|
||||
case SortByManaValue:
|
||||
// getCmc returns the int as a string. We pad with 0's so that string comp also works on it
|
||||
return [](CardState *c) { return c->getCard() ? c->getCardInfo().getCmc().rightJustified(4, '0') : ""; };
|
||||
return [](CardItem *c) { return c->getCard() ? c->getCardInfo().getCmc().rightJustified(4, '0') : ""; };
|
||||
case SortByColorGrouping:
|
||||
return [](CardState *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), false) : ""; };
|
||||
return [](CardItem *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), false) : ""; };
|
||||
case SortByName:
|
||||
return [](CardState *c) { return c->getName(); };
|
||||
return [](CardItem *c) { return c->getName(); };
|
||||
case SortByType:
|
||||
return [](CardState *c) { return c->getCardInfo().getCardType(); };
|
||||
return [](CardItem *c) { return c->getCardInfo().getCardType(); };
|
||||
case SortByManaCost:
|
||||
return [](CardState *c) {
|
||||
return [](CardItem *c) {
|
||||
if (!c->getCard()) {
|
||||
return QString();
|
||||
}
|
||||
|
|
@ -146,18 +147,18 @@ std::function<QString(CardState *)> CardList::getExtractorFor(SortOption option)
|
|||
return QString("%1%2").arg(info.getCmc(), 4, QChar('0')).arg(info.getManaCost());
|
||||
};
|
||||
case SortByColors:
|
||||
return [](CardState *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), true) : ""; };
|
||||
return [](CardItem *c) { return c->getCard() ? getColorSortString(c->getCardInfo(), true) : ""; };
|
||||
case SortByPt:
|
||||
// do the same padding trick as above
|
||||
return
|
||||
[](CardState *c) { return c->getCard() ? c->getCardInfo().getPowTough().rightJustified(10, '0') : ""; };
|
||||
[](CardItem *c) { return c->getCard() ? c->getCardInfo().getPowTough().rightJustified(10, '0') : ""; };
|
||||
case SortBySet:
|
||||
return [](CardState *c) { return c->getCardInfo().getSetsNames(); };
|
||||
return [](CardItem *c) { return c->getCardInfo().getSetsNames(); };
|
||||
case SortByPrinting:
|
||||
return [](CardState *c) { return c->getProviderId(); };
|
||||
return [](CardItem *c) { return c->getProviderId(); };
|
||||
}
|
||||
|
||||
// this line should never be reached
|
||||
qCWarning(CardListLog) << "cardlist.cpp: Could not find extractor for SortOption" << option;
|
||||
return [](CardState *) { return ""; };
|
||||
return [](CardItem *) { return ""; };
|
||||
}
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
inline Q_LOGGING_CATEGORY(CardListLog, "card_list");
|
||||
|
||||
class CardState;
|
||||
class CardItem;
|
||||
|
||||
class CardList : public QList<CardState *>
|
||||
class CardList : public QList<CardItem *>
|
||||
{
|
||||
protected:
|
||||
bool contentsKnown;
|
||||
|
|
@ -43,7 +43,7 @@ public:
|
|||
SortByPrinting
|
||||
};
|
||||
explicit CardList(bool _contentsKnown);
|
||||
CardState *findCard(const int cardId) const;
|
||||
CardItem *findCard(const int cardId) const;
|
||||
bool getContentsKnown() const
|
||||
{
|
||||
return contentsKnown;
|
||||
|
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
void sortBy(const QList<SortOption> &options);
|
||||
|
||||
static std::function<QString(CardState *)> getExtractorFor(SortOption option);
|
||||
static std::function<QString(CardItem *)> getExtractorFor(SortOption option);
|
||||
};
|
||||
|
||||
#endif
|
||||
113
cockatrice/src/game/board/card_state.cpp
Normal file
113
cockatrice/src/game/board/card_state.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#include "card_state.h"
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
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();
|
||||
}
|
||||
106
cockatrice/src/game/board/card_state.h
Normal file
106
cockatrice/src/game/board/card_state.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef COCKATRICE_CARD_STATE_H
|
||||
#define COCKATRICE_CARD_STATE_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
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
|
||||
|
|
@ -16,16 +16,13 @@ Game::Game(QObject *_parent,
|
|||
bool isLocalGame,
|
||||
QList<AbstractClient *> &_clients,
|
||||
const Event_GameJoined &event,
|
||||
const QMap<int, QString> &_roomGameTypes,
|
||||
IInterfaceSettingsProvider *interfaceSettings,
|
||||
ICardPreferenceProvider *cardPreferences)
|
||||
const QMap<int, QString> &_roomGameTypes)
|
||||
: AbstractGame(_parent)
|
||||
{
|
||||
gameMetaInfo->setFromProto(event.game_info());
|
||||
gameMetaInfo->setRoomGameTypes(_roomGameTypes);
|
||||
gameState = new GameState(this, 0, event.host_id(), isLocalGame, _clients, false, event.resuming(), -1, false);
|
||||
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
|
||||
playerManager = new PlayerManager(this, event.player_id(), event.judge(), event.spectator(), interfaceSettings,
|
||||
cardPreferences);
|
||||
playerManager = new PlayerManager(this, event.player_id(), event.judge(), event.spectator());
|
||||
gameMetaInfo->setStarted(false);
|
||||
}
|
||||
|
|
@ -18,9 +18,6 @@ class QString;
|
|||
template <class Key, class T> class QMap;
|
||||
template <typename T> class QList;
|
||||
|
||||
class ICardPreferenceProvider;
|
||||
class IInterfaceSettingsProvider;
|
||||
|
||||
class Game : public AbstractGame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -30,9 +27,7 @@ public:
|
|||
bool isLocalGame,
|
||||
QList<AbstractClient *> &_clients,
|
||||
const Event_GameJoined &event,
|
||||
const QMap<int, QString> &_roomGameTypes,
|
||||
IInterfaceSettingsProvider *interfaceSettings = nullptr,
|
||||
ICardPreferenceProvider *cardPreferences = nullptr);
|
||||
const QMap<int, QString> &_roomGameTypes);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_GAME_H
|
||||
|
|
@ -28,20 +28,12 @@
|
|||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||
#include <libcockatrice/protocol/get_pb_extension.h>
|
||||
#include <libcockatrice/protocol/pb/command_concede.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_select.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_delete_arrow.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_draw_cards.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_game_say.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_leave_game.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_ready_start.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_reverse_turn.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_playmat.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_connection_state_changed.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_deck_select.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_game_closed.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_game_host_changed.pb.h>
|
||||
|
|
@ -56,7 +48,6 @@
|
|||
#include <libcockatrice/protocol/pb/event_set_active_player.pb.h>
|
||||
#include <libcockatrice/protocol/pb/game_event_container.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -232,89 +223,6 @@ void GameEventHandler::handleActivePhaseChanged(int phase)
|
|||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void GameEventHandler::handleUntapAll()
|
||||
{
|
||||
Command_SetCardAttr cmd;
|
||||
cmd.set_zone(ZoneNames::TABLE);
|
||||
cmd.set_attribute(AttrTapped);
|
||||
cmd.set_attr_value("0");
|
||||
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void GameEventHandler::handleDrawCard()
|
||||
{
|
||||
Command_DrawCards cmd;
|
||||
cmd.set_number(1);
|
||||
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
PendingCommand *GameEventHandler::prepareDeckSelect(const QString &deckList)
|
||||
{
|
||||
Command_DeckSelect cmd;
|
||||
cmd.set_deck(deckList.toStdString());
|
||||
|
||||
return prepareGameCommand(cmd);
|
||||
}
|
||||
|
||||
PendingCommand *GameEventHandler::prepareDeckSelectId(int deckId)
|
||||
{
|
||||
Command_DeckSelect cmd;
|
||||
cmd.set_deck_id(deckId);
|
||||
|
||||
return prepareGameCommand(cmd);
|
||||
}
|
||||
|
||||
PendingCommand *GameEventHandler::prepareSetPlaymat(const PlaymatInfo &playmat)
|
||||
{
|
||||
Command_SetPlaymat cmd;
|
||||
auto *pp = cmd.mutable_playmat_params();
|
||||
pp->set_card_name(playmat.card.name.toStdString());
|
||||
pp->set_card_provider_id(playmat.card.providerId.toStdString());
|
||||
pp->set_margin_pct_l(playmat.params.marginPctL);
|
||||
pp->set_margin_pct_r(playmat.params.marginPctR);
|
||||
pp->set_vertical_offset(playmat.params.verticalOffset);
|
||||
pp->set_zoom(playmat.params.zoom);
|
||||
|
||||
return prepareGameCommand(cmd);
|
||||
}
|
||||
|
||||
void GameEventHandler::sendReadyStart(bool ready, int playerId)
|
||||
{
|
||||
Command_ReadyStart cmd;
|
||||
cmd.set_ready(ready);
|
||||
|
||||
sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void GameEventHandler::sendForceStart(int playerId)
|
||||
{
|
||||
Command_ReadyStart cmd;
|
||||
cmd.set_force_start(true);
|
||||
cmd.set_ready(true);
|
||||
|
||||
sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void GameEventHandler::sendSetSideboardLock(bool locked, int playerId)
|
||||
{
|
||||
Command_SetSideboardLock cmd;
|
||||
cmd.set_locked(locked);
|
||||
|
||||
sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void GameEventHandler::sendSetSideboardPlan(const QList<MoveCard_ToZone> &plan, int playerId)
|
||||
{
|
||||
Command_SetSideboardPlan cmd;
|
||||
for (const auto &zone : plan) {
|
||||
cmd.add_move_list()->CopyFrom(zone);
|
||||
}
|
||||
|
||||
sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void GameEventHandler::handleGameLeft()
|
||||
{
|
||||
sendGameCommand(Command_LeaveGame());
|
||||
|
|
@ -29,14 +29,13 @@
|
|||
// GameEventContext, ServerInfo_Player and ServerInfo_User are passed by value
|
||||
// to signals and slots, so the moc-generated code needs the complete types.
|
||||
#include <libcockatrice/protocol/pb/game_event_context.pb.h>
|
||||
#include <libcockatrice/protocol/pb/move_card_to_zone.pb.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
||||
#include <libcockatrice/utility/playmat_params.h>
|
||||
|
||||
class AbstractClient;
|
||||
class AbstractGame;
|
||||
class GameEventContainer;
|
||||
class GameEventContext;
|
||||
class PendingCommand;
|
||||
class PlayerLogic;
|
||||
class Response;
|
||||
|
|
@ -128,12 +127,6 @@ public:
|
|||
*/
|
||||
void handleActivePhaseChanged(int phase);
|
||||
|
||||
/** @brief Request untapping every permanent on the table. */
|
||||
void handleUntapAll();
|
||||
|
||||
/** @brief Request drawing a single card. */
|
||||
void handleDrawCard();
|
||||
|
||||
/** @brief Leave the current game session. */
|
||||
void handleGameLeft();
|
||||
|
||||
|
|
@ -152,70 +145,6 @@ public:
|
|||
void handleArrowDeletion(int creatorId, int arrowId);
|
||||
void handleArrowDeletionFinished(const Response &response, int creatorId, int arrowId);
|
||||
|
||||
/**
|
||||
* @brief Prepare a deck selection from its native deck list text.
|
||||
*
|
||||
* The returned command is not sent yet, so the caller can connect to
|
||||
* PendingCommand::finished before handing it to sendGameCommand().
|
||||
*
|
||||
* @param deckList Serialized deck list.
|
||||
* @return The pending command awaiting the deck download response.
|
||||
*/
|
||||
PendingCommand *prepareDeckSelect(const QString &deckList);
|
||||
|
||||
/**
|
||||
* @brief Prepare a deck selection for a deck stored on the server.
|
||||
*
|
||||
* The returned command is not sent yet, so the caller can connect to
|
||||
* PendingCommand::finished before handing it to sendGameCommand().
|
||||
*
|
||||
* @param deckId Server-side deck identifier.
|
||||
* @return The pending command awaiting the deck download response.
|
||||
*/
|
||||
PendingCommand *prepareDeckSelectId(int deckId);
|
||||
|
||||
/**
|
||||
* @brief Build the playmat command for a player without sending it.
|
||||
*
|
||||
* The returned command is not sent yet, so the caller can connect to
|
||||
* PendingCommand::finished before handing it to sendGameCommand().
|
||||
*
|
||||
* @param playmat Resolved playmat card and positioning parameters.
|
||||
* @return The pending command awaiting the playmat response.
|
||||
*/
|
||||
PendingCommand *prepareSetPlaymat(const PlaymatInfo &playmat);
|
||||
|
||||
/**
|
||||
* @brief Set a player's ready state.
|
||||
*
|
||||
* @param ready Whether the player is ready.
|
||||
* @param playerId Player the state applies to.
|
||||
*/
|
||||
void sendReadyStart(bool ready, int playerId);
|
||||
|
||||
/**
|
||||
* @brief Force-start the game, kicking every player who is not ready.
|
||||
*
|
||||
* @param playerId Player issuing the force start.
|
||||
*/
|
||||
void sendForceStart(int playerId);
|
||||
|
||||
/**
|
||||
* @brief Lock or unlock a player's sideboard.
|
||||
*
|
||||
* @param locked Whether the sideboard is locked.
|
||||
* @param playerId Player the lock applies to.
|
||||
*/
|
||||
void sendSetSideboardLock(bool locked, int playerId);
|
||||
|
||||
/**
|
||||
* @brief Send a player's sideboard plan.
|
||||
*
|
||||
* @param plan Cards to move between zones when leaving sideboarding.
|
||||
* @param playerId Player the plan belongs to.
|
||||
*/
|
||||
void sendSetSideboardPlan(const QList<MoveCard_ToZone> &plan, int playerId);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Incoming event processing
|
||||
|
|
@ -1,8 +1,13 @@
|
|||
#include "player_actions.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/dialogs/dlg_create_token.h"
|
||||
#include "../../game_graphics/dialogs/dlg_move_top_cards_until.h"
|
||||
#include "../../game_graphics/player/card_menu_action_type.h"
|
||||
#include "../../game_graphics/zones/table_zone.h"
|
||||
#include "../../interface/deck_loader/loaded_deck.h"
|
||||
#include "../abstract_game.h"
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "../board/counter_state.h"
|
||||
#include "../game_event_handler.h"
|
||||
#include "../zones/card_zone_logic.h"
|
||||
|
|
@ -26,6 +31,8 @@
|
|||
#include <QChar>
|
||||
#include <QColor>
|
||||
#include <QFlags>
|
||||
#include <QInputDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMapIterator>
|
||||
|
|
@ -44,15 +51,10 @@
|
|||
#include <google/protobuf/stubs/port.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/relation/card_relation.h>
|
||||
#include <libcockatrice/deck_list/loaded_deck.h>
|
||||
#include <libcockatrice/interfaces/interface_card_preference_provider.h>
|
||||
#include <libcockatrice/interfaces/interface_interface_settings_provider.h>
|
||||
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_change_zone_properties.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_create_token.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_draw_cards.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_dump_zone.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_flip_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_game_say.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_inc_counter.pb.h>
|
||||
|
|
@ -62,12 +64,11 @@
|
|||
#include <libcockatrice/protocol/pb/command_roll_die.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_undo_draw.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||
#include <libcockatrice/settings/card_override_settings.h>
|
||||
#include <libcockatrice/settings/interface_settings.h>
|
||||
#include <libcockatrice/utility/clamped_arithmetic.h>
|
||||
#include <libcockatrice/utility/color.h>
|
||||
#include <libcockatrice/utility/counter_limits.h>
|
||||
#include <libcockatrice/utility/expression.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
|
@ -79,11 +80,8 @@
|
|||
// milliseconds in between triggers of the move top cards until action
|
||||
static constexpr int MOVE_TOP_CARD_UNTIL_INTERVAL = 100;
|
||||
|
||||
PlayerActions::PlayerActions(PlayerLogic *_player,
|
||||
IInterfaceSettingsProvider *_interfaceSettings,
|
||||
ICardPreferenceProvider *_cardPreferences)
|
||||
: QObject(_player), player(_player), interfaceSettings(_interfaceSettings), cardPreferences(_cardPreferences),
|
||||
lastTokenTableRow(0), movingCardsUntil(false)
|
||||
PlayerActions::PlayerActions(PlayerLogic *_player)
|
||||
: QObject(_player), player(_player), lastTokenTableRow(0), movingCardsUntil(false)
|
||||
{
|
||||
connect(this, &PlayerActions::requestZoneViewToggle, player, &PlayerLogic::onRequestZoneViewToggle);
|
||||
|
||||
|
|
@ -93,27 +91,7 @@ PlayerActions::PlayerActions(PlayerLogic *_player,
|
|||
connect(moveTopCardTimer, &QTimer::timeout, [this]() { actMoveTopCardToPlay(); });
|
||||
}
|
||||
|
||||
bool PlayerActions::getPlayToStack() const
|
||||
{
|
||||
return interfaceSettings ? interfaceSettings->getPlayToStack() : true;
|
||||
}
|
||||
|
||||
int PlayerActions::getStartingHandSize() const
|
||||
{
|
||||
return interfaceSettings ? interfaceSettings->getStartingHandSize() : 7;
|
||||
}
|
||||
|
||||
bool PlayerActions::getAnnotateTokens() const
|
||||
{
|
||||
return interfaceSettings ? interfaceSettings->getAnnotateTokens() : false;
|
||||
}
|
||||
|
||||
QString PlayerActions::getCardPreferenceOverride(const QString &cardName) const
|
||||
{
|
||||
return cardPreferences ? cardPreferences->getCardPreferenceOverride(cardName) : QString();
|
||||
}
|
||||
|
||||
void PlayerActions::playCard(CardState *card, bool faceDown)
|
||||
void PlayerActions::playCard(CardItem *card, bool faceDown)
|
||||
{
|
||||
if (card == nullptr) {
|
||||
return;
|
||||
|
|
@ -134,7 +112,7 @@ void PlayerActions::playCard(CardState *card, bool faceDown)
|
|||
const CardInfo &info = exactCard.getInfo();
|
||||
|
||||
int tableRow = info.getUiAttributes().tableRow;
|
||||
bool playToStack = getPlayToStack();
|
||||
bool playToStack = SettingsCache::instance().userInterface().getPlayToStack();
|
||||
QString currentZone = card->getZone()->getName();
|
||||
if (!faceDown && currentZone == ZoneNames::STACK && tableRow == 3) {
|
||||
cmd.set_target_zone(ZoneNames::GRAVE);
|
||||
|
|
@ -147,7 +125,7 @@ void PlayerActions::playCard(CardState *card, bool faceDown)
|
|||
cmd.set_y(0);
|
||||
} else {
|
||||
tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
||||
QPoint gridPoint = QPoint(-1, TableZoneLogic::tableRowToGridY(tableRow));
|
||||
QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(tableRow));
|
||||
cardToMove->set_face_down(faceDown);
|
||||
if (!faceDown) {
|
||||
cardToMove->set_pt(info.getPowTough().toStdString());
|
||||
|
|
@ -166,7 +144,7 @@ void PlayerActions::playCard(CardState *card, bool faceDown)
|
|||
* Like {@link PlayerActions::playCard}, but forces the card to be played to the table zone.
|
||||
* Cards with tablerow 3 (the stack) will be played to tablerow 1 (the noncreatures row).
|
||||
*/
|
||||
void PlayerActions::playCardToTable(const CardState *card, bool faceDown)
|
||||
void PlayerActions::playCardToTable(const CardItem *card, bool faceDown)
|
||||
{
|
||||
if (card == nullptr) {
|
||||
return;
|
||||
|
|
@ -187,7 +165,7 @@ void PlayerActions::playCardToTable(const CardState *card, bool faceDown)
|
|||
const CardInfo &info = exactCard.getInfo();
|
||||
|
||||
int tableRow = faceDown ? 2 : info.getUiAttributes().tableRow;
|
||||
QPoint gridPoint = QPoint(-1, TableZoneLogic::tableRowToGridY(tableRow));
|
||||
QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(tableRow));
|
||||
cardToMove->set_face_down(faceDown);
|
||||
if (!faceDown) {
|
||||
cardToMove->set_pt(info.getPowTough().toStdString());
|
||||
|
|
@ -199,60 +177,6 @@ void PlayerActions::playCardToTable(const CardState *card, bool faceDown)
|
|||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::attachCards(CardState *startCard, const CardState *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) {
|
||||
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());
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::createArrow(CardState *startCard, const ArrowData &arrow, int deleteInPhase)
|
||||
{
|
||||
Command_CreateArrow cmd;
|
||||
cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(arrow.color));
|
||||
cmd.set_start_player_id(arrow.startPlayerId);
|
||||
cmd.set_start_zone(arrow.startZone.toStdString());
|
||||
cmd.set_start_card_id(arrow.startCardId);
|
||||
cmd.set_target_player_id(arrow.targetPlayerId);
|
||||
|
||||
if (!arrow.isPlayerTargeted()) {
|
||||
cmd.set_target_zone(arrow.targetZone.toStdString());
|
||||
cmd.set_target_card_id(arrow.targetCardId);
|
||||
}
|
||||
|
||||
// if the card is in hand then it has just been moved to the stack or table as part of drawing the arrow
|
||||
if (arrow.startZone == ZoneNames::HAND) {
|
||||
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
||||
bool playToStack = getPlayToStack();
|
||||
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
|
||||
(playToStack && ci->getUiAttributes().tableRow != 0 &&
|
||||
startCard->getZone()->getName() != ZoneNames::STACK))) {
|
||||
cmd.set_start_zone(ZoneNames::STACK);
|
||||
} else {
|
||||
cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteInPhase != 0) {
|
||||
cmd.set_delete_in_phase(deleteInPhase);
|
||||
}
|
||||
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::actViewLibrary()
|
||||
{
|
||||
emit requestZoneViewToggle(ZoneNames::DECK, -1);
|
||||
|
|
@ -431,7 +355,7 @@ void PlayerActions::actDrawCard()
|
|||
|
||||
void PlayerActions::actRequestMulliganDialog()
|
||||
{
|
||||
int startSize = getStartingHandSize();
|
||||
int startSize = SettingsCache::instance().userInterface().getStartingHandSize();
|
||||
int handSize = player->getHandZone()->getCards().size();
|
||||
int deckSize = player->getDeckZone()->getCards().size() + handSize;
|
||||
|
||||
|
|
@ -447,7 +371,7 @@ void PlayerActions::actMulligan(int number)
|
|||
}
|
||||
|
||||
doMulligan(number);
|
||||
emit startingHandSizeChosen(number);
|
||||
SettingsCache::instance().userInterface().setStartingHandSize(number);
|
||||
}
|
||||
|
||||
void PlayerActions::actMulliganSameSize()
|
||||
|
|
@ -625,7 +549,7 @@ void PlayerActions::moveTopCardsUntil(const QString &expr, MoveTopCardsUntilOpti
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerActions::moveOneCardUntil(CardState *card)
|
||||
void PlayerActions::moveOneCardUntil(CardItem *card)
|
||||
{
|
||||
moveTopCardTimer->stop();
|
||||
|
||||
|
|
@ -817,6 +741,61 @@ void PlayerActions::actMoveBottomCardToTop()
|
|||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects all cards in the given zone.
|
||||
*
|
||||
* @param zone The zone to select from
|
||||
* @param filter A predicate to filter which cards are selected. Defaults to always returning true.
|
||||
*/
|
||||
static void selectCardsInZone(
|
||||
const CardZoneLogic *zone,
|
||||
std::function<bool(const CardItem *)> filter = [](const CardItem *) { return true; })
|
||||
{
|
||||
if (!zone) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &cardItem : zone->getCards()) {
|
||||
if (cardItem && filter(cardItem)) {
|
||||
cardItem->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actSelectAll()
|
||||
{
|
||||
const CardItem *card = player->getGame()->getActiveCard();
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectCardsInZone(card->getZone());
|
||||
}
|
||||
|
||||
void PlayerActions::actSelectRow()
|
||||
{
|
||||
const CardItem *card = player->getGame()->getActiveCard();
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto isSameRow = [card](const CardItem *cardItem) {
|
||||
return qAbs(card->scenePos().y() - cardItem->scenePos().y()) < 50;
|
||||
};
|
||||
selectCardsInZone(card->getZone(), isSameRow);
|
||||
}
|
||||
|
||||
void PlayerActions::actSelectColumn()
|
||||
{
|
||||
const CardItem *card = player->getGame()->getActiveCard();
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto isSameColumn = [card](const CardItem *cardItem) { return cardItem->x() == card->x(); };
|
||||
selectCardsInZone(card->getZone(), isSameColumn);
|
||||
}
|
||||
|
||||
void PlayerActions::actDrawBottomCard()
|
||||
{
|
||||
if (player->getDeckZone()->getCards().empty()) {
|
||||
|
|
@ -950,7 +929,7 @@ void PlayerActions::actCreateToken(TokenInfo tokenToCreate)
|
|||
if (correctedCard) {
|
||||
lastTokenInfo.name = correctedCard.getName();
|
||||
int tableRow = lastTokenInfo.faceDown ? 2 : correctedCard.getInfo().getUiAttributes().tableRow;
|
||||
lastTokenTableRow = TableZoneLogic::tableRowToGridY(tableRow);
|
||||
lastTokenTableRow = TableZone::tableRowToGridY(tableRow);
|
||||
if (lastTokenInfo.pt.isEmpty()) {
|
||||
lastTokenInfo.pt = correctedCard.getInfo().getPowTough();
|
||||
}
|
||||
|
|
@ -996,14 +975,15 @@ void PlayerActions::setLastTokenInfo(CardInfoPtr cardInfo)
|
|||
return;
|
||||
}
|
||||
|
||||
lastTokenInfo = {.name = cardInfo->getName(),
|
||||
.color = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower(),
|
||||
.pt = cardInfo->getPowTough(),
|
||||
.annotation = getAnnotateTokens() ? cardInfo->getText() : "",
|
||||
.destroy = true,
|
||||
.providerId = getCardPreferenceOverride(cardInfo->getName())};
|
||||
lastTokenInfo = {
|
||||
.name = cardInfo->getName(),
|
||||
.color = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower(),
|
||||
.pt = cardInfo->getPowTough(),
|
||||
.annotation = SettingsCache::instance().userInterface().getAnnotateTokens() ? cardInfo->getText() : "",
|
||||
.destroy = true,
|
||||
.providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())};
|
||||
|
||||
lastTokenTableRow = TableZoneLogic::tableRowToGridY(cardInfo->getUiAttributes().tableRow);
|
||||
lastTokenTableRow = TableZone::tableRowToGridY(cardInfo->getUiAttributes().tableRow);
|
||||
|
||||
emit requestEnableAndSetCreateAnotherTokenAction(lastTokenInfo.name);
|
||||
}
|
||||
|
|
@ -1021,20 +1001,25 @@ void PlayerActions::actCreatePredefinedToken()
|
|||
actCreateAnotherToken();
|
||||
}
|
||||
|
||||
void PlayerActions::actCreateRelatedCard(const CardState *sourceCard, int index)
|
||||
void PlayerActions::actCreateRelatedCard()
|
||||
{
|
||||
const CardItem *sourceCard = player->getGame()->getActiveCard();
|
||||
|
||||
if (!sourceCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *action = static_cast<QAction *>(sender());
|
||||
// If there is a better way of passing a CardRelation through a QAction, please add it here.
|
||||
auto relatedCards = sourceCard->getCardInfo().getAllRelatedCards();
|
||||
|
||||
CardRelation *cardRelation = relatedCards.at(index);
|
||||
CardRelation *cardRelation = relatedCards.at(action->data().toInt());
|
||||
actRequestCreateRelatedFromRelationDialog(sourceCard, cardRelation);
|
||||
}
|
||||
|
||||
void PlayerActions::actCreateAllRelatedCards(const CardState *sourceCard)
|
||||
void PlayerActions::actCreateAllRelatedCards()
|
||||
{
|
||||
const CardItem *sourceCard = player->getGame()->getActiveCard();
|
||||
if (!sourceCard) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1120,13 +1105,13 @@ void PlayerActions::actCreateAllRelatedCards(const CardState *sourceCard)
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actRequestCreateRelatedFromRelationDialog(const CardState *sourceCard,
|
||||
void PlayerActions::actRequestCreateRelatedFromRelationDialog(const CardItem *sourceCard,
|
||||
const CardRelation *cardRelation)
|
||||
{
|
||||
emit requestCreateRelatedFromRelationDialog(sourceCard, cardRelation);
|
||||
}
|
||||
|
||||
bool PlayerActions::createRelatedFromRelation(const CardState *sourceCard,
|
||||
bool PlayerActions::createRelatedFromRelation(const CardItem *sourceCard,
|
||||
const CardRelation *cardRelation,
|
||||
int variableCount)
|
||||
{
|
||||
|
|
@ -1178,7 +1163,7 @@ bool PlayerActions::createRelatedFromRelation(const CardState *sourceCard,
|
|||
return true;
|
||||
}
|
||||
|
||||
void PlayerActions::onRelatedCardCreated(const CardState *sourceCard, const CardRelation *cardRelation)
|
||||
void PlayerActions::onRelatedCardCreated(const CardItem *sourceCard, const CardRelation *cardRelation)
|
||||
{
|
||||
if (sourceCard == nullptr || cardRelation == nullptr) {
|
||||
return;
|
||||
|
|
@ -1198,7 +1183,7 @@ void PlayerActions::onRelatedCardCreated(const CardState *sourceCard, const Card
|
|||
setLastToken(relatedCard.getCardPtr());
|
||||
}
|
||||
|
||||
void PlayerActions::createCard(const CardState *sourceCard,
|
||||
void PlayerActions::createCard(const CardItem *sourceCard,
|
||||
const QString &dbCardName,
|
||||
CardRelationType attachType,
|
||||
bool persistent,
|
||||
|
|
@ -1210,7 +1195,7 @@ void PlayerActions::createCard(const CardState *sourceCard,
|
|||
return;
|
||||
}
|
||||
|
||||
QPoint gridPoint = QPoint(-1, TableZoneLogic::tableRowToGridY(cardInfo->getUiAttributes().tableRow));
|
||||
QPoint gridPoint = QPoint(-1, TableZone::tableRowToGridY(cardInfo->getUiAttributes().tableRow));
|
||||
|
||||
// create the token for the related card
|
||||
Command_CreateToken cmd;
|
||||
|
|
@ -1229,7 +1214,7 @@ void PlayerActions::createCard(const CardState *sourceCard,
|
|||
}
|
||||
|
||||
cmd.set_pt(cardInfo->getPowTough().toStdString());
|
||||
if (getAnnotateTokens()) {
|
||||
if (SettingsCache::instance().userInterface().getAnnotateTokens()) {
|
||||
cmd.set_annotation(cardInfo->getText().toStdString());
|
||||
} else {
|
||||
cmd.set_annotation("");
|
||||
|
|
@ -1284,7 +1269,7 @@ void PlayerActions::actRequestMoveCardXCardsFromTopDialog()
|
|||
emit requestMoveCardXCardsFromTopDialog(defaultNumberTopCardsToPlaceBelow, deckSize);
|
||||
}
|
||||
|
||||
void PlayerActions::actMoveCardXCardsFromTop(QList<CardState *> selectedCards, int number)
|
||||
void PlayerActions::actMoveCardXCardsFromTop(QList<CardItem *> selectedCards, int number)
|
||||
{
|
||||
defaultNumberTopCardsToPlaceBelow = number;
|
||||
|
||||
|
|
@ -1318,14 +1303,14 @@ void PlayerActions::actMoveCardXCardsFromTop(QList<CardState *> selectedCards, i
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actIncPT(QList<CardState *> selectedCards, int deltaP, int deltaT)
|
||||
void PlayerActions::actIncPT(QList<CardItem *> selectedCards, int deltaP, int deltaT)
|
||||
{
|
||||
int playerid = player->getPlayerInfo()->getId();
|
||||
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
for (auto card : selectedCards) {
|
||||
QString pt = card->getPT();
|
||||
const auto ptList = CardState::parsePT(pt);
|
||||
const auto ptList = CardItem::parsePT(pt);
|
||||
QString newpt;
|
||||
if (ptList.isEmpty()) {
|
||||
newpt = QString::number(deltaP) + (deltaT ? "/" + QString::number(deltaT) : "");
|
||||
|
|
@ -1351,7 +1336,7 @@ void PlayerActions::actIncPT(QList<CardState *> selectedCards, int deltaP, int d
|
|||
player->getGame()->getGameEventHandler()->sendGameCommand(prepareGameCommand(commandList), playerid);
|
||||
}
|
||||
|
||||
void PlayerActions::actResetPT(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actResetPT(QList<CardItem *> selectedCards)
|
||||
{
|
||||
int playerid = player->getPlayerInfo()->getId();
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
|
|
@ -1384,7 +1369,7 @@ void PlayerActions::actResetPT(QList<CardState *> selectedCards)
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actRequestSetPTDialog(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actRequestSetPTDialog(QList<CardItem *> selectedCards)
|
||||
{
|
||||
QString oldPT;
|
||||
|
||||
|
|
@ -1397,11 +1382,11 @@ void PlayerActions::actRequestSetPTDialog(QList<CardState *> selectedCards)
|
|||
emit requestSetPTDialog(oldPT);
|
||||
}
|
||||
|
||||
void PlayerActions::actSetPT(QList<CardState *> selectedCards, const QString &pt)
|
||||
void PlayerActions::actSetPT(QList<CardItem *> selectedCards, const QString &pt)
|
||||
{
|
||||
int playerid = player->getPlayerInfo()->getId();
|
||||
|
||||
const auto ptList = CardState::parsePT(pt);
|
||||
const auto ptList = CardItem::parsePT(pt);
|
||||
bool empty = ptList.isEmpty();
|
||||
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
|
|
@ -1409,7 +1394,7 @@ void PlayerActions::actSetPT(QList<CardState *> selectedCards, const QString &pt
|
|||
auto *cmd = new Command_SetCardAttr;
|
||||
QString newpt = QString();
|
||||
if (!empty) {
|
||||
const auto oldpt = CardState::parsePT(card->getPT());
|
||||
const auto oldpt = CardItem::parsePT(card->getPT());
|
||||
int ptIter = 0;
|
||||
for (const auto &_item : ptList) {
|
||||
if (_item.typeId() == QMetaType::Type::Int) {
|
||||
|
|
@ -1437,65 +1422,55 @@ void PlayerActions::actSetPT(QList<CardState *> selectedCards, const QString &pt
|
|||
player->getGame()->getGameEventHandler()->sendGameCommand(prepareGameCommand(commandList), playerid);
|
||||
}
|
||||
|
||||
void PlayerActions::actIncP(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actDrawArrow()
|
||||
{
|
||||
auto *card = player->getGame()->getActiveCard();
|
||||
if (card) {
|
||||
card->drawArrow(Qt::red);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actIncP(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, 1, 0);
|
||||
}
|
||||
|
||||
void PlayerActions::actDecP(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actDecP(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, -1, 0);
|
||||
}
|
||||
|
||||
void PlayerActions::actIncT(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actIncT(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, 0, 1);
|
||||
}
|
||||
|
||||
void PlayerActions::actDecT(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actDecT(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, 0, -1);
|
||||
}
|
||||
|
||||
void PlayerActions::actIncPT(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actIncPT(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, 1, 1);
|
||||
}
|
||||
|
||||
void PlayerActions::actDecPT(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actDecPT(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, -1, -1);
|
||||
}
|
||||
|
||||
void PlayerActions::actFlowP(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actFlowP(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, 1, -1);
|
||||
}
|
||||
|
||||
void PlayerActions::actFlowT(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actFlowT(QList<CardItem *> selectedCards)
|
||||
{
|
||||
actIncPT(selectedCards, -1, 1);
|
||||
}
|
||||
|
||||
void PlayerActions::actIncrementCounter(int counterId, int delta)
|
||||
{
|
||||
Command_IncCounter cmd;
|
||||
cmd.set_counter_id(counterId);
|
||||
cmd.set_delta(delta);
|
||||
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::actSetCounter(int counterId, int value)
|
||||
{
|
||||
Command_SetCounter cmd;
|
||||
cmd.set_counter_id(counterId);
|
||||
cmd.set_value(value);
|
||||
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::actReduceLifeByPower(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actReduceLifeByPower(QList<CardItem *> selectedCards)
|
||||
{
|
||||
// find life counter
|
||||
auto lifeCounter = player->getLifeCounter();
|
||||
|
|
@ -1506,7 +1481,7 @@ void PlayerActions::actReduceLifeByPower(QList<CardState *> selectedCards)
|
|||
// calculate total power;
|
||||
int total = 0;
|
||||
for (auto card : selectedCards) {
|
||||
QVariantList parsed = CardState::parsePT(card->getPT());
|
||||
QVariantList parsed = CardItem::parsePT(card->getPT());
|
||||
if (!parsed.isEmpty()) {
|
||||
int power = parsed.first().toInt(); // toInt will default to 0 if it's not an int
|
||||
total += qMax(power, 0);
|
||||
|
|
@ -1520,7 +1495,17 @@ void PlayerActions::actReduceLifeByPower(QList<CardState *> selectedCards)
|
|||
sendGameCommand(prepareGameCommand(cmd));
|
||||
}
|
||||
|
||||
void PlayerActions::actRequestSetAnnotationDialog(QList<CardState *> selectedCards)
|
||||
void AnnotationDialog::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Return && event->modifiers() & Qt::ControlModifier) {
|
||||
event->accept();
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
QInputDialog::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void PlayerActions::actRequestSetAnnotationDialog(QList<CardItem *> selectedCards)
|
||||
{
|
||||
QString oldAnnotation;
|
||||
for (auto card : selectedCards) {
|
||||
|
|
@ -1532,7 +1517,7 @@ void PlayerActions::actRequestSetAnnotationDialog(QList<CardState *> selectedCar
|
|||
emit requestSetAnnotationDialog(oldAnnotation);
|
||||
}
|
||||
|
||||
void PlayerActions::actSetAnnotation(QList<CardState *> selectedCards, const QString &annotation)
|
||||
void PlayerActions::actSetAnnotation(QList<CardItem *> selectedCards, const QString &annotation)
|
||||
{
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
for (auto card : selectedCards) {
|
||||
|
|
@ -1546,7 +1531,17 @@ void PlayerActions::actSetAnnotation(QList<CardState *> selectedCards, const QSt
|
|||
sendGameCommand(prepareGameCommand(commandList));
|
||||
}
|
||||
|
||||
void PlayerActions::actUnattach(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actAttach()
|
||||
{
|
||||
auto *card = player->getGame()->getActiveCard();
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
card->drawAttachArrow();
|
||||
}
|
||||
|
||||
void PlayerActions::actUnattach(QList<CardItem *> selectedCards)
|
||||
{
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
for (auto card : selectedCards) {
|
||||
|
|
@ -1562,17 +1557,17 @@ void PlayerActions::actUnattach(QList<CardState *> selectedCards)
|
|||
sendGameCommand(prepareGameCommand(commandList));
|
||||
}
|
||||
|
||||
void PlayerActions::actAddCardCounter(QList<CardState *> selectedCards, int counterId)
|
||||
void PlayerActions::actAddCardCounter(QList<CardItem *> selectedCards, int counterId)
|
||||
{
|
||||
offsetCardCounter(selectedCards, counterId, 1);
|
||||
}
|
||||
|
||||
void PlayerActions::actRemoveCardCounter(QList<CardState *> selectedCards, int counterId)
|
||||
void PlayerActions::actRemoveCardCounter(QList<CardItem *> selectedCards, int counterId)
|
||||
{
|
||||
offsetCardCounter(selectedCards, counterId, -1);
|
||||
}
|
||||
|
||||
void PlayerActions::offsetCardCounter(QList<CardState *> selectedCards, int counterId, int offset)
|
||||
void PlayerActions::offsetCardCounter(QList<CardItem *> selectedCards, int counterId, int offset)
|
||||
{
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
for (auto card : selectedCards) {
|
||||
|
|
@ -1598,7 +1593,7 @@ void PlayerActions::offsetCardCounter(QList<CardState *> selectedCards, int coun
|
|||
sendGameCommand(prepareGameCommand(commandList));
|
||||
}
|
||||
|
||||
void PlayerActions::actRequestSetCardCounterDialog(QList<CardState *> selectedCards, int counterId)
|
||||
void PlayerActions::actRequestSetCardCounterDialog(QList<CardItem *> selectedCards, int counterId)
|
||||
{
|
||||
// If a single card is selected, we show the old value in the dialog. Otherwise, we show "x"
|
||||
QString oldValueForDlg = "x";
|
||||
|
|
@ -1610,7 +1605,7 @@ void PlayerActions::actRequestSetCardCounterDialog(QList<CardState *> selectedCa
|
|||
emit requestSetCardCounterDialog(counterId, oldValueForDlg);
|
||||
}
|
||||
|
||||
void PlayerActions::actSetCardCounter(QList<CardState *> selectedCards, int counterId, const QString &counterValue)
|
||||
void PlayerActions::actSetCardCounter(QList<CardItem *> selectedCards, int counterId, const QString &counterValue)
|
||||
{
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
for (auto card : selectedCards) {
|
||||
|
|
@ -1631,13 +1626,11 @@ void PlayerActions::actSetCardCounter(QList<CardState *> selectedCards, int coun
|
|||
sendGameCommand(prepareGameCommand(commandList));
|
||||
}
|
||||
|
||||
void PlayerActions::actIncrementAllCardCounters(QList<CardState *> cardsToUpdate)
|
||||
void PlayerActions::actIncrementAllCardCounters(QList<CardItem *> cardsToUpdate)
|
||||
{
|
||||
if (cardsToUpdate.isEmpty()) {
|
||||
// If no cards selected, update all cards on table
|
||||
for (auto *state : player->getTableZone()->getCards()) {
|
||||
cardsToUpdate.append(state);
|
||||
}
|
||||
cardsToUpdate = static_cast<QList<CardItem *>>(player->getTableZone()->getCards());
|
||||
}
|
||||
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
|
|
@ -1680,7 +1673,7 @@ static bool isUnwritableRevealZone(CardZoneLogic *zone)
|
|||
return false;
|
||||
}
|
||||
|
||||
void PlayerActions::playSelectedCards(QList<CardState *> selectedCards, const bool faceDown)
|
||||
void PlayerActions::playSelectedCards(QList<CardItem *> selectedCards, const bool faceDown)
|
||||
{
|
||||
// CardIds will get shuffled downwards when cards leave the deck.
|
||||
// We need to iterate through the cards in reverse order so cardIds don't get changed out from under us as we play
|
||||
|
|
@ -1695,26 +1688,27 @@ void PlayerActions::playSelectedCards(QList<CardState *> selectedCards, const bo
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actPlay(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actPlay(QList<CardItem *> selectedCards)
|
||||
{
|
||||
playSelectedCards(selectedCards, false);
|
||||
}
|
||||
|
||||
void PlayerActions::actPlayFacedown(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actPlayFacedown(QList<CardItem *> selectedCards)
|
||||
{
|
||||
playSelectedCards(selectedCards, true);
|
||||
}
|
||||
|
||||
void PlayerActions::actHide(QList<CardState *> selectedCards)
|
||||
void PlayerActions::actHide(QList<CardItem *> selectedCards)
|
||||
{
|
||||
for (const auto &card : selectedCards) {
|
||||
if (isUnwritableRevealZone(card->getZone())) {
|
||||
for (const auto &item : selectedCards) {
|
||||
auto *card = static_cast<CardItem *>(item);
|
||||
if (card && isUnwritableRevealZone(card->getZone())) {
|
||||
card->getZone()->removeCard(card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerActions::actReveal(QList<CardState *> selectedCards, QAction *action)
|
||||
void PlayerActions::actReveal(QList<CardItem *> selectedCards, QAction *action)
|
||||
{
|
||||
const int otherPlayerId = action->data().toInt();
|
||||
|
||||
|
|
@ -1805,9 +1799,9 @@ void PlayerActions::actRevealRandomGraveyardCard(int revealToPlayerId)
|
|||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::cardMenuAction(QList<CardState *> selectedCards, CardMenuActionType type)
|
||||
void PlayerActions::cardMenuAction(QList<CardItem *> selectedCards, CardMenuActionType type)
|
||||
{
|
||||
QList<CardState *> cardList = selectedCards;
|
||||
QList<CardItem *> cardList = selectedCards;
|
||||
|
||||
QList<const ::google::protobuf::Message *> commandList;
|
||||
if (type <= cmClone) {
|
||||
|
|
@ -1997,7 +1991,7 @@ void PlayerActions::cardMenuAction(QList<CardState *> selectedCards, CardMenuAct
|
|||
ctm->set_tapped(info.getUiAttributes().cipt);
|
||||
}
|
||||
|
||||
cmd->set_y(TableZoneLogic::tableRowToGridY(tableRow));
|
||||
cmd->set_y(TableZone::tableRowToGridY(tableRow));
|
||||
commandList.append(cmd);
|
||||
}
|
||||
break;
|
||||
|
|
@ -2046,76 +2040,6 @@ PendingCommand *PlayerActions::prepareGameCommand(const QList<const ::google::pr
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerActions::moveCards(CardZoneLogic *startZone,
|
||||
CardZoneLogic *targetZone,
|
||||
int x,
|
||||
int y,
|
||||
const QList<CardMoveRequest> &cards)
|
||||
{
|
||||
if (!startZone || !targetZone) {
|
||||
return;
|
||||
}
|
||||
|
||||
Command_MoveCard cmd;
|
||||
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
|
||||
cmd.set_start_zone(startZone->getName().toStdString());
|
||||
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
|
||||
cmd.set_target_zone(targetZone->getName().toStdString());
|
||||
cmd.set_x(x);
|
||||
cmd.set_y(y);
|
||||
|
||||
if (auto *viewLogic = qobject_cast<ZoneViewZoneLogic *>(targetZone)) {
|
||||
cmd.set_is_reversed(viewLogic->getIsReversed());
|
||||
}
|
||||
|
||||
for (const CardMoveRequest &card : cards) {
|
||||
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||
cardToMove->set_card_id(card.cardId);
|
||||
if (card.faceDown) {
|
||||
cardToMove->set_face_down(true);
|
||||
}
|
||||
if (!card.pt.isEmpty()) {
|
||||
cardToMove->set_pt(card.pt.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
PendingCommand *PlayerActions::prepareZoneDump(CardZoneLogic *zone, int numberCards)
|
||||
{
|
||||
if (!zone) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Command_DumpZone cmd;
|
||||
cmd.set_player_id(zone->getPlayer()->getPlayerInfo()->getId());
|
||||
cmd.set_zone_name(zone->getName().toStdString());
|
||||
cmd.set_number_cards(numberCards);
|
||||
if (auto *viewLogic = qobject_cast<ZoneViewZoneLogic *>(zone)) {
|
||||
cmd.set_is_reversed(viewLogic->getIsReversed());
|
||||
}
|
||||
|
||||
return prepareGameCommand(cmd);
|
||||
}
|
||||
|
||||
void PlayerActions::actToggleTapped(const QString &zoneName, const QList<CardState *> &cards, bool tapped)
|
||||
{
|
||||
QList<const ::google::protobuf::Message *> cmdList;
|
||||
for (CardState *card : cards) {
|
||||
if (card->getTapped() != tapped) {
|
||||
auto *cmd = new Command_SetCardAttr;
|
||||
cmd->set_zone(zoneName.toStdString());
|
||||
cmd->set_card_id(card->getId());
|
||||
cmd->set_attribute(AttrTapped);
|
||||
cmd->set_attr_value(tapped ? "1" : "0");
|
||||
cmdList.append(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
sendGameCommand(prepareGameCommand(cmdList));
|
||||
}
|
||||
|
||||
void PlayerActions::sendGameCommand(const google::protobuf::Message &command)
|
||||
{
|
||||
if (player->getPlayerInfo()->getJudge() && !player->getPlayerInfo()->getLocal()) {
|
||||
|
|
@ -8,13 +8,12 @@
|
|||
#ifndef COCKATRICE_PLAYER_ACTIONS_H
|
||||
#define COCKATRICE_PLAYER_ACTIONS_H
|
||||
|
||||
#include "../../game_graphics/board/card_item.h" // IWYU pragma: keep - moc instantiates the metatype for QList<CardItem *>, which Qt 6.4 needs complete
|
||||
#include "../../game_graphics/dialogs/dlg_create_token.h"
|
||||
#include "../../game_graphics/dialogs/dlg_move_top_cards_until.h"
|
||||
#include "../../game_graphics/player/card_menu_action_type.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "card_menu_action_type.h"
|
||||
#include "card_move_request.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include "move_top_cards_until_options.h"
|
||||
#include "token_info.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
|
@ -23,6 +22,7 @@
|
|||
#include <libcockatrice/filters/filter_string.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardItem;
|
||||
class CardRelation;
|
||||
class QAction;
|
||||
class QTimer;
|
||||
|
|
@ -36,16 +36,10 @@ class Message;
|
|||
}
|
||||
} // namespace google
|
||||
|
||||
class CardState;
|
||||
class CardZoneLogic;
|
||||
class Command_MoveCard;
|
||||
class GameEventContext;
|
||||
class ICardPreferenceProvider;
|
||||
class IInterfaceSettingsProvider;
|
||||
class PendingCommand;
|
||||
class PlayerLogic;
|
||||
class QAction;
|
||||
struct ArrowData;
|
||||
|
||||
class PlayerActions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -56,9 +50,7 @@ public:
|
|||
RANDOM_CARD_FROM_ZONE = -2
|
||||
};
|
||||
|
||||
explicit PlayerActions(PlayerLogic *player,
|
||||
IInterfaceSettingsProvider *interfaceSettings = nullptr,
|
||||
ICardPreferenceProvider *cardPreferences = nullptr);
|
||||
explicit PlayerActions(PlayerLogic *player);
|
||||
|
||||
void sendGameCommand(PendingCommand *pend);
|
||||
void sendGameCommand(const google::protobuf::Message &command);
|
||||
|
|
@ -66,52 +58,7 @@ public:
|
|||
PendingCommand *prepareGameCommand(const ::google::protobuf::Message &cmd);
|
||||
PendingCommand *prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList);
|
||||
|
||||
/**
|
||||
* @brief Moves the requested cards between zones on behalf of a view.
|
||||
* @param startZone Zone the cards are dragged out of.
|
||||
* @param targetZone Zone the cards are dropped onto.
|
||||
* @param x Horizontal target index within the zone.
|
||||
* @param y Vertical target index within the zone.
|
||||
* @param cards The cards to move, as chosen by the view.
|
||||
*/
|
||||
void
|
||||
moveCards(CardZoneLogic *startZone, CardZoneLogic *targetZone, int x, int y, const QList<CardMoveRequest> &cards);
|
||||
|
||||
/**
|
||||
* @brief Prepares a dump of the given zone, for the caller to connect to and send.
|
||||
* @param zone Zone to dump.
|
||||
* @param numberCards How many cards to dump, -1 for all.
|
||||
*/
|
||||
PendingCommand *prepareZoneDump(CardZoneLogic *zone, int numberCards);
|
||||
|
||||
/**
|
||||
* @brief Sets the tapped state of the cards that do not already have it.
|
||||
* @param zoneName Zone the cards belong to.
|
||||
* @param cards Cards the view wants toggled.
|
||||
* @param tapped Desired tapped state.
|
||||
*/
|
||||
void actToggleTapped(const QString &zoneName, const QList<CardState *> &cards, bool tapped);
|
||||
|
||||
/**
|
||||
* @brief Attaches one card to another on the table on behalf of a view.
|
||||
* @param startCard Card being attached.
|
||||
* @param targetCard Card being attached to.
|
||||
*/
|
||||
void attachCards(CardState *startCard, const CardState *targetCard);
|
||||
|
||||
/**
|
||||
* @brief Draws an arrow from a card to another card or a player on behalf of a view.
|
||||
*
|
||||
* The view resolves the endpoints before playing the card out of hand, so the
|
||||
* arrow still records the zone the card started in.
|
||||
*
|
||||
* @param startCard Card the arrow starts from.
|
||||
* @param arrow Arrow endpoints and color, as resolved by the view.
|
||||
* @param deleteInPhase Phase the arrow expires in, 0 to keep it until removed.
|
||||
*/
|
||||
void createArrow(CardState *startCard, const ArrowData &arrow, int deleteInPhase);
|
||||
|
||||
void moveOneCardUntil(CardState *card);
|
||||
void moveOneCardUntil(CardItem *card);
|
||||
void stopMoveTopCardsUntil();
|
||||
|
||||
[[nodiscard]] bool isMovingCardsUntil() const
|
||||
|
|
@ -140,7 +87,7 @@ signals:
|
|||
void requestDrawBottomCardsDialog(int defaultNumberBottomCards, int maxCards);
|
||||
void requestRollDieDialog();
|
||||
void requestCreateTokenDialog(const QStringList &predefinedTokens);
|
||||
void requestCreateRelatedFromRelationDialog(const CardState *sourceCard, const CardRelation *cardRelation);
|
||||
void requestCreateRelatedFromRelationDialog(const CardItem *sourceCard, const CardRelation *cardRelation);
|
||||
void requestMoveCardXCardsFromTopDialog(int defaultNumberTopCardsToPlaceBelow, int deckSize);
|
||||
void requestSetPTDialog(const QString &oldPT);
|
||||
void requestSetAnnotationDialog(const QString &oldAnnotation);
|
||||
|
|
@ -149,18 +96,12 @@ signals:
|
|||
void requestSortHand(const QList<CardList::SortOption> &options);
|
||||
void requestEnableAndSetCreateAnotherTokenAction(const QString &lastTokenName);
|
||||
void requestSetLastToken(CardInfoPtr lastToken);
|
||||
/**
|
||||
* @brief The player chose a mulligan size to remember as the starting hand size.
|
||||
*
|
||||
* Game logic must not write client settings itself, so persistence is left to the application.
|
||||
*/
|
||||
void startingHandSizeChosen(int number);
|
||||
|
||||
public slots:
|
||||
void setLastToken(CardInfoPtr cardInfo);
|
||||
void setLastTokenInfo(CardInfoPtr cardInfo);
|
||||
void playCard(CardState *c, bool faceDown);
|
||||
void playCardToTable(const CardState *c, bool faceDown);
|
||||
void playCard(CardItem *c, bool faceDown);
|
||||
void playCardToTable(const CardItem *c, bool faceDown);
|
||||
|
||||
void actUntapAll();
|
||||
void actRequestRollDieDialog();
|
||||
|
|
@ -169,9 +110,9 @@ public slots:
|
|||
void actRequestCreateTokenDialog(const QStringList &predefinedTokens);
|
||||
void actCreateToken(TokenInfo tokenToCreate);
|
||||
void actCreateAnotherToken();
|
||||
void actRequestCreateRelatedFromRelationDialog(const CardState *sourceCard, const CardRelation *cardRelation);
|
||||
bool createRelatedFromRelation(const CardState *sourceCard, const CardRelation *cardRelation, int variableCount);
|
||||
void onRelatedCardCreated(const CardState *sourceCard, const CardRelation *cardRelation);
|
||||
void actRequestCreateRelatedFromRelationDialog(const CardItem *sourceCard, const CardRelation *cardRelation);
|
||||
bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation, int variableCount);
|
||||
void onRelatedCardCreated(const CardItem *sourceCard, const CardRelation *cardRelation);
|
||||
void setLastRelatedCreationSucceeded(bool succeeded)
|
||||
{
|
||||
lastRelatedCreationSucceeded = succeeded;
|
||||
|
|
@ -191,9 +132,9 @@ public slots:
|
|||
void actMulliganMinusOne();
|
||||
void doMulligan(int number);
|
||||
|
||||
void actPlay(QList<CardState *> selectedCards);
|
||||
void actPlayFacedown(QList<CardState *> selectedCards);
|
||||
void actHide(QList<CardState *> selectedCards);
|
||||
void actPlay(QList<CardItem *> selectedCards);
|
||||
void actPlayFacedown(QList<CardItem *> selectedCards);
|
||||
void actHide(QList<CardItem *> selectedCards);
|
||||
|
||||
void actMoveTopCardToPlay();
|
||||
void actMoveTopCardToPlayFaceDown();
|
||||
|
|
@ -223,6 +164,10 @@ public slots:
|
|||
void actRequestMoveBottomCardsToDialog(const QString &targetZone, const QString &zoneDisplayName, bool faceDown);
|
||||
void moveBottomCardsTo(int number, const QString &targetZone, bool faceDown);
|
||||
|
||||
void actSelectAll();
|
||||
void actSelectRow();
|
||||
void actSelectColumn();
|
||||
|
||||
void actViewLibrary();
|
||||
void actViewHand();
|
||||
void actRequestViewTopCardsDialog();
|
||||
|
|
@ -242,55 +187,47 @@ public slots:
|
|||
|
||||
void actOpenDeckInDeckEditor();
|
||||
void actCreatePredefinedToken();
|
||||
void actCreateRelatedCard(const CardState *sourceCard, int index);
|
||||
void actCreateAllRelatedCards(const CardState *sourceCard);
|
||||
void actCreateRelatedCard();
|
||||
void actCreateAllRelatedCards();
|
||||
|
||||
void actRequestMoveCardXCardsFromTopDialog();
|
||||
void actMoveCardXCardsFromTop(QList<CardState *> selectedCards, int number);
|
||||
void actRemoveCardCounter(QList<CardState *> selectedCards, int counterId);
|
||||
void actAddCardCounter(QList<CardState *> selectedCards, int counterId);
|
||||
void actRequestSetCardCounterDialog(QList<CardState *> selectedCards, int counterId);
|
||||
void actSetCardCounter(QList<CardState *> selectedCards, int counterId, const QString &counterValue);
|
||||
void actIncrementAllCardCounters(QList<CardState *> cardsToUpdate);
|
||||
void actUnattach(QList<CardState *> selectedCards);
|
||||
void actIncPT(QList<CardState *> selectedCards, int deltaP, int deltaT);
|
||||
void actResetPT(QList<CardState *> selectedCards);
|
||||
void actRequestSetPTDialog(QList<CardState *> selectedCards);
|
||||
void actSetPT(QList<CardState *> selectedCards, const QString &pt);
|
||||
void actIncP(QList<CardState *> selectedCards);
|
||||
void actDecP(QList<CardState *> selectedCards);
|
||||
void actIncT(QList<CardState *> selectedCards);
|
||||
void actDecT(QList<CardState *> selectedCards);
|
||||
void actIncPT(QList<CardState *> selectedCards);
|
||||
void actDecPT(QList<CardState *> selectedCards);
|
||||
void actFlowP(QList<CardState *> selectedCards);
|
||||
void actFlowT(QList<CardState *> selectedCards);
|
||||
void actMoveCardXCardsFromTop(QList<CardItem *> selectedCards, int number);
|
||||
void actRemoveCardCounter(QList<CardItem *> selectedCards, int counterId);
|
||||
void actAddCardCounter(QList<CardItem *> selectedCards, int counterId);
|
||||
void actRequestSetCardCounterDialog(QList<CardItem *> selectedCards, int counterId);
|
||||
void actSetCardCounter(QList<CardItem *> selectedCards, int counterId, const QString &counterValue);
|
||||
void actIncrementAllCardCounters(QList<CardItem *> cardsToUpdate);
|
||||
void actAttach();
|
||||
void actUnattach(QList<CardItem *> selectedCards);
|
||||
void actDrawArrow();
|
||||
void actIncPT(QList<CardItem *> selectedCards, int deltaP, int deltaT);
|
||||
void actResetPT(QList<CardItem *> selectedCards);
|
||||
void actRequestSetPTDialog(QList<CardItem *> selectedCards);
|
||||
void actSetPT(QList<CardItem *> selectedCards, const QString &pt);
|
||||
void actIncP(QList<CardItem *> selectedCards);
|
||||
void actDecP(QList<CardItem *> selectedCards);
|
||||
void actIncT(QList<CardItem *> selectedCards);
|
||||
void actDecT(QList<CardItem *> selectedCards);
|
||||
void actIncPT(QList<CardItem *> selectedCards);
|
||||
void actDecPT(QList<CardItem *> selectedCards);
|
||||
void actFlowP(QList<CardItem *> selectedCards);
|
||||
void actFlowT(QList<CardItem *> selectedCards);
|
||||
|
||||
/** @brief Adjusts a player counter by a signed delta. */
|
||||
void actIncrementCounter(int counterId, int delta);
|
||||
void actReduceLifeByPower(QList<CardItem *> selectedCards);
|
||||
|
||||
/** @brief Sets a player counter to an absolute value. */
|
||||
void actSetCounter(int counterId, int value);
|
||||
|
||||
void actReduceLifeByPower(QList<CardState *> selectedCards);
|
||||
|
||||
void actRequestSetAnnotationDialog(QList<CardState *> selectedCards);
|
||||
void actSetAnnotation(QList<CardState *> selectedCards, const QString &annotation);
|
||||
void actReveal(QList<CardState *> selectedCards, QAction *action);
|
||||
void actRequestSetAnnotationDialog(QList<CardItem *> selectedCards);
|
||||
void actSetAnnotation(QList<CardItem *> selectedCards, const QString &annotation);
|
||||
void actReveal(QList<CardItem *> selectedCards, QAction *action);
|
||||
void actRevealHand(int revealToPlayerId);
|
||||
void actRevealRandomHandCard(int revealToPlayerId);
|
||||
void actRevealLibrary(int revealToPlayerId);
|
||||
|
||||
void actSortHand();
|
||||
|
||||
void cardMenuAction(QList<CardState *> selectedCards, CardMenuActionType type);
|
||||
void cardMenuAction(QList<CardItem *> selectedCards, CardMenuActionType type);
|
||||
|
||||
private:
|
||||
PlayerLogic *player;
|
||||
// Borrowed settings providers (owned by the application). Null outside the client, in which case the compiled-in
|
||||
// defaults below apply.
|
||||
IInterfaceSettingsProvider *interfaceSettings;
|
||||
ICardPreferenceProvider *cardPreferences;
|
||||
|
||||
int defaultNumberTopCards = 1;
|
||||
int defaultNumberTopCardsToPlaceBelow = 1;
|
||||
|
|
@ -308,23 +245,18 @@ private:
|
|||
|
||||
bool lastRelatedCreationSucceeded = false;
|
||||
|
||||
[[nodiscard]] bool getPlayToStack() const;
|
||||
[[nodiscard]] int getStartingHandSize() const;
|
||||
[[nodiscard]] bool getAnnotateTokens() const;
|
||||
[[nodiscard]] QString getCardPreferenceOverride(const QString &cardName) const;
|
||||
|
||||
void createCard(const CardState *sourceCard,
|
||||
void createCard(const CardItem *sourceCard,
|
||||
const QString &dbCardName,
|
||||
CardRelationType attach = CardRelationType::DoesNotAttach,
|
||||
bool persistent = false,
|
||||
bool faceDown = false);
|
||||
|
||||
void playSelectedCards(QList<CardState *> selectedCards, bool faceDown = false);
|
||||
void playSelectedCards(QList<CardItem *> selectedCards, bool faceDown = false);
|
||||
|
||||
void cmdSetTopCard(Command_MoveCard &cmd);
|
||||
void cmdSetBottomCard(Command_MoveCard &cmd);
|
||||
|
||||
void offsetCardCounter(QList<CardState *> selectedCards, int counterId, int offset);
|
||||
void offsetCardCounter(QList<CardItem *> selectedCards, int counterId, int offset);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PLAYER_ACTIONS_H
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
#include "player_event_handler.h"
|
||||
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/zones/view_zone.h"
|
||||
#include "../abstract_game.h"
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "../board/counter_state.h"
|
||||
#include "../zones/card_zone_logic.h"
|
||||
#include "../zones/hand_zone_logic.h"
|
||||
#include "../zones/pile_zone_logic.h"
|
||||
#include "../zones/view_zone_logic.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include "libcockatrice/card/printing/exact_card.h"
|
||||
#include "libcockatrice/protocol/pb/card_attributes.pb.h"
|
||||
|
|
@ -27,9 +27,6 @@
|
|||
#include <QSharedPointer>
|
||||
#include <QtGlobal>
|
||||
#include <algorithm>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/database/card_database_querier.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_undo_draw.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_attach_card.pb.h>
|
||||
|
|
@ -52,7 +49,6 @@
|
|||
#include <libcockatrice/protocol/pb/event_set_card_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_set_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/event_shuffle.pb.h>
|
||||
#include <libcockatrice/utility/color.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <qlogging.h>
|
||||
#include <string>
|
||||
|
|
@ -80,12 +76,12 @@ void PlayerEventHandler::eventShuffle(const Event_Shuffle &event)
|
|||
}
|
||||
|
||||
// close all views that contain shuffled cards
|
||||
for (auto *viewLogic : zone->getViews()) {
|
||||
if (viewLogic != nullptr) {
|
||||
int length = viewLogic->getCards().length();
|
||||
for (ZoneViewZone *view : zone->getViews()) {
|
||||
if (view != nullptr) {
|
||||
int length = view->getLogic()->getCards().length();
|
||||
// we want to close empty views as well
|
||||
if (length == 0 || length > absStart) { // note this assumes views always start at the top of the library
|
||||
viewLogic->requestClose();
|
||||
view->close();
|
||||
}
|
||||
} else {
|
||||
qWarning() << zone->getName() << "of" << player->getPlayerInfo()->getName() << "holds empty zoneview!";
|
||||
|
|
@ -159,29 +155,23 @@ void PlayerEventHandler::eventCreateToken(const Event_CreateToken &event)
|
|||
}
|
||||
|
||||
CardRef cardRef = {QString::fromStdString(event.card_name()), QString::fromStdString(event.card_provider_id())};
|
||||
CardItem *card = new CardItem(player, nullptr, cardRef, event.card_id());
|
||||
// use db PT if not provided in event and not face-down
|
||||
QString pt = QString::fromStdString(event.pt());
|
||||
if (pt.isEmpty() && !event.face_down()) {
|
||||
ExactCard dbCard = CardDatabaseManager::query()->getCard(cardRef);
|
||||
if (!QString::fromStdString(event.pt()).isEmpty()) {
|
||||
card->setPT(QString::fromStdString(event.pt()));
|
||||
} else if (!event.face_down()) {
|
||||
ExactCard dbCard = card->getCard();
|
||||
if (dbCard) {
|
||||
pt = dbCard.getInfo().getPowTough();
|
||||
card->setPT(dbCard.getInfo().getPowTough());
|
||||
}
|
||||
}
|
||||
card->setColor(QString::fromStdString(event.color()));
|
||||
card->setAnnotation(QString::fromStdString(event.annotation()));
|
||||
card->setDestroyOnZoneChange(event.destroy_on_zone_change());
|
||||
card->setFaceDown(event.face_down());
|
||||
|
||||
emit logCreateToken(player, cardRef.name, pt, event.face_down());
|
||||
|
||||
ServerInfo_Card cardInfo;
|
||||
cardInfo.set_id(event.card_id());
|
||||
cardInfo.set_name(event.card_name());
|
||||
cardInfo.set_provider_id(event.card_provider_id());
|
||||
cardInfo.set_pt(pt.toStdString());
|
||||
cardInfo.set_color(event.color());
|
||||
cardInfo.set_annotation(event.annotation());
|
||||
cardInfo.set_destroy_on_zone_change(event.destroy_on_zone_change());
|
||||
cardInfo.set_face_down(event.face_down());
|
||||
cardInfo.set_x(event.x());
|
||||
cardInfo.set_y(event.y());
|
||||
emit zone->createCardRequested(cardInfo, true);
|
||||
emit logCreateToken(player, card->getName(), card->getPT(), card->getFaceDown());
|
||||
zone->addCard(card, true, event.x(), event.y());
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event,
|
||||
|
|
@ -203,7 +193,7 @@ void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event,
|
|||
emit logSetTapped(player, nullptr, event.attr_value() == "1");
|
||||
}
|
||||
} else {
|
||||
CardState *card = zone->getCard(event.card_id());
|
||||
CardItem *card = zone->getCard(event.card_id());
|
||||
if (!card) {
|
||||
qWarning() << "PlayerEventHandler::eventSetCardAttr: card id=" << event.card_id() << "not found";
|
||||
return;
|
||||
|
|
@ -213,7 +203,7 @@ void PlayerEventHandler::eventSetCardAttr(const Event_SetCardAttr &event,
|
|||
}
|
||||
|
||||
void PlayerEventHandler::setCardAttrHelper(const GameEventContext &context,
|
||||
CardState *card,
|
||||
CardItem *card,
|
||||
CardAttribute attribute,
|
||||
const QString &avalue,
|
||||
bool allCards,
|
||||
|
|
@ -274,7 +264,7 @@ void PlayerEventHandler::eventSetCardCounter(const Event_SetCardCounter &event)
|
|||
return;
|
||||
}
|
||||
|
||||
CardState *card = zone->getCard(event.card_id());
|
||||
CardItem *card = zone->getCard(event.card_id());
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -351,13 +341,13 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv
|
|||
if (x == -1) {
|
||||
x = 0;
|
||||
}
|
||||
CardState *card = startZone->takeCard(position, event.card_id(), startZone != targetZone);
|
||||
CardItem *card = startZone->takeCard(position, event.card_id(), startZone != targetZone);
|
||||
if (card == nullptr) {
|
||||
return;
|
||||
}
|
||||
const bool zoneChanged = startZone != targetZone;
|
||||
const bool ownerChanged = zoneChanged && startZone->getPlayer() != targetZone->getPlayer();
|
||||
emit cardViewRefreshRequested(card, zoneChanged, ownerChanged ? targetZone->getPlayer() : nullptr);
|
||||
if (startZone != targetZone) {
|
||||
card->deleteCardInfoPopup();
|
||||
}
|
||||
if (event.has_card_name()) {
|
||||
QString name = QString::fromStdString(event.card_name());
|
||||
QString providerId =
|
||||
|
|
@ -366,19 +356,27 @@ void PlayerEventHandler::eventMoveCard(const Event_MoveCard &event, const GameEv
|
|||
}
|
||||
|
||||
if (card->getAttachedTo() && (startZone != targetZone)) {
|
||||
CardState *parentCard = card->getAttachedTo();
|
||||
// CardState::setAttachedTo removes the card from the old parent's attachedCards list and emits the zone events.
|
||||
CardItem *parentCard = card->getAttachedTo();
|
||||
card->setAttachedTo(nullptr);
|
||||
parentCard->getZone()->reorganizeCards();
|
||||
}
|
||||
|
||||
card->deleteDragItem();
|
||||
|
||||
card->setId(event.new_card_id());
|
||||
card->setFaceDown(event.face_down());
|
||||
if (startZone != targetZone) {
|
||||
const QList<CardState *> &attachedCards = card->getAttachedCards();
|
||||
card->setBeingPointedAt(false);
|
||||
card->setHovered(false);
|
||||
|
||||
const QList<CardItem *> &attachedCards = card->getAttachedCards();
|
||||
for (auto attachedCard : attachedCards) {
|
||||
emit targetZone->cardAdded(attachedCard);
|
||||
}
|
||||
|
||||
if (startZone->getPlayer() != targetZone->getPlayer()) {
|
||||
card->setOwner(targetZone->getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
// The log event has to be sent before the card is added to the target zone
|
||||
|
|
@ -406,7 +404,7 @@ void PlayerEventHandler::eventFlipCard(const Event_FlipCard &event)
|
|||
if (!zone) {
|
||||
return;
|
||||
}
|
||||
CardState *card = zone->getCard(event.card_id());
|
||||
CardItem *card = zone->getCard(event.card_id());
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -429,28 +427,20 @@ void PlayerEventHandler::eventDestroyCard(const Event_DestroyCard &event)
|
|||
return;
|
||||
}
|
||||
|
||||
CardState *card = zone->getCard(event.card_id());
|
||||
CardItem *card = zone->getCard(event.card_id());
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<CardState *> attachedCards = card->getAttachedCards();
|
||||
QList<CardItem *> attachedCards = card->getAttachedCards();
|
||||
// This list is always empty except for buggy server implementations.
|
||||
for (auto &attachedCard : attachedCards) {
|
||||
card->removeAttachedCard(attachedCard);
|
||||
attachedCard->setGridPoint(QPoint(-1, attachedCard->getGridPoint().y()));
|
||||
attachedCard->setAttachedTo(nullptr);
|
||||
if (attachedCard->getZone() == nullptr) {
|
||||
attachedCard->deleteView();
|
||||
} else {
|
||||
emit attachedCard->getZone()->cardAdded(attachedCard);
|
||||
attachedCard->getZone()->reorganizeCards();
|
||||
}
|
||||
}
|
||||
|
||||
emit logDestroyCard(player, card->getName());
|
||||
zone->takeCard(-1, event.card_id(), true);
|
||||
card->deleteView();
|
||||
card->deleteLater();
|
||||
}
|
||||
|
||||
void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event)
|
||||
|
|
@ -458,7 +448,7 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event)
|
|||
const QMap<int, PlayerLogic *> &playerList = player->getGame()->getPlayerManager()->getPlayers();
|
||||
PlayerLogic *targetPlayer = nullptr;
|
||||
CardZoneLogic *targetZone = nullptr;
|
||||
CardState *targetCard = nullptr;
|
||||
CardItem *targetCard = nullptr;
|
||||
if (event.has_target_player_id()) {
|
||||
targetPlayer = playerList.value(event.target_player_id(), 0);
|
||||
if (targetPlayer) {
|
||||
|
|
@ -474,12 +464,12 @@ void PlayerEventHandler::eventAttachCard(const Event_AttachCard &event)
|
|||
return;
|
||||
}
|
||||
|
||||
CardState *startCard = startZone->getCard(event.card_id());
|
||||
CardItem *startCard = startZone->getCard(event.card_id());
|
||||
if (!startCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
CardState *oldParent = startCard->getAttachedTo();
|
||||
CardItem *oldParent = startCard->getAttachedTo();
|
||||
|
||||
startCard->setAttachedTo(targetCard);
|
||||
|
||||
|
|
@ -508,7 +498,7 @@ void PlayerEventHandler::eventDrawCards(const Event_DrawCards &event)
|
|||
if (listSize) {
|
||||
for (int i = 0; i < listSize; ++i) {
|
||||
const ServerInfo_Card &cardInfo = event.cards(i);
|
||||
CardState *card = _deck->takeCard(0, cardInfo.id());
|
||||
CardItem *card = _deck->takeCard(0, cardInfo.id());
|
||||
QString cardName = QString::fromStdString(cardInfo.name());
|
||||
QString providerId = QString::fromStdString(cardInfo.provider_id());
|
||||
card->setCardRef({cardName, providerId});
|
||||
|
|
@ -556,7 +546,7 @@ void PlayerEventHandler::eventRevealCards(const Event_RevealCards &event, EventP
|
|||
for (const auto &card : cardList) {
|
||||
QString cardName = QString::fromStdString(card->name());
|
||||
QString providerId = QString::fromStdString(card->provider_id());
|
||||
CardState *cardItem = zone->getCard(card->id());
|
||||
CardItem *cardItem = zone->getCard(card->id());
|
||||
if (!cardItem) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
#include <qtmetamacros.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
class CardState;
|
||||
class CardItem;
|
||||
class CardZoneLogic;
|
||||
class PlayerLogic;
|
||||
class Event_AttachCard;
|
||||
|
|
@ -61,7 +61,7 @@ template <typename T> class QList;
|
|||
* Design notes:
|
||||
* - All event handlers assume events are authoritative and already validated
|
||||
* by the server.
|
||||
* - Most handlers mutate both logical state (CardState, CardZoneLogic, counters)
|
||||
* - Most handlers mutate both logical state (CardItem, CardZoneLogic, counters)
|
||||
* and visual/UI state (views, arrows, menus).
|
||||
* - Logging signals are emitted *after* or *during* state mutation, depending
|
||||
* on whether later mutations would invalidate log data.
|
||||
|
|
@ -238,7 +238,7 @@ signals:
|
|||
void logUndoDraw(PlayerLogic *player, QString cardName);
|
||||
void logUndoDrawFailed(PlayerLogic *player);
|
||||
void logMoveCard(PlayerLogic *player,
|
||||
CardState *card,
|
||||
CardItem *card,
|
||||
CardZoneLogic *startZone,
|
||||
int oldX,
|
||||
CardZoneLogic *targetZone,
|
||||
|
|
@ -248,11 +248,11 @@ signals:
|
|||
void logAttachCard(PlayerLogic *player, QString cardName, PlayerLogic *targetPlayer, QString targetCardName);
|
||||
void logUnattachCard(PlayerLogic *player, QString cardName);
|
||||
void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue);
|
||||
void logSetTapped(PlayerLogic *player, CardState *card, bool tapped);
|
||||
void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped);
|
||||
void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue);
|
||||
void logSetDoesntUntap(PlayerLogic *player, CardState *card, bool doesntUntap);
|
||||
void logSetPT(PlayerLogic *player, CardState *card, QString newPT);
|
||||
void logSetAnnotation(PlayerLogic *player, CardState *card, QString newAnnotation);
|
||||
void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap);
|
||||
void logSetPT(PlayerLogic *player, CardItem *card, QString newPT);
|
||||
void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation);
|
||||
void logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed = false);
|
||||
void logRevealCards(PlayerLogic *player,
|
||||
CardZoneLogic *zone,
|
||||
|
|
@ -266,23 +266,15 @@ signals:
|
|||
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
||||
/** @} */
|
||||
|
||||
void cardZoneChanged(CardState *card, bool sameZone);
|
||||
void requestCardMenuUpdate(CardState *card);
|
||||
/**
|
||||
* @brief A card was just moved by the server and its view needs refreshing.
|
||||
*
|
||||
* @param card The card that moved.
|
||||
* @param zoneChanged Whether the card crossed a zone boundary.
|
||||
* @param newOwner The player the card now belongs to, or nullptr to leave the owner alone.
|
||||
*/
|
||||
void cardViewRefreshRequested(CardState *card, bool zoneChanged, PlayerLogic *newOwner);
|
||||
void cardZoneChanged(CardItem *card, bool sameZone);
|
||||
void requestCardMenuUpdate(const CardItem *card);
|
||||
|
||||
private:
|
||||
/** Owning player instance. */
|
||||
PlayerLogic *player;
|
||||
|
||||
void setCardAttrHelper(const GameEventContext &context,
|
||||
CardState *card,
|
||||
CardItem *card,
|
||||
CardAttribute attribute,
|
||||
const QString &avalue,
|
||||
bool allCards,
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
#include "player_logic.h"
|
||||
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../abstract_game.h"
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "../board/counter_state.h"
|
||||
#include "../game_meta_info.h"
|
||||
#include "../zones/hand_zone_logic.h"
|
||||
|
|
@ -34,17 +33,10 @@
|
|||
#include <qalgorithms.h>
|
||||
#include <string>
|
||||
|
||||
PlayerLogic::PlayerLogic(const ServerInfo_User &info,
|
||||
int _id,
|
||||
bool _local,
|
||||
bool _judge,
|
||||
AbstractGame *_parent,
|
||||
IInterfaceSettingsProvider *interfaceSettings,
|
||||
ICardPreferenceProvider *cardPreferences)
|
||||
PlayerLogic::PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent)
|
||||
: QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)),
|
||||
playerEventHandler(new PlayerEventHandler(this)),
|
||||
playerActions(new PlayerActions(this, interfaceSettings, cardPreferences)), active(false), conceded(false),
|
||||
zoneId(0), dialogSemaphore(false)
|
||||
playerEventHandler(new PlayerEventHandler(this)), playerActions(new PlayerActions(this)), active(false),
|
||||
conceded(false), zoneId(0), dialogSemaphore(false)
|
||||
{
|
||||
initializeZones();
|
||||
}
|
||||
|
|
@ -180,20 +172,22 @@ void PlayerLogic::processPlayerInfo(const ServerInfo_Player &info)
|
|||
const int cardListSize = zoneInfo.card_list_size();
|
||||
if (!cardListSize) {
|
||||
for (int j = 0; j < zoneInfo.card_count(); ++j) {
|
||||
emit zone->createCardRequested(ServerInfo_Card(), false);
|
||||
zone->addCard(new CardItem(this), false, -1);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < cardListSize; ++j) {
|
||||
ServerInfo_Card cardInfo = zoneInfo.card_list(j);
|
||||
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
||||
auto *card = new CardItem(this);
|
||||
card->processCardInfo(cardInfo);
|
||||
// Zones without coordinates (hand, piles, stack) preserve the order
|
||||
// they arrive in on the server in the positions of their cards list.
|
||||
// The x coordinate of such cards is always 0, so inserting at it
|
||||
// would reverse the list on reconnect. Append instead.
|
||||
if (!zoneInfo.with_coords()) {
|
||||
cardInfo.set_x(-1);
|
||||
cardInfo.set_y(-1);
|
||||
if (zoneInfo.with_coords()) {
|
||||
zone->addCard(card, false, cardInfo.x(), cardInfo.y());
|
||||
} else {
|
||||
zone->addCard(card, false, -1);
|
||||
}
|
||||
emit zone->createCardRequested(cardInfo, false);
|
||||
}
|
||||
}
|
||||
if (zoneInfo.has_always_reveal_top_card()) {
|
||||
|
|
@ -225,8 +219,8 @@ void PlayerLogic::processCardAttachment(const ServerInfo_Player &info)
|
|||
for (int j = 0; j < cardListSize; ++j) {
|
||||
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
||||
if (cardInfo.has_attach_player_id()) {
|
||||
CardState *startCard = zone->getCard(cardInfo.id());
|
||||
CardState *targetCard =
|
||||
CardItem *startCard = zone->getCard(cardInfo.id());
|
||||
CardItem *targetCard =
|
||||
game->getCard(cardInfo.attach_player_id(), QString::fromStdString(cardInfo.attach_zone()),
|
||||
cardInfo.attach_card_id());
|
||||
if (!targetCard) {
|
||||
|
|
@ -245,19 +239,19 @@ void PlayerLogic::processCardAttachment(const ServerInfo_Player &info)
|
|||
}
|
||||
}
|
||||
|
||||
void PlayerLogic::addCard(AbstractCardItem *card)
|
||||
void PlayerLogic::addCard(CardItem *card)
|
||||
{
|
||||
emit newCardAdded(card);
|
||||
}
|
||||
|
||||
void PlayerLogic::deleteCard(CardState *card)
|
||||
void PlayerLogic::deleteCard(CardItem *card)
|
||||
{
|
||||
if (card == nullptr) {
|
||||
return;
|
||||
} else if (dialogSemaphore) {
|
||||
cardsToDelete.append(card);
|
||||
} else {
|
||||
card->deleteView();
|
||||
card->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -338,7 +332,7 @@ bool PlayerLogic::clearCardsToDelete()
|
|||
|
||||
for (auto &i : cardsToDelete) {
|
||||
if (i != nullptr) {
|
||||
i->deleteView();
|
||||
i->deleteLater();
|
||||
}
|
||||
}
|
||||
cardsToDelete.clear();
|
||||
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef PLAYER_H
|
||||
#define PLAYER_H
|
||||
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../board/counter_state.h"
|
||||
#include "../zones/card_zone_logic.h"
|
||||
#include "../zones/hand_zone_logic.h"
|
||||
#include "../zones/pile_zone_logic.h"
|
||||
|
|
@ -19,16 +17,12 @@
|
|||
#include "libcockatrice/utility/playmat_params.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QInputDialog>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
#include <libcockatrice/deck_list/loaded_deck.h>
|
||||
#include <libcockatrice/filters/filter_string.h>
|
||||
#include <libcockatrice/protocol/pb/card_attributes.pb.h>
|
||||
#include <libcockatrice/protocol/pb/game_event.pb.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
|
|
@ -37,6 +31,7 @@
|
|||
// signatures, which the moc-generated code needs to be complete.
|
||||
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
|
||||
|
||||
class CardItem;
|
||||
class CounterState;
|
||||
class QWidget;
|
||||
class ServerInfo_PlayerProperties;
|
||||
|
|
@ -47,8 +42,6 @@ template <class T> class QSharedPointer;
|
|||
inline Q_LOGGING_CATEGORY(PlayerLog, "player");
|
||||
class AbstractCardItem;
|
||||
class AbstractGame;
|
||||
class ICardPreferenceProvider;
|
||||
class IInterfaceSettingsProvider;
|
||||
class PlayerInfo;
|
||||
class PlayerEventHandler;
|
||||
class PlayerActions;
|
||||
|
|
@ -74,7 +67,7 @@ signals:
|
|||
/** @brief Emitted when the remote playmat (card/params) is updated from player properties. */
|
||||
void playmatChanged();
|
||||
void newCardAdded(AbstractCardItem *card);
|
||||
void requestCardMenuUpdate(CardState *card);
|
||||
void requestCardMenuUpdate(const CardItem *card);
|
||||
void counterAdded(CounterState *state);
|
||||
void counterRemoved(int counterId);
|
||||
void rearrangeCounters();
|
||||
|
|
@ -94,13 +87,7 @@ public slots:
|
|||
void onRequestZoneViewToggle(const QString &zoneName, int numberCards, bool isReversed);
|
||||
|
||||
public:
|
||||
PlayerLogic(const ServerInfo_User &info,
|
||||
int _id,
|
||||
bool _local,
|
||||
bool _judge,
|
||||
AbstractGame *_parent,
|
||||
IInterfaceSettingsProvider *interfaceSettings = nullptr,
|
||||
ICardPreferenceProvider *cardPreferences = nullptr);
|
||||
PlayerLogic(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent);
|
||||
~PlayerLogic() override;
|
||||
|
||||
void initializeZones();
|
||||
|
|
@ -110,8 +97,8 @@ public:
|
|||
void processPlayerInfo(const ServerInfo_Player &info);
|
||||
void processCardAttachment(const ServerInfo_Player &info);
|
||||
|
||||
void addCard(AbstractCardItem *c);
|
||||
void deleteCard(CardState *c);
|
||||
void addCard(CardItem *c);
|
||||
void deleteCard(CardItem *c);
|
||||
|
||||
bool clearCardsToDelete();
|
||||
|
||||
|
|
@ -263,7 +250,7 @@ private:
|
|||
QMap<int, CounterState *> counters;
|
||||
|
||||
bool dialogSemaphore;
|
||||
QList<CardState *> cardsToDelete;
|
||||
QList<CardItem *> cardsToDelete;
|
||||
|
||||
// Playmat from player properties (for opponent display)
|
||||
CardRef remotePlaymatCard;
|
||||
|
|
@ -271,4 +258,15 @@ private:
|
|||
bool hasRemotePlaymat = false;
|
||||
};
|
||||
|
||||
class AnnotationDialog : public QInputDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
public:
|
||||
explicit AnnotationDialog(QWidget *parent = nullptr) : QInputDialog(parent)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -12,12 +12,9 @@
|
|||
PlayerManager::PlayerManager(AbstractGame *_game,
|
||||
int _localPlayerId,
|
||||
bool _localPlayerIsJudge,
|
||||
bool localPlayerIsSpectator,
|
||||
IInterfaceSettingsProvider *_interfaceSettings,
|
||||
ICardPreferenceProvider *_cardPreferences)
|
||||
bool localPlayerIsSpectator)
|
||||
: QObject(_game), game(_game), players(QMap<int, PlayerLogic *>()), localPlayerId(_localPlayerId),
|
||||
localPlayerIsJudge(_localPlayerIsJudge), localPlayerIsSpectator(localPlayerIsSpectator),
|
||||
interfaceSettings(_interfaceSettings), cardPreferences(_cardPreferences)
|
||||
localPlayerIsJudge(_localPlayerIsJudge), localPlayerIsSpectator(localPlayerIsSpectator)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +52,7 @@ bool PlayerManager::isLocalPlayer(int playerId)
|
|||
PlayerLogic *PlayerManager::addPlayer(int playerId, const ServerInfo_User &info)
|
||||
{
|
||||
auto *newPlayer = new PlayerLogic(info, playerId, isLocalPlayer(playerId) || game->getGameState()->getIsLocalGame(),
|
||||
isJudge(), getGame(), interfaceSettings, cardPreferences);
|
||||
isJudge(), getGame());
|
||||
connect(newPlayer, &PlayerLogic::concededChanged, this, &PlayerManager::onPlayerConceded);
|
||||
players.insert(playerId, newPlayer);
|
||||
emit playerAdded(newPlayer);
|
||||
|
|
@ -16,8 +16,6 @@
|
|||
#include <qtmetamacros.h>
|
||||
|
||||
class AbstractGame;
|
||||
class ICardPreferenceProvider;
|
||||
class IInterfaceSettingsProvider;
|
||||
class PlayerLogic;
|
||||
|
||||
class PlayerManager : public QObject
|
||||
|
|
@ -25,12 +23,7 @@ class PlayerManager : public QObject
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlayerManager(AbstractGame *_game,
|
||||
int _localPlayerId,
|
||||
bool _localPlayerIsJudge,
|
||||
bool localPlayerIsSpectator,
|
||||
IInterfaceSettingsProvider *interfaceSettings = nullptr,
|
||||
ICardPreferenceProvider *cardPreferences = nullptr);
|
||||
PlayerManager(AbstractGame *_game, int _localPlayerId, bool _localPlayerIsJudge, bool localPlayerIsSpectator);
|
||||
|
||||
AbstractGame *game;
|
||||
QMap<int, PlayerLogic *> players;
|
||||
|
|
@ -38,9 +31,6 @@ public:
|
|||
bool localPlayerIsJudge;
|
||||
bool localPlayerIsSpectator;
|
||||
QMap<int, ServerInfo_User> spectators;
|
||||
// Borrowed settings providers forwarded to each PlayerLogic (owned by the application).
|
||||
IInterfaceSettingsProvider *interfaceSettings;
|
||||
ICardPreferenceProvider *cardPreferences;
|
||||
|
||||
[[nodiscard]] bool isSpectator() const
|
||||
{
|
||||
|
|
@ -9,15 +9,10 @@
|
|||
class GameReplay;
|
||||
class QObject;
|
||||
|
||||
Replay::Replay(QObject *_parent,
|
||||
const GameReplay *_replay,
|
||||
bool isLocalGame,
|
||||
IInterfaceSettingsProvider *interfaceSettings,
|
||||
ICardPreferenceProvider *cardPreferences)
|
||||
: AbstractGame(_parent)
|
||||
Replay::Replay(QObject *_parent, const GameReplay *_replay, bool isLocalGame) : AbstractGame(_parent)
|
||||
{
|
||||
gameState = new GameState(this, 0, -1, isLocalGame, {}, false, false, -1, false);
|
||||
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
|
||||
playerManager = new PlayerManager(this, -1, false, true, interfaceSettings, cardPreferences);
|
||||
playerManager = new PlayerManager(this, -1, false, true);
|
||||
loadReplay(_replay);
|
||||
}
|
||||
26
cockatrice/src/game/replay.h
Normal file
26
cockatrice/src/game/replay.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* @file replay.h
|
||||
* @ingroup GameLogic
|
||||
* @ingroup Replay
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_REPLAY_H
|
||||
#define COCKATRICE_REPLAY_H
|
||||
|
||||
#include "abstract_game.h"
|
||||
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class GameReplay;
|
||||
class QObject;
|
||||
|
||||
class Replay : public AbstractGame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Replay(QObject *_parent, const GameReplay *_replay, bool isLocalGame);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_REPLAY_H
|
||||
|
|
@ -5,9 +5,9 @@ namespace CardZoneAlgorithms
|
|||
{
|
||||
|
||||
/**
|
||||
* Shared insertion logic for zones where cards follow the standard pattern:
|
||||
* clamp index, insert, clear identity if contents unknown, reset state.
|
||||
* Visibility and parenting are handled by the graphics zone's onCardAdded().
|
||||
* Shared insertion logic for zones where cards become visible on add and follow
|
||||
* the standard pattern: clamp index, insert, clear identity if contents unknown,
|
||||
* reset state, show card.
|
||||
*
|
||||
* Zones with different post-add behavior (signal connections, positional resets,
|
||||
* hidden cards, or coordinate-based placement) should NOT use this — implement
|
||||
|
|
@ -18,7 +18,8 @@ namespace CardZoneAlgorithms
|
|||
*
|
||||
* @tparam CardList Must provide: size() -> int, insert(int, CardType*),
|
||||
* getContentsKnown() -> bool
|
||||
* @tparam CardType Must provide: setId(int), setCardRef(CardRefType), resetState(bool)
|
||||
* @tparam CardType Must provide: setId(int), setCardRef(CardRefType),
|
||||
* resetState(bool), setVisible(bool)
|
||||
* @param keepAnnotations Forwarded to card->resetState(). Stack-like zones preserve
|
||||
* annotations across zone transitions; hand-like zones clear them.
|
||||
*/
|
||||
|
|
@ -36,6 +37,7 @@ void addCardToList(CardList &cards, CardType *card, int x, bool keepAnnotations)
|
|||
}
|
||||
|
||||
card->resetState(keepAnnotations);
|
||||
card->setVisible(true);
|
||||
}
|
||||
|
||||
} // namespace CardZoneAlgorithms
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
#include "card_zone_logic.h"
|
||||
|
||||
#include "../../client/translation.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/zones/card_zone.h"
|
||||
#include "../../game_graphics/zones/view_zone.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/card_state.h"
|
||||
#include "../player/player_actions.h"
|
||||
#include "../player/player_info.h"
|
||||
#include "../player/player_logic.h"
|
||||
#include "../translation.h"
|
||||
#include "libcockatrice/card/database/card_database.h"
|
||||
#include "view_zone_logic.h"
|
||||
|
||||
|
|
@ -42,24 +44,19 @@ CardZoneLogic::CardZoneLogic(PlayerLogic *_player,
|
|||
&CardZoneLogic::refreshCardInfos);
|
||||
}
|
||||
|
||||
void CardZoneLogic::addCard(CardState *card, const bool reorganize, const int x, const int y)
|
||||
void CardZoneLogic::addCard(CardItem *card, const bool reorganize, const int x, const int y)
|
||||
{
|
||||
if (!card) {
|
||||
qCWarning(CardZoneLogicLog) << "CardZoneLogic::addCard() card is null; this shouldn't normally happen";
|
||||
qCWarning(CardZoneLog) << "CardZoneLogic::addCard() card is null; this shouldn't normally happen";
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto *viewLogic : views) {
|
||||
if (viewLogic->prepareAddCard(x)) {
|
||||
ServerInfo_Card cardInfo;
|
||||
const CardRef &cardRef = card->getCardRef();
|
||||
cardInfo.set_name(cardRef.name.toStdString());
|
||||
cardInfo.set_provider_id(cardRef.providerId.toStdString());
|
||||
cardInfo.set_id(card->getId());
|
||||
cardInfo.set_face_down(card->getFaceDown());
|
||||
cardInfo.set_x(x);
|
||||
cardInfo.set_y(y);
|
||||
emit viewLogic->createCardRequested(cardInfo, reorganize);
|
||||
for (auto *view : views) {
|
||||
if (qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->prepareAddCard(x)) {
|
||||
auto copy = new CardItem(player, nullptr, card->getCardRef(), card->getId());
|
||||
copy->setFaceDown(card->getFaceDown());
|
||||
|
||||
view->getLogic()->addCard(copy, reorganize, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +71,7 @@ void CardZoneLogic::addCard(CardState *card, const bool reorganize, const int x,
|
|||
emit cardCountChanged();
|
||||
}
|
||||
|
||||
CardState *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone)
|
||||
CardItem *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone)
|
||||
{
|
||||
if (position == -1) {
|
||||
// position == -1 means either that the zone is indexed by card id
|
||||
|
|
@ -93,11 +90,11 @@ CardState *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto *viewLogic : views) {
|
||||
viewLogic->removeCard(position, toNewZone);
|
||||
for (auto *view : views) {
|
||||
qobject_cast<ZoneViewZoneLogic *>(view->getLogic())->removeCard(position, toNewZone);
|
||||
}
|
||||
|
||||
CardState *c = cards.takeAt(position);
|
||||
CardItem *c = cards.takeAt(position);
|
||||
|
||||
c->setId(cardId);
|
||||
|
||||
|
|
@ -106,11 +103,11 @@ CardState *CardZoneLogic::takeCard(int position, int cardId, bool toNewZone)
|
|||
return c;
|
||||
}
|
||||
|
||||
CardState *CardZoneLogic::getCard(int cardId)
|
||||
CardItem *CardZoneLogic::getCard(int cardId)
|
||||
{
|
||||
CardState *c = cards.findCard(cardId);
|
||||
CardItem *c = cards.findCard(cardId);
|
||||
if (!c) {
|
||||
qCWarning(CardZoneLogicLog) << "CardZoneLogic::getCard: card id=" << cardId << "not found";
|
||||
qCWarning(CardZoneLog) << "CardZoneLogic::getCard: card id=" << cardId << "not found";
|
||||
return nullptr;
|
||||
}
|
||||
// If the card's id is -1, this zone is invisible,
|
||||
|
|
@ -122,10 +119,10 @@ CardState *CardZoneLogic::getCard(int cardId)
|
|||
return c;
|
||||
}
|
||||
|
||||
void CardZoneLogic::removeCard(CardState *card)
|
||||
void CardZoneLogic::removeCard(CardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
qCWarning(CardZoneLogicLog) << "CardZoneLogic::removeCard: card is null, this shouldn't normally happen";
|
||||
qCWarning(CardZoneLog) << "CardZoneLogic::removeCard: card is null, this shouldn't normally happen";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -138,8 +135,8 @@ void CardZoneLogic::removeCard(CardState *card)
|
|||
|
||||
void CardZoneLogic::refreshCardInfos()
|
||||
{
|
||||
for (const auto &cardState : cards) {
|
||||
cardState->refreshCardInfo();
|
||||
for (const auto &cardItem : cards) {
|
||||
cardItem->refreshCardInfo();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,17 +168,17 @@ void CardZoneLogic::clearContents()
|
|||
const CardList toClear = cards;
|
||||
|
||||
// Detach and notify attached cards and zones *before* deleting anything.
|
||||
for (CardState *card : toClear) {
|
||||
for (CardItem *card : toClear) {
|
||||
// If an incorrectly implemented server doesn't return attached cards to whom they belong before dropping a
|
||||
// player, we have to return them to avoid a crash.
|
||||
const QList<CardState *> &attachedCards = card->getAttachedCards();
|
||||
for (CardState *attachedCard : attachedCards) {
|
||||
const QList<CardItem *> &attachedCards = card->getAttachedCards();
|
||||
for (CardItem *attachedCard : attachedCards) {
|
||||
emit attachedCard->getZone()->cardAdded(attachedCard);
|
||||
}
|
||||
}
|
||||
|
||||
// Now request deletions after all manipulations are done.
|
||||
for (CardState *card : toClear) {
|
||||
for (CardItem *card : toClear) {
|
||||
player->deleteCard(card);
|
||||
}
|
||||
|
||||
|
|
@ -7,30 +7,28 @@
|
|||
#ifndef COCKATRICE_CARD_ZONE_LOGIC_H
|
||||
#define COCKATRICE_CARD_ZONE_LOGIC_H
|
||||
|
||||
#include "../../client/translation.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../translation.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardItem;
|
||||
|
||||
inline Q_LOGGING_CATEGORY(CardZoneLogicLog, "card_zone_logic");
|
||||
|
||||
class PlayerLogic;
|
||||
class ZoneViewZoneLogic;
|
||||
class CardDragItem;
|
||||
class ZoneViewZone;
|
||||
|
||||
class CardZoneLogic : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void cardAdded(CardState *addedCard);
|
||||
/** @brief Asks the graphics side to build the card item for @p cardInfo and add it to this zone. */
|
||||
void createCardRequested(const ServerInfo_Card &cardInfo, bool reorganize);
|
||||
void cardAdded(CardItem *addedCard);
|
||||
void cardCountChanged();
|
||||
void reorganizeCards();
|
||||
void updateGraphics();
|
||||
|
|
@ -45,17 +43,16 @@ public:
|
|||
bool _contentsKnown,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
void addCard(CardState *card, bool reorganize, int x, int y = -1);
|
||||
void addCard(CardItem *card, bool reorganize, int x, int y = -1);
|
||||
// getCard() finds a card by id.
|
||||
CardState *getCard(int cardId);
|
||||
void removeCard(CardState *card);
|
||||
CardItem *getCard(int cardId);
|
||||
void removeCard(CardItem *card);
|
||||
// takeCard() finds a card by position and removes it from the zone and from all of its views.
|
||||
virtual CardState *takeCard(int position, int cardId, bool canResize = true);
|
||||
virtual CardItem *takeCard(int position, int cardId, bool canResize = true);
|
||||
|
||||
void rawInsertCard(CardState *card, int index)
|
||||
void rawInsertCard(CardItem *card, int index)
|
||||
{
|
||||
cards.insert(index, card);
|
||||
emit cardCountChanged();
|
||||
}
|
||||
|
||||
[[nodiscard]] const CardList &getCards() const
|
||||
|
|
@ -66,7 +63,6 @@ public:
|
|||
void sortCards(const QList<CardList::SortOption> &options)
|
||||
{
|
||||
cards.sortBy(options);
|
||||
emit cardCountChanged();
|
||||
}
|
||||
[[nodiscard]] QString getName() const
|
||||
{
|
||||
|
|
@ -81,7 +77,7 @@ public:
|
|||
{
|
||||
return cards.getContentsKnown();
|
||||
}
|
||||
QList<ZoneViewZoneLogic *> &getViews()
|
||||
QList<ZoneViewZone *> &getViews()
|
||||
{
|
||||
return views;
|
||||
}
|
||||
|
|
@ -113,12 +109,12 @@ protected:
|
|||
PlayerLogic *player;
|
||||
QString name;
|
||||
CardList cards;
|
||||
QList<ZoneViewZoneLogic *> views;
|
||||
QList<ZoneViewZone *> views;
|
||||
bool hasCardAttr;
|
||||
bool isShufflable;
|
||||
bool alwaysRevealTopCard;
|
||||
|
||||
virtual void addCardImpl(CardState *card, int x, int y) = 0;
|
||||
virtual void addCardImpl(CardItem *card, int x, int y) = 0;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CARD_ZONE_LOGIC_H
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include "hand_zone_logic.h"
|
||||
|
||||
#include "../board/card_state.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "card_zone_algorithms.h"
|
||||
|
||||
class PlayerLogic;
|
||||
|
|
@ -16,7 +16,7 @@ HandZoneLogic::HandZoneLogic(PlayerLogic *_player,
|
|||
{
|
||||
}
|
||||
|
||||
void HandZoneLogic::addCardImpl(CardState *card, int x, int /*y*/)
|
||||
void HandZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
||||
{
|
||||
CardZoneAlgorithms::addCardToList(cards, card, x, false);
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ public:
|
|||
QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void addCardImpl(CardState *card, int x, int y) override;
|
||||
void addCardImpl(CardItem *card, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_HAND_ZONE_LOGIC_H
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
#include "pile_zone_logic.h"
|
||||
|
||||
#include "../board/card_state.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../board/card_list.h"
|
||||
|
||||
class PlayerLogic;
|
||||
class QObject;
|
||||
|
||||
PileZoneLogic::PileZoneLogic(PlayerLogic *_player,
|
||||
const QString &_name,
|
||||
|
|
@ -12,14 +16,15 @@ PileZoneLogic::PileZoneLogic(PlayerLogic *_player,
|
|||
{
|
||||
}
|
||||
|
||||
void PileZoneLogic::addCardImpl(CardState *card, int x, int /*y*/)
|
||||
void PileZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
||||
{
|
||||
connect(card, &CardState::cardPixmapUpdated, this, &PileZoneLogic::callUpdate);
|
||||
connect(card, &CardItem::sigPixmapUpdated, this, &PileZoneLogic::callUpdate);
|
||||
// if x is negative set it to add at end
|
||||
if (x < 0 || x >= cards.size()) {
|
||||
x = cards.size();
|
||||
}
|
||||
cards.insert(x, card);
|
||||
card->setPos(0, 0);
|
||||
if (!contentsKnown()) {
|
||||
card->setCardRef({});
|
||||
card->setId(-1);
|
||||
|
|
@ -28,5 +33,6 @@ void PileZoneLogic::addCardImpl(CardState *card, int x, int /*y*/)
|
|||
cards.at(x + 1)->setCardRef({});
|
||||
}
|
||||
}
|
||||
card->resetState(false);
|
||||
card->setVisible(false);
|
||||
card->resetState();
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ public:
|
|||
QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void addCardImpl(CardState *card, int x, int y) override;
|
||||
void addCardImpl(CardItem *card, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PILE_ZONE_LOGIC_H
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include "stack_zone_logic.h"
|
||||
|
||||
#include "../board/card_state.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "card_zone_algorithms.h"
|
||||
|
||||
class PlayerLogic;
|
||||
|
|
@ -16,7 +16,7 @@ StackZoneLogic::StackZoneLogic(PlayerLogic *_player,
|
|||
{
|
||||
}
|
||||
|
||||
void StackZoneLogic::addCardImpl(CardState *card, int x, int /*y*/)
|
||||
void StackZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
||||
{
|
||||
CardZoneAlgorithms::addCardToList(cards, card, x, true);
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ public:
|
|||
QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
void addCardImpl(CardState *card, int x, int y) override;
|
||||
void addCardImpl(CardItem *card, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_STACK_ZONE_LOGIC_H
|
||||
|
|
@ -1,9 +1,14 @@
|
|||
#include "table_zone_logic.h"
|
||||
|
||||
#include "../board/card_state.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
class PlayerLogic;
|
||||
class QObject;
|
||||
|
||||
TableZoneLogic::TableZoneLogic(PlayerLogic *_player,
|
||||
const QString &_name,
|
||||
bool _hasCardAttr,
|
||||
|
|
@ -14,7 +19,7 @@ TableZoneLogic::TableZoneLogic(PlayerLogic *_player,
|
|||
{
|
||||
}
|
||||
|
||||
void TableZoneLogic::addCardImpl(CardState *card, int _x, int _y)
|
||||
void TableZoneLogic::addCardImpl(CardItem *card, int _x, int _y)
|
||||
{
|
||||
cards.append(card);
|
||||
if (!card->getFaceDown() && card->getPT().isEmpty()) {
|
||||
|
|
@ -24,33 +29,15 @@ void TableZoneLogic::addCardImpl(CardState *card, int _x, int _y)
|
|||
card->setDoesntUntap(true);
|
||||
}
|
||||
card->setGridPoint(QPoint(_x, _y));
|
||||
card->setVisible(true);
|
||||
}
|
||||
|
||||
CardState *TableZoneLogic::takeCard(int position, int cardId, bool toNewZone)
|
||||
CardItem *TableZoneLogic::takeCard(int position, int cardId, bool toNewZone)
|
||||
{
|
||||
CardState *result = CardZoneLogic::takeCard(position, cardId);
|
||||
CardItem *result = CardZoneLogic::takeCard(position, cardId);
|
||||
|
||||
if (toNewZone) {
|
||||
emit contentSizeChanged();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int TableZoneLogic::clampValidTableRow(const int row)
|
||||
{
|
||||
if (row < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (row >= ROW_COUNT) {
|
||||
return ROW_COUNT - 1;
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
int TableZoneLogic::tableRowToGridY(int tableRow)
|
||||
{
|
||||
if (tableRow > 2) {
|
||||
tableRow = 1;
|
||||
}
|
||||
return clampValidTableRow(2 - tableRow);
|
||||
}
|
||||
}
|
||||
|
|
@ -29,23 +29,8 @@ public:
|
|||
bool _contentsKnown,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
/** @brief Number of rows in the table zone grid (0=creatures, 1=noncreatures, 2=lands). */
|
||||
static const int ROW_COUNT = 3;
|
||||
|
||||
/**
|
||||
* Clamps a grid row index into [0, ROW_COUNT - 1].
|
||||
*/
|
||||
static int clampValidTableRow(const int row);
|
||||
|
||||
/**
|
||||
* Converts a card's logical table row (0=creatures, 1=noncreatures, 2=lands)
|
||||
* to the corresponding grid Y coordinate. Cards with tableRow > 2 (e.g.,
|
||||
* instants/sorceries) default to the noncreatures row.
|
||||
*/
|
||||
static int tableRowToGridY(int tableRow);
|
||||
|
||||
protected:
|
||||
void addCardImpl(CardState *card, int x, int y) override;
|
||||
void addCardImpl(CardItem *card, int x, int y) override;
|
||||
|
||||
/**
|
||||
* @brief Removes a card from view.
|
||||
|
|
@ -53,9 +38,9 @@ protected:
|
|||
* @param position card position
|
||||
* @param cardId id of card to take
|
||||
* @param toNewZone Whether the destination of the card is not the same as the starting zone. Defaults to true
|
||||
* @return CardState that has been removed
|
||||
* @return CardItem that has been removed
|
||||
*/
|
||||
CardState *takeCard(int position, int cardId, bool toNewZone = true) override;
|
||||
CardItem *takeCard(int position, int cardId, bool toNewZone = true) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_TABLE_ZONE_LOGIC_H
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
#include "view_zone_logic.h"
|
||||
|
||||
#include "../board/card_state.h"
|
||||
#include "../player/player_actions.h"
|
||||
#include "../player/player_logic.h"
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../board/card_list.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/interfaces/interface_interface_settings_provider.h>
|
||||
#include <libcockatrice/settings/interface_settings.h>
|
||||
|
||||
class PlayerLogic;
|
||||
|
|
@ -23,19 +22,13 @@ ZoneViewZoneLogic::ZoneViewZoneLogic(PlayerLogic *_player,
|
|||
bool _revealZone,
|
||||
bool _writeableRevealZone,
|
||||
bool _isReversed,
|
||||
IInterfaceSettingsProvider *_interfaceSettings,
|
||||
QObject *parent)
|
||||
: CardZoneLogic(_player, _origZone->getName(), false, false, true, parent), origZone(_origZone),
|
||||
numberCards(_numberCards), revealZone(_revealZone), writeableRevealZone(_writeableRevealZone),
|
||||
isReversed(_isReversed), interfaceSettings(_interfaceSettings)
|
||||
isReversed(_isReversed)
|
||||
{
|
||||
}
|
||||
|
||||
bool ZoneViewZoneLogic::getCloseEmptyCardView() const
|
||||
{
|
||||
return interfaceSettings ? interfaceSettings->getCloseEmptyCardView() : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if inserting a card at the given position requires an actual new card to be created and added to the view.
|
||||
* Also does any cardId updates that would be required if a card is inserted in that position.
|
||||
|
|
@ -43,7 +36,7 @@ bool ZoneViewZoneLogic::getCloseEmptyCardView() const
|
|||
* Note that this method can end up modifying the cardIds despite returning false.
|
||||
* (for example, if the card is inserted into a hidden portion of the deck while the view is reversed)
|
||||
*
|
||||
* Make sure to call this method once before calling addCard(), so that you skip creating the card and calling
|
||||
* Make sure to call this method once before calling addCard(), so that you skip creating a new CardItem and calling
|
||||
* addCard() if it's not required.
|
||||
*
|
||||
* @param x The position to insert the card at.
|
||||
|
|
@ -71,7 +64,7 @@ bool ZoneViewZoneLogic::prepareAddCard(int x)
|
|||
|
||||
// autoclose check is done both here and in removeCard
|
||||
|
||||
if (cards.isEmpty() && !doInsert && getCloseEmptyCardView()) {
|
||||
if (cards.isEmpty() && !doInsert && SettingsCache::instance().userInterface().getCloseEmptyCardView()) {
|
||||
emit closeView();
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +75,7 @@ bool ZoneViewZoneLogic::prepareAddCard(int x)
|
|||
* Make sure prepareAddCard() was called before calling addCard().
|
||||
* This method assumes we already checked that the card is being inserted into the visible portion
|
||||
*/
|
||||
void ZoneViewZoneLogic::addCardImpl(CardState *card, int x, int /*y*/)
|
||||
void ZoneViewZoneLogic::addCardImpl(CardItem *card, int x, int /*y*/)
|
||||
{
|
||||
if (!isReversed) {
|
||||
// if x is negative set it to add at end
|
||||
|
|
@ -151,14 +144,14 @@ void ZoneViewZoneLogic::removeCard(int position, bool toNewZone)
|
|||
return;
|
||||
}
|
||||
|
||||
CardState *card = cards.takeAt(position);
|
||||
card->deleteView();
|
||||
CardItem *card = cards.takeAt(position);
|
||||
card->deleteLater();
|
||||
|
||||
// The toNewZone check is to prevent the view from auto-closing if the view contains only a single card and that
|
||||
// card gets dragged within the view.
|
||||
// Another autoclose check is done in prepareAddCard so that the view autocloses if the last card was moved to an
|
||||
// unrevealed portion of the same zone.
|
||||
if (cards.isEmpty() && getCloseEmptyCardView() && toNewZone) {
|
||||
if (cards.isEmpty() && SettingsCache::instance().userInterface().getCloseEmptyCardView() && toNewZone) {
|
||||
emit closeView();
|
||||
return;
|
||||
}
|
||||
|
|
@ -167,18 +160,12 @@ void ZoneViewZoneLogic::removeCard(int position, bool toNewZone)
|
|||
reorganizeCards();
|
||||
}
|
||||
|
||||
void ZoneViewZoneLogic::requestClose()
|
||||
{
|
||||
emit closeView();
|
||||
}
|
||||
|
||||
void ZoneViewZoneLogic::clearCards()
|
||||
{
|
||||
for (auto card : cards) {
|
||||
card->deleteView();
|
||||
card->deleteLater();
|
||||
}
|
||||
cards.clear();
|
||||
emit cardCountChanged();
|
||||
}
|
||||
|
||||
void ZoneViewZoneLogic::setWriteableRevealZone(bool _writeableRevealZone)
|
||||
|
|
@ -190,16 +177,4 @@ void ZoneViewZoneLogic::setWriteableRevealZone(bool _writeableRevealZone)
|
|||
emit removeFromViews();
|
||||
}
|
||||
writeableRevealZone = _writeableRevealZone;
|
||||
}
|
||||
|
||||
PendingCommand *ZoneViewZoneLogic::prepareZoneDump()
|
||||
{
|
||||
return getPlayer()->getPlayerActions()->prepareZoneDump(this, numberCards);
|
||||
}
|
||||
|
||||
void ZoneViewZoneLogic::sendZoneDump(PendingCommand *pendingCommand)
|
||||
{
|
||||
if (pendingCommand != nullptr) {
|
||||
getPlayer()->getPlayerActions()->sendGameCommand(pendingCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
class PlayerLogic;
|
||||
class QObject;
|
||||
class PendingCommand;
|
||||
class IInterfaceSettingsProvider;
|
||||
|
||||
class ZoneViewZoneLogic : public CardZoneLogic
|
||||
{
|
||||
|
|
@ -28,8 +26,6 @@ private:
|
|||
int numberCards;
|
||||
bool revealZone, writeableRevealZone;
|
||||
bool isReversed;
|
||||
// Borrowed settings provider (owned by the application). Null outside the client, in which case views stay open.
|
||||
IInterfaceSettingsProvider *interfaceSettings;
|
||||
|
||||
public:
|
||||
enum CardAction
|
||||
|
|
@ -45,25 +41,15 @@ public:
|
|||
bool _revealZone,
|
||||
bool _writeableRevealZone,
|
||||
bool _isReversed,
|
||||
IInterfaceSettingsProvider *interfaceSettings = nullptr,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
bool prepareAddCard(int x);
|
||||
void removeCard(int position, bool toNewZone);
|
||||
void updateCardIds(CardAction action);
|
||||
|
||||
/**
|
||||
* @brief Asks the graphics view showing this zone to close itself.
|
||||
*
|
||||
* Logic code has no handle on the view, so it goes through the logic object the view was built from.
|
||||
*/
|
||||
void requestClose();
|
||||
|
||||
/** @brief Removes all cards from the view, without touching anything else. Used in replay rewind */
|
||||
void clearCards();
|
||||
|
||||
[[nodiscard]] bool getCloseEmptyCardView() const;
|
||||
|
||||
int getNumberCards() const
|
||||
{
|
||||
return numberCards;
|
||||
|
|
@ -87,25 +73,8 @@ public:
|
|||
return origZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Builds the zone-dump command for this view without sending it.
|
||||
* @return The pending command, or nullptr when there is no zone to dump.
|
||||
*
|
||||
* Keeps command construction in game/ so graphics views don't reach
|
||||
* through the player into PlayerActions to set it up. The response can
|
||||
* arrive synchronously (local games), so callers must connect to
|
||||
* PendingCommand::finished before calling sendZoneDump().
|
||||
*/
|
||||
PendingCommand *prepareZoneDump();
|
||||
|
||||
/**
|
||||
* @brief Sends a command returned by prepareZoneDump().
|
||||
* @param pendingCommand The prepared command; nullptr is ignored.
|
||||
*/
|
||||
void sendZoneDump(PendingCommand *pendingCommand);
|
||||
|
||||
protected:
|
||||
void addCardImpl(CardState *card, int x, int y) override;
|
||||
void addCardImpl(CardItem *card, int x, int y) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_VIEW_ZONE_LOGIC_H
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QCursor>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
|
@ -52,20 +51,7 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
|||
update();
|
||||
});
|
||||
|
||||
// The source card can be destroyed mid-drag (e.g. moved by a server event). deleteLater() alone is not enough:
|
||||
// a scene repaint can run before the deferred delete and paint the dead card. Detach from the scene immediately.
|
||||
connect(_item, &QObject::destroyed, this, [this]() {
|
||||
hide();
|
||||
if (QGraphicsScene *sc = scene()) {
|
||||
sc->removeItem(this);
|
||||
}
|
||||
deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
AbstractCardItem *AbstractCardDragItem::getItem() const
|
||||
{
|
||||
return item.data();
|
||||
connect(item, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
|
||||
}
|
||||
|
||||
QPainterPath AbstractCardDragItem::shape() const
|
||||
|
|
@ -79,10 +65,6 @@ QPainterPath AbstractCardDragItem::shape() const
|
|||
|
||||
void AbstractCardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
if (item.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
item->paint(painter, option, widget);
|
||||
|
||||
// adds a mask to the card so it looks like the card hasnt been placed yet
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QPointF>
|
||||
#include <QPointer>
|
||||
#include <QRectF>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
|
|
@ -25,8 +24,7 @@ class AbstractCardDragItem : public QObject, public QGraphicsItem
|
|||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
protected:
|
||||
/// Guarded pointer: the source card may be destroyed while this drag item still exists.
|
||||
QPointer<AbstractCardItem> item;
|
||||
AbstractCardItem *item;
|
||||
QPointF hotSpot;
|
||||
QList<AbstractCardDragItem *> childDrags;
|
||||
|
||||
|
|
@ -46,8 +44,10 @@ public:
|
|||
}
|
||||
[[nodiscard]] QPainterPath shape() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
/// @return the source card, or nullptr if it has already been destroyed.
|
||||
[[nodiscard]] AbstractCardItem *getItem() const;
|
||||
[[nodiscard]] AbstractCardItem *getItem() const
|
||||
{
|
||||
return item;
|
||||
}
|
||||
[[nodiscard]] QPointF getHotSpot() const
|
||||
{
|
||||
return hotSpot;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
#include <algorithm>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/settings/appearance_settings.h>
|
||||
#include <libcockatrice/settings/cards_display_settings.h>
|
||||
#include <libcockatrice/settings/debug_settings.h>
|
||||
|
|
@ -42,23 +43,13 @@
|
|||
class QSizeF;
|
||||
|
||||
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, PlayerLogic *_owner, int _id)
|
||||
: ArrowTarget(_owner, parent), state(new CardState(this, nullptr, cardRef, _id)), tapAngle(0),
|
||||
bgColor(Qt::transparent), isHovered(false), realZValue(0)
|
||||
: ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0),
|
||||
bgColor(Qt::transparent), isHovered(false), realZValue(0), pendingSelectionCollapse(false)
|
||||
{
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
setFlag(ItemIsSelectable);
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
|
||||
connect(state, &CardState::cardPixmapUpdated, this, &AbstractCardItem::pixmapUpdated);
|
||||
connect(state, &CardState::cardInfoChanged, this, &AbstractCardItem::onCardInfoChanged);
|
||||
connect(state, &CardState::cardRefChanged, this, &AbstractCardItem::onCardRefChanged);
|
||||
connect(state, &CardState::tappedChanged, this, &AbstractCardItem::onTappedChanged);
|
||||
connect(state, &CardState::facedownChanged, this, [this] { update(); });
|
||||
connect(state, &CardState::colorChanged, this, [this] {
|
||||
cacheBgColor();
|
||||
update();
|
||||
});
|
||||
|
||||
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::displayCardNamesChanged, this,
|
||||
[this] { update(); });
|
||||
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
|
||||
|
|
@ -76,7 +67,7 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef
|
|||
|
||||
AbstractCardItem::~AbstractCardItem()
|
||||
{
|
||||
emit deleteCardInfoPopup(state->getCardRef().name);
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
}
|
||||
|
||||
QRectF AbstractCardItem::boundingRect() const
|
||||
|
|
@ -99,20 +90,21 @@ void AbstractCardItem::pixmapUpdated()
|
|||
emit sigPixmapUpdated();
|
||||
}
|
||||
|
||||
void AbstractCardItem::onCardInfoChanged()
|
||||
{
|
||||
cacheBgColor();
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractCardItem::onCardRefChanged(const CardRef &oldCardRef, const CardRef & /*newCardRef*/)
|
||||
{
|
||||
emit deleteCardInfoPopup(oldCardRef.name);
|
||||
}
|
||||
|
||||
void AbstractCardItem::refreshCardInfo()
|
||||
{
|
||||
state->refreshCardInfo();
|
||||
exactCard = CardDatabaseManager::query()->getCard(cardRef);
|
||||
|
||||
if (!exactCard && !cardRef.name.isEmpty()) {
|
||||
CardInfo::UiAttributes attributes = {.tableRow = -1};
|
||||
auto info = CardInfo::newInstance(cardRef.name, "", true, {}, {}, {}, {}, attributes);
|
||||
exactCard = ExactCard(info);
|
||||
}
|
||||
if (exactCard) {
|
||||
connect(exactCard.getCardPtr().data(), &CardInfo::pixmapUpdated, this, &AbstractCardItem::pixmapUpdated);
|
||||
}
|
||||
|
||||
cacheBgColor();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -121,7 +113,7 @@ void AbstractCardItem::refreshCardInfo()
|
|||
*/
|
||||
const CardInfo &AbstractCardItem::getCardInfo() const
|
||||
{
|
||||
return state->getCardInfo();
|
||||
return exactCard.getInfo();
|
||||
}
|
||||
|
||||
void AbstractCardItem::setRealZValue(qreal _zValue)
|
||||
|
|
@ -166,13 +158,13 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
|
|||
QPixmap translatedPixmap;
|
||||
bool paintImage = true;
|
||||
|
||||
if (state->getFaceDown() || state->getCardRef().name.isEmpty()) {
|
||||
if (facedown || cardRef.name.isEmpty()) {
|
||||
// never reveal card color, always paint the card back
|
||||
CardPictureLoader::getCardBackPixmap(translatedPixmap, translatedSize.toSize());
|
||||
} else {
|
||||
// don't even spend time trying to load the picture if our size is too small
|
||||
if (translatedSize.width() > 10) {
|
||||
CardPictureLoader::getPixmap(translatedPixmap, state->getCard(), translatedSize.toSize());
|
||||
CardPictureLoader::getPixmap(translatedPixmap, exactCard, translatedSize.toSize());
|
||||
if (translatedPixmap.isNull()) {
|
||||
paintImage = false;
|
||||
}
|
||||
|
|
@ -193,20 +185,19 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
|
|||
painter->drawPath(shape());
|
||||
}
|
||||
|
||||
if (translatedPixmap.isNull() || SettingsCache::instance().cardsDisplay().getDisplayCardNames() ||
|
||||
state->getFaceDown()) {
|
||||
if (translatedPixmap.isNull() || SettingsCache::instance().cardsDisplay().getDisplayCardNames() || facedown) {
|
||||
painter->save();
|
||||
transformPainter(painter, translatedSize, angle);
|
||||
painter->setPen(Qt::white);
|
||||
painter->setBackground(Qt::black);
|
||||
painter->setBackgroundMode(Qt::OpaqueMode);
|
||||
QString nameStr;
|
||||
if (state->getFaceDown()) {
|
||||
nameStr = "# " + QString::number(state->getId());
|
||||
if (facedown) {
|
||||
nameStr = "# " + QString::number(id);
|
||||
} else {
|
||||
QString prefix = "";
|
||||
if (SettingsCache::instance().debug().getShowCardId()) {
|
||||
prefix = "#" + QString::number(state->getId()) + " ";
|
||||
prefix = "#" + QString::number(id) + " ";
|
||||
}
|
||||
nameStr = prefix + CardLocalization::displayName(getCardInfo());
|
||||
}
|
||||
|
|
@ -244,6 +235,21 @@ void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
|
|||
painter->restore();
|
||||
}
|
||||
|
||||
void AbstractCardItem::setCardRef(const CardRef &_cardRef)
|
||||
{
|
||||
if (cardRef == _cardRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
if (exactCard) {
|
||||
disconnect(exactCard.getCardPtr().data(), nullptr, this, nullptr);
|
||||
}
|
||||
cardRef = _cardRef;
|
||||
|
||||
refreshCardInfo();
|
||||
}
|
||||
|
||||
void AbstractCardItem::setHovered(bool _hovered)
|
||||
{
|
||||
if (isHovered == _hovered) {
|
||||
|
|
@ -269,17 +275,18 @@ void AbstractCardItem::setHovered(bool _hovered)
|
|||
|
||||
void AbstractCardItem::setColor(const QString &_color)
|
||||
{
|
||||
state->setColor(_color);
|
||||
color = _color;
|
||||
cacheBgColor();
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractCardItem::cacheBgColor()
|
||||
{
|
||||
QChar colorChar;
|
||||
const QString cardColor = state->getColor();
|
||||
if (cardColor.isEmpty()) {
|
||||
colorChar = state->getCardInfo().getColorChar();
|
||||
if (color.isEmpty()) {
|
||||
colorChar = exactCard.getInfo().getColorChar();
|
||||
} else {
|
||||
colorChar = cardColor.at(0);
|
||||
colorChar = color.at(0);
|
||||
}
|
||||
|
||||
switch (colorChar.toLower().toLatin1()) {
|
||||
|
|
@ -307,12 +314,17 @@ void AbstractCardItem::cacheBgColor()
|
|||
}
|
||||
}
|
||||
|
||||
void AbstractCardItem::onTappedChanged(bool newTapped, bool canAnimate)
|
||||
void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
|
||||
{
|
||||
if (tapped == _tapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
tapped = _tapped;
|
||||
if (SettingsCache::instance().cardsDisplay().getTapAnimation() && canAnimate) {
|
||||
static_cast<GameScene *>(scene())->registerAnimationItem(this);
|
||||
} else {
|
||||
tapAngle = newTapped ? 90 : 0;
|
||||
tapAngle = tapped ? 90 : 0;
|
||||
setTransform(QTransform()
|
||||
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||
.rotate(tapAngle)
|
||||
|
|
@ -326,6 +338,12 @@ bool AbstractCardItem::animationEvent()
|
|||
return false;
|
||||
}
|
||||
|
||||
void AbstractCardItem::setFaceDown(bool _facedown)
|
||||
{
|
||||
facedown = _facedown;
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
cancelPendingSelectionCollapse();
|
||||
|
|
@ -339,7 +357,7 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||
}
|
||||
}
|
||||
if ((event->modifiers() & Qt::AltModifier) && event->button() == Qt::LeftButton) {
|
||||
emit cardShiftClicked(state->getCardRef().name);
|
||||
emit cardShiftClicked(cardRef.name);
|
||||
} else if ((event->modifiers() & Qt::ControlModifier)) {
|
||||
setSelected(!isSelected());
|
||||
} else if (!isSelected()) {
|
||||
|
|
@ -353,7 +371,7 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||
if (event->button() == Qt::LeftButton) {
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
} else if (event->button() == Qt::MiddleButton) {
|
||||
emit showCardInfoPopup(event->screenPos(), state->getCardRef());
|
||||
emit showCardInfoPopup(event->screenPos(), cardRef);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
|
@ -387,7 +405,7 @@ void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
}
|
||||
|
||||
if (event->button() == Qt::MiddleButton) {
|
||||
emit deleteCardInfoPopup(state->getCardRef().name);
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
}
|
||||
|
||||
// This function ensures the parent function doesn't mess around with our selection.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
#include <QSizeF>
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/game/board/card_state.h>
|
||||
#include <libcockatrice/card/printing/exact_card.h>
|
||||
#include <libcockatrice/utility/card_ref.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class PlayerLogic;
|
||||
|
|
@ -28,8 +29,13 @@ class AbstractCardItem : public ArrowTarget, public IAnimatedItem
|
|||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
CardState *state;
|
||||
ExactCard exactCard;
|
||||
int id;
|
||||
CardRef cardRef;
|
||||
bool tapped;
|
||||
bool facedown;
|
||||
int tapAngle;
|
||||
QString color;
|
||||
QColor bgColor;
|
||||
|
||||
private:
|
||||
|
|
@ -39,9 +45,6 @@ private:
|
|||
int selectionCollapseGeneration = 0; ///< Guards the deferred collapse timer against stale firings
|
||||
private slots:
|
||||
void pixmapUpdated();
|
||||
void onCardInfoChanged();
|
||||
void onCardRefChanged(const CardRef &oldCardRef, const CardRef &newCardRef);
|
||||
void onTappedChanged(bool newTapped, bool canAnimate);
|
||||
|
||||
public slots:
|
||||
void refreshCardInfo();
|
||||
|
|
@ -77,38 +80,31 @@ public:
|
|||
QSizeF getTranslatedSize(QPainter *painter) const;
|
||||
void paintPicture(QPainter *painter, const QSizeF &translatedSize, int angle);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
[[nodiscard]] CardState *getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
ExactCard getCard() const
|
||||
{
|
||||
return state->getCard();
|
||||
return exactCard;
|
||||
}
|
||||
const CardInfo &getCardInfo() const;
|
||||
int getId() const
|
||||
{
|
||||
return state->getId();
|
||||
return id;
|
||||
}
|
||||
void setId(int _id)
|
||||
{
|
||||
state->setId(_id);
|
||||
id = _id;
|
||||
}
|
||||
QString getName() const
|
||||
{
|
||||
return state->getCardRef().name;
|
||||
return cardRef.name;
|
||||
}
|
||||
QString getProviderId() const
|
||||
{
|
||||
return state->getCardRef().providerId;
|
||||
}
|
||||
void setCardRef(const CardRef &_cardRef)
|
||||
{
|
||||
state->setCardRef(_cardRef);
|
||||
return cardRef.providerId;
|
||||
}
|
||||
void setCardRef(const CardRef &_cardRef);
|
||||
CardRef getCardRef() const
|
||||
{
|
||||
return state->getCardRef();
|
||||
return cardRef;
|
||||
}
|
||||
qreal getRealZValue() const
|
||||
{
|
||||
|
|
@ -120,33 +116,27 @@ public:
|
|||
{
|
||||
return isHovered;
|
||||
}
|
||||
[[nodiscard]] QString getColor() const
|
||||
QString getColor() const
|
||||
{
|
||||
return state->getColor();
|
||||
return color;
|
||||
}
|
||||
void setColor(const QString &_color);
|
||||
bool getTapped() const
|
||||
{
|
||||
return state->getTapped();
|
||||
}
|
||||
void setTapped(bool _tapped, bool canAnimate = false)
|
||||
{
|
||||
state->setTapped(_tapped, canAnimate);
|
||||
return tapped;
|
||||
}
|
||||
void setTapped(bool _tapped, bool canAnimate = false);
|
||||
bool getFaceDown() const
|
||||
{
|
||||
return state->getFaceDown();
|
||||
}
|
||||
void setFaceDown(bool _facedown)
|
||||
{
|
||||
state->setFaceDown(_facedown);
|
||||
return facedown;
|
||||
}
|
||||
void setFaceDown(bool _facedown);
|
||||
void processHoverEvent();
|
||||
/** @brief Drop a pending collapse and disarm any deferred collapse timer. */
|
||||
void cancelPendingSelectionCollapse();
|
||||
void deleteCardInfoPopup()
|
||||
{
|
||||
emit deleteCardInfoPopup(state->getCardRef().name);
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
}
|
||||
|
||||
/** @brief Default: no per-tick animation. Subclasses override to animate. */
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../client/settings/shortcuts_settings.h"
|
||||
#include "../../game/board/counter_state.h"
|
||||
#include "../../game/player/player_actions.h"
|
||||
#include "../../game/player/player_info.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../../game_graphics/board/translate_counter_name.h"
|
||||
#include "../../interface/widgets/menus/tearoff_menu.h"
|
||||
|
||||
|
|
@ -19,10 +23,8 @@
|
|||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/game/board/counter_state.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/protocol/pb/command_inc_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
|
||||
#include <libcockatrice/utility/expression.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
|
|
@ -149,7 +151,10 @@ void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||
menu->exec(event->screenPos());
|
||||
}
|
||||
} else {
|
||||
player->getPlayerActions()->actIncrementCounter(id, event->button() == Qt::LeftButton ? 1 : -1);
|
||||
Command_IncCounter cmd;
|
||||
cmd.set_counter_id(id);
|
||||
cmd.set_delta(event->button() == Qt::LeftButton ? 1 : -1);
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
|
@ -167,7 +172,10 @@ void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
|
|||
|
||||
void AbstractCounter::incrementCounter()
|
||||
{
|
||||
player->getPlayerActions()->actIncrementCounter(id, static_cast<QAction *>(sender())->data().toInt());
|
||||
Command_IncCounter cmd;
|
||||
cmd.set_counter_id(id);
|
||||
cmd.set_delta(static_cast<QAction *>(sender())->data().toInt());
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void AbstractCounter::setCounter()
|
||||
|
|
@ -191,7 +199,10 @@ void AbstractCounter::setCounter()
|
|||
}
|
||||
|
||||
Expression exp(value);
|
||||
player->getPlayerActions()->actSetCounter(id, static_cast<int>(exp.parse(dlg.textValue())));
|
||||
Command_SetCounter cmd;
|
||||
cmd.set_counter_id(id);
|
||||
cmd.set_value(static_cast<int>(exp.parse(dlg.textValue())));
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
AbstractCounterDialog::AbstractCounterDialog(const QString &name, const QString &value, QWidget *parent)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
#include "arrow_item.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game/board/arrow_data.h"
|
||||
#include "../../game/player/player_actions.h"
|
||||
#include "../../game/player/player_info.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../../game/zones/card_zone_logic.h"
|
||||
#include "../game_scene.h"
|
||||
#include "../player/player_target.h"
|
||||
#include "../z_values.h"
|
||||
|
|
@ -22,12 +27,12 @@
|
|||
#include <QTransform>
|
||||
#include <QtGlobal>
|
||||
#include <QtMath>
|
||||
#include <libcockatrice/game/board/arrow_data.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
|
||||
#include <libcockatrice/settings/cards_display_settings.h>
|
||||
#include <libcockatrice/settings/interface_settings.h>
|
||||
#include <libcockatrice/utility/color.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <math.h>
|
||||
#include <qnamespace.h>
|
||||
|
|
@ -421,19 +426,19 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
|
||||
CardZoneLogic *startZone = startCard->getZone();
|
||||
|
||||
ArrowData arrow;
|
||||
arrow.color = data->color;
|
||||
arrow.startPlayerId = startZone->getPlayer()->getPlayerInfo()->getId();
|
||||
arrow.startZone = startZone->getName();
|
||||
arrow.startCardId = startCard->getId();
|
||||
Command_CreateArrow cmd;
|
||||
cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(data->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)) {
|
||||
CardZoneLogic *targetZone = targetCard->getZone();
|
||||
arrow.targetPlayerId = targetZone->getPlayer()->getPlayerInfo()->getId();
|
||||
arrow.targetZone = targetZone->getName();
|
||||
arrow.targetCardId = targetCard->getId();
|
||||
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)) {
|
||||
arrow.targetPlayerId = targetPlayer->getOwner()->getPlayerInfo()->getId();
|
||||
cmd.set_target_player_id(targetPlayer->getOwner()->getPlayerInfo()->getId());
|
||||
} else {
|
||||
delArrow();
|
||||
return;
|
||||
|
|
@ -442,9 +447,22 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
|
||||
if (startZone->getName() == ZoneNames::HAND) {
|
||||
startCard->playCard(false);
|
||||
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
||||
bool playToStack = SettingsCache::instance().userInterface().getPlayToStack();
|
||||
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
|
||||
(playToStack && ci->getUiAttributes().tableRow != 0 &&
|
||||
startCard->getZone()->getName() != ZoneNames::STACK))) {
|
||||
cmd.set_start_zone(ZoneNames::STACK);
|
||||
} else {
|
||||
cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE);
|
||||
}
|
||||
}
|
||||
|
||||
player->getPlayerActions()->createArrow(startCard->getState(), arrow, deleteInPhase);
|
||||
if (deleteInPhase != 0) {
|
||||
cmd.set_delete_in_phase(deleteInPhase);
|
||||
}
|
||||
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
delArrow();
|
||||
|
|
@ -536,7 +554,7 @@ void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
auto *startCard = qgraphicsitem_cast<CardItem *>(startItem);
|
||||
auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
|
||||
if (startCard && targetCard) {
|
||||
player->getPlayerActions()->attachCards(startCard->getState(), targetCard->getState());
|
||||
attachCards(startCard, targetCard);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -545,3 +563,23 @@ void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
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);
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef ARROWITEM_H
|
||||
#define ARROWITEM_H
|
||||
|
||||
#include "../../game/board/arrow_data.h"
|
||||
#include "../animated_item.h"
|
||||
#include "arrow_target.h"
|
||||
#include "graphics_item_type.h"
|
||||
|
|
@ -17,7 +18,6 @@
|
|||
#include <QRectF>
|
||||
#include <QSharedPointer>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/game/board/arrow_data.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardItem;
|
||||
|
|
@ -131,6 +131,7 @@ private:
|
|||
PlayerLogic *player;
|
||||
QList<ArrowAttachItem *> childArrows;
|
||||
QMetaObject::Connection positionConnection;
|
||||
void attachCards(CardItem *startCard, const CardItem *targetCard);
|
||||
|
||||
public:
|
||||
explicit ArrowAttachItem(ArrowTarget *_startItem);
|
||||
|
|
|
|||
|
|
@ -130,9 +130,8 @@ void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
sc->removeItem(this);
|
||||
|
||||
QList<CardDragItem *> dragItemList;
|
||||
CardZoneLogic *startZone = static_cast<CardItem *>(item.data())->getZone();
|
||||
if (currentZone &&
|
||||
!(static_cast<CardItem *>(item.data())->getAttachedTo() && (startZone == currentZone->getLogic()))) {
|
||||
CardZoneLogic *startZone = static_cast<CardItem *>(item)->getZone();
|
||||
if (currentZone && !(static_cast<CardItem *>(item)->getAttachedTo() && (startZone == currentZone->getLogic()))) {
|
||||
if (!occupied) {
|
||||
dragItemList.append(this);
|
||||
}
|
||||
|
|
@ -140,7 +139,7 @@ void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|||
for (int i = 0; i < childDrags.size(); i++) {
|
||||
CardDragItem *c = static_cast<CardDragItem *>(childDrags[i]);
|
||||
if (!occupied &&
|
||||
!(static_cast<CardItem *>(c->item.data())->getAttachedTo() && (startZone == currentZone->getLogic())) &&
|
||||
!(static_cast<CardItem *>(c->item)->getAttachedTo() && (startZone == currentZone->getLogic())) &&
|
||||
!c->occupied) {
|
||||
dragItemList.append(c);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
#include "card_item.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game/abstract_game.h"
|
||||
#include "../../game/board/card_state.h"
|
||||
#include "../../game/game_state.h"
|
||||
#include "../../game/phase.h"
|
||||
#include "../../game/player/player_actions.h"
|
||||
#include "../../game/player/player_info.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../../game/player/player_manager.h"
|
||||
#include "../../game/zones/card_zone_logic.h"
|
||||
#include "../../game/zones/table_zone_logic.h"
|
||||
#include "../../game/zones/view_zone_logic.h"
|
||||
#include "../card_dimensions.h"
|
||||
#include "../game_scene.h"
|
||||
#include "arrow_item.h"
|
||||
|
|
@ -30,17 +41,6 @@
|
|||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/board/card_state.h>
|
||||
#include <libcockatrice/game/game_state.h>
|
||||
#include <libcockatrice/game/phase.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/player/player_manager.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <libcockatrice/game/zones/table_zone_logic.h>
|
||||
#include <libcockatrice/game/zones/view_zone_logic.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
|
||||
#include <libcockatrice/settings/interface_settings.h>
|
||||
#include <libcockatrice/utility/card_ref.h>
|
||||
|
|
@ -53,9 +53,8 @@ CardItem::CardItem(PlayerLogic *_owner,
|
|||
const CardRef &cardRef,
|
||||
int _cardid,
|
||||
CardZoneLogic *_zone)
|
||||
: AbstractCardItem(parent, cardRef, _owner, _cardid), dragItem(nullptr)
|
||||
: AbstractCardItem(parent, cardRef, _owner, _cardid), state(new CardState(this, _zone)), dragItem(nullptr)
|
||||
{
|
||||
state->setZone(_zone);
|
||||
owner->addCard(this);
|
||||
|
||||
connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) {
|
||||
|
|
@ -63,44 +62,25 @@ CardItem::CardItem(PlayerLogic *_owner,
|
|||
update();
|
||||
}
|
||||
});
|
||||
|
||||
connect(state, &CardState::stateReset, this, [this] {
|
||||
if (scene()) {
|
||||
static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
|
||||
}
|
||||
update();
|
||||
});
|
||||
|
||||
// The retyped logic layer drives CardState setters directly (bypassing the CardItem wrappers that called
|
||||
// update()), so repaint on every state change: attacking, annotation, doesntUntap, P/T and counters.
|
||||
connect(state, &CardState::stateChanged, this, [this] { update(); });
|
||||
|
||||
connect(state, &CardState::viewDeleteRequested, this, &CardItem::deleteLater);
|
||||
}
|
||||
|
||||
void CardItem::prepareDelete()
|
||||
{
|
||||
if (owner != nullptr) {
|
||||
auto *gameScene = qobject_cast<GameScene *>(scene());
|
||||
if (gameScene && gameScene->getActiveCard() == this) {
|
||||
if (owner->getGame()->getActiveCard() == this) {
|
||||
emit owner->requestCardMenuUpdate(nullptr);
|
||||
gameScene->setActiveCard(nullptr);
|
||||
owner->getGame()->setActiveCard(nullptr);
|
||||
}
|
||||
owner = nullptr;
|
||||
}
|
||||
|
||||
const QList<CardState *> &attachedStates = state->getAttachedCards();
|
||||
while (!attachedStates.isEmpty()) {
|
||||
auto *attachedItem = qobject_cast<CardItem *>(attachedStates.first()->parent());
|
||||
if (attachedItem == nullptr) {
|
||||
break;
|
||||
}
|
||||
attachedItem->setZone(nullptr); // so that it won't try to call reorganizeCards()
|
||||
attachedItem->setAttachedTo(nullptr);
|
||||
while (!attachedCards.isEmpty()) {
|
||||
attachedCards.first()->setZone(nullptr); // so that it won't try to call reorganizeCards()
|
||||
attachedCards.first()->setAttachedTo(nullptr);
|
||||
}
|
||||
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
state->getAttachedTo()->removeAttachedCard(state);
|
||||
state->getAttachedTo()->removeAttachedCard(this);
|
||||
state->setAttachedTo(nullptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -147,7 +127,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|||
painter->save();
|
||||
transformPainter(painter, translatedSize, tapAngle);
|
||||
|
||||
if (!getFaceDown() && state->getPT() == state->getCardInfo().getPowTough()) {
|
||||
if (!getFaceDown() && state->getPT() == exactCard.getInfo().getPowTough()) {
|
||||
painter->setPen(Qt::white);
|
||||
} else {
|
||||
painter->setPen(QColor(255, 150, 0)); // dark orange
|
||||
|
|
@ -229,13 +209,36 @@ void CardItem::setPT(const QString &_pt)
|
|||
|
||||
void CardItem::setAttachedTo(CardItem *_attachedTo)
|
||||
{
|
||||
CardState *newParent = _attachedTo == nullptr ? nullptr : _attachedTo->getState();
|
||||
state->setAttachedTo(newParent);
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
state->getAttachedTo()->removeAttachedCard(this);
|
||||
}
|
||||
|
||||
// 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 (newParent != nullptr ? newParent->getZone() == nullptr : state->getZone() == nullptr) {
|
||||
deleteLater();
|
||||
gridPoint.setX(-1);
|
||||
state->setAttachedTo(_attachedTo);
|
||||
if (state->getAttachedTo() != 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) {
|
||||
deleteLater();
|
||||
} else {
|
||||
emit state->getAttachedTo()->getZone()->cardAdded(this);
|
||||
state->getAttachedTo()->addAttachedCard(this);
|
||||
if (state->getZone() != state->getAttachedTo()->getZone()) {
|
||||
state->getAttachedTo()->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) {
|
||||
deleteLater();
|
||||
} else {
|
||||
emit state->getZone()->cardAdded(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->getZone() != nullptr) {
|
||||
state->getZone()->reorganizeCards();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -245,6 +248,13 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
|
|||
void CardItem::resetState(bool keepAnnotations)
|
||||
{
|
||||
state->resetState(keepAnnotations);
|
||||
attachedCards.clear();
|
||||
setTapped(false, false);
|
||||
setDoesntUntap(false);
|
||||
if (scene()) {
|
||||
static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::processCardInfo(const ServerInfo_Card &_info)
|
||||
|
|
@ -380,7 +390,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|||
|
||||
// Use the buttonDownPos to align the hot spot with the position when
|
||||
// the user originally clicked
|
||||
createDragItem(state->getId(), event->buttonDownPos(Qt::LeftButton), event->scenePos(), forceFaceDown);
|
||||
createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), forceFaceDown);
|
||||
dragItem->grabMouse();
|
||||
|
||||
int childIndex = 0;
|
||||
|
|
@ -423,11 +433,42 @@ void CardItem::playCard(bool faceDown)
|
|||
emit playSelected(this);
|
||||
}
|
||||
} else {
|
||||
state->getZone()->getPlayer()->getPlayerActions()->playCard(state, faceDown);
|
||||
state->getZone()->getPlayer()->getPlayerActions()->playCard(this, faceDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList CardItem::parsePT(const QString &pt)
|
||||
{
|
||||
QVariantList ptList = QVariantList();
|
||||
if (!pt.isEmpty()) {
|
||||
int sep = pt.indexOf('/');
|
||||
if (sep == 0) {
|
||||
ptList.append(QVariant(pt.mid(1))); // cut off starting '/' and take full string
|
||||
} else {
|
||||
int start = 0;
|
||||
for (;;) {
|
||||
QString item = pt.mid(start, sep - start);
|
||||
if (item.isEmpty()) {
|
||||
ptList.append(QVariant(QString()));
|
||||
} else if (item[0] == '+') {
|
||||
ptList.append(QVariant(item.mid(1).toInt())); // add as int
|
||||
} else if (item[0] == '-') {
|
||||
ptList.append(QVariant(item.toInt())); // add as int
|
||||
} else {
|
||||
ptList.append(QVariant(item)); // add as qstring
|
||||
}
|
||||
if (sep == -1) {
|
||||
break;
|
||||
}
|
||||
start = sep + 1;
|
||||
sep = pt.indexOf('/', start);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns true if the zone is a unwritable reveal zone view (eg a card reveal window). Will return false if zone
|
||||
* is nullptr.
|
||||
|
|
@ -452,7 +493,7 @@ void CardItem::handleClickedToPlay(bool shiftHeld)
|
|||
if (SettingsCache::instance().userInterface().getClickPlaysAllSelected()) {
|
||||
emit hideSelected(this);
|
||||
} else {
|
||||
state->getZone()->removeCard(state);
|
||||
state->getZone()->removeCard(this);
|
||||
}
|
||||
} else {
|
||||
playCard(shiftHeld);
|
||||
|
|
@ -496,16 +537,16 @@ bool CardItem::animationEvent()
|
|||
{
|
||||
int rotation = ROTATION_DEGREES_PER_FRAME;
|
||||
bool animationIncomplete = true;
|
||||
if (!state->getTapped()) {
|
||||
if (!tapped) {
|
||||
rotation *= -1;
|
||||
}
|
||||
|
||||
tapAngle += rotation;
|
||||
if (state->getTapped() && (tapAngle > 90)) {
|
||||
if (tapped && (tapAngle > 90)) {
|
||||
tapAngle = 90;
|
||||
animationIncomplete = false;
|
||||
}
|
||||
if (!state->getTapped() && (tapAngle < 0)) {
|
||||
if (!tapped && (tapAngle < 0)) {
|
||||
tapAngle = 0;
|
||||
animationIncomplete = false;
|
||||
}
|
||||
|
|
@ -526,9 +567,7 @@ QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
|||
bool selected = value.toBool();
|
||||
|
||||
if (selected) {
|
||||
if (auto *gameScene = qobject_cast<GameScene *>(scene())) {
|
||||
gameScene->setActiveCard(this);
|
||||
}
|
||||
owner->getGame()->setActiveCard(this);
|
||||
}
|
||||
|
||||
emit selectionChanged(this, selected);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef CARDITEM_H
|
||||
#define CARDITEM_H
|
||||
|
||||
#include "../../game/board/card_state.h"
|
||||
#include "abstract_card_item.h"
|
||||
#include "graphics_item_type.h"
|
||||
|
||||
|
|
@ -15,7 +16,6 @@
|
|||
#include <QPointF>
|
||||
#include <QString>
|
||||
#include <QVariantList>
|
||||
#include <libcockatrice/game/board/card_state.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardDragItem;
|
||||
|
|
@ -33,7 +33,11 @@ class CardItem : public AbstractCardItem
|
|||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
CardState *state;
|
||||
|
||||
QPoint gridPoint;
|
||||
CardDragItem *dragItem;
|
||||
QList<CardItem *> attachedCards;
|
||||
|
||||
void prepareDelete();
|
||||
void handleClickedToPlay(bool shiftHeld);
|
||||
|
|
@ -56,6 +60,10 @@ public:
|
|||
CardZoneLogic *_zone = nullptr);
|
||||
|
||||
void retranslateUi();
|
||||
[[nodiscard]] CardState *getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
[[nodiscard]] CardZoneLogic *getZone() const
|
||||
{
|
||||
return state->getZone();
|
||||
|
|
@ -64,15 +72,15 @@ public:
|
|||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
[[nodiscard]] QPoint getGridPoint() const
|
||||
{
|
||||
return state->getGridPoint();
|
||||
return gridPoint;
|
||||
}
|
||||
void setGridPoint(const QPoint &_gridPoint)
|
||||
{
|
||||
state->setGridPoint(_gridPoint);
|
||||
gridPoint = _gridPoint;
|
||||
}
|
||||
[[nodiscard]] QPoint getGridPos() const
|
||||
{
|
||||
return state->getGridPoint();
|
||||
return gridPoint;
|
||||
}
|
||||
[[nodiscard]] PlayerLogic *getOwner() const
|
||||
{
|
||||
|
|
@ -115,22 +123,22 @@ public:
|
|||
{
|
||||
state->setDestroyOnZoneChange(_destroy);
|
||||
}
|
||||
[[nodiscard]] CardState *getAttachedTo() const
|
||||
[[nodiscard]] CardItem *getAttachedTo() const
|
||||
{
|
||||
return state->getAttachedTo();
|
||||
}
|
||||
void setAttachedTo(CardItem *_attachedTo);
|
||||
void addAttachedCard(CardState *card)
|
||||
void addAttachedCard(CardItem *card)
|
||||
{
|
||||
state->addAttachedCard(card);
|
||||
attachedCards.append(card);
|
||||
}
|
||||
void removeAttachedCard(CardState *card)
|
||||
void removeAttachedCard(CardItem *card)
|
||||
{
|
||||
state->removeAttachedCard(card);
|
||||
attachedCards.removeOne(card);
|
||||
}
|
||||
[[nodiscard]] const QList<CardState *> &getAttachedCards() const
|
||||
[[nodiscard]] const QList<CardItem *> &getAttachedCards() const
|
||||
{
|
||||
return state->getAttachedCards();
|
||||
return attachedCards;
|
||||
}
|
||||
void resetState(bool keepAnnotations = false);
|
||||
void processCardInfo(const ServerInfo_Card &_info);
|
||||
|
|
@ -142,6 +150,26 @@ public:
|
|||
void drawAttachArrow();
|
||||
void playCard(bool faceDown);
|
||||
|
||||
/**
|
||||
* @brief Parses a string representing a p/t in order to extract the values from it.
|
||||
*
|
||||
* If the string contains '/', the string will be split at the '/' and each side will be parsed separately,
|
||||
* which means the result list will have two elements.
|
||||
*
|
||||
* If '/' is not found, then the entire string is parsed together, which means the result list will
|
||||
* have a single element.
|
||||
*
|
||||
* If either side of the split is empty, there will also only be a single element in the result list.
|
||||
*
|
||||
* This function will attempt to parse each substring as an int first, handling plus and minus prefixes.
|
||||
* If successful, it will put the parsed value into the QVariant as an int.
|
||||
* If failed, it will just put the substring into the QVariant as a QString.
|
||||
*
|
||||
* @param pt The p/t string
|
||||
* @return A QVariantList that can contain one or two elements, where each QVariant can be either int or QString
|
||||
*/
|
||||
static QVariantList parsePT(const QString &pt);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void DeckViewCardDragItem::updatePosition(const QPointF &cursorScenePos)
|
|||
|
||||
void DeckViewCardDragItem::handleDrop(DeckViewCardContainer *target)
|
||||
{
|
||||
auto *card = static_cast<DeckViewCard *>(item.data());
|
||||
auto *card = static_cast<DeckViewCard *>(item);
|
||||
auto *start = static_cast<DeckViewCardContainer *>(item->parentItem());
|
||||
start->removeCard(card);
|
||||
target->addCard(card);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,13 @@
|
|||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../client/settings/shortcuts_settings.h"
|
||||
#include "../../game/abstract_game.h"
|
||||
#include "../../game/game_event_handler.h"
|
||||
#include "../../game/game_state.h"
|
||||
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
||||
#include "../../interface/deck_loader/deck_file_format.h"
|
||||
#include "../../interface/deck_loader/deck_loader.h"
|
||||
#include "../../interface/deck_loader/loaded_deck.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_load_deck.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_load_deck_from_clipboard.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_load_deck_from_website.h"
|
||||
|
|
@ -28,17 +33,16 @@
|
|||
#include <QRect>
|
||||
#include <QVBoxLayout>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/deck_list/deck_file_format.h>
|
||||
#include <libcockatrice/deck_list/loaded_deck.h>
|
||||
#include <libcockatrice/deck_list/playmat_resolver.h>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/game_event_handler.h>
|
||||
#include <libcockatrice/game/game_state.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_select.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_ready_start.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_playmat.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
||||
#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/settings/interface_settings.h>
|
||||
#include <libcockatrice/settings/visual_deck_storage_settings.h>
|
||||
#include <libcockatrice/utility/qt_utils.h>
|
||||
#include <libcockatrice/utility/string_limits.h>
|
||||
#include <optional>
|
||||
#include <qnamespace.h>
|
||||
|
|
@ -107,9 +111,10 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
|||
connect(deckView, &DeckView::newCardAdded, this, &DeckViewContainer::newCardAdded);
|
||||
connect(deckView, &DeckView::sideboardPlanChanged, this, &DeckViewContainer::sideboardPlanChanged);
|
||||
|
||||
deckViewLayout = QtUtils::makeLayout<QVBoxLayout>();
|
||||
deckViewLayout = new QVBoxLayout;
|
||||
deckViewLayout->addLayout(buttonHBox);
|
||||
deckViewLayout->addWidget(deckView);
|
||||
deckViewLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(deckViewLayout);
|
||||
|
||||
retranslateUi();
|
||||
|
|
@ -309,7 +314,9 @@ void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
|||
return;
|
||||
}
|
||||
|
||||
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareDeckSelect(deckString);
|
||||
Command_DeckSelect cmd;
|
||||
cmd.set_deck(deckString.toStdString());
|
||||
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(cmd);
|
||||
connect(pend, &PendingCommand::finished, this, &DeckViewContainer::deckSelectFinished);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(pend, playerId);
|
||||
|
||||
|
|
@ -338,7 +345,15 @@ void DeckViewContainer::resolveAndSendPlaymat()
|
|||
|
||||
lastResolvedPlaymat = resolved;
|
||||
|
||||
PendingCommand *playmatPend = parentGame->getGame()->getGameEventHandler()->prepareSetPlaymat(resolved);
|
||||
Command_SetPlaymat playmatCmd;
|
||||
auto *pp = playmatCmd.mutable_playmat_params();
|
||||
pp->set_card_name(resolved.card.name.toStdString());
|
||||
pp->set_card_provider_id(resolved.card.providerId.toStdString());
|
||||
pp->set_margin_pct_l(resolved.params.marginPctL);
|
||||
pp->set_margin_pct_r(resolved.params.marginPctR);
|
||||
pp->set_vertical_offset(resolved.params.verticalOffset);
|
||||
pp->set_zoom(resolved.params.zoom);
|
||||
PendingCommand *playmatPend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(playmatCmd);
|
||||
const QString sentName = resolved.card.name;
|
||||
connect(playmatPend, &PendingCommand::finished, this, [this, sentName](const Response &r) {
|
||||
// Only RespFunctionNotAllowed signals a card art DENY rule. Older servers that predate
|
||||
|
|
@ -369,7 +384,9 @@ void DeckViewContainer::loadRemoteDeck()
|
|||
{
|
||||
DlgLoadRemoteDeck dlg(parentGame->getGame()->getClientForPlayer(playerId), this);
|
||||
if (dlg.exec()) {
|
||||
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareDeckSelectId(dlg.getDeckId());
|
||||
Command_DeckSelect cmd;
|
||||
cmd.set_deck_id(dlg.getDeckId());
|
||||
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(cmd);
|
||||
connect(pend, &PendingCommand::finished, this, &DeckViewContainer::deckSelectFinished);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(pend, playerId);
|
||||
}
|
||||
|
|
@ -425,21 +442,34 @@ void DeckViewContainer::readyStart()
|
|||
void DeckViewContainer::forceStart()
|
||||
{
|
||||
const auto msg = tr("Are you sure you want to force start?\nThis will kick all non-ready players from the game.");
|
||||
if (!QtUtils::confirm(this, tr("Cockatrice"), msg, QMessageBox::Yes)) {
|
||||
const auto res =
|
||||
QMessageBox::question(this, tr("Cockatrice"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if (res == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
|
||||
parentGame->getGame()->getGameEventHandler()->sendForceStart(playerId);
|
||||
Command_ReadyStart cmd;
|
||||
cmd.set_force_start(true);
|
||||
cmd.set_ready(true);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void DeckViewContainer::sideboardLockButtonClicked()
|
||||
{
|
||||
parentGame->getGame()->getGameEventHandler()->sendSetSideboardLock(sideboardLockButton->getState(), playerId);
|
||||
Command_SetSideboardLock cmd;
|
||||
cmd.set_locked(sideboardLockButton->getState());
|
||||
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void DeckViewContainer::sideboardPlanChanged()
|
||||
{
|
||||
parentGame->getGame()->getGameEventHandler()->sendSetSideboardPlan(deckView->getSideboardPlan(), playerId);
|
||||
Command_SetSideboardPlan cmd;
|
||||
const QList<MoveCard_ToZone> &newPlan = deckView->getSideboardPlan();
|
||||
for (const auto &i : newPlan) {
|
||||
cmd.add_move_list()->CopyFrom(i);
|
||||
}
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -451,7 +481,9 @@ void DeckViewContainer::sendReadyStartCommand(bool ready)
|
|||
resolveAndSendPlaymat();
|
||||
}
|
||||
|
||||
parentGame->getGame()->getGameEventHandler()->sendReadyStart(ready, playerId);
|
||||
Command_ReadyStart cmd;
|
||||
cmd.set_ready(ready);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
#include "dlg_annotation.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
|
||||
void AnnotationDialog::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Return && event->modifiers() & Qt::ControlModifier) {
|
||||
event->accept();
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
QInputDialog::keyPressEvent(event);
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
/**
|
||||
* @file dlg_annotation.h
|
||||
* @ingroup GameDialogs
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_DLG_ANNOTATION_H
|
||||
#define COCKATRICE_DLG_ANNOTATION_H
|
||||
|
||||
#include <QInputDialog>
|
||||
|
||||
class AnnotationDialog : public QInputDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
public:
|
||||
explicit AnnotationDialog(QWidget *parent = nullptr) : QInputDialog(parent)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_DLG_ANNOTATION_H
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <libcockatrice/game/player/token_info.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class QLabel;
|
||||
|
|
@ -26,6 +25,17 @@ class CardInfoPictureWidget;
|
|||
class QModelIndex;
|
||||
class QWidget;
|
||||
|
||||
struct TokenInfo
|
||||
{
|
||||
QString name;
|
||||
QString color;
|
||||
QString pt;
|
||||
QString annotation;
|
||||
bool destroy = true;
|
||||
bool faceDown = false;
|
||||
QString providerId;
|
||||
};
|
||||
|
||||
class DlgCreateToken : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <libcockatrice/game/player/move_top_cards_until_options.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class FilterString;
|
||||
|
|
@ -22,6 +21,13 @@ class QLabel;
|
|||
class QSpinBox;
|
||||
class QWidget;
|
||||
|
||||
struct MoveTopCardsUntilOptions
|
||||
{
|
||||
QStringList exprs = {};
|
||||
int numberOfHits = 1;
|
||||
bool autoPlay = false;
|
||||
};
|
||||
|
||||
class DlgMoveTopCardsUntil : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
#include "game_scene.h"
|
||||
|
||||
#include "../client/settings/cache_settings.h"
|
||||
#include "../game/abstract_game.h"
|
||||
#include "../game/arrow_registry.h"
|
||||
#include "../game/board/arrow_data.h"
|
||||
#include "../game/player/player_actions.h"
|
||||
#include "../game/player/player_event_handler.h"
|
||||
#include "../game/player/player_info.h"
|
||||
#include "../game/player/player_logic.h"
|
||||
#include "../game/zones/card_zone_logic.h"
|
||||
#include "../game/zones/view_zone_logic.h"
|
||||
#include "animated_item.h"
|
||||
#include "board/abstract_card_item.h"
|
||||
#include "board/arrow_item.h"
|
||||
#include "board/arrow_registry.h"
|
||||
#include "board/card_item.h"
|
||||
#include "phases_toolbar.h"
|
||||
#include "player/menu/player_menu.h"
|
||||
|
|
@ -32,15 +40,6 @@
|
|||
#include <QSharedPointer>
|
||||
#include <QtMath>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/board/arrow_data.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_event_handler.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <libcockatrice/game/zones/view_zone_logic.h>
|
||||
#include <libcockatrice/settings/interface_settings.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <numeric>
|
||||
|
|
@ -113,15 +112,6 @@ void GameScene::retranslateUi()
|
|||
}
|
||||
}
|
||||
|
||||
QList<CardState *> GameScene::selectedCardStates() const
|
||||
{
|
||||
QList<CardState *> selectedStates;
|
||||
for (auto *card : selectedCards()) {
|
||||
selectedStates.append(card->getState());
|
||||
}
|
||||
return selectedStates;
|
||||
}
|
||||
|
||||
QList<CardItem *> GameScene::selectedCards() const
|
||||
{
|
||||
QList<CardItem *> selectedCards;
|
||||
|
|
@ -134,67 +124,6 @@ QList<CardItem *> GameScene::selectedCards() const
|
|||
return selectedCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects every card of @p zone for which @p filter holds.
|
||||
* @param filter A predicate to filter which cards are selected.
|
||||
*/
|
||||
static void selectCardsInZone(
|
||||
const CardZoneLogic *zone,
|
||||
std::function<bool(const CardItem *)> filter = [](const CardItem *) { return true; })
|
||||
{
|
||||
if (!zone) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto *cardState : zone->getCards()) {
|
||||
auto *cardItem = cardState == nullptr ? nullptr : qobject_cast<CardItem *>(cardState->parent());
|
||||
if (cardItem && filter(cardItem)) {
|
||||
cardItem->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::selectAllInZone(const CardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectCardsInZone(card->getZone());
|
||||
}
|
||||
|
||||
void GameScene::selectSameRow(const CardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto isSameRow = [card](const CardItem *cardItem) {
|
||||
return qAbs(card->scenePos().y() - cardItem->scenePos().y()) < 50;
|
||||
};
|
||||
selectCardsInZone(card->getZone(), isSameRow);
|
||||
}
|
||||
|
||||
void GameScene::selectSameColumn(const CardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto isSameColumn = [card](const CardItem *cardItem) { return cardItem->x() == card->x(); };
|
||||
selectCardsInZone(card->getZone(), isSameColumn);
|
||||
}
|
||||
|
||||
CardItem *GameScene::getActiveCard() const
|
||||
{
|
||||
return activeCard;
|
||||
}
|
||||
|
||||
void GameScene::setActiveCard(CardItem *card)
|
||||
{
|
||||
activeCard = card;
|
||||
}
|
||||
|
||||
void GameScene::onCardSelectionChanged(AbstractCardItem *abstractCard, bool selected)
|
||||
{
|
||||
CardItem *card = qobject_cast<CardItem *>(abstractCard);
|
||||
|
|
@ -205,12 +134,12 @@ void GameScene::onCardSelectionChanged(AbstractCardItem *abstractCard, bool sele
|
|||
auto *owner = card->getOwner();
|
||||
|
||||
if (selected) {
|
||||
owner->requestCardMenuUpdate(card->getState());
|
||||
owner->requestCardMenuUpdate(card);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItems().isEmpty()) {
|
||||
setActiveCard(nullptr);
|
||||
owner->getGame()->setActiveCard(nullptr);
|
||||
owner->requestCardMenuUpdate(nullptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -229,9 +158,9 @@ void GameScene::onCardRightClicked(AbstractCardItem *abstractCard, QPoint screen
|
|||
return;
|
||||
}
|
||||
|
||||
setActiveCard(card);
|
||||
card->getOwner()->getGame()->setActiveCard(card);
|
||||
|
||||
if (auto *menu = view->getPlayerMenu()->updateCardMenu(card->getState())) {
|
||||
if (auto *menu = view->getPlayerMenu()->updateCardMenu(card)) {
|
||||
menu->popup(screenPos);
|
||||
}
|
||||
}
|
||||
|
|
@ -244,7 +173,7 @@ void GameScene::playSelected(AbstractCardItem *card)
|
|||
if (!card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
card->getOwner()->getPlayerActions()->actPlay(selectedCardStates());
|
||||
card->getOwner()->getPlayerActions()->actPlay(selectedCards());
|
||||
}
|
||||
|
||||
void GameScene::playSelectedFaceDown(AbstractCardItem *card)
|
||||
|
|
@ -255,7 +184,7 @@ void GameScene::playSelectedFaceDown(AbstractCardItem *card)
|
|||
if (!card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
card->getOwner()->getPlayerActions()->actPlayFacedown(selectedCardStates());
|
||||
card->getOwner()->getPlayerActions()->actPlayFacedown(selectedCards());
|
||||
}
|
||||
|
||||
void GameScene::hideSelected(AbstractCardItem *card)
|
||||
|
|
@ -266,7 +195,7 @@ void GameScene::hideSelected(AbstractCardItem *card)
|
|||
if (!card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
card->getOwner()->getPlayerActions()->actHide(selectedCardStates());
|
||||
card->getOwner()->getPlayerActions()->actHide(selectedCards());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -301,8 +230,6 @@ void GameScene::addPlayer(PlayerLogic *player)
|
|||
[this, id = player->getPlayerInfo()->getId()]() { clearArrowsForPlayerLocally(id); });
|
||||
|
||||
connect(player->getPlayerEventHandler(), &PlayerEventHandler::cardZoneChanged, this, &GameScene::onCardZoneChanged);
|
||||
connect(player->getPlayerEventHandler(), &PlayerEventHandler::cardViewRefreshRequested, this,
|
||||
&GameScene::onCardViewRefreshRequested);
|
||||
|
||||
rearrange();
|
||||
}
|
||||
|
|
@ -606,11 +533,7 @@ void GameScene::addArrow(QSharedPointer<ArrowData> data)
|
|||
return;
|
||||
}
|
||||
|
||||
CardState *startCardState = startZone->getCard(data->startCardId);
|
||||
if (!startCardState) {
|
||||
return;
|
||||
}
|
||||
CardItem *startCard = qobject_cast<CardItem *>(startCardState->parent());
|
||||
CardItem *startCard = startZone->getCard(data->startCardId);
|
||||
if (!startCard) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -621,8 +544,7 @@ void GameScene::addArrow(QSharedPointer<ArrowData> data)
|
|||
} else {
|
||||
auto *zone = targetView->getLogic()->getZones().value(data->targetZone);
|
||||
if (zone) {
|
||||
CardState *targetCardState = zone->getCard(data->targetCardId);
|
||||
targetItem = targetCardState == nullptr ? nullptr : qobject_cast<CardItem *>(targetCardState->parent());
|
||||
targetItem = zone->getCard(data->targetCardId);
|
||||
}
|
||||
}
|
||||
if (!targetItem) {
|
||||
|
|
@ -650,15 +572,11 @@ void GameScene::requestArrowDeletion(int playerId, int arrowId)
|
|||
}
|
||||
}
|
||||
|
||||
void GameScene::onCardZoneChanged(CardState *card, bool sameZone)
|
||||
void GameScene::onCardZoneChanged(CardItem *card, bool sameZone)
|
||||
{
|
||||
auto *item = qobject_cast<CardItem *>(card->parent());
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
QList<ArrowItem *> toDelete;
|
||||
for (auto *arrow : arrowRegistry.all()) {
|
||||
if (arrow->getStartItem() == item || arrow->getTargetItem() == item) {
|
||||
if (arrow->getStartItem() == card || arrow->getTargetItem() == card) {
|
||||
if (sameZone) {
|
||||
arrow->updatePath();
|
||||
} else {
|
||||
|
|
@ -671,25 +589,6 @@ void GameScene::onCardZoneChanged(CardState *card, bool sameZone)
|
|||
}
|
||||
}
|
||||
|
||||
void GameScene::onCardViewRefreshRequested(CardState *card, bool zoneChanged, PlayerLogic *newOwner)
|
||||
{
|
||||
auto *item = qobject_cast<CardItem *>(card->parent());
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
if (zoneChanged) {
|
||||
item->deleteCardInfoPopup();
|
||||
}
|
||||
item->deleteDragItem();
|
||||
if (zoneChanged) {
|
||||
item->setBeingPointedAt(false);
|
||||
item->setHovered(false);
|
||||
}
|
||||
if (newOwner) {
|
||||
item->setOwner(newOwner);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::clearArrowsForPlayer(int playerId)
|
||||
{
|
||||
for (int arrowId : arrowRegistry.idsForPlayer(playerId)) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
#ifndef GAMESCENE_H
|
||||
#define GAMESCENE_H
|
||||
|
||||
#include "animated_item.h"
|
||||
#include "board/arrow_item.h"
|
||||
#include "board/arrow_registry.h"
|
||||
#include "../game/arrow_registry.h"
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QHash>
|
||||
|
|
@ -18,8 +16,6 @@
|
|||
#include <QString>
|
||||
#include <QTransform>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/game/board/arrow_data.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
// IWYU pragma: keep
|
||||
|
|
@ -43,7 +39,6 @@ class ZoneViewWidget;
|
|||
class CardZone;
|
||||
class AbstractCardItem;
|
||||
class CardItem;
|
||||
class CardState;
|
||||
class ServerInfo_Card;
|
||||
class PhasesToolbar;
|
||||
class QBasicTimer;
|
||||
|
|
@ -74,7 +69,6 @@ private:
|
|||
QList<ZoneViewWidget *> zoneViews; ///< Active zone view widgets
|
||||
QSize viewSize; ///< Current view size
|
||||
QPointer<CardItem> hoveredCard; ///< Currently hovered card
|
||||
QPointer<CardItem> activeCard; ///< Card the currently open context menu targets
|
||||
QBasicTimer *animationTimer; ///< Timer for scene animations
|
||||
QHash<QObject *, IAnimatedItem *> animatedItems; ///< Items currently animating
|
||||
QHash<QObject *, QMetaObject::Connection>
|
||||
|
|
@ -113,22 +107,6 @@ public:
|
|||
|
||||
/** @brief Gets all selected CardItems. */
|
||||
QList<CardItem *> selectedCards() const;
|
||||
QList<CardState *> selectedCardStates() const;
|
||||
|
||||
/** @brief Selects every card sharing the zone of @p card. */
|
||||
void selectAllInZone(const CardItem *card);
|
||||
|
||||
/** @brief Selects the cards laid out in the same visual row as @p card. */
|
||||
void selectSameRow(const CardItem *card);
|
||||
|
||||
/** @brief Selects the cards laid out in the same visual column as @p card. */
|
||||
void selectSameColumn(const CardItem *card);
|
||||
|
||||
/** @brief Card the currently open context menu targets, or null. */
|
||||
CardItem *getActiveCard() const;
|
||||
|
||||
/** @brief Sets the card the currently open context menu targets. */
|
||||
void setActiveCard(CardItem *card);
|
||||
|
||||
/**
|
||||
* @brief Adds a player to the scene and stores their graphics item.
|
||||
|
|
@ -283,15 +261,7 @@ public slots:
|
|||
/// Queues up arrow deletion but doesn't directly modify the scene
|
||||
void requestArrowDeletion(int playerId, int arrowId);
|
||||
|
||||
void onCardZoneChanged(CardState *card, bool sameZone);
|
||||
/**
|
||||
* @brief Refreshes the view of a card that the server just moved.
|
||||
*
|
||||
* @param card The card that moved.
|
||||
* @param zoneChanged Whether the card crossed a zone boundary.
|
||||
* @param newOwner The player the card now belongs to, or nullptr to leave the owner alone.
|
||||
*/
|
||||
void onCardViewRefreshRequested(CardState *card, bool zoneChanged, PlayerLogic *newOwner);
|
||||
void onCardZoneChanged(CardItem *card, bool sameZone);
|
||||
|
||||
protected:
|
||||
/** @brief Handles hover updates. */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "hand_counter.h"
|
||||
|
||||
#include "../game/board/card_list.h"
|
||||
#include "../game/zones/card_zone_logic.h"
|
||||
#include "../interface/pixel_map_generator.h"
|
||||
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
|
|
@ -12,8 +14,6 @@
|
|||
#include <QString>
|
||||
#include <QStringLiteral>
|
||||
#include <QTransform>
|
||||
#include <libcockatrice/game/board/card_list.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
class QGraphicsItem;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,16 @@
|
|||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../client/settings/card_counter_settings.h"
|
||||
#include "../../client/sound_engine.h"
|
||||
#include "../../client/translation.h"
|
||||
#include "../../game/abstract_game.h"
|
||||
#include "../../game/board/card_list.h"
|
||||
#include "../../game/game_state.h"
|
||||
#include "../../game/phase.h"
|
||||
#include "../../game/player/player_event_handler.h"
|
||||
#include "../../game/player/player_info.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../../game/player/player_manager.h"
|
||||
#include "../../game/zones/card_zone_logic.h"
|
||||
#include "../../interface/card_localization.h"
|
||||
#include "../../interface/theme_icon.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
|
@ -20,16 +30,6 @@
|
|||
#include <QStringList>
|
||||
#include <QTextDocument>
|
||||
#include <QUrl>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/board/card_list.h>
|
||||
#include <libcockatrice/game/game_state.h>
|
||||
#include <libcockatrice/game/phase.h>
|
||||
#include <libcockatrice/game/player/player_event_handler.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/player/player_manager.h>
|
||||
#include <libcockatrice/game/translation.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
|
||||
#include <libcockatrice/settings/chat_settings.h>
|
||||
|
|
@ -290,7 +290,7 @@ void MessageLogWidget::logDestroyCard(PlayerLogic *player, QString cardName)
|
|||
}
|
||||
|
||||
void MessageLogWidget::logMoveCard(PlayerLogic *player,
|
||||
CardState *card,
|
||||
CardItem *card,
|
||||
CardZoneLogic *startZone,
|
||||
int oldX,
|
||||
CardZoneLogic *targetZone,
|
||||
|
|
@ -669,7 +669,7 @@ void MessageLogWidget::logSetActivePlayer(PlayerLogic *player)
|
|||
QString(tr("%1's turn.")).arg(player->getPlayerInfo()->getName()) + "</b></font><br>");
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardState *card, QString newAnnotation)
|
||||
void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation)
|
||||
{
|
||||
appendHtmlServerMessage(
|
||||
QString(tr("%1 sets annotation of %2 to %3."))
|
||||
|
|
@ -713,7 +713,7 @@ void MessageLogWidget::logSetCounter(PlayerLogic *player, QString counterName, i
|
|||
.arg(value - oldValue));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardState *card, bool doesntUntap)
|
||||
void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap)
|
||||
{
|
||||
QString str;
|
||||
if (doesntUntap) {
|
||||
|
|
@ -724,7 +724,7 @@ void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardState *card, b
|
|||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetPT(PlayerLogic *player, CardState *card, QString newPT)
|
||||
void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString newPT)
|
||||
{
|
||||
if (currentContext == MessageContext_MoveCard) {
|
||||
return;
|
||||
|
|
@ -762,7 +762,7 @@ void MessageLogWidget::logSetSideboardLock(PlayerLogic *player, bool locked)
|
|||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetTapped(PlayerLogic *player, CardState *card, bool tapped)
|
||||
void MessageLogWidget::logSetTapped(PlayerLogic *player, CardItem *card, bool tapped)
|
||||
{
|
||||
if (currentContext == MessageContext_MoveCard) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <qtmetamacros.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
class CardState;
|
||||
class AbstractGame;
|
||||
class CardItem;
|
||||
class GameEventContext;
|
||||
|
|
@ -79,7 +78,7 @@ public slots:
|
|||
void logLeaveSpectator(QString name, QString reason);
|
||||
void logNotReadyStart(PlayerLogic *player);
|
||||
void logMoveCard(PlayerLogic *player,
|
||||
CardState *card,
|
||||
CardItem *card,
|
||||
CardZoneLogic *startZone,
|
||||
int oldX,
|
||||
CardZoneLogic *targetZone,
|
||||
|
|
@ -100,13 +99,13 @@ public slots:
|
|||
void logSay(PlayerLogic *player, QString message);
|
||||
void logSetActivePhase(int phase);
|
||||
void logSetActivePlayer(PlayerLogic *player);
|
||||
void logSetAnnotation(PlayerLogic *player, CardState *card, QString newAnnotation);
|
||||
void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation);
|
||||
void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue);
|
||||
void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue);
|
||||
void logSetDoesntUntap(PlayerLogic *player, CardState *card, bool doesntUntap);
|
||||
void logSetPT(PlayerLogic *player, CardState *card, QString newPT);
|
||||
void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap);
|
||||
void logSetPT(PlayerLogic *player, CardItem *card, QString newPT);
|
||||
void logSetSideboardLock(PlayerLogic *player, bool locked);
|
||||
void logSetTapped(PlayerLogic *player, CardState *card, bool tapped);
|
||||
void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped);
|
||||
void logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end);
|
||||
void logSpectatorSay(const ServerInfo_User &spectator, QString message);
|
||||
void logUnattachCard(PlayerLogic *player, QString cardName);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@
|
|||
#include <QTransform>
|
||||
#include <QtGlobal>
|
||||
#include <google/protobuf/stubs/port.h>
|
||||
#include <libcockatrice/protocol/pb/command_draw_cards.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <qnamespace.h>
|
||||
#include <qnumeric.h>
|
||||
|
||||
|
|
@ -115,9 +120,9 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
|
|||
: QGraphicsItem(parent), width(100), height(100), ySpacing(1), symbolSize(8)
|
||||
{
|
||||
auto *aUntapAll = new QAction(this);
|
||||
connect(aUntapAll, &QAction::triggered, this, &PhasesToolbar::untapAllRequested);
|
||||
connect(aUntapAll, &QAction::triggered, this, &PhasesToolbar::actUntapAll);
|
||||
auto *aDrawCard = new QAction(this);
|
||||
connect(aDrawCard, &QAction::triggered, this, &PhasesToolbar::drawCardRequested);
|
||||
connect(aDrawCard, &QAction::triggered, this, &PhasesToolbar::actDrawCard);
|
||||
|
||||
PhaseButton *untapButton = new PhaseButton("untap", this, aUntapAll);
|
||||
PhaseButton *upkeepButton = new PhaseButton("upkeep", this);
|
||||
|
|
@ -139,7 +144,7 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
|
|||
}
|
||||
|
||||
nextTurnButton = new PhaseButton("nextturn", this, nullptr, false);
|
||||
connect(nextTurnButton, &PhaseButton::clicked, this, &PhasesToolbar::nextTurnRequested);
|
||||
connect(nextTurnButton, &PhaseButton::clicked, this, &PhasesToolbar::actNextTurn);
|
||||
|
||||
rearrangeButtons();
|
||||
|
||||
|
|
@ -260,5 +265,31 @@ void PhasesToolbar::phaseButtonClicked()
|
|||
button->triggerDoubleClickAction();
|
||||
}
|
||||
|
||||
emit setActivePhaseRequested(buttonList.indexOf(button));
|
||||
Command_SetActivePhase cmd;
|
||||
cmd.set_phase(static_cast<google::protobuf::uint32>(buttonList.indexOf(button)));
|
||||
|
||||
emit sendGameCommand(cmd, -1);
|
||||
}
|
||||
|
||||
void PhasesToolbar::actNextTurn()
|
||||
{
|
||||
emit sendGameCommand(Command_NextTurn(), -1);
|
||||
}
|
||||
|
||||
void PhasesToolbar::actUntapAll()
|
||||
{
|
||||
Command_SetCardAttr cmd;
|
||||
cmd.set_zone(ZoneNames::TABLE);
|
||||
cmd.set_attribute(AttrTapped);
|
||||
cmd.set_attr_value("0");
|
||||
|
||||
emit sendGameCommand(cmd, -1);
|
||||
}
|
||||
|
||||
void PhasesToolbar::actDrawCard()
|
||||
{
|
||||
Command_DrawCards cmd;
|
||||
cmd.set_number(1);
|
||||
|
||||
emit sendGameCommand(cmd, -1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,14 @@
|
|||
class QAction;
|
||||
class QTimer;
|
||||
|
||||
namespace google
|
||||
{
|
||||
namespace protobuf
|
||||
{
|
||||
class Message;
|
||||
}
|
||||
} // namespace google
|
||||
|
||||
class PhaseButton : public QObject, public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -87,16 +95,11 @@ public slots:
|
|||
void triggerPhaseAction(int phase);
|
||||
private slots:
|
||||
void phaseButtonClicked();
|
||||
void actNextTurn();
|
||||
void actUntapAll();
|
||||
void actDrawCard();
|
||||
signals:
|
||||
/** @name Intent signals
|
||||
* The view reports what the user asked for; GameEventHandler builds the commands.
|
||||
* @{
|
||||
*/
|
||||
void setActivePhaseRequested(int phase);
|
||||
void nextTurnRequested();
|
||||
void untapAllRequested();
|
||||
void drawCardRequested();
|
||||
/** @} */
|
||||
void sendGameCommand(const ::google::protobuf::Message &command, int playerId);
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) override;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file card_menu_action_type.h
|
||||
* @ingroup GameLogicPlayers
|
||||
* @ingroup GameMenusPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
|
|
@ -3,8 +3,16 @@
|
|||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../../../client/settings/card_counter_settings.h"
|
||||
#include "../../../client/settings/shortcuts_settings.h"
|
||||
#include "../../../game/abstract_game.h"
|
||||
#include "../../../game/player/player_info.h"
|
||||
#include "../../../game/player/player_manager.h"
|
||||
#include "../../../game/zones/card_zone_logic.h"
|
||||
#include "../../board/card_item.h"
|
||||
#include "../../game/player/player_actions.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../../game/zones/view_zone_logic.h"
|
||||
#include "../../game_scene.h"
|
||||
#include "../card_menu_action_type.h"
|
||||
#include "../player_graphics_item.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
|
|
@ -27,14 +35,6 @@
|
|||
#include <QtGlobal>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/relation/card_relation.h>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/player/card_menu_action_type.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/player/player_manager.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <libcockatrice/game/zones/view_zone_logic.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <qnamespace.h>
|
||||
#include <utility>
|
||||
|
|
@ -67,7 +67,7 @@ static QAction *makeAction(QObject *parent, Slot &&slot, bool checkable = false,
|
|||
return a;
|
||||
}
|
||||
|
||||
CardMenu::CardMenu(PlayerGraphicsItem *_player, CardItem *_card, bool _shortcutsActive)
|
||||
CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _shortcutsActive)
|
||||
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
|
||||
{
|
||||
const QList<PlayerLogic *> &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
|
|
@ -86,7 +86,7 @@ CardMenu::CardMenu(PlayerGraphicsItem *_player, CardItem *_card, bool _shortcuts
|
|||
auto *gameScene = player->getGameScene();
|
||||
|
||||
// Single selection resolver used by all lambdas — called at trigger time
|
||||
auto sel = [gameScene]() { return gameScene->selectedCardStates(); };
|
||||
auto sel = [gameScene]() { return gameScene->selectedCards(); };
|
||||
|
||||
// Unified dispatcher for card menu actions
|
||||
auto invoke = [actions, sel](CardMenuActionType type) {
|
||||
|
|
@ -108,18 +108,18 @@ CardMenu::CardMenu(PlayerGraphicsItem *_player, CardItem *_card, bool _shortcuts
|
|||
aHide = makeAction(this, [actions, sel]() { actions->actHide(sel()); });
|
||||
aReduceLifeByPower = makeAction(this, [actions, sel]() { actions->actReduceLifeByPower(sel()); });
|
||||
|
||||
// Actions bound to the card this menu was opened for, not to the current selection
|
||||
// Actions that use activeCard, not selection — direct connection
|
||||
aAttach = new QAction(this);
|
||||
aDrawArrow = new QAction(this);
|
||||
aSelectAll = new QAction(this);
|
||||
aSelectRow = new QAction(this);
|
||||
aSelectColumn = new QAction(this);
|
||||
|
||||
connect(aAttach, &QAction::triggered, this, &CardMenu::attachCard);
|
||||
connect(aDrawArrow, &QAction::triggered, this, &CardMenu::drawArrow);
|
||||
connect(aSelectAll, &QAction::triggered, this, [this, gameScene]() { gameScene->selectAllInZone(card); });
|
||||
connect(aSelectRow, &QAction::triggered, this, [this, gameScene]() { gameScene->selectSameRow(card); });
|
||||
connect(aSelectColumn, &QAction::triggered, this, [this, gameScene]() { gameScene->selectSameColumn(card); });
|
||||
connect(aAttach, &QAction::triggered, actions, &PlayerActions::actAttach);
|
||||
connect(aDrawArrow, &QAction::triggered, actions, &PlayerActions::actDrawArrow);
|
||||
connect(aSelectAll, &QAction::triggered, actions, &PlayerActions::actSelectAll);
|
||||
connect(aSelectRow, &QAction::triggered, actions, &PlayerActions::actSelectRow);
|
||||
connect(aSelectColumn, &QAction::triggered, actions, &PlayerActions::actSelectColumn);
|
||||
|
||||
aRevealToAll = new QAction(this);
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ void CardMenu::createHandOrCustomZoneMenu(bool canModifyCard)
|
|||
initContextualPlayersMenu(revealMenu, aRevealToAll);
|
||||
|
||||
connect(revealMenu, &QMenu::triggered, this, [this](QAction *action) {
|
||||
player->getLogic()->getPlayerActions()->actReveal(player->getGameScene()->selectedCardStates(), action);
|
||||
player->getLogic()->getPlayerActions()->actReveal(player->getGameScene()->selectedCards(), action);
|
||||
});
|
||||
|
||||
addSeparator();
|
||||
|
|
@ -441,7 +441,6 @@ void CardMenu::addRelatedCardActions()
|
|||
if (relatedCards.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
auto *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
addSeparator();
|
||||
int index = 0;
|
||||
|
|
@ -485,10 +484,9 @@ void CardMenu::addRelatedCardActions()
|
|||
}
|
||||
|
||||
auto *createRelated = new QAction(text, this);
|
||||
const int relatedIndex = index++;
|
||||
connect(createRelated, &QAction::triggered, this, [this, playerActions, relatedIndex] {
|
||||
playerActions->actCreateRelatedCard(card->getState(), relatedIndex);
|
||||
});
|
||||
createRelated->setData(QVariant(index++));
|
||||
connect(createRelated, &QAction::triggered, player->getLogic()->getPlayerActions(),
|
||||
&PlayerActions::actCreateRelatedCard);
|
||||
addAction(createRelated);
|
||||
}
|
||||
|
||||
|
|
@ -497,26 +495,12 @@ void CardMenu::addRelatedCardActions()
|
|||
createRelatedCards->setShortcuts(
|
||||
SettingsCache::instance().shortcuts().getShortcut("Player/aCreateRelatedTokens"));
|
||||
}
|
||||
connect(createRelatedCards, &QAction::triggered, this,
|
||||
[this, playerActions] { playerActions->actCreateAllRelatedCards(card->getState()); });
|
||||
connect(createRelatedCards, &QAction::triggered, player->getLogic()->getPlayerActions(),
|
||||
&PlayerActions::actCreateAllRelatedCards);
|
||||
addAction(createRelatedCards);
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::attachCard()
|
||||
{
|
||||
if (card) {
|
||||
card->drawAttachArrow();
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::drawArrow()
|
||||
{
|
||||
if (card) {
|
||||
card->drawArrow(Qt::red);
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::retranslateUi()
|
||||
{
|
||||
aSelectAll->setText(tr("&Select All"));
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ signals:
|
|||
void cardInfoRequested(const CardRef &cardRef);
|
||||
|
||||
public:
|
||||
explicit CardMenu(PlayerGraphicsItem *player, CardItem *card, bool shortcutsActive);
|
||||
explicit CardMenu(PlayerGraphicsItem *player, const CardItem *card, bool shortcutsActive);
|
||||
void removePlayer(PlayerLogic *playerToRemove);
|
||||
void createTableMenu(bool canModifyCard);
|
||||
void createStackMenu(bool canModifyCard);
|
||||
|
|
@ -53,13 +53,11 @@ public:
|
|||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
CardItem *card;
|
||||
const CardItem *card;
|
||||
QList<QPair<QString, int>> playersInfo;
|
||||
bool shortcutsActive;
|
||||
|
||||
void addRelatedCardActions();
|
||||
void attachCard();
|
||||
void drawArrow();
|
||||
void retranslateUi();
|
||||
void initContextualPlayersMenu(QMenu *menu, QAction *allPlayersAction);
|
||||
void setShortcutsActive();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#include "custom_zone_menu.h"
|
||||
|
||||
#include "../../../game/player/player_info.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../../game_scene.h"
|
||||
#include "../player_graphics_item.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
|
||||
CustomZoneMenu::CustomZoneMenu(PlayerGraphicsItem *_player) : player(_player)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,13 @@
|
|||
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../../../client/settings/shortcuts_settings.h"
|
||||
#include "../../../game/player/player_info.h"
|
||||
#include "../../../game/player/player_manager.h"
|
||||
#include "../../../game/zones/pile_zone_logic.h"
|
||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "../../game/abstract_game.h"
|
||||
#include "../../game/player/player_actions.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../player_graphics_item.h"
|
||||
|
||||
#include <QAction>
|
||||
|
|
@ -13,12 +19,6 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/player/player_manager.h>
|
||||
#include <libcockatrice/game/zones/pile_zone_logic.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
class QWidget;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,14 @@
|
|||
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../../../client/settings/shortcuts_settings.h"
|
||||
#include "../../../game/board/card_list.h"
|
||||
#include "../../../game/player/player_info.h"
|
||||
#include "../../../game/player/player_manager.h"
|
||||
#include "../../../game/zones/hand_zone_logic.h"
|
||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "../../game/abstract_game.h"
|
||||
#include "../../game/player/player_actions.h"
|
||||
#include "../../game/player/player_logic.h"
|
||||
#include "../player_graphics_item.h"
|
||||
|
||||
#include <QAction>
|
||||
|
|
@ -13,13 +20,6 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <libcockatrice/game/abstract_game.h>
|
||||
#include <libcockatrice/game/board/card_list.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/game/player/player_manager.h>
|
||||
#include <libcockatrice/game/zones/hand_zone_logic.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
class QWidget;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue