Merge branch 'master' into tooomm-qt5

This commit is contained in:
tooomm 2026-05-30 14:49:55 +02:00 committed by GitHub
commit 9d4cf57c70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
593 changed files with 12518 additions and 6581 deletions

View file

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

View file

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

View file

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

View file

@ -1,9 +1,9 @@
name: Generate Docs name: Generate Docs
on: on:
push: release:
tags: types:
- '*' # Only re-generate docs when a new tagged version is pushed - published # publishing of stable releases and pre-releases
pull_request: pull_request:
paths: paths:
- 'doc/doxygen/**' - 'doc/doxygen/**'
@ -53,11 +53,11 @@ jobs:
run: doxygen Doxyfile run: doxygen Doxyfile
- name: Deploy to cockatrice.github.io - name: Deploy to cockatrice.github.io
if: github.event_name != 'pull_request' if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
uses: peaceiris/actions-gh-pages@v4 uses: peaceiris/actions-gh-pages@v4
with: with:
deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }} deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }}
external_repository: Cockatrice/cockatrice.github.io external_repository: Cockatrice/cockatrice.github.io
publish_branch: master publish_branch: master
publish_dir: ./docs/html publish_dir: ./docs/html
destination_dir: docs # Docs will live under https://cockatrice.github.io/docs/ destination_dir: docs # Docs will live under https://cockatrice.github.io/docs/

View file

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

View file

@ -59,12 +59,15 @@ set(cockatrice_SOURCES
src/game/board/abstract_card_drag_item.cpp src/game/board/abstract_card_drag_item.cpp
src/game/board/abstract_card_item.cpp src/game/board/abstract_card_item.cpp
src/game/board/abstract_counter.cpp src/game/board/abstract_counter.cpp
src/game/board/arrow_data.cpp
src/game/board/arrow_item.cpp src/game/board/arrow_item.cpp
src/game/board/arrow_target.cpp src/game/board/arrow_target.cpp
src/game/board/card_drag_item.cpp src/game/board/card_drag_item.cpp
src/game/board/card_item.cpp src/game/board/card_item.cpp
src/game/board/card_list.cpp src/game/board/card_list.cpp
src/game/board/card_state.cpp
src/game/board/counter_general.cpp src/game/board/counter_general.cpp
src/game/board/counter_state.cpp
src/game/board/translate_counter_name.cpp src/game/board/translate_counter_name.cpp
src/game/deckview/deck_view.cpp src/game/deckview/deck_view.cpp
src/game/deckview/deck_view_container.cpp src/game/deckview/deck_view_container.cpp
@ -94,30 +97,30 @@ set(cockatrice_SOURCES
src/game/player/menu/say_menu.cpp src/game/player/menu/say_menu.cpp
src/game/player/menu/sideboard_menu.cpp src/game/player/menu/sideboard_menu.cpp
src/game/player/menu/utility_menu.cpp src/game/player/menu/utility_menu.cpp
src/game/player/player.cpp
src/game/player/player_actions.cpp src/game/player/player_actions.cpp
src/game/player/player_area.cpp src/game/player/player_area.cpp
src/game/player/player_event_handler.cpp src/game/player/player_event_handler.cpp
src/game/player/player_graphics_item.cpp src/game/player/player_graphics_item.cpp
src/game/player/player_info.cpp src/game/player/player_info.cpp
src/game/player/player_list_widget.cpp src/game/player/player_list_widget.cpp
src/game/player/player_logic.cpp
src/game/player/player_manager.cpp src/game/player/player_manager.cpp
src/game/player/player_target.cpp src/game/player/player_target.cpp
src/game/replay.cpp src/game/replay.cpp
src/game/zones/card_zone.cpp src/game/zones/card_zone_logic.cpp
src/game/zones/hand_zone.cpp src/game/zones/hand_zone_logic.cpp
src/game/zones/logic/card_zone_logic.cpp src/game/zones/pile_zone_logic.cpp
src/game/zones/logic/hand_zone_logic.cpp src/game/zones/stack_zone_logic.cpp
src/game/zones/logic/pile_zone_logic.cpp src/game/zones/table_zone_logic.cpp
src/game/zones/logic/stack_zone_logic.cpp src/game/zones/view_zone_logic.cpp
src/game/zones/logic/table_zone_logic.cpp src/game_graphics/zones/card_zone.cpp
src/game/zones/logic/view_zone_logic.cpp src/game_graphics/zones/hand_zone.cpp
src/game/zones/pile_zone.cpp src/game_graphics/zones/pile_zone.cpp
src/game/zones/select_zone.cpp src/game_graphics/zones/select_zone.cpp
src/game/zones/stack_zone.cpp src/game_graphics/zones/stack_zone.cpp
src/game/zones/table_zone.cpp src/game_graphics/zones/table_zone.cpp
src/game/zones/view_zone.cpp src/game_graphics/zones/view_zone.cpp
src/game/zones/view_zone_widget.cpp src/game_graphics/zones/view_zone_widget.cpp
src/game_graphics/board/abstract_graphics_item.cpp src/game_graphics/board/abstract_graphics_item.cpp
src/interface/card_picture_loader/card_picture_loader.cpp src/interface/card_picture_loader/card_picture_loader.cpp
src/interface/card_picture_loader/card_picture_loader_local.cpp src/interface/card_picture_loader/card_picture_loader_local.cpp
@ -130,7 +133,13 @@ set(cockatrice_SOURCES
src/interface/layouts/overlap_layout.cpp src/interface/layouts/overlap_layout.cpp
src/interface/widgets/utility/line_edit_completer.cpp src/interface/widgets/utility/line_edit_completer.cpp
src/interface/pixel_map_generator.cpp src/interface/pixel_map_generator.cpp
src/interface/theme_config.cpp
src/interface/theme_manager.cpp src/interface/theme_manager.cpp
src/interface/palette_editor/color_button.cpp
src/interface/palette_editor/palette_generator.cpp
src/interface/palette_editor/quick_setup_panel.cpp
src/interface/palette_editor/palette_grid_widget.cpp
src/interface/palette_editor/palette_editor_dialog.cpp
src/interface/widgets/cards/additional_info/color_identity_widget.cpp src/interface/widgets/cards/additional_info/color_identity_widget.cpp
src/interface/widgets/cards/additional_info/mana_cost_widget.cpp src/interface/widgets/cards/additional_info/mana_cost_widget.cpp
src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp
@ -229,6 +238,14 @@ set(cockatrice_SOURCES
src/interface/widgets/server/user/user_info_connection.cpp src/interface/widgets/server/user/user_info_connection.cpp
src/interface/widgets/server/user/user_list_manager.cpp src/interface/widgets/server/user/user_list_manager.cpp
src/interface/widgets/server/user/user_list_widget.cpp src/interface/widgets/server/user/user_list_widget.cpp
src/interface/widgets/settings_page/appearance_settings_page.cpp
src/interface/widgets/settings_page/deck_editor_settings_page.cpp
src/interface/widgets/settings_page/general_settings_page.cpp
src/interface/widgets/settings_page/messages_settings_page.cpp
src/interface/widgets/settings_page/shortcut_settings_page.cpp
src/interface/widgets/settings_page/sound_settings_page.cpp
src/interface/widgets/settings_page/storage_settings_page.cpp
src/interface/widgets/settings_page/user_interface_settings_page.cpp
src/interface/widgets/utility/custom_line_edit.cpp src/interface/widgets/utility/custom_line_edit.cpp
src/interface/widgets/utility/get_text_with_max.cpp src/interface/widgets/utility/get_text_with_max.cpp
src/interface/widgets/utility/sequence_edit.cpp src/interface/widgets/utility/sequence_edit.cpp
@ -327,6 +344,8 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
src/interface/widgets/utility/compact_push_button.cpp
src/interface/widgets/utility/compact_push_button.h
) )
add_subdirectory(sounds) add_subdirectory(sounds)

View file

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

View file

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

View file

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

After

Width:  |  Height:  |  Size: 40 KiB

View file

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

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -140,13 +140,15 @@ void ConnectionController::onConnectionClosedEvent(const Event_ConnectionClosed
} }
case Event_ConnectionClosed::BANNED: { case Event_ConnectionClosed::BANNED: {
reasonStr = tr("Banned by moderator"); reasonStr = tr("Banned by moderator");
if (event.has_end_time()) if (event.has_end_time()) {
reasonStr.append( reasonStr.append(
"\n" + tr("Expected end time: %1").arg(QDateTime::fromSecsSinceEpoch(event.end_time()).toString())); "\n" + tr("Expected end time: %1").arg(QDateTime::fromSecsSinceEpoch(event.end_time()).toString()));
else } else {
reasonStr.append("\n" + tr("This ban lasts indefinitely.")); reasonStr.append("\n" + tr("This ban lasts indefinitely."));
if (event.has_reason_str()) }
if (event.has_reason_str()) {
reasonStr.append("\n\n" + QString::fromStdString(event.reason_str())); reasonStr.append("\n\n" + QString::fromStdString(event.reason_str()));
}
break; break;
} }
case Event_ConnectionClosed::SERVER_SHUTDOWN: { case Event_ConnectionClosed::SERVER_SHUTDOWN: {
@ -240,8 +242,9 @@ void ConnectionController::onLoginError(int r,
QString bannedStr = QString bannedStr =
endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()) endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString())
: tr("You are banned indefinitely."); : tr("You are banned indefinitely.");
if (!reasonStr.isEmpty()) if (!reasonStr.isEmpty()) {
bannedStr.append("\n\n" + reasonStr); bannedStr.append("\n\n" + reasonStr);
}
QMessageBox::critical(dialogParent, tr("Error"), bannedStr); QMessageBox::critical(dialogParent, tr("Error"), bannedStr);
break; break;
} }
@ -354,8 +357,9 @@ void ConnectionController::onRegisterError(int r, QString reasonStr, quint32 end
QString bannedStr = QString bannedStr =
endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()) endTime ? tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString())
: tr("You are banned indefinitely."); : tr("You are banned indefinitely.");
if (!reasonStr.isEmpty()) if (!reasonStr.isEmpty()) {
bannedStr.append("\n\n" + reasonStr); bannedStr.append("\n\n" + reasonStr);
}
QMessageBox::critical(dialogParent, tr("Error"), bannedStr); QMessageBox::critical(dialogParent, tr("Error"), bannedStr);
break; break;
} }
@ -545,8 +549,9 @@ QString ConnectionController::extractInvalidUsernameMessage(QString &in)
out += out +=
"<li>" + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "</li>"; "<li>" + tr("can %1 contain numeric characters").arg((rules.at(4).toInt() > 0) ? "" : tr("NOT")) + "</li>";
if (rules.at(6).size() > 0) if (rules.at(6).size() > 0) {
out += "<li>" + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "</li>"; out += "<li>" + tr("can contain the following punctuation: %1").arg(rules.at(6).toHtmlEscaped()) + "</li>";
}
out += "<li>" + out += "<li>" +
tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) + tr("first character can %1 be a punctuation mark").arg((rules.at(5).toInt() > 0) ? "" : tr("NOT")) +
@ -566,10 +571,11 @@ QString ConnectionController::extractInvalidUsernameMessage(QString &in)
} }
} }
if (rules.at(8).size() > 0) if (rules.at(8).size() > 0) {
out += "<li>" + out += "<li>" +
tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) + tr("can not match any of the following expressions: %1").arg(rules.at(8).toHtmlEscaped()) +
"</li>"; "</li>";
}
} }
out += "</ul>"; out += "</ul>";

View file

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

View file

@ -99,14 +99,16 @@ void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckLi
{ {
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) { auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName()); CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
if (!dbCard || dbCard->getIsToken()) if (!dbCard || dbCard->getIsToken()) {
return; return;
}
DecklistCardNode *addedCard; DecklistCardNode *addedCard;
if (node->getName() == DECK_ZONE_SIDE) if (node->getName() == DECK_ZONE_SIDE) {
addedCard = sideboard.addCard(card->getName(), node->getName(), -1); addedCard = sideboard.addCard(card->getName(), node->getName(), -1);
else } else {
addedCard = mainboard.addCard(card->getName(), node->getName(), -1); addedCard = mainboard.addCard(card->getName(), node->getName(), -1);
}
addedCard->setNumber(card->getNumber()); addedCard->setNumber(card->getNumber());
}; };

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -129,8 +129,9 @@ void StableReleaseChannel::releaseListFinished()
return; return;
} }
if (!lastRelease) if (!lastRelease) {
lastRelease = new Release; lastRelease = new Release;
}
lastRelease->setName(resultMap["name"].toString()); lastRelease->setName(resultMap["name"].toString());
lastRelease->setDescriptionUrl(resultMap["html_url"].toString()); lastRelease->setDescriptionUrl(resultMap["html_url"].toString());
@ -246,8 +247,9 @@ void BetaReleaseChannel::releaseListFinished()
return; return;
} }
if (lastRelease == nullptr) if (lastRelease == nullptr) {
lastRelease = new Release; lastRelease = new Release;
}
lastRelease->setCommitHash(resultMap["target_commitish"].toString()); lastRelease->setCommitHash(resultMap["target_commitish"].toString());
lastRelease->setPublishDate(resultMap["published_at"].toDate()); lastRelease->setPublishDate(resultMap["published_at"].toDate());

View file

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

View file

@ -10,8 +10,9 @@ UpdateDownloader::UpdateDownloader(QObject *parent) : QObject(parent), response(
void UpdateDownloader::beginDownload(QUrl downloadUrl) void UpdateDownloader::beginDownload(QUrl downloadUrl)
{ {
// Save the original URL because we need it for the filename // Save the original URL because we need it for the filename
if (originalUrl.isEmpty()) if (originalUrl.isEmpty()) {
originalUrl = downloadUrl; originalUrl = downloadUrl;
}
response = netMan->get(QNetworkRequest(downloadUrl)); response = netMan->get(QNetworkRequest(downloadUrl));
connect(response, &QNetworkReply::finished, this, &UpdateDownloader::fileFinished); connect(response, &QNetworkReply::finished, this, &UpdateDownloader::fileFinished);
@ -21,8 +22,9 @@ void UpdateDownloader::beginDownload(QUrl downloadUrl)
void UpdateDownloader::downloadError(QNetworkReply::NetworkError) void UpdateDownloader::downloadError(QNetworkReply::NetworkError)
{ {
if (response == nullptr) if (response == nullptr) {
return; return;
}
emit error(response->errorString().toUtf8()); emit error(response->errorString().toUtf8());
} }

View file

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

View file

@ -1,5 +1,7 @@
#include "cache_settings.h" #include "cache_settings.h"
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
#include "../network/update/client/release_channel.h" #include "../network/update/client/release_channel.h"
#include "card_counter_settings.h" #include "card_counter_settings.h"
#include "version_string.h" #include "version_string.h"
@ -24,10 +26,11 @@ SettingsCache &SettingsCache::instance()
QString SettingsCache::getDataPath() QString SettingsCache::getDataPath()
{ {
if (isPortableBuild) if (isPortableBuild) {
return qApp->applicationDirPath() + "/data"; return qApp->applicationDirPath() + "/data";
else } else {
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
}
} }
QString SettingsCache::getSettingsPath() QString SettingsCache::getSettingsPath()
@ -37,10 +40,11 @@ QString SettingsCache::getSettingsPath()
QString SettingsCache::getCachePath() const QString SettingsCache::getCachePath() const
{ {
if (isPortableBuild) if (isPortableBuild) {
return qApp->applicationDirPath() + "/cache"; return qApp->applicationDirPath() + "/cache";
else } else {
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation); return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
}
} }
QString SettingsCache::getNetworkCachePath() const QString SettingsCache::getNetworkCachePath() const
@ -50,14 +54,17 @@ QString SettingsCache::getNetworkCachePath() const
void SettingsCache::translateLegacySettings() void SettingsCache::translateLegacySettings()
{ {
if (isPortableBuild) if (isPortableBuild) {
return; return;
}
// Layouts // Layouts
QFile layoutFile(getSettingsPath() + "layouts/deckLayout.ini"); QFile layoutFile(getSettingsPath() + "layouts/deckLayout.ini");
if (layoutFile.exists()) if (layoutFile.exists()) {
if (layoutFile.copy(getSettingsPath() + "layouts.ini")) if (layoutFile.copy(getSettingsPath() + "layouts.ini")) {
layoutFile.remove(); layoutFile.remove();
}
}
QStringList usedKeys; QStringList usedKeys;
QSettings legacySetting; QSettings legacySetting;
@ -116,10 +123,11 @@ void SettingsCache::translateLegacySettings()
gameFilters().setHideIgnoredUserGames(legacySetting.value("hide_ignored_user_games").toBool()); gameFilters().setHideIgnoredUserGames(legacySetting.value("hide_ignored_user_games").toBool());
gameFilters().setMinPlayers(legacySetting.value("min_players").toInt()); gameFilters().setMinPlayers(legacySetting.value("min_players").toInt());
if (legacySetting.value("max_players").toInt() > 1) if (legacySetting.value("max_players").toInt() > 1) {
gameFilters().setMaxPlayers(legacySetting.value("max_players").toInt()); gameFilters().setMaxPlayers(legacySetting.value("max_players").toInt());
else } else {
gameFilters().setMaxPlayers(99); // This prevents a bug where no games will show if max was not set before gameFilters().setMaxPlayers(99); // This prevents a bug where no games will show if max was not set before
}
QStringList allFilters = legacySetting.allKeys(); QStringList allFilters = legacySetting.allKeys();
for (int i = 0; i < allFilters.size(); ++i) { for (int i = 0; i < allFilters.size(); ++i) {
@ -135,8 +143,9 @@ void SettingsCache::translateLegacySettings()
QStringList allLegacyKeys = legacySetting.allKeys(); QStringList allLegacyKeys = legacySetting.allKeys();
for (int i = 0; i < allLegacyKeys.size(); ++i) { for (int i = 0; i < allLegacyKeys.size(); ++i) {
if (usedKeys.contains(allLegacyKeys.at(i))) if (usedKeys.contains(allLegacyKeys.at(i))) {
continue; continue;
}
settings->setValue(allLegacyKeys.at(i), legacySetting.value(allLegacyKeys.at(i))); settings->setValue(allLegacyKeys.at(i), legacySetting.value(allLegacyKeys.at(i)));
} }
} }
@ -147,8 +156,9 @@ QString SettingsCache::getSafeConfigPath(QString configEntry, QString defaultPat
// if the config settings is empty or refers to a not-existing folder, // if the config settings is empty or refers to a not-existing folder,
// ensure that the defaut path exists and return it // ensure that the defaut path exists and return it
if (tmp.isEmpty() || !QDir(tmp).exists()) { if (tmp.isEmpty() || !QDir(tmp).exists()) {
if (!QDir().mkpath(defaultPath)) if (!QDir().mkpath(defaultPath)) {
qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath; qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath;
}
tmp = defaultPath; tmp = defaultPath;
} }
return tmp; return tmp;
@ -159,8 +169,9 @@ QString SettingsCache::getSafeConfigFilePath(QString configEntry, QString defaul
QString tmp = settings->value(configEntry).toString(); QString tmp = settings->value(configEntry).toString();
// if the config settings is empty or refers to a not-existing file, // if the config settings is empty or refers to a not-existing file,
// return the default Path // return the default Path
if (!QFile::exists(tmp) || tmp.isEmpty()) if (!QFile::exists(tmp) || tmp.isEmpty()) {
tmp = std::move(defaultPath); tmp = std::move(defaultPath);
}
return tmp; return tmp;
} }
@ -168,8 +179,9 @@ SettingsCache::SettingsCache()
{ {
// first, figure out if we are running in portable mode // first, figure out if we are running in portable mode
isPortableBuild = QFile::exists(qApp->applicationDirPath() + "/portable.dat"); isPortableBuild = QFile::exists(qApp->applicationDirPath() + "/portable.dat");
if (isPortableBuild) if (isPortableBuild) {
qCInfo(SettingsCacheLog) << "Portable mode enabled"; qCInfo(SettingsCacheLog) << "Portable mode enabled";
}
// define a dummy context that will be used where needed // define a dummy context that will be used where needed
QString dummy = QT_TRANSLATE_NOOP("i18n", "English"); QString dummy = QT_TRANSLATE_NOOP("i18n", "English");
@ -189,8 +201,9 @@ SettingsCache::SettingsCache()
cardCounterSettings = new CardCounterSettings(settingsPath, this); cardCounterSettings = new CardCounterSettings(settingsPath, this);
if (!QFile(settingsPath + "global.ini").exists()) if (!QFile(settingsPath + "global.ini").exists()) {
translateLegacySettings(); translateLegacySettings();
}
// updates - don't reorder them or their index in the settings won't match // updates - don't reorder them or their index in the settings won't match
// append channels one by one, or msvc will add them in the wrong order. // append channels one by one, or msvc will add them in the wrong order.
@ -257,14 +270,26 @@ SettingsCache::SettingsCache()
settings->setValue("personal/pixmapCacheSize", pixmapCacheSize); settings->setValue("personal/pixmapCacheSize", pixmapCacheSize);
settings->setValue("personal/picturedownloadhq", false); settings->setValue("personal/picturedownloadhq", false);
settings->setValue("revert/pixmapCacheSize", true); settings->setValue("revert/pixmapCacheSize", true);
} else } else {
pixmapCacheSize = settings->value("personal/pixmapCacheSize", PIXMAPCACHE_SIZE_DEFAULT).toInt(); pixmapCacheSize = settings->value("personal/pixmapCacheSize", PIXMAPCACHE_SIZE_DEFAULT).toInt();
}
// sanity check // sanity check
if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX) if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX) {
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT; pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
}
networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt(); networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt(); redirectCacheTtl = settings->value("personal/redirectCacheTtl", NETWORK_REDIRECT_CACHE_TTL_DEFAULT).toInt();
cardPictureLoaderCacheMethod =
settings
->value("personal/cardPictureLoaderCacheMethod",
static_cast<int>(CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE))
.toInt();
localCardImageStorageNamingScheme =
settings
->value("personal/localCardImageStorageNamingScheme",
static_cast<int>(CardPictureLoaderLocalSchemes::NamingScheme::Set_Folder_Name_Set_Collector))
.toInt();
picDownload = settings->value("personal/picturedownload", true).toBool(); picDownload = settings->value("personal/picturedownload", true).toBool();
showStatusBar = settings->value("personal/showStatusBar", false).toBool(); showStatusBar = settings->value("personal/showStatusBar", false).toBool();
@ -770,8 +795,9 @@ void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
void SettingsCache::setIncludeRebalancedCards(bool _includeRebalancedCards) void SettingsCache::setIncludeRebalancedCards(bool _includeRebalancedCards)
{ {
if (includeRebalancedCards == _includeRebalancedCards) if (includeRebalancedCards == _includeRebalancedCards) {
return; return;
}
includeRebalancedCards = _includeRebalancedCards; includeRebalancedCards = _includeRebalancedCards;
settings->setValue("cards/includerebalancedcards", includeRebalancedCards); settings->setValue("cards/includerebalancedcards", includeRebalancedCards);
@ -1098,6 +1124,13 @@ void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
emit pixmapCacheSizeChanged(pixmapCacheSize); emit pixmapCacheSizeChanged(pixmapCacheSize);
} }
void SettingsCache::setCardImageCacheMethod(const CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod)
{
cardPictureLoaderCacheMethod = static_cast<int>(_cardImageCachingMethod);
settings->setValue("personal/cardPictureLoaderCacheMethod", cardPictureLoaderCacheMethod);
emit cardPictureLoaderCacheMethodChanged(cardPictureLoaderCacheMethod);
}
void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize) void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
{ {
networkCacheSize = _networkCacheSize; networkCacheSize = _networkCacheSize;
@ -1112,6 +1145,14 @@ void SettingsCache::setNetworkRedirectCacheTtl(const int _redirectCacheTtl)
emit redirectCacheTtlChanged(redirectCacheTtl); emit redirectCacheTtlChanged(redirectCacheTtl);
} }
void SettingsCache::setLocalCardImageStorageNamingScheme(
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme)
{
localCardImageStorageNamingScheme = static_cast<int>(_localCardImageStorageNamingScheme);
settings->setValue("personal/localCardImageStorageNamingScheme", localCardImageStorageNamingScheme);
emit localCardImageStorageNamingSchemeChanged(localCardImageStorageNamingScheme);
}
void SettingsCache::setClientID(const QString &_clientID) void SettingsCache::setClientID(const QString &_clientID)
{ {
clientID = _clientID; clientID = _clientID;
@ -1310,8 +1351,9 @@ void SettingsCache::setMaxFontSize(int _max)
void SettingsCache::setRoundCardCorners(bool _roundCardCorners) void SettingsCache::setRoundCardCorners(bool _roundCardCorners)
{ {
if (_roundCardCorners == roundCardCorners) if (_roundCardCorners == roundCardCorners) {
return; return;
}
roundCardCorners = _roundCardCorners; roundCardCorners = _roundCardCorners;
settings->setValue("cards/roundcardcorners", _roundCardCorners); settings->setValue("cards/roundcardcorners", _roundCardCorners);

View file

@ -1,12 +1,14 @@
/** /**
* @file cache_settings.h * @file cache_settings.h
* @ingroup Settings * @ingroup Settings
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef SETTINGSCACHE_H #ifndef SETTINGSCACHE_H
#define SETTINGSCACHE_H #define SETTINGSCACHE_H
#include "../../interface/card_picture_loader/card_picture_loader_cache_method.h"
#include "../../interface/card_picture_loader/card_picture_loader_local_schemes.h"
#include "shortcuts_settings.h" #include "shortcuts_settings.h"
#include <QDate> #include <QDate>
@ -184,6 +186,8 @@ signals:
void pixmapCacheSizeChanged(int newSizeInMBs); void pixmapCacheSizeChanged(int newSizeInMBs);
void networkCacheSizeChanged(int newSizeInMBs); void networkCacheSizeChanged(int newSizeInMBs);
void redirectCacheTtlChanged(int newTtl); void redirectCacheTtlChanged(int newTtl);
void cardPictureLoaderCacheMethodChanged(int cardPictureLoaderCacheMethod);
void localCardImageStorageNamingSchemeChanged(int localCardImageStorageNamingScheme);
void masterVolumeChanged(int value); void masterVolumeChanged(int value);
void chatMentionCompleterChanged(); void chatMentionCompleterChanged();
void downloadSpoilerTimeIndexChanged(); void downloadSpoilerTimeIndexChanged();
@ -303,6 +307,8 @@ private:
int pixmapCacheSize; int pixmapCacheSize;
int networkCacheSize; int networkCacheSize;
int redirectCacheTtl; int redirectCacheTtl;
int cardPictureLoaderCacheMethod;
int localCardImageStorageNamingScheme;
bool scaleCards; bool scaleCards;
int verticalCardOverlapPercent; int verticalCardOverlapPercent;
bool showMessagePopups; bool showMessagePopups;
@ -786,6 +792,10 @@ public:
{ {
return pixmapCacheSize; return pixmapCacheSize;
} }
[[nodiscard]] CardPictureLoaderCacheMethod::CacheMethod getCardPictureLoaderCacheMethod() const
{
return static_cast<CardPictureLoaderCacheMethod::CacheMethod>(cardPictureLoaderCacheMethod);
}
[[nodiscard]] int getNetworkCacheSizeInMB() const [[nodiscard]] int getNetworkCacheSizeInMB() const
{ {
return networkCacheSize; return networkCacheSize;
@ -794,6 +804,10 @@ public:
{ {
return redirectCacheTtl; return redirectCacheTtl;
} }
[[nodiscard]] CardPictureLoaderLocalSchemes::NamingScheme getLocalCardImageStorageNamingScheme() const
{
return static_cast<CardPictureLoaderLocalSchemes::NamingScheme>(localCardImageStorageNamingScheme);
}
[[nodiscard]] bool getScaleCards() const [[nodiscard]] bool getScaleCards() const
{ {
return scaleCards; return scaleCards;
@ -1098,8 +1112,11 @@ public slots:
void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers); void setIgnoreUnregisteredUsers(QT_STATE_CHANGED_T _ignoreUnregisteredUsers);
void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages); void setIgnoreUnregisteredUserMessages(QT_STATE_CHANGED_T _ignoreUnregisteredUserMessages);
void setPixmapCacheSize(const int _pixmapCacheSize); void setPixmapCacheSize(const int _pixmapCacheSize);
void setCardImageCacheMethod(CardPictureLoaderCacheMethod::CacheMethod _cardImageCachingMethod);
void setNetworkCacheSizeInMB(const int _networkCacheSize); void setNetworkCacheSizeInMB(const int _networkCacheSize);
void setNetworkRedirectCacheTtl(const int _redirectCacheTtl); void setNetworkRedirectCacheTtl(const int _redirectCacheTtl);
void setLocalCardImageStorageNamingScheme(
const CardPictureLoaderLocalSchemes::NamingScheme _localCardImageStorageNamingScheme);
void setCardScaling(const QT_STATE_CHANGED_T _scaleCards); void setCardScaling(const QT_STATE_CHANGED_T _scaleCards);
void setStackCardOverlapPercent(const int _verticalCardOverlapPercent); void setStackCardOverlapPercent(const int _verticalCardOverlapPercent);
void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups); void setShowMessagePopups(const QT_STATE_CHANGED_T _showMessagePopups);

View file

@ -15,8 +15,9 @@ void CardCounterSettings::setColor(int counterId, const QColor &color)
QString key = QString("cards/counters/%1/color").arg(counterId); QString key = QString("cards/counters/%1/color").arg(counterId);
if (settings.value(key).value<QColor>() == color) if (settings.value(key).value<QColor>() == color) {
return; return;
}
settings.setValue(key, color); settings.setValue(key, color);
emit colorChanged(counterId, color); emit colorChanged(counterId, color);

View file

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

View file

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

View file

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

View file

@ -1,8 +1,8 @@
/** /**
* @file shortcuts_settings.h * @file shortcuts_settings.h
* @ingroup CoreSettings * @ingroup CoreSettings
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef SHORTCUTSSETTINGS_H #ifndef SHORTCUTSSETTINGS_H
#define SHORTCUTSSETTINGS_H #define SHORTCUTSSETTINGS_H
@ -537,6 +537,9 @@ private:
{"Player/aSetAnnotation", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Annotation..."), {"Player/aSetAnnotation", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Annotation..."),
parseSequenceString("Alt+N"), parseSequenceString("Alt+N"),
ShortcutGroup::Playing_Area)}, ShortcutGroup::Playing_Area)},
{"Player/aReduceLifeByPower", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Reduce Life by Power"),
parseSequenceString("Ctrl+Shift+L"),
ShortcutGroup::Playing_Area)},
{"Player/aSelectAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Zone"), {"Player/aSelectAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Select All Cards in Zone"),
parseSequenceString("Ctrl+A"), parseSequenceString("Ctrl+A"),
ShortcutGroup::Playing_Area)}, ShortcutGroup::Playing_Area)},

View file

@ -95,8 +95,9 @@ QStringMap &SoundEngine::getAvailableThemes()
dir.setPath(SettingsCache::instance().getDataPath() + "/sounds"); dir.setPath(SettingsCache::instance().getDataPath() + "/sounds");
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) { for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
if (!availableThemes.contains(themeName)) if (!availableThemes.contains(themeName)) {
availableThemes.insert(themeName, dir.absoluteFilePath(themeName)); availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
}
} }
// load themes from cockatrice system dir // load themes from cockatrice system dir
@ -111,8 +112,9 @@ QStringMap &SoundEngine::getAvailableThemes()
); );
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) { for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
if (!availableThemes.contains(themeName)) if (!availableThemes.contains(themeName)) {
availableThemes.insert(themeName, dir.absoluteFilePath(themeName)); availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
}
} }
return availableThemes; return availableThemes;

View file

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

View file

@ -88,20 +88,27 @@ static void setupParserRules()
const auto arg = std::any_cast<int>(sv[1]); const auto arg = std::any_cast<int>(sv[1]);
const auto op = std::any_cast<QString>(sv[0]); const auto op = std::any_cast<QString>(sv[0]);
if (op == ">") if (op == ">") {
return [=](const int s) { return s > arg; }; return [=](const int s) { return s > arg; };
if (op == ">=") }
if (op == ">=") {
return [=](const int s) { return s >= arg; }; return [=](const int s) { return s >= arg; };
if (op == "<") }
if (op == "<") {
return [=](const int s) { return s < arg; }; return [=](const int s) { return s < arg; };
if (op == "<=") }
if (op == "<=") {
return [=](const int s) { return s <= arg; }; return [=](const int s) { return s <= arg; };
if (op == "=") }
if (op == "=") {
return [=](const int s) { return s == arg; }; return [=](const int s) { return s == arg; };
if (op == ":") }
if (op == ":") {
return [=](const int s) { return s == arg; }; return [=](const int s) { return s == arg; };
if (op == "!=") }
if (op == "!=") {
return [=](const int s) { return s != arg; }; return [=](const int s) { return s != arg; };
}
return [](int) { return false; }; return [](int) { return false; };
}; };

View file

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

View file

@ -11,13 +11,15 @@ FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
{ {
filterCombo = new QComboBox; filterCombo = new QComboBox;
filterCombo->setObjectName("filterCombo"); filterCombo->setObjectName("filterCombo");
for (int i = 0; i < CardFilter::AttrEnd; i++) for (int i = 0; i < CardFilter::AttrEnd; i++) {
filterCombo->addItem(CardFilter::attrName(static_cast<CardFilter::Attr>(i)), QVariant(i)); filterCombo->addItem(CardFilter::attrName(static_cast<CardFilter::Attr>(i)), QVariant(i));
}
typeCombo = new QComboBox; typeCombo = new QComboBox;
typeCombo->setObjectName("typeCombo"); typeCombo->setObjectName("typeCombo");
for (int i = 0; i < CardFilter::TypeEnd; i++) for (int i = 0; i < CardFilter::TypeEnd; i++) {
typeCombo->addItem(CardFilter::typeName(static_cast<CardFilter::Type>(i)), QVariant(i)); typeCombo->addItem(CardFilter::typeName(static_cast<CardFilter::Type>(i)), QVariant(i));
}
QPushButton *ok = new QPushButton(QPixmap("theme:icons/increment"), QString()); QPushButton *ok = new QPushButton(QPixmap("theme:icons/increment"), QString());
ok->setObjectName("ok"); ok->setObjectName("ok");
@ -53,8 +55,9 @@ FilterBuilder::~FilterBuilder()
void FilterBuilder::destroyFilter() void FilterBuilder::destroyFilter()
{ {
if (fltr) if (fltr) {
delete fltr; delete fltr;
}
} }
static int comboCurrentIntData(const QComboBox *combo) static int comboCurrentIntData(const QComboBox *combo)
@ -67,8 +70,9 @@ void FilterBuilder::emit_add()
QString txt; QString txt;
txt = edit->text(); txt = edit->text();
if (txt.length() < 1) if (txt.length() < 1) {
return; return;
}
destroyFilter(); destroyFilter();
fltr = new CardFilter(txt, static_cast<CardFilter::Type>(comboCurrentIntData(typeCombo)), fltr = new CardFilter(txt, static_cast<CardFilter::Type>(comboCurrentIntData(typeCombo)),

View file

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

View file

@ -23,8 +23,9 @@ void FilterTreeModel::proxyBeginInsertRow(const FilterTreeNode *node, int i)
int idx; int idx;
idx = node->index(); idx = node->index();
if (idx >= 0) if (idx >= 0) {
beginInsertRows(createIndex(idx, 0, (void *)node), i, i); beginInsertRows(createIndex(idx, 0, (void *)node), i, i);
}
} }
void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int) void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
@ -32,8 +33,9 @@ void FilterTreeModel::proxyEndInsertRow(const FilterTreeNode *node, int)
int idx; int idx;
idx = node->index(); idx = node->index();
if (idx >= 0) if (idx >= 0) {
endInsertRows(); endInsertRows();
}
} }
void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i) void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
@ -41,8 +43,9 @@ void FilterTreeModel::proxyBeginRemoveRow(const FilterTreeNode *node, int i)
int idx; int idx;
idx = node->index(); idx = node->index();
if (idx >= 0) if (idx >= 0) {
beginRemoveRows(createIndex(idx, 0, (void *)node), i, i); beginRemoveRows(createIndex(idx, 0, (void *)node), i, i);
}
} }
void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int) void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
@ -50,8 +53,9 @@ void FilterTreeModel::proxyEndRemoveRow(const FilterTreeNode *node, int)
int idx; int idx;
idx = node->index(); idx = node->index();
if (idx >= 0) if (idx >= 0) {
endRemoveRows(); endRemoveRows();
}
} }
FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
@ -59,12 +63,14 @@ FilterTreeNode *FilterTreeModel::indexToNode(const QModelIndex &idx) const
void *ip; void *ip;
FilterTreeNode *node; FilterTreeNode *node;
if (!idx.isValid()) if (!idx.isValid()) {
return fTree; return fTree;
}
ip = idx.internalPointer(); ip = idx.internalPointer();
if (ip == NULL) if (ip == NULL) {
return fTree; return fTree;
}
node = static_cast<FilterTreeNode *>(ip); node = static_cast<FilterTreeNode *>(ip);
return node; return node;
@ -145,14 +151,16 @@ int FilterTreeModel::rowCount(const QModelIndex &parent) const
const FilterTreeNode *node; const FilterTreeNode *node;
int result; int result;
if (parent.column() > 0) if (parent.column() > 0) {
return 0; return 0;
}
node = indexToNode(parent); node = indexToNode(parent);
if (node) if (node) {
result = node->childCount(); result = node->childCount();
else } else {
result = 0; result = 0;
}
return result; return result;
} }
@ -166,14 +174,17 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
{ {
const FilterTreeNode *node; const FilterTreeNode *node;
if (!index.isValid()) if (!index.isValid()) {
return QVariant(); return QVariant();
if (index.column() >= columnCount()) }
if (index.column() >= columnCount()) {
return QVariant(); return QVariant();
}
node = indexToNode(index); node = indexToNode(index);
if (node == NULL) if (node == NULL) {
return QVariant(); return QVariant();
}
switch (role) { switch (role) {
case Qt::FontRole: case Qt::FontRole:
@ -190,10 +201,11 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
case Qt::WhatsThisRole: case Qt::WhatsThisRole:
return node->text(); return node->text();
case Qt::CheckStateRole: case Qt::CheckStateRole:
if (node->isEnabled()) if (node->isEnabled()) {
return Qt::Checked; return Qt::Checked;
else } else {
return Qt::Unchecked; return Qt::Unchecked;
}
default: default:
return QVariant(); return QVariant();
} }
@ -205,22 +217,27 @@ bool FilterTreeModel::setData(const QModelIndex &index, const QVariant &value, i
{ {
FilterTreeNode *node; FilterTreeNode *node;
if (!index.isValid()) if (!index.isValid()) {
return false; return false;
if (index.column() >= columnCount()) }
if (index.column() >= columnCount()) {
return false; return false;
if (role != Qt::CheckStateRole) }
if (role != Qt::CheckStateRole) {
return false; return false;
}
node = indexToNode(index); node = indexToNode(index);
if (node == NULL || node == fTree) if (node == NULL || node == fTree) {
return false; return false;
}
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt()); Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
if (state == Qt::Checked) if (state == Qt::Checked) {
node->enable(); node->enable();
else } else {
node->disable(); node->disable();
}
emit dataChanged(index, index); emit dataChanged(index, index);
return true; return true;
@ -231,16 +248,19 @@ Qt::ItemFlags FilterTreeModel::flags(const QModelIndex &index) const
const FilterTreeNode *node; const FilterTreeNode *node;
Qt::ItemFlags result; Qt::ItemFlags result;
if (!index.isValid()) if (!index.isValid()) {
return Qt::NoItemFlags; return Qt::NoItemFlags;
}
node = indexToNode(index); node = indexToNode(index);
if (node == NULL) if (node == NULL) {
return Qt::NoItemFlags; return Qt::NoItemFlags;
}
result = Qt::ItemIsEnabled; result = Qt::ItemIsEnabled;
if (node == fTree) if (node == fTree) {
return result; return result;
}
result |= Qt::ItemIsSelectable; result |= Qt::ItemIsSelectable;
result |= Qt::ItemIsUserCheckable; result |= Qt::ItemIsUserCheckable;
@ -252,8 +272,9 @@ QModelIndex FilterTreeModel::nodeIndex(const FilterTreeNode *node, int row, int
{ {
FilterTreeNode *child; FilterTreeNode *child;
if (column > 0 || row >= node->childCount()) if (column > 0 || row >= node->childCount()) {
return QModelIndex(); return QModelIndex();
}
child = node->nodeAt(row); child = node->nodeAt(row);
return createIndex(row, column, child); return createIndex(row, column, child);
@ -263,12 +284,14 @@ QModelIndex FilterTreeModel::index(int row, int column, const QModelIndex &paren
{ {
const FilterTreeNode *node; const FilterTreeNode *node;
if (!hasIndex(row, column, parent)) if (!hasIndex(row, column, parent)) {
return QModelIndex(); return QModelIndex();
}
node = indexToNode(parent); node = indexToNode(parent);
if (node == NULL) if (node == NULL) {
return QModelIndex(); return QModelIndex();
}
return nodeIndex(node, row, column); return nodeIndex(node, row, column);
} }
@ -279,18 +302,21 @@ QModelIndex FilterTreeModel::parent(const QModelIndex &ind) const
FilterTreeNode *parent; FilterTreeNode *parent;
QModelIndex idx; QModelIndex idx;
if (!ind.isValid()) if (!ind.isValid()) {
return QModelIndex(); return QModelIndex();
}
node = indexToNode(ind); node = indexToNode(ind);
if (node == NULL || node == fTree) if (node == NULL || node == fTree) {
return QModelIndex(); return QModelIndex();
}
parent = node->parent(); parent = node->parent();
if (parent) { if (parent) {
int row = parent->index(); int row = parent->index();
if (row < 0) if (row < 0) {
return QModelIndex(); return QModelIndex();
}
idx = createIndex(row, 0, parent); idx = createIndex(row, 0, parent);
return idx; return idx;
} }
@ -304,18 +330,22 @@ bool FilterTreeModel::removeRows(int row, int count, const QModelIndex &parent)
int i, last; int i, last;
last = row + count - 1; last = row + count - 1;
if (!parent.isValid() || count < 1 || row < 0) if (!parent.isValid() || count < 1 || row < 0) {
return false; return false;
}
node = indexToNode(parent); node = indexToNode(parent);
if (node == NULL || last >= node->childCount()) if (node == NULL || last >= node->childCount()) {
return false; return false;
}
for (i = 0; i < count; i++) for (i = 0; i < count; i++) {
node->deleteAt(row); node->deleteAt(row);
}
if (node != fTree && node->childCount() < 1) if (node != fTree && node->childCount() < 1) {
return removeRow(parent.row(), parent.parent()); return removeRow(parent.row(), parent.parent());
}
return true; return true;
} }

View file

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

View file

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

View file

@ -1,7 +1,7 @@
#include "abstract_game.h" #include "abstract_game.h"
#include "../interface/widgets/tabs/tab_game.h" #include "../interface/widgets/tabs/tab_game.h"
#include "player/player.h" #include "player/player_logic.h"
AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab) AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab)
{ {
@ -24,10 +24,11 @@ AbstractClient *AbstractGame::getClientForPlayer(int playerId) const
} }
return gameState->getClients().at(playerId); return gameState->getClients().at(playerId);
} else if (gameState->getClients().isEmpty()) } else if (gameState->getClients().isEmpty()) {
return nullptr; return nullptr;
else } else {
return gameState->getClients().first(); return gameState->getClients().first();
}
} }
void AbstractGame::loadReplay(GameReplay *replay) void AbstractGame::loadReplay(GameReplay *replay)
@ -43,13 +44,15 @@ void AbstractGame::setActiveCard(CardItem *card)
CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const CardItem *AbstractGame::getCard(int playerId, const QString &zoneName, int cardId) const
{ {
Player *player = playerManager->getPlayer(playerId); PlayerLogic *player = playerManager->getPlayer(playerId);
if (!player) if (!player) {
return nullptr; return nullptr;
}
CardZoneLogic *zone = player->getZones().value(zoneName, 0); CardZoneLogic *zone = player->getZones().value(zoneName, 0);
if (!zone) if (!zone) {
return nullptr; return nullptr;
}
return zone->getCard(cardId); return zone->getCard(cardId);
} }

View file

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

View file

@ -25,11 +25,12 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
setCursor(Qt::ClosedHandCursor); setCursor(Qt::ClosedHandCursor);
setZValue(ZValues::DRAG_ITEM); setZValue(ZValues::DRAG_ITEM);
} }
if (item->getTapped()) if (item->getTapped()) {
setTransform(QTransform() setTransform(QTransform()
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F) .translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
.rotate(90) .rotate(90)
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F)); .translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
}
setCacheMode(DeviceCoordinateCache); setCacheMode(DeviceCoordinateCache);

View file

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

View file

@ -13,7 +13,7 @@
#include <libcockatrice/card/database/card_database.h> #include <libcockatrice/card/database/card_database.h>
#include <libcockatrice/card/database/card_database_manager.h> #include <libcockatrice/card/database/card_database_manager.h>
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, Player *_owner, int _id) AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, PlayerLogic *_owner, int _id)
: ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0), : ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0),
bgColor(Qt::transparent), isHovered(false), realZValue(0) bgColor(Qt::transparent), isHovered(false), realZValue(0)
{ {
@ -85,7 +85,12 @@ const CardInfo &AbstractCardItem::getCardInfo() const
void AbstractCardItem::setRealZValue(qreal _zValue) void AbstractCardItem::setRealZValue(qreal _zValue)
{ {
realZValue = _zValue; realZValue = _zValue;
setZValue(_zValue); // During hover, zValue is overridden to HOVERED_CARD. Layout operations
// like reorganizeCards() call setRealZValue() on all cards including the
// hovered one — skip setZValue() here to avoid clobbering the override.
if (!isHovered) {
setZValue(_zValue);
}
} }
QSizeF AbstractCardItem::getTranslatedSize(QPainter *painter) const QSizeF AbstractCardItem::getTranslatedSize(QPainter *painter) const
@ -126,8 +131,9 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
// don't even spend time trying to load the picture if our size is too small // don't even spend time trying to load the picture if our size is too small
if (translatedSize.width() > 10) { if (translatedSize.width() > 10) {
CardPictureLoader::getPixmap(translatedPixmap, exactCard, translatedSize.toSize()); CardPictureLoader::getPixmap(translatedPixmap, exactCard, translatedSize.toSize());
if (translatedPixmap.isNull()) if (translatedPixmap.isNull()) {
paintImage = false; paintImage = false;
}
} else { } else {
paintImage = false; paintImage = false;
} }
@ -152,9 +158,9 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
painter->setBackground(Qt::black); painter->setBackground(Qt::black);
painter->setBackgroundMode(Qt::OpaqueMode); painter->setBackgroundMode(Qt::OpaqueMode);
QString nameStr; QString nameStr;
if (facedown) if (facedown) {
nameStr = "# " + QString::number(id); nameStr = "# " + QString::number(id);
else { } else {
QString prefix = ""; QString prefix = "";
if (SettingsCache::instance().debug().getShowCardId()) { if (SettingsCache::instance().debug().getShowCardId()) {
prefix = "#" + QString::number(id) + " "; prefix = "#" + QString::number(id) + " ";
@ -181,10 +187,12 @@ void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
if (isSelected() || isHovered) { if (isSelected() || isHovered) {
QPen pen; QPen pen;
if (isHovered) if (isHovered) {
pen.setColor(Qt::yellow); pen.setColor(Qt::yellow);
if (isSelected()) }
if (isSelected()) {
pen.setColor(Qt::red); pen.setColor(Qt::red);
}
pen.setWidth(0); // Cosmetic pen pen.setWidth(0); // Cosmetic pen
painter->setPen(pen); painter->setPen(pen);
painter->drawPath(shape()); painter->drawPath(shape());
@ -210,11 +218,20 @@ void AbstractCardItem::setCardRef(const CardRef &_cardRef)
void AbstractCardItem::setHovered(bool _hovered) void AbstractCardItem::setHovered(bool _hovered)
{ {
if (isHovered == _hovered) if (isHovered == _hovered) {
return; return;
}
if (_hovered) if (_hovered) {
processHoverEvent(); processHoverEvent();
} else {
// Mark the hovered card's current scene footprint dirty so overlapped
// sibling zones (e.g. StackZone) repaint after the card moves away.
if (scene()) {
scene()->update(sceneBoundingRect());
}
}
isHovered = _hovered; isHovered = _hovered;
setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue); setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue);
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1); setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
@ -265,13 +282,14 @@ void AbstractCardItem::cacheBgColor()
void AbstractCardItem::setTapped(bool _tapped, bool canAnimate) void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
{ {
if (tapped == _tapped) if (tapped == _tapped) {
return; return;
}
tapped = _tapped; tapped = _tapped;
if (SettingsCache::instance().getTapAnimation() && canAnimate) if (SettingsCache::instance().getTapAnimation() && canAnimate) {
static_cast<GameScene *>(scene())->registerAnimationItem(this); static_cast<GameScene *>(scene())->registerAnimationItem(this);
else { } else {
tapAngle = tapped ? 90 : 0; tapAngle = tapped ? 90 : 0;
setTransform(QTransform() setTransform(QTransform()
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F) .translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
@ -297,17 +315,19 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
scene()->clearSelection(); scene()->clearSelection();
setSelected(true); setSelected(true);
} }
if (event->button() == Qt::LeftButton) if (event->button() == Qt::LeftButton) {
setCursor(Qt::ClosedHandCursor); setCursor(Qt::ClosedHandCursor);
else if (event->button() == Qt::MiddleButton) } else if (event->button() == Qt::MiddleButton) {
emit showCardInfoPopup(event->screenPos(), cardRef); emit showCardInfoPopup(event->screenPos(), cardRef);
}
event->accept(); event->accept();
} }
void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::MiddleButton) if (event->button() == Qt::MiddleButton) {
emit deleteCardInfoPopup(cardRef.name); emit deleteCardInfoPopup(cardRef.name);
}
// This function ensures the parent function doesn't mess around with our selection. // This function ensures the parent function doesn't mess around with our selection.
event->accept(); event->accept();
@ -323,6 +343,7 @@ QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change,
if (change == ItemSelectedHasChanged) { if (change == ItemSelectedHasChanged) {
update(); update();
return value; return value;
} else } else {
return ArrowTarget::itemChange(change, value); return ArrowTarget::itemChange(change, value);
}
} }

View file

@ -1,7 +1,7 @@
/** /**
* @file abstract_card_item.h * @file abstract_card_item.h
* @ingroup GameGraphicsCards * @ingroup GameGraphicsCards
* @brief TODO: Document this. * @brief Base class for graphical card items, providing shared rendering, identity, and interaction logic.
*/ */
#ifndef ABSTRACTCARDITEM_H #ifndef ABSTRACTCARDITEM_H
@ -14,7 +14,7 @@
#include <libcockatrice/card/printing/exact_card.h> #include <libcockatrice/card/printing/exact_card.h>
#include <libcockatrice/utility/card_ref.h> #include <libcockatrice/utility/card_ref.h>
class Player; class PlayerLogic;
class AbstractCardItem : public ArrowTarget class AbstractCardItem : public ArrowTarget
{ {
@ -56,7 +56,7 @@ public:
} }
explicit AbstractCardItem(QGraphicsItem *parent = nullptr, explicit AbstractCardItem(QGraphicsItem *parent = nullptr,
const CardRef &cardRef = {}, const CardRef &cardRef = {},
Player *_owner = nullptr, PlayerLogic *_owner = nullptr,
int _id = -1); int _id = -1);
~AbstractCardItem() override; ~AbstractCardItem() override;
QRectF boundingRect() const override; QRectF boundingRect() const override;
@ -96,6 +96,10 @@ public:
} }
void setRealZValue(qreal _zValue); void setRealZValue(qreal _zValue);
void setHovered(bool _hovered); void setHovered(bool _hovered);
bool getIsHovered() const
{
return isHovered;
}
QString getColor() const QString getColor() const
{ {
return color; return color;

View file

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

View file

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

View file

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

View file

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

View file

@ -2,11 +2,11 @@
#include "arrow_item.h" #include "arrow_item.h"
#include "../../client/settings/cache_settings.h" #include "../../client/settings/cache_settings.h"
#include "../player/player.h" #include "../../game_graphics/zones/card_zone.h"
#include "../player/player_actions.h" #include "../player/player_actions.h"
#include "../player/player_logic.h"
#include "../player/player_target.h" #include "../player/player_target.h"
#include "../z_values.h" #include "../z_values.h"
#include "../zones/card_zone.h"
#include "card_item.h" #include "card_item.h"
#include <QDebug> #include <QDebug>
@ -21,46 +21,53 @@
#include <libcockatrice/utility/color.h> #include <libcockatrice/utility/color.h>
#include <libcockatrice/utility/zone_names.h> #include <libcockatrice/utility/zone_names.h>
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color) ArrowItem::ArrowItem(PlayerLogic *_player,
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), targetLocked(false), int _id,
color(_color), fullColor(true) ArrowTarget *_startItem,
ArrowTarget *_targetItem,
const QColor &_color)
: player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), color(_color)
{ {
setZValue(ZValues::ARROWS); setZValue(ZValues::ARROWS);
if (startItem) auto doUpdate = [this]() {
startItem->addArrowFrom(this); if (startItem && targetItem) {
if (targetItem) updatePath();
targetItem->addArrowTo(this); }
};
if (startItem && targetItem) if (startItem) {
connect(startItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
connect(startItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
}
if (targetItem) {
connect(targetItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
connect(targetItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
}
if (startItem && targetItem) {
updatePath(); updatePath();
}
} }
ArrowItem::~ArrowItem() void ArrowItem::onTargetDestroyed()
{ {
emit requestDeletion(id);
} }
void ArrowItem::delArrow() void ArrowItem::delArrow()
{ {
if (startItem) {
startItem->removeArrowFrom(this);
startItem = 0;
}
if (targetItem) { if (targetItem) {
targetItem->setBeingPointedAt(false); targetItem->setBeingPointedAt(false);
targetItem->removeArrowTo(this);
targetItem = 0;
} }
player->removeArrow(this);
deleteLater(); deleteLater();
} }
void ArrowItem::updatePath() void ArrowItem::updatePath()
{ {
if (!targetItem) if (!targetItem) {
return; return;
}
QPointF endPoint = targetItem->mapToScene( QPointF endPoint = targetItem->mapToScene(
QPointF(targetItem->boundingRect().width() / 2, targetItem->boundingRect().height() / 2)); QPointF(targetItem->boundingRect().width() / 2, targetItem->boundingRect().height() / 2));
@ -75,8 +82,9 @@ void ArrowItem::updatePath(const QPointF &endPoint)
headWidth / qPow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++ headWidth / qPow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++
const double phi = 15; const double phi = 15;
if (!startItem) if (!startItem) {
return; return;
}
QPointF startPoint = QPointF startPoint =
startItem->mapToScene(QPointF(startItem->boundingRect().width() / 2, startItem->boundingRect().height() / 2)); startItem->mapToScene(QPointF(startItem->boundingRect().width() / 2, startItem->boundingRect().height() / 2));
@ -84,9 +92,9 @@ void ArrowItem::updatePath(const QPointF &endPoint)
qreal lineLength = line.length(); qreal lineLength = line.length();
prepareGeometryChange(); prepareGeometryChange();
if (lineLength < 30) if (lineLength < 30) {
path = QPainterPath(); path = QPainterPath();
else { } else {
QPointF c(lineLength / 2, qTan(phi * M_PI / 180) * lineLength); QPointF c(lineLength / 2, qTan(phi * M_PI / 180) * lineLength);
QPainterPath centerLine; QPainterPath centerLine;
@ -123,10 +131,11 @@ void ArrowItem::updatePath(const QPointF &endPoint)
void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{ {
QColor paintColor(color); QColor paintColor(color);
if (fullColor) if (fullColor) {
paintColor.setAlpha(200); paintColor.setAlpha(200);
else } else {
paintColor.setAlpha(150); paintColor.setAlpha(150);
}
painter->setBrush(paintColor); painter->setBrush(paintColor);
painter->drawPath(path); painter->drawPath(path);
} }
@ -138,8 +147,7 @@ void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
return; return;
} }
QList<QGraphicsItem *> colliding = scene()->items(event->scenePos()); for (auto *item : scene()->items(event->scenePos())) {
for (QGraphicsItem *item : colliding) {
if (qgraphicsitem_cast<CardItem *>(item)) { if (qgraphicsitem_cast<CardItem *>(item)) {
event->ignore(); event->ignore();
return; return;
@ -148,80 +156,86 @@ void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
event->accept(); event->accept();
if (event->button() == Qt::RightButton) { if (event->button() == Qt::RightButton) {
Command_DeleteArrow cmd; emit requestDeletion(id);
cmd.set_arrow_id(id);
player->getPlayerActions()->sendGameCommand(cmd);
} }
} }
ArrowDragItem::ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase) // ArrowDragItem
: ArrowItem(_owner, -1, _startItem, 0, _color), deleteInPhase(_deleteInPhase)
ArrowDragItem::ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase)
: ArrowItem(_owner, -1, _startItem, nullptr, _color), deleteInPhase(_deleteInPhase)
{ {
} }
void ArrowDragItem::addChildArrow(ArrowDragItem *childArrow) void ArrowDragItem::addChildArrow(ArrowDragItem *child)
{ {
childArrows.append(childArrow); childArrows.append(child);
} }
void ArrowDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void ArrowDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{ {
// This ensures that if a mouse move event happens after a call to delArrow(), if (targetLocked || !startItem) {
// the event will be discarded as it would create some stray pointers.
if (targetLocked || !startItem)
return; return;
}
QPointF endPos = event->scenePos(); const QPointF endPos = event->scenePos();
QList<QGraphicsItem *> colliding = scene()->items(endPos); ArrowTarget *cursorItem = nullptr;
ArrowTarget *cursorItem = 0;
qreal cursorItemZ = -1; qreal cursorItemZ = -1;
for (int i = colliding.size() - 1; i >= 0; i--) { for (auto *item : scene()->items(endPos)) {
if (qgraphicsitem_cast<PlayerTarget *>(colliding.at(i)) || qgraphicsitem_cast<CardItem *>(colliding.at(i))) { ArrowTarget *candidate = nullptr;
if (colliding.at(i)->zValue() > cursorItemZ) { if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
cursorItem = static_cast<ArrowTarget *>(colliding.at(i)); candidate = card;
cursorItemZ = cursorItem->zValue(); } else if (auto *pt = qgraphicsitem_cast<PlayerTarget *>(item)) {
} candidate = pt;
}
if (candidate && candidate->zValue() > cursorItemZ) {
cursorItem = candidate;
cursorItemZ = candidate->zValue();
} }
} }
if ((cursorItem != targetItem) && targetItem) { if (cursorItem != targetItem) {
targetItem->setBeingPointedAt(false); if (targetItem) {
targetItem->removeArrowTo(this); disconnect(positionConnection);
} targetItem->setBeingPointedAt(false);
if (!cursorItem) { }
fullColor = false;
targetItem = 0; targetItem = cursorItem;
updatePath(endPos); fullColor = (cursorItem != nullptr);
} else {
if (cursorItem != targetItem) { if (cursorItem && cursorItem != startItem) {
fullColor = true; cursorItem->setBeingPointedAt(true);
if (cursorItem != startItem) { positionConnection =
cursorItem->setBeingPointedAt(true); connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
cursorItem->addArrowTo(this);
}
targetItem = cursorItem;
} }
updatePath();
} }
targetItem ? updatePath() : updatePath(endPos);
update(); update();
for (ArrowDragItem *child : childArrows) { for (auto *child : childArrows) {
child->mouseMoveEvent(event); child->mouseMoveEvent(event);
} }
} }
void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ {
if (!startItem) if (!startItem) {
return; return;
}
if (targetItem && (targetItem != startItem)) { if (targetItem && targetItem != startItem) {
CardZoneLogic *startZone = static_cast<CardItem *>(startItem)->getZone(); CardItem *startCard = qgraphicsitem_cast<CardItem *>(startItem);
// For now, we can safely assume that the start item is always a card. // For now, we can safely assume that the start item is always a card.
// The target item can be a player as well. // The target item can be a player as well.
CardItem *startCard = qgraphicsitem_cast<CardItem *>(startItem); if (!startCard) {
CardItem *targetCard = qgraphicsitem_cast<CardItem *>(targetItem); delArrow();
return;
}
CardZoneLogic *startZone = startCard->getZone();
Command_CreateArrow cmd; Command_CreateArrow cmd;
cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(color)); cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(color));
@ -229,14 +243,16 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
cmd.set_start_zone(startZone->getName().toStdString()); cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_start_card_id(startCard->getId()); cmd.set_start_card_id(startCard->getId());
if (targetCard) { if (auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem)) {
CardZoneLogic *targetZone = targetCard->getZone(); CardZoneLogic *targetZone = targetCard->getZone();
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId()); cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone->getName().toStdString()); cmd.set_target_zone(targetZone->getName().toStdString());
cmd.set_target_card_id(targetCard->getId()); cmd.set_target_card_id(targetCard->getId());
} else { // failed to cast target to card, this means it's a player } else if (auto *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem)) {
PlayerTarget *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem);
cmd.set_target_player_id(targetPlayer->getOwner()->getPlayerInfo()->getId()); cmd.set_target_player_id(targetPlayer->getOwner()->getPlayerInfo()->getId());
} else {
delArrow();
return;
} }
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow // if the card is in hand then we will move the card to stack or table as part of drawing the arrow
@ -246,10 +262,11 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
bool playToStack = SettingsCache::instance().getPlayToStack(); bool playToStack = SettingsCache::instance().getPlayToStack();
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) || if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
(playToStack && ci->getUiAttributes().tableRow != 0 && (playToStack && ci->getUiAttributes().tableRow != 0 &&
startCard->getZone()->getName() != ZoneNames::STACK))) startCard->getZone()->getName() != ZoneNames::STACK))) {
cmd.set_start_zone(ZoneNames::STACK); cmd.set_start_zone(ZoneNames::STACK);
else } else {
cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE); cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE);
}
} }
if (deleteInPhase != 0) { if (deleteInPhase != 0) {
@ -258,111 +275,109 @@ void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
player->getPlayerActions()->sendGameCommand(cmd); player->getPlayerActions()->sendGameCommand(cmd);
} }
delArrow();
for (ArrowDragItem *child : childArrows) { delArrow();
for (auto *child : childArrows) {
child->mouseReleaseEvent(event); child->mouseReleaseEvent(event);
} }
} }
// ArrowAttachItem
ArrowAttachItem::ArrowAttachItem(ArrowTarget *_startItem) ArrowAttachItem::ArrowAttachItem(ArrowTarget *_startItem)
: ArrowItem(_startItem->getOwner(), -1, _startItem, 0, Qt::green) : ArrowItem(_startItem->getOwner(), -1, _startItem, nullptr, Qt::green)
{ {
} }
void ArrowAttachItem::addChildArrow(ArrowAttachItem *childArrow) void ArrowAttachItem::addChildArrow(ArrowAttachItem *child)
{ {
childArrows.append(childArrow); childArrows.append(child);
} }
void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{ {
if (targetLocked || !startItem) if (targetLocked || !startItem) {
return; return;
}
QPointF endPos = event->scenePos(); const QPointF endPos = event->scenePos();
QList<QGraphicsItem *> colliding = scene()->items(endPos); ArrowTarget *cursorItem = nullptr;
ArrowTarget *cursorItem = 0;
qreal cursorItemZ = -1; qreal cursorItemZ = -1;
for (int i = colliding.size() - 1; i >= 0; i--) { for (auto *item : scene()->items(endPos)) {
if (qgraphicsitem_cast<CardItem *>(colliding.at(i))) { if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
if (colliding.at(i)->zValue() > cursorItemZ) { if (card->zValue() > cursorItemZ) {
cursorItem = static_cast<ArrowTarget *>(colliding.at(i)); cursorItem = card;
cursorItemZ = cursorItem->zValue(); cursorItemZ = card->zValue();
} }
} }
} }
if ((cursorItem != targetItem) && targetItem) { if (cursorItem != targetItem) {
targetItem->setBeingPointedAt(false); if (targetItem) {
} disconnect(positionConnection);
if (!cursorItem) { targetItem->setBeingPointedAt(false);
fullColor = false;
targetItem = 0;
updatePath(endPos);
} else {
fullColor = true;
if (cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
} }
targetItem = cursorItem; targetItem = cursorItem;
updatePath(); fullColor = (cursorItem != nullptr);
if (cursorItem && cursorItem != startItem) {
cursorItem->setBeingPointedAt(true);
positionConnection =
connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
}
} }
targetItem ? updatePath() : updatePath(endPos);
update(); update();
for (ArrowAttachItem *child : childArrows) { for (auto *child : childArrows) {
child->mouseMoveEvent(event); child->mouseMoveEvent(event);
} }
} }
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
{
// do nothing if target is already attached to another card or is not in play
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
return;
}
CardZoneLogic *startZone = startCard->getZone();
CardZoneLogic *targetZone = targetCard->getZone();
// move card onto table first if attaching from some other zone
if (startZone->getName() != ZoneNames::TABLE) {
player->getPlayerActions()->playCardToTable(startCard, false);
}
Command_AttachCard cmd;
cmd.set_start_zone(ZoneNames::TABLE);
cmd.set_card_id(startCard->getId());
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
cmd.set_target_zone(targetZone->getName().toStdString());
cmd.set_target_card_id(targetCard->getId());
player->getPlayerActions()->sendGameCommand(cmd);
}
void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ {
if (!startItem) if (!startItem) {
return; return;
}
// Attaching could move startItem under the current cursor position, causing all children to retarget to it right // Attaching could move startItem under the current cursor position, causing all children to retarget to it right
// before they are processed. Prevent that. // before they are processed. Prevent that.
for (ArrowAttachItem *child : childArrows) { for (auto *child : childArrows) {
child->setTargetLocked(true); child->setTargetLocked(true);
} }
if (targetItem && (targetItem != startItem)) { if (targetItem && targetItem != startItem) {
auto startCard = qgraphicsitem_cast<CardItem *>(startItem); auto *startCard = qgraphicsitem_cast<CardItem *>(startItem);
auto targetCard = qgraphicsitem_cast<CardItem *>(targetItem); auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
if (startCard && targetCard) { if (startCard && targetCard) {
attachCards(startCard, targetCard); attachCards(startCard, targetCard);
} }
} }
delArrow(); delArrow();
for (auto *child : childArrows) {
for (ArrowAttachItem *child : childArrows) {
child->mouseReleaseEvent(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);
}

View file

@ -1,40 +1,47 @@
/** /**
* @file arrow_item.h * @file arrow_item.h
* @ingroup GameGraphics * @ingroup GameGraphics
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef ARROWITEM_H #ifndef ARROWITEM_H
#define ARROWITEM_H #define ARROWITEM_H
#include "arrow_target.h"
#include <QGraphicsItem> #include <QGraphicsItem>
#include <QPointer>
class CardItem; class CardItem;
class QGraphicsSceneMouseEvent; class QGraphicsSceneMouseEvent;
class QMenu; class QMenu;
class Player; class PlayerLogic;
class ArrowTarget;
class ArrowItem : public QObject, public QGraphicsItem class ArrowItem : public QObject, public QGraphicsItem
{ {
Q_OBJECT Q_OBJECT
Q_INTERFACES(QGraphicsItem) Q_INTERFACES(QGraphicsItem)
signals:
void requestDeletion(int id);
private: private:
QPainterPath path; QPainterPath path;
QMenu *menu;
protected: protected:
Player *player; PlayerLogic *player;
int id; int id;
ArrowTarget *startItem, *targetItem; QPointer<ArrowTarget> startItem;
bool targetLocked; QPointer<ArrowTarget> targetItem;
bool targetLocked = false;
QColor color; QColor color;
bool fullColor; bool fullColor = true;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
public: public:
ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &color); ArrowItem(PlayerLogic *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color);
~ArrowItem() override; void onTargetDestroyed();
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
[[nodiscard]] QRectF boundingRect() const override [[nodiscard]] QRectF boundingRect() const override
{ {
@ -44,6 +51,7 @@ public:
{ {
return path; return path;
} }
void updatePath(); void updatePath();
void updatePath(const QPointF &endPoint); void updatePath(const QPointF &endPoint);
@ -51,18 +59,10 @@ public:
{ {
return id; return id;
} }
[[nodiscard]] Player *getPlayer() const [[nodiscard]] PlayerLogic *getPlayer() const
{ {
return player; return player;
} }
void setStartItem(ArrowTarget *_item)
{
startItem = _item;
}
void setTargetItem(ArrowTarget *_item)
{
targetItem = _item;
}
[[nodiscard]] ArrowTarget *getStartItem() const [[nodiscard]] ArrowTarget *getStartItem() const
{ {
return startItem; return startItem;
@ -75,6 +75,7 @@ public:
{ {
targetLocked = _targetLocked; targetLocked = _targetLocked;
} }
void delArrow(); void delArrow();
}; };
@ -84,10 +85,11 @@ class ArrowDragItem : public ArrowItem
private: private:
int deleteInPhase; int deleteInPhase;
QList<ArrowDragItem *> childArrows; QList<ArrowDragItem *> childArrows;
QMetaObject::Connection positionConnection;
public: public:
ArrowDragItem(Player *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase); ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase);
void addChildArrow(ArrowDragItem *childArrow); void addChildArrow(ArrowDragItem *child);
protected: protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
@ -99,12 +101,12 @@ class ArrowAttachItem : public ArrowItem
Q_OBJECT Q_OBJECT
private: private:
QList<ArrowAttachItem *> childArrows; QList<ArrowAttachItem *> childArrows;
QMetaObject::Connection positionConnection;
void attachCards(CardItem *startCard, const CardItem *targetCard); void attachCards(CardItem *startCard, const CardItem *targetCard);
public: public:
explicit ArrowAttachItem(ArrowTarget *_startItem); explicit ArrowAttachItem(ArrowTarget *_startItem);
void addChildArrow(ArrowAttachItem *childArrow); void addChildArrow(ArrowAttachItem *child);
protected: protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;

View file

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

View file

@ -1,8 +1,8 @@
/** /**
* @file arrow_target.h * @file arrow_target.h
* @ingroup GameGraphics * @ingroup GameGraphics
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef ARROWTARGET_H #ifndef ARROWTARGET_H
#define ARROWTARGET_H #define ARROWTARGET_H
@ -11,24 +11,26 @@
#include <QList> #include <QList>
class Player; class PlayerLogic;
class ArrowItem; class ArrowItem;
class ArrowTarget : public AbstractGraphicsItem class ArrowTarget : public AbstractGraphicsItem
{ {
Q_OBJECT Q_OBJECT
protected: protected:
Player *owner; PlayerLogic *owner;
private: private:
bool beingPointedAt; bool beingPointedAt = false;
QList<ArrowItem *> arrowsFrom, arrowsTo;
signals:
void scenePositionChanged();
public: public:
explicit ArrowTarget(Player *_owner, QGraphicsItem *parent = nullptr); explicit ArrowTarget(PlayerLogic *_owner, QGraphicsItem *parent = nullptr);
~ArrowTarget() override; ~ArrowTarget() override = default;
[[nodiscard]] Player *getOwner() const [[nodiscard]] PlayerLogic *getOwner() const
{ {
return owner; return owner;
} }
@ -39,32 +41,7 @@ public:
return beingPointedAt; return beingPointedAt;
} }
[[nodiscard]] const QList<ArrowItem *> &getArrowsFrom() const
{
return arrowsFrom;
}
void addArrowFrom(ArrowItem *arrow)
{
arrowsFrom.append(arrow);
}
void removeArrowFrom(ArrowItem *arrow)
{
arrowsFrom.removeOne(arrow);
}
[[nodiscard]] const QList<ArrowItem *> &getArrowsTo() const
{
return arrowsTo;
}
void addArrowTo(ArrowItem *arrow)
{
arrowsTo.append(arrow);
}
void removeArrowTo(ArrowItem *arrow)
{
arrowsTo.removeOne(arrow);
}
protected: protected:
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override; QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
}; };
#endif #endif

View file

@ -1,9 +1,9 @@
#include "card_drag_item.h" #include "card_drag_item.h"
#include "../../game_graphics/zones/card_zone.h"
#include "../../game_graphics/zones/table_zone.h"
#include "../../game_graphics/zones/view_zone.h"
#include "../game_scene.h" #include "../game_scene.h"
#include "../zones/card_zone.h"
#include "../zones/table_zone.h"
#include "../zones/view_zone.h"
#include "card_item.h" #include "card_item.h"
#include <QCursor> #include <QCursor>
@ -24,8 +24,9 @@ void CardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
{ {
AbstractCardDragItem::paint(painter, option, widget); AbstractCardDragItem::paint(painter, option, widget);
if (occupied) if (occupied) {
painter->fillPath(shape(), QColor(200, 0, 0, 100)); painter->fillPath(shape(), QColor(200, 0, 0, 100));
}
} }
void CardDragItem::updatePosition(const QPointF &cursorScenePos) void CardDragItem::updatePosition(const QPointF &cursorScenePos)
@ -38,16 +39,19 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
ZoneViewZone *zoneViewZone = 0; ZoneViewZone *zoneViewZone = 0;
for (int i = colliding.size() - 1; i >= 0; i--) { for (int i = colliding.size() - 1; i >= 0; i--) {
CardZone *temp = qgraphicsitem_cast<CardZone *>(colliding.at(i)); CardZone *temp = qgraphicsitem_cast<CardZone *>(colliding.at(i));
if (!cardZone) if (!cardZone) {
cardZone = temp; cardZone = temp;
if (!zoneViewZone) }
if (!zoneViewZone) {
zoneViewZone = qobject_cast<ZoneViewZone *>(temp); zoneViewZone = qobject_cast<ZoneViewZone *>(temp);
}
} }
CardZone *cursorZone = 0; CardZone *cursorZone = 0;
if (zoneViewZone) if (zoneViewZone) {
cursorZone = zoneViewZone; cursorZone = zoneViewZone;
else if (cardZone) } else if (cardZone) {
cursorZone = cardZone; cursorZone = cardZone;
}
// Always update the current zone, even if its null, to cancel the drag // Always update the current zone, even if its null, to cancel the drag
// instead of dropping cards into an non-intuitive location. // instead of dropping cards into an non-intuitive location.
@ -59,8 +63,9 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
QPointF newPos = cursorScenePos - hotSpot; QPointF newPos = cursorScenePos - hotSpot;
if (newPos != pos()) { if (newPos != pos()) {
for (int i = 0; i < childDrags.size(); i++) for (int i = 0; i < childDrags.size(); i++) {
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot()); childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
}
setPos(newPos); setPos(newPos);
} }
@ -78,23 +83,27 @@ void CardDragItem::updatePosition(const QPointF &cursorScenePos)
// position. // position.
TableZone *tableZone = qobject_cast<TableZone *>(cursorZone); TableZone *tableZone = qobject_cast<TableZone *>(cursorZone);
QPointF closestGridPoint; QPointF closestGridPoint;
if (tableZone) if (tableZone) {
closestGridPoint = tableZone->closestGridPoint(cursorPosInZone); closestGridPoint = tableZone->closestGridPoint(cursorPosInZone);
else } else {
closestGridPoint = cursorPosInZone - hotSpot; closestGridPoint = cursorPosInZone - hotSpot;
}
QPointF newPos = zonePos + closestGridPoint; QPointF newPos = zonePos + closestGridPoint;
if (newPos != pos()) { if (newPos != pos()) {
for (int i = 0; i < childDrags.size(); i++) for (int i = 0; i < childDrags.size(); i++) {
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot()); childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
}
setPos(newPos); setPos(newPos);
bool newOccupied = false; bool newOccupied = false;
TableZone *table = qobject_cast<TableZone *>(cursorZone); TableZone *table = qobject_cast<TableZone *>(cursorZone);
if (table) if (table) {
if (table->getCardFromCoords(closestGridPoint)) if (table->getCardFromCoords(closestGridPoint)) {
newOccupied = true; newOccupied = true;
}
}
if (newOccupied != occupied) { if (newOccupied != occupied) {
occupied = newOccupied; occupied = newOccupied;
update(); update();

View file

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

View file

@ -1,14 +1,14 @@
#include "card_item.h" #include "card_item.h"
#include "../../client/settings/cache_settings.h" #include "../../client/settings/cache_settings.h"
#include "../../game_graphics/zones/table_zone.h"
#include "../../game_graphics/zones/view_zone.h"
#include "../../interface/widgets/tabs/tab_game.h" #include "../../interface/widgets/tabs/tab_game.h"
#include "../game_scene.h" #include "../game_scene.h"
#include "../phase.h" #include "../phase.h"
#include "../player/player.h"
#include "../player/player_actions.h" #include "../player/player_actions.h"
#include "../zones/logic/view_zone_logic.h" #include "../player/player_logic.h"
#include "../zones/table_zone.h" #include "../zones/view_zone_logic.h"
#include "../zones/view_zone.h"
#include "arrow_item.h" #include "arrow_item.h"
#include "card_drag_item.h" #include "card_drag_item.h"
@ -20,15 +20,19 @@
#include <libcockatrice/card/card_info.h> #include <libcockatrice/card/card_info.h>
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h> #include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
CardItem::CardItem(Player *_owner, QGraphicsItem *parent, const CardRef &cardRef, int _cardid, CardZoneLogic *_zone) CardItem::CardItem(PlayerLogic *_owner,
: AbstractCardItem(parent, cardRef, _owner, _cardid), zone(_zone), attacking(false), destroyOnZoneChange(false), QGraphicsItem *parent,
doesntUntap(false), dragItem(nullptr), attachedTo(nullptr) const CardRef &cardRef,
int _cardid,
CardZoneLogic *_zone)
: AbstractCardItem(parent, cardRef, _owner, _cardid), state(new CardState(this, _zone)), dragItem(nullptr)
{ {
owner->addCard(this); owner->addCard(this);
connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) { connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) {
if (counters.contains(counterId)) if (state->getCounters().contains(counterId)) {
update(); update();
}
}); });
} }
@ -47,23 +51,24 @@ void CardItem::prepareDelete()
attachedCards.first()->setAttachedTo(nullptr); attachedCards.first()->setAttachedTo(nullptr);
} }
if (attachedTo != nullptr) { if (state->getAttachedTo() != nullptr) {
attachedTo->removeAttachedCard(this); state->getAttachedTo()->removeAttachedCard(this);
attachedTo = nullptr; state->setAttachedTo(nullptr);
} }
} }
void CardItem::deleteLater() void CardItem::deleteLater()
{ {
prepareDelete(); prepareDelete();
if (scene()) if (scene()) {
static_cast<GameScene *>(scene())->unregisterAnimationItem(this); static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
}
AbstractCardItem::deleteLater(); AbstractCardItem::deleteLater();
} }
void CardItem::setZone(CardZoneLogic *_zone) void CardItem::setZone(CardZoneLogic *_zone)
{ {
zone = _zone; state->setZone(_zone);
} }
void CardItem::retranslateUi() void CardItem::retranslateUi()
@ -78,23 +83,23 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
AbstractCardItem::paint(painter, option, widget); AbstractCardItem::paint(painter, option, widget);
int i = 0; int i = 0;
QMapIterator<int, int> counterIterator(counters); QMapIterator<int, int> counterIterator(state->getCounters());
while (counterIterator.hasNext()) { while (counterIterator.hasNext()) {
counterIterator.next(); counterIterator.next();
QColor _color = cardCounterSettings.color(counterIterator.key()); QColor _color = cardCounterSettings.color(counterIterator.key());
paintNumberEllipse(counterIterator.value(), 14, _color, i, counters.size(), painter); paintNumberEllipse(counterIterator.value(), 14, _color, i, state->getCounters().size(), painter);
++i; ++i;
} }
QSizeF translatedSize = getTranslatedSize(painter); QSizeF translatedSize = getTranslatedSize(painter);
qreal scaleFactor = translatedSize.width() / boundingRect().width(); qreal scaleFactor = translatedSize.width() / boundingRect().width();
if (!pt.isEmpty()) { if (!state->getPT().isEmpty()) {
painter->save(); painter->save();
transformPainter(painter, translatedSize, tapAngle); transformPainter(painter, translatedSize, tapAngle);
if (!getFaceDown() && pt == exactCard.getInfo().getPowTough()) { if (!getFaceDown() && state->getPT() == exactCard.getInfo().getPowTough()) {
painter->setPen(Qt::white); painter->setPen(Qt::white);
} else { } else {
painter->setPen(QColor(255, 150, 0)); // dark orange painter->setPen(QColor(255, 150, 0)); // dark orange
@ -105,11 +110,11 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 10 * scaleFactor, painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 10 * scaleFactor,
translatedSize.height() - 8 * scaleFactor), translatedSize.height() - 8 * scaleFactor),
Qt::AlignRight | Qt::AlignBottom, pt); Qt::AlignRight | Qt::AlignBottom, state->getPT());
painter->restore(); painter->restore();
} }
if (!annotation.isEmpty()) { if (!state->getAnnotation().isEmpty()) {
painter->save(); painter->save();
transformPainter(painter, translatedSize, tapAngle); transformPainter(painter, translatedSize, tapAngle);
@ -119,7 +124,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 8 * scaleFactor, painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 8 * scaleFactor,
translatedSize.height() - 8 * scaleFactor), translatedSize.height() - 8 * scaleFactor),
Qt::AlignCenter | Qt::TextWrapAnywhere, annotation); Qt::AlignCenter | Qt::TextWrapAnywhere, state->getAnnotation());
painter->restore(); painter->restore();
} }
@ -127,7 +132,7 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->fillPath(shape(), QBrush(QColor(255, 0, 0, 100))); painter->fillPath(shape(), QBrush(QColor(255, 0, 0, 100)));
} }
if (doesntUntap) { if (state->getDoesntUntap()) {
painter->save(); painter->save();
painter->setRenderHint(QPainter::Antialiasing, false); painter->setRenderHint(QPainter::Antialiasing, false);
@ -146,69 +151,66 @@ void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
void CardItem::setAttacking(bool _attacking) void CardItem::setAttacking(bool _attacking)
{ {
attacking = _attacking; state->setAttacking(_attacking);
update(); update();
} }
void CardItem::setCounter(int _id, int _value) void CardItem::setCounter(int _id, int _value)
{ {
if (_value) state->setCounter(_id, _value);
counters.insert(_id, _value);
else
counters.remove(_id);
update(); update();
} }
void CardItem::setAnnotation(const QString &_annotation) void CardItem::setAnnotation(const QString &_annotation)
{ {
annotation = _annotation; state->setAnnotation(_annotation);
update(); update();
} }
void CardItem::setDoesntUntap(bool _doesntUntap) void CardItem::setDoesntUntap(bool _doesntUntap)
{ {
doesntUntap = _doesntUntap; state->setDoesntUntap(_doesntUntap);
update(); update();
} }
void CardItem::setPT(const QString &_pt) void CardItem::setPT(const QString &_pt)
{ {
pt = _pt; state->setPT(_pt);
update(); update();
} }
void CardItem::setAttachedTo(CardItem *_attachedTo) void CardItem::setAttachedTo(CardItem *_attachedTo)
{ {
if (attachedTo != nullptr) { if (state->getAttachedTo() != nullptr) {
attachedTo->removeAttachedCard(this); state->getAttachedTo()->removeAttachedCard(this);
} }
gridPoint.setX(-1); gridPoint.setX(-1);
attachedTo = _attachedTo; state->setAttachedTo(_attachedTo);
if (attachedTo != nullptr) { 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 // 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 // attached cards
if (attachedTo->zone == nullptr) { if (state->getAttachedTo()->getZone() == nullptr) {
deleteLater(); deleteLater();
} else { } else {
emit attachedTo->zone->cardAdded(this); emit state->getAttachedTo()->getZone()->cardAdded(this);
attachedTo->addAttachedCard(this); state->getAttachedTo()->addAttachedCard(this);
if (zone != attachedTo->getZone()) { if (state->getZone() != state->getAttachedTo()->getZone()) {
attachedTo->getZone()->reorganizeCards(); state->getAttachedTo()->getZone()->reorganizeCards();
} }
} }
} else { } else {
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its // 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 // attached cards
if (zone == nullptr) { if (state->getZone() == nullptr) {
deleteLater(); deleteLater();
} else { } else {
emit zone->cardAdded(this); emit state->getZone()->cardAdded(this);
} }
} }
if (zone != nullptr) { if (state->getZone() != nullptr) {
zone->reorganizeCards(); state->getZone()->reorganizeCards();
} }
} }
@ -217,28 +219,23 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
*/ */
void CardItem::resetState(bool keepAnnotations) void CardItem::resetState(bool keepAnnotations)
{ {
attacking = false; state->resetState(keepAnnotations);
counters.clear();
pt.clear();
if (!keepAnnotations) {
annotation.clear();
}
attachedTo = 0;
attachedCards.clear(); attachedCards.clear();
setTapped(false, false); setTapped(false, false);
setDoesntUntap(false); setDoesntUntap(false);
if (scene()) if (scene()) {
static_cast<GameScene *>(scene())->unregisterAnimationItem(this); static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
}
update(); update();
} }
void CardItem::processCardInfo(const ServerInfo_Card &_info) void CardItem::processCardInfo(const ServerInfo_Card &_info)
{ {
counters.clear(); state->clearCounters();
const int counterListSize = _info.counter_list_size(); const int counterListSize = _info.counter_list_size();
for (int i = 0; i < counterListSize; ++i) { for (int i = 0; i < counterListSize; ++i) {
const ServerInfo_CardCounter &counterInfo = _info.counter_list(i); const ServerInfo_CardCounter &counterInfo = _info.counter_list(i);
counters.insert(counterInfo.id(), counterInfo.value()); state->insertCounter(counterInfo.id(), counterInfo.value());
} }
setId(_info.id()); setId(_info.id());
@ -275,11 +272,12 @@ void CardItem::deleteDragItem()
void CardItem::drawArrow(const QColor &arrowColor) void CardItem::drawArrow(const QColor &arrowColor)
{ {
if (owner->getGame()->getPlayerManager()->isSpectator()) if (owner->getGame()->getPlayerManager()->isSpectator()) {
return; return;
}
auto *game = owner->getGame(); auto *game = owner->getGame();
Player *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer()); PlayerLogic *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
int phase = 0; // 0 means to not set the phase int phase = 0; // 0 means to not set the phase
if (SettingsCache::instance().getDoNotDeleteArrowsInSubPhases()) { if (SettingsCache::instance().getDoNotDeleteArrowsInSubPhases()) {
int currentPhase = game->getGameState()->getCurrentPhase(); int currentPhase = game->getGameState()->getCurrentPhase();
@ -291,10 +289,12 @@ void CardItem::drawArrow(const QColor &arrowColor)
for (const auto &item : scene()->selectedItems()) { for (const auto &item : scene()->selectedItems()) {
CardItem *card = qgraphicsitem_cast<CardItem *>(item); CardItem *card = qgraphicsitem_cast<CardItem *>(item);
if (card == nullptr || card == this) if (card == nullptr || card == this) {
continue; continue;
if (card->getZone() != zone) }
if (card->getZone() != state->getZone()) {
continue; continue;
}
ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, card, arrowColor, phase); ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, card, arrowColor, phase);
scene()->addItem(childArrow); scene()->addItem(childArrow);
@ -304,8 +304,9 @@ void CardItem::drawArrow(const QColor &arrowColor)
void CardItem::drawAttachArrow() void CardItem::drawAttachArrow()
{ {
if (owner->getGame()->getPlayerManager()->isSpectator()) if (owner->getGame()->getPlayerManager()->isSpectator()) {
return; return;
}
auto *arrow = new ArrowAttachItem(this); auto *arrow = new ArrowAttachItem(this);
scene()->addItem(arrow); scene()->addItem(arrow);
@ -313,10 +314,12 @@ void CardItem::drawAttachArrow()
for (const auto &item : scene()->selectedItems()) { for (const auto &item : scene()->selectedItems()) {
CardItem *card = qgraphicsitem_cast<CardItem *>(item); CardItem *card = qgraphicsitem_cast<CardItem *>(item);
if (card == nullptr) if (card == nullptr) {
continue; continue;
if (card->getZone() != zone) }
if (card->getZone() != state->getZone()) {
continue; continue;
}
ArrowAttachItem *childArrow = new ArrowAttachItem(card); ArrowAttachItem *childArrow = new ArrowAttachItem(card);
scene()->addItem(childArrow); scene()->addItem(childArrow);
@ -328,27 +331,32 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->buttons().testFlag(Qt::RightButton)) { if (event->buttons().testFlag(Qt::RightButton)) {
if ((event->screenPos() - event->buttonDownScreenPos(Qt::RightButton)).manhattanLength() < if ((event->screenPos() - event->buttonDownScreenPos(Qt::RightButton)).manhattanLength() <
2 * QApplication::startDragDistance()) 2 * QApplication::startDragDistance()) {
return; return;
}
QColor arrowColor = Qt::red; QColor arrowColor = Qt::red;
if (event->modifiers().testFlag(Qt::ControlModifier)) if (event->modifiers().testFlag(Qt::ControlModifier)) {
arrowColor = Qt::yellow; arrowColor = Qt::yellow;
else if (event->modifiers().testFlag(Qt::AltModifier)) } else if (event->modifiers().testFlag(Qt::AltModifier)) {
arrowColor = Qt::blue; arrowColor = Qt::blue;
else if (event->modifiers().testFlag(Qt::ShiftModifier)) } else if (event->modifiers().testFlag(Qt::ShiftModifier)) {
arrowColor = Qt::green; arrowColor = Qt::green;
}
drawArrow(arrowColor); drawArrow(arrowColor);
} else if (event->buttons().testFlag(Qt::LeftButton)) { } else if (event->buttons().testFlag(Qt::LeftButton)) {
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() <
2 * QApplication::startDragDistance()) 2 * QApplication::startDragDistance()) {
return; return;
if (const ZoneViewZoneLogic *view = qobject_cast<const ZoneViewZoneLogic *>(zone)) { }
if (view->getRevealZone() && !view->getWriteableRevealZone()) if (const ZoneViewZoneLogic *view = qobject_cast<const ZoneViewZoneLogic *>(state->getZone())) {
if (view->getRevealZone() && !view->getWriteableRevealZone()) {
return; return;
} else if (!owner->getPlayerInfo()->getLocalOrJudge()) }
} else if (!owner->getPlayerInfo()->getLocalOrJudge()) {
return; return;
}
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier); bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
@ -360,14 +368,16 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
int childIndex = 0; int childIndex = 0;
for (const auto &item : scene()->selectedItems()) { for (const auto &item : scene()->selectedItems()) {
CardItem *card = static_cast<CardItem *>(item); CardItem *card = static_cast<CardItem *>(item);
if ((card == this) || (card->getZone() != zone)) if ((card == this) || (card->getZone() != state->getZone())) {
continue; continue;
}
++childIndex; ++childIndex;
QPointF childPos; QPointF childPos;
if (zone->getHasCardAttr()) if (state->getZone()->getHasCardAttr()) {
childPos = card->pos() - pos(); childPos = card->pos() - pos();
else } else {
childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0); childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0);
}
CardDragItem *drag = CardDragItem *drag =
new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem); new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem);
drag->setPos(dragItem->pos() + childPos); drag->setPos(dragItem->pos() + childPos);
@ -380,18 +390,19 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void CardItem::playCard(bool faceDown) void CardItem::playCard(bool faceDown)
{ {
// Do nothing if the card belongs to another player // Do nothing if the card belongs to another player
if (!owner->getPlayerInfo()->getLocalOrJudge()) if (!owner->getPlayerInfo()->getLocalOrJudge()) {
return; return;
}
TableZoneLogic *tz = qobject_cast<TableZoneLogic *>(zone); TableZoneLogic *tz = qobject_cast<TableZoneLogic *>(state->getZone());
if (tz) if (tz) {
emit tz->toggleTapped(); emit tz->toggleTapped();
else { } else {
if (SettingsCache::instance().getClickPlaysAllSelected()) { if (SettingsCache::instance().getClickPlaysAllSelected()) {
faceDown ? zone->getPlayer()->getPlayerActions()->actPlayFacedown() faceDown ? state->getZone()->getPlayer()->getPlayerActions()->actPlayFacedown()
: zone->getPlayer()->getPlayerActions()->actPlay(); : state->getZone()->getPlayer()->getPlayerActions()->actPlay();
} else { } else {
zone->getPlayer()->getPlayerActions()->playCard(this, faceDown); state->getZone()->getPlayer()->getPlayerActions()->playCard(this, faceDown);
} }
} }
} }
@ -447,11 +458,11 @@ static bool isUnwritableRevealZone(CardZoneLogic *zone)
*/ */
void CardItem::handleClickedToPlay(bool shiftHeld) void CardItem::handleClickedToPlay(bool shiftHeld)
{ {
if (isUnwritableRevealZone(zone)) { if (isUnwritableRevealZone(state->getZone())) {
if (SettingsCache::instance().getClickPlaysAllSelected()) { if (SettingsCache::instance().getClickPlaysAllSelected()) {
zone->getPlayer()->getPlayerActions()->actHide(); state->getZone()->getPlayer()->getPlayerActions()->actHide();
} else { } else {
zone->removeCard(this); state->getZone()->removeCard(this);
} }
} else { } else {
playCard(shiftHeld); playCard(shiftHeld);
@ -493,8 +504,9 @@ bool CardItem::animationEvent()
{ {
int rotation = ROTATION_DEGREES_PER_FRAME; int rotation = ROTATION_DEGREES_PER_FRAME;
bool animationIncomplete = true; bool animationIncomplete = true;
if (!tapped) if (!tapped) {
rotation *= -1; rotation *= -1;
}
tapAngle += rotation; tapAngle += rotation;
if (tapped && (tapAngle > 90)) { if (tapped && (tapAngle > 90)) {

View file

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

View file

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

View file

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

View file

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

View file

@ -5,15 +5,8 @@
#include <QPainter> #include <QPainter>
GeneralCounter::GeneralCounter(Player *_player, GeneralCounter::GeneralCounter(CounterState *state, PlayerLogic *player, bool useNameForShortcut, QGraphicsItem *parent)
int _id, : AbstractCounter(state, player, true, useNameForShortcut, parent)
const QString &_name,
const QColor &_color,
int _radius,
int _value,
bool useNameForShortcut,
QGraphicsItem *parent)
: AbstractCounter(_player, _id, _name, true, _value, useNameForShortcut, parent), color(_color), radius(_radius)
{ {
setCacheMode(DeviceCoordinateCache); setCacheMode(DeviceCoordinateCache);
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -12,16 +12,16 @@
*/ */
namespace CardDimensions namespace CardDimensions
{ {
/// Card width in pixels /** @brief Card width in pixels. */
constexpr int WIDTH = 72; constexpr int WIDTH = 72;
/// Card height in pixels /** @brief Card height in pixels. */
constexpr int HEIGHT = 102; constexpr int HEIGHT = 102;
/// Pre-converted for floating-point contexts (Z-value calculations) /** @brief Pre-converted for floating-point contexts (Z-value calculations). */
constexpr qreal WIDTH_F = static_cast<qreal>(WIDTH); constexpr qreal WIDTH_F = static_cast<qreal>(WIDTH);
constexpr qreal HEIGHT_F = static_cast<qreal>(HEIGHT); constexpr qreal HEIGHT_F = static_cast<qreal>(HEIGHT);
/// Half-dimensions for centering and rotation transforms /** @brief Half-dimensions for centering and rotation transforms. */
constexpr qreal WIDTH_HALF_F = WIDTH_F / 2; constexpr qreal WIDTH_HALF_F = WIDTH_F / 2;
constexpr qreal HEIGHT_HALF_F = HEIGHT_F / 2; constexpr qreal HEIGHT_HALF_F = HEIGHT_F / 2;
} // namespace CardDimensions } // namespace CardDimensions

View file

@ -24,17 +24,21 @@ void DeckViewCardDragItem::updatePosition(const QPointF &cursorScenePos)
QList<QGraphicsItem *> colliding = scene()->items(cursorScenePos); QList<QGraphicsItem *> colliding = scene()->items(cursorScenePos);
DeckViewCardContainer *cursorZone = 0; DeckViewCardContainer *cursorZone = 0;
for (int i = colliding.size() - 1; i >= 0; i--) for (int i = colliding.size() - 1; i >= 0; i--) {
if ((cursorZone = qgraphicsitem_cast<DeckViewCardContainer *>(colliding.at(i)))) if ((cursorZone = qgraphicsitem_cast<DeckViewCardContainer *>(colliding.at(i)))) {
break; break;
if (!cursorZone) }
}
if (!cursorZone) {
return; return;
}
currentZone = cursorZone; currentZone = cursorZone;
QPointF newPos = cursorScenePos; QPointF newPos = cursorScenePos;
if (newPos != pos()) { if (newPos != pos()) {
for (int i = 0; i < childDrags.size(); i++) for (int i = 0; i < childDrags.size(); i++) {
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot()); childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
}
setPos(newPos); setPos(newPos);
} }
} }
@ -104,11 +108,13 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event) void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{ {
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() <
2 * QApplication::startDragDistance()) 2 * QApplication::startDragDistance()) {
return; return;
}
if (static_cast<DeckViewScene *>(scene())->getLocked()) if (static_cast<DeckViewScene *>(scene())->getLocked()) {
return; return;
}
delete dragItem; delete dragItem;
dragItem = new DeckViewCardDragItem(this, event->pos()); dragItem = new DeckViewCardDragItem(this, event->pos());
@ -120,8 +126,9 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
int j = 0; int j = 0;
for (int i = 0; i < sel.size(); i++) { for (int i = 0; i < sel.size(); i++) {
auto *c = static_cast<DeckViewCard *>(sel.at(i)); auto *c = static_cast<DeckViewCard *>(sel.at(i));
if (c == this) if (c == this) {
continue; continue;
}
++j; ++j;
auto childPos = QPointF(j * CardDimensions::WIDTH_HALF_F, 0); auto childPos = QPointF(j * CardDimensions::WIDTH_HALF_F, 0);
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem); auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
@ -133,8 +140,9 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void DeckView::mouseDoubleClickEvent(QMouseEvent *event) void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
{ {
if (static_cast<DeckViewScene *>(scene())->getLocked()) if (static_cast<DeckViewScene *>(scene())->getLocked()) {
return; return;
}
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
QList<MoveCard_ToZone> result; QList<MoveCard_ToZone> result;
@ -147,12 +155,13 @@ void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
m.set_card_name(c->getName().toStdString()); m.set_card_name(c->getName().toStdString());
m.set_start_zone(zone->getName().toStdString()); m.set_start_zone(zone->getName().toStdString());
if (zone->getName() == DECK_ZONE_MAIN) if (zone->getName() == DECK_ZONE_MAIN) {
m.set_target_zone(DECK_ZONE_SIDE); m.set_target_zone(DECK_ZONE_SIDE);
else if (zone->getName() == DECK_ZONE_SIDE) } else if (zone->getName() == DECK_ZONE_SIDE) {
m.set_target_zone(DECK_ZONE_MAIN); m.set_target_zone(DECK_ZONE_MAIN);
else // Trying to move from another zone } else { // Trying to move from another zone
m.set_target_zone(zone->getName().toStdString()); m.set_target_zone(zone->getName().toStdString());
}
result.append(m); result.append(m);
} }
@ -232,8 +241,9 @@ QList<QPair<int, int>> DeckViewCardContainer::getRowsAndCols() const
{ {
QList<QPair<int, int>> result; QList<QPair<int, int>> result;
QList<QString> cardTypeList = cardsByType.uniqueKeys(); QList<QString> cardTypeList = cardsByType.uniqueKeys();
for (int i = 0; i < cardTypeList.size(); ++i) for (int i = 0; i < cardTypeList.size(); ++i) {
result.append(QPair<int, int>(1, cardsByType.count(cardTypeList[i]))); result.append(QPair<int, int>(1, cardsByType.count(cardTypeList[i])));
}
return result; return result;
} }
@ -262,8 +272,9 @@ QSizeF DeckViewCardContainer::calculateBoundingRect(const QList<QPair<int, int>>
// Calculate space needed for cards // Calculate space needed for cards
for (int i = 0; i < rowsAndCols.size(); ++i) { for (int i = 0; i < rowsAndCols.size(); ++i) {
totalHeight += CardDimensions::HEIGHT_F * rowsAndCols[i].first + paddingY; totalHeight += CardDimensions::HEIGHT_F * rowsAndCols[i].first + paddingY;
if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth) if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth) {
totalWidth = CardDimensions::WIDTH_F * rowsAndCols[i].second; totalWidth = CardDimensions::WIDTH_F * rowsAndCols[i].second;
}
} }
return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY); return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY);
@ -271,8 +282,9 @@ QSizeF DeckViewCardContainer::calculateBoundingRect(const QList<QPair<int, int>>
bool DeckViewCardContainer::sortCardsByName(DeckViewCard *c1, DeckViewCard *c2) bool DeckViewCardContainer::sortCardsByName(DeckViewCard *c1, DeckViewCard *c2)
{ {
if (c1 && c2) if (c1 && c2) {
return c1->getName() < c2->getName(); return c1->getName() < c2->getName();
}
return false; return false;
} }
@ -322,15 +334,17 @@ DeckViewScene::~DeckViewScene()
void DeckViewScene::clearContents() void DeckViewScene::clearContents()
{ {
QMapIterator<QString, DeckViewCardContainer *> i(cardContainers); QMapIterator<QString, DeckViewCardContainer *> i(cardContainers);
while (i.hasNext()) while (i.hasNext()) {
delete i.next().value(); delete i.next().value();
}
cardContainers.clear(); cardContainers.clear();
} }
void DeckViewScene::setDeck(const DeckList &_deck) void DeckViewScene::setDeck(const DeckList &_deck)
{ {
if (deck) if (deck) {
delete deck; delete deck;
}
deck = new DeckList(_deck.writeToString_Native()); deck = new DeckList(_deck.writeToString_Native());
rebuildTree(); rebuildTree();
@ -342,8 +356,9 @@ void DeckViewScene::rebuildTree()
{ {
clearContents(); clearContents();
if (!deck) if (!deck) {
return; return;
}
for (auto *currentZone : deck->getZoneNodes()) { for (auto *currentZone : deck->getZoneNodes()) {
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0); DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
@ -355,8 +370,9 @@ void DeckViewScene::rebuildTree()
for (int j = 0; j < currentZone->size(); j++) { for (int j = 0; j < currentZone->size(); j++) {
auto *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j)); auto *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
if (!currentCard) if (!currentCard) {
continue; continue;
}
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
auto *newCard = new DeckViewCard(container, currentCard->toCardRef(), currentZone->getName()); auto *newCard = new DeckViewCard(container, currentCard->toCardRef(), currentZone->getName());
@ -373,18 +389,21 @@ void DeckViewScene::applySideboardPlan(const QList<MoveCard_ToZone> &plan)
const MoveCard_ToZone &m = plan[i]; const MoveCard_ToZone &m = plan[i];
DeckViewCardContainer *start = cardContainers.value(QString::fromStdString(m.start_zone())); DeckViewCardContainer *start = cardContainers.value(QString::fromStdString(m.start_zone()));
DeckViewCardContainer *target = cardContainers.value(QString::fromStdString(m.target_zone())); DeckViewCardContainer *target = cardContainers.value(QString::fromStdString(m.target_zone()));
if (!start || !target) if (!start || !target) {
continue; continue;
}
DeckViewCard *card = 0; DeckViewCard *card = 0;
const QList<DeckViewCard *> &cardList = start->getCards(); const QList<DeckViewCard *> &cardList = start->getCards();
for (int j = 0; j < cardList.size(); ++j) for (int j = 0; j < cardList.size(); ++j) {
if (cardList[j]->getName() == QString::fromStdString(m.card_name())) { if (cardList[j]->getName() == QString::fromStdString(m.card_name())) {
card = cardList[j]; card = cardList[j];
break; break;
} }
if (!card) }
if (!card) {
continue; continue;
}
start->removeCard(card); start->removeCard(card);
target->addCard(card); target->addCard(card);
@ -405,8 +424,9 @@ void DeckViewScene::rearrangeItems()
rowsAndColsList.append(rowsAndCols); rowsAndColsList.append(rowsAndCols);
cardCountList.append(QList<int>()); cardCountList.append(QList<int>());
for (int j = 0; j < rowsAndCols.size(); ++j) for (int j = 0; j < rowsAndCols.size(); ++j) {
cardCountList[i].append(rowsAndCols[j].second); cardCountList[i].append(rowsAndCols[j].second);
}
} }
qreal totalHeight, totalWidth; qreal totalHeight, totalWidth;
@ -417,23 +437,27 @@ void DeckViewScene::rearrangeItems()
for (int i = 0; i < contList.size(); ++i) { for (int i = 0; i < contList.size(); ++i) {
QSizeF contSize = contList[i]->calculateBoundingRect(rowsAndColsList[i]); QSizeF contSize = contList[i]->calculateBoundingRect(rowsAndColsList[i]);
totalHeight += contSize.height() + spacing; totalHeight += contSize.height() + spacing;
if (contSize.width() > totalWidth) if (contSize.width() > totalWidth) {
totalWidth = contSize.width(); totalWidth = contSize.width();
}
} }
// We're done when the aspect ratio shifts from too high to too low. // We're done when the aspect ratio shifts from too high to too low.
if (totalWidth / totalHeight <= optimalAspectRatio) if (totalWidth / totalHeight <= optimalAspectRatio) {
break; break;
}
// Find category with highest column count // Find category with highest column count
int maxIndex1 = -1, maxIndex2 = -1, maxCols = 0; int maxIndex1 = -1, maxIndex2 = -1, maxCols = 0;
for (int i = 0; i < rowsAndColsList.size(); ++i) for (int i = 0; i < rowsAndColsList.size(); ++i) {
for (int j = 0; j < rowsAndColsList[i].size(); ++j) for (int j = 0; j < rowsAndColsList[i].size(); ++j) {
if (rowsAndColsList[i][j].second > maxCols) { if (rowsAndColsList[i][j].second > maxCols) {
maxIndex1 = i; maxIndex1 = i;
maxIndex2 = j; maxIndex2 = j;
maxCols = rowsAndColsList[i][j].second; maxCols = rowsAndColsList[i][j].second;
} }
}
}
// Add row to category // Add row to category
const int maxRows = rowsAndColsList[maxIndex1][maxIndex2].first; const int maxRows = rowsAndColsList[maxIndex1][maxIndex2].first;
@ -451,8 +475,9 @@ void DeckViewScene::rearrangeItems()
} }
totalWidth = totalHeight * optimalAspectRatio; totalWidth = totalHeight * optimalAspectRatio;
for (int i = 0; i < contList.size(); ++i) for (int i = 0; i < contList.size(); ++i) {
contList[i]->setWidth(totalWidth); contList[i]->setWidth(totalWidth);
}
setSceneRect(QRectF(0, 0, totalWidth, totalHeight)); setSceneRect(QRectF(0, 0, totalWidth, totalHeight));
} }
@ -470,7 +495,7 @@ QList<MoveCard_ToZone> DeckViewScene::getSideboardPlan() const
while (containerIterator.hasNext()) { while (containerIterator.hasNext()) {
DeckViewCardContainer *cont = containerIterator.next().value(); DeckViewCardContainer *cont = containerIterator.next().value();
const QList<DeckViewCard *> cardList = cont->getCards(); const QList<DeckViewCard *> cardList = cont->getCards();
for (int i = 0; i < cardList.size(); ++i) for (int i = 0; i < cardList.size(); ++i) {
if (cardList[i]->getOriginZone() != cont->getName()) { if (cardList[i]->getOriginZone() != cont->getName()) {
MoveCard_ToZone m; MoveCard_ToZone m;
m.set_card_name(cardList[i]->getName().toStdString()); m.set_card_name(cardList[i]->getName().toStdString());
@ -478,6 +503,7 @@ QList<MoveCard_ToZone> DeckViewScene::getSideboardPlan() const
m.set_target_zone(cont->getName().toStdString()); m.set_target_zone(cont->getName().toStdString());
result.append(m); result.append(m);
} }
}
} }
return result; return result;
} }

View file

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

View file

@ -251,8 +251,9 @@ void DeckViewContainer::unloadDeck()
void DeckViewContainer::loadLocalDeck() void DeckViewContainer::loadLocalDeck()
{ {
DlgLoadDeck dialog(this); DlgLoadDeck dialog(this);
if (!dialog.exec()) if (!dialog.exec()) {
return; return;
}
loadDeckFromFile(dialog.selectedFiles().at(0)); loadDeckFromFile(dialog.selectedFiles().at(0));
} }
@ -364,8 +365,9 @@ void DeckViewContainer::sideboardPlanChanged()
{ {
Command_SetSideboardPlan cmd; Command_SetSideboardPlan cmd;
const QList<MoveCard_ToZone> &newPlan = deckView->getSideboardPlan(); const QList<MoveCard_ToZone> &newPlan = deckView->getSideboardPlan();
for (const auto &i : newPlan) for (const auto &i : newPlan) {
cmd.add_move_list()->CopyFrom(i); cmd.add_move_list()->CopyFrom(i);
}
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId); parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
} }
@ -404,8 +406,9 @@ void DeckViewContainer::setSideboardLocked(bool locked)
{ {
sideboardLockButton->setState(!locked); sideboardLockButton->setState(!locked);
deckView->setLocked(readyStartButton->getState() || !sideboardLockButton->getState()); deckView->setLocked(readyStartButton->getState() || !sideboardLockButton->getState());
if (locked) if (locked) {
deckView->resetSideboardPlan(); deckView->resetSideboardPlan();
}
} }
void DeckViewContainer::setDeck(const DeckList &deck) void DeckViewContainer::setDeck(const DeckList &deck)

View file

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

View file

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

View file

@ -101,8 +101,9 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
chooseTokenView->resizeColumnToContents(0); chooseTokenView->resizeColumnToContents(0);
chooseTokenView->setWordWrap(true); chooseTokenView->setWordWrap(true);
if (!deckHeaderState.isNull()) if (!deckHeaderState.isNull()) {
chooseTokenView->header()->restoreState(deckHeaderState); chooseTokenView->header()->restoreState(deckHeaderState);
}
chooseTokenView->header()->setStretchLastSection(false); chooseTokenView->header()->setStretchLastSection(false);
chooseTokenView->header()->hideSection(1); // Sets chooseTokenView->header()->hideSection(1); // Sets
@ -185,8 +186,9 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex &current, const QMo
const QChar cardColor = cardInfo->getColorChar(); const QChar cardColor = cardInfo->getColorChar();
colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString)); colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString));
ptEdit->setText(cardInfo->getPowTough()); ptEdit->setText(cardInfo->getPowTough());
if (SettingsCache::instance().getAnnotateTokens()) if (SettingsCache::instance().getAnnotateTokens()) {
annotationEdit->setText(cardInfo->getText()); annotationEdit->setText(cardInfo->getText());
}
} else { } else {
nameEdit->setText(""); nameEdit->setText("");
colorEdit->setCurrentIndex(colorEdit->findData(QString(), Qt::UserRole, Qt::MatchFixedString)); colorEdit->setCurrentIndex(colorEdit->findData(QString(), Qt::UserRole, Qt::MatchFixedString));

View file

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

View file

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

View file

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

View file

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

View file

@ -36,8 +36,9 @@ GameEventHandler::GameEventHandler(AbstractGame *_game) : QObject(_game), game(_
void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId) void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId)
{ {
AbstractClient *client = game->getClientForPlayer(playerId); AbstractClient *client = game->getClientForPlayer(playerId);
if (!client) if (!client) {
return; return;
}
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished); connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
client->sendCommand(pend); client->sendCommand(pend);
@ -46,8 +47,9 @@ void GameEventHandler::sendGameCommand(PendingCommand *pend, int playerId)
void GameEventHandler::sendGameCommand(const google::protobuf::Message &command, int playerId) void GameEventHandler::sendGameCommand(const google::protobuf::Message &command, int playerId)
{ {
AbstractClient *client = game->getClientForPlayer(playerId); AbstractClient *client = game->getClientForPlayer(playerId);
if (!client) if (!client) {
return; return;
}
PendingCommand *pend = prepareGameCommand(command); PendingCommand *pend = prepareGameCommand(command);
connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished); connect(pend, &PendingCommand::finished, this, &GameEventHandler::commandFinished);
@ -56,8 +58,9 @@ void GameEventHandler::sendGameCommand(const google::protobuf::Message &command,
void GameEventHandler::commandFinished(const Response &response) void GameEventHandler::commandFinished(const Response &response)
{ {
if (response.response_code() == Response::RespChatFlood) if (response.response_code() == Response::RespChatFlood) {
emit gameFlooded(); emit gameFlooded();
}
} }
PendingCommand *GameEventHandler::prepareGameCommand(const ::google::protobuf::Message &cmd) PendingCommand *GameEventHandler::prepareGameCommand(const ::google::protobuf::Message &cmd)
@ -96,7 +99,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
if (cont.has_forced_by_judge()) { if (cont.has_forced_by_judge()) {
auto id = cont.forced_by_judge(); auto id = cont.forced_by_judge();
Player *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr); PlayerLogic *judgep = game->getPlayerManager()->getPlayers().value(id, nullptr);
if (judgep) { if (judgep) {
emit setContextJudgeName(judgep->getPlayerInfo()->getName()); emit setContextJudgeName(judgep->getPlayerInfo()->getName());
} else if (game->getPlayerManager()->getSpectators().contains(id)) { } else if (game->getPlayerManager()->getSpectators().contains(id)) {
@ -117,9 +120,11 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
break; break;
} }
} else { } else {
if ((game->getGameState()->getClients().size() > 1) && (playerId != -1)) if ((game->getGameState()->getClients().size() > 1) && (playerId != -1)) {
if (game->getGameState()->getClients().at(playerId) != client) if (game->getGameState()->getClients().at(playerId) != client) {
continue; continue;
}
}
switch (eventType) { switch (eventType) {
case GameEvent::GAME_STATE_CHANGED: case GameEvent::GAME_STATE_CHANGED:
@ -155,7 +160,7 @@ void GameEventHandler::processGameEventContainer(const GameEventContainer &cont,
break; break;
default: { default: {
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0); PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
if (!player) { if (!player) {
qCWarning(GameEventHandlerLog) << "unhandled game event: invalid player id"; qCWarning(GameEventHandlerLog) << "unhandled game event: invalid player id";
break; break;
@ -212,7 +217,20 @@ void GameEventHandler::handleArrowDeletion(int arrowId)
{ {
Command_DeleteArrow cmd; Command_DeleteArrow cmd;
cmd.set_arrow_id(arrowId); cmd.set_arrow_id(arrowId);
sendGameCommand(cmd);
auto preparedCommand = prepareGameCommand(cmd);
connect(preparedCommand, &PendingCommand::finished, this,
[arrowId, this](const Response &response) { handleArrowDeletionFinished(response, arrowId); });
sendGameCommand(preparedCommand);
}
void GameEventHandler::handleArrowDeletionFinished(const Response &response, int arrowId)
{
if (response.response_code() == Response::RespNameNotFound) {
emit arrowDeleted(arrowId);
}
} }
void GameEventHandler::eventSpectatorSay(const Event_GameSay &event, void GameEventHandler::eventSpectatorSay(const Event_GameSay &event,
@ -256,7 +274,7 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
emit spectatorJoined(prop); emit spectatorJoined(prop);
} }
} else { } else {
Player *player = game->getPlayerManager()->getPlayers().value(playerId, 0); PlayerLogic *player = game->getPlayerManager()->getPlayers().value(playerId, 0);
if (!player) { if (!player) {
player = game->getPlayerManager()->addPlayer(playerId, prop.user_info()); player = game->getPlayerManager()->addPlayer(playerId, prop.user_info());
emit playerJoined(prop); emit playerJoined(prop);
@ -284,8 +302,9 @@ void GameEventHandler::eventGameStateChanged(const Event_GameStateChanged &event
if (event.game_started() && !game->getGameMetaInfo()->started()) { if (event.game_started() && !game->getGameMetaInfo()->started()) {
game->getGameState()->setResuming(!game->getGameState()->isGameStateKnown()); game->getGameState()->setResuming(!game->getGameState()->isGameStateKnown());
game->getGameMetaInfo()->setStarted(event.game_started()); game->getGameMetaInfo()->setStarted(event.game_started());
if (game->getGameState()->isGameStateKnown()) if (game->getGameState()->isGameStateKnown()) {
emit logGameStart(); emit logGameStart();
}
game->getGameState()->setActivePlayer(event.active_player_id()); game->getGameState()->setActivePlayer(event.active_player_id());
game->getGameState()->setCurrentPhase(event.active_phase()); game->getGameState()->setCurrentPhase(event.active_phase());
} else if (!event.game_started() && game->getGameMetaInfo()->started()) { } else if (!event.game_started() && game->getGameMetaInfo()->started()) {
@ -304,9 +323,10 @@ void GameEventHandler::processCardAttachmentsForPlayers(const Event_GameStateCha
const ServerInfo_Player &playerInfo = event.player_list(i); const ServerInfo_Player &playerInfo = event.player_list(i);
const ServerInfo_PlayerProperties &prop = playerInfo.properties(); const ServerInfo_PlayerProperties &prop = playerInfo.properties();
if (!prop.spectator()) { if (!prop.spectator()) {
Player *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0); PlayerLogic *player = game->getPlayerManager()->getPlayers().value(prop.player_id(), 0);
if (!player) if (!player) {
continue; continue;
}
player->processCardAttachment(playerInfo); player->processCardAttachment(playerInfo);
} }
} }
@ -316,9 +336,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
int eventPlayerId, int eventPlayerId,
const GameEventContext &context) const GameEventContext &context)
{ {
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0); PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) if (!player) {
return; return;
}
const ServerInfo_PlayerProperties &prop = event.player_properties(); const ServerInfo_PlayerProperties &prop = event.player_properties();
emit playerPropertiesChanged(prop, eventPlayerId); emit playerPropertiesChanged(prop, eventPlayerId);
@ -326,8 +347,9 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
switch (contextType) { switch (contextType) {
case GameEventContext::READY_START: { case GameEventContext::READY_START: {
bool ready = prop.ready_start(); bool ready = prop.ready_start();
if (player->getPlayerInfo()->getLocal()) if (player->getPlayerInfo()->getLocal()) {
emit localPlayerReadyStateChanged(player->getPlayerInfo()->getId(), ready); emit localPlayerReadyStateChanged(player->getPlayerInfo()->getId(), ready);
}
if (ready) { if (ready) {
emit logReadyStart(player); emit logReadyStart(player);
} else { } else {
@ -338,9 +360,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
case GameEventContext::CONCEDE: { case GameEventContext::CONCEDE: {
player->setConceded(true); player->setConceded(true);
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers()); QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones(); playerIterator.next().value()->updateZones();
}
emit logConcede(eventPlayerId); emit logConcede(eventPlayerId);
@ -349,9 +372,10 @@ void GameEventHandler::eventPlayerPropertiesChanged(const Event_PlayerProperties
case GameEventContext::UNCONCEDE: { case GameEventContext::UNCONCEDE: {
player->setConceded(false); player->setConceded(false);
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers()); QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones(); playerIterator.next().value()->updateZones();
}
emit logUnconcede(eventPlayerId); emit logUnconcede(eventPlayerId);
@ -389,15 +413,16 @@ void GameEventHandler::eventJoin(const Event_Join &event, int /*eventPlayerId*/,
QString playerName = QString::fromStdString(playerInfo.user_info().name()); QString playerName = QString::fromStdString(playerInfo.user_info().name());
emit addPlayerToAutoCompleteList(playerName); emit addPlayerToAutoCompleteList(playerName);
if (game->getPlayerManager()->getPlayers().contains(playerId)) if (game->getPlayerManager()->getPlayers().contains(playerId)) {
return; return;
}
if (playerInfo.spectator()) { if (playerInfo.spectator()) {
game->getPlayerManager()->addSpectator(playerId, playerInfo); game->getPlayerManager()->addSpectator(playerId, playerInfo);
emit logJoinSpectator(playerName); emit logJoinSpectator(playerName);
emit spectatorJoined(playerInfo); emit spectatorJoined(playerInfo);
} else { } else {
Player *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info()); PlayerLogic *newPlayer = game->getPlayerManager()->addPlayer(playerId, playerInfo.user_info());
emit logJoinPlayer(newPlayer); emit logJoinPlayer(newPlayer);
emit playerJoined(playerInfo); emit playerJoined(playerInfo);
} }
@ -425,9 +450,10 @@ QString GameEventHandler::getLeaveReason(Event_Leave::LeaveReason reason)
} }
void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext & /*context*/) void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, const GameEventContext & /*context*/)
{ {
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0); PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) if (!player) {
return; return;
}
player->clear(); player->clear();
emit playerLeft(eventPlayerId); emit playerLeft(eventPlayerId);
@ -439,9 +465,10 @@ void GameEventHandler::eventLeave(const Event_Leave &event, int eventPlayerId, c
player->deleteLater(); player->deleteLater();
// Rearrange all remaining zones so that attachment relationship updates take place // Rearrange all remaining zones so that attachment relationship updates take place
QMapIterator<int, Player *> playerIterator(game->getPlayerManager()->getPlayers()); QMapIterator<int, PlayerLogic *> playerIterator(game->getPlayerManager()->getPlayers());
while (playerIterator.hasNext()) while (playerIterator.hasNext()) {
playerIterator.next().value()->updateZones(); playerIterator.next().value()->updateZones();
}
emitUserEvent(); emitUserEvent();
} }
@ -460,9 +487,10 @@ void GameEventHandler::eventReverseTurn(const Event_ReverseTurn &event,
int eventPlayerId, int eventPlayerId,
const GameEventContext & /*context*/) const GameEventContext & /*context*/)
{ {
Player *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0); PlayerLogic *player = game->getPlayerManager()->getPlayers().value(eventPlayerId, 0);
if (!player) if (!player) {
return; return;
}
emit logTurnReversed(player, event.reversed()); emit logTurnReversed(player, event.reversed());
} }
@ -490,9 +518,10 @@ void GameEventHandler::eventSetActivePlayer(const Event_SetActivePlayer &event,
const GameEventContext & /*context*/) const GameEventContext & /*context*/)
{ {
game->getGameState()->setActivePlayer(event.active_player_id()); game->getGameState()->setActivePlayer(event.active_player_id());
Player *player = game->getPlayerManager()->getPlayer(event.active_player_id()); PlayerLogic *player = game->getPlayerManager()->getPlayer(event.active_player_id());
if (!player) if (!player) {
return; return;
}
emit logActivePlayer(player); emit logActivePlayer(player);
emitUserEvent(); emitUserEvent();
} }

View file

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

View file

@ -1,8 +1,8 @@
/** /**
* @file game_meta_info.h * @file game_meta_info.h
* @ingroup GameLogic * @ingroup GameLogic
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef GAME_META_INFO_H #ifndef GAME_META_INFO_H
#define GAME_META_INFO_H #define GAME_META_INFO_H
@ -87,15 +87,17 @@ public:
public slots: public slots:
void setStarted(bool s) void setStarted(bool s)
{ {
if (gameInfo_.started() == s) if (gameInfo_.started() == s) {
return; return;
}
gameInfo_.set_started(s); gameInfo_.set_started(s);
emit startedChanged(s); emit startedChanged(s);
} }
void setSpectatorsOmniscient(bool v) void setSpectatorsOmniscient(bool v)
{ {
if (gameInfo_.spectators_omniscient() == v) if (gameInfo_.spectators_omniscient() == v) {
return; return;
}
gameInfo_.set_spectators_omniscient(v); gameInfo_.set_spectators_omniscient(v);
emit spectatorsOmniscienceChanged(v); emit spectatorsOmniscienceChanged(v);
} }

View file

@ -1,12 +1,13 @@
#include "game_scene.h" #include "game_scene.h"
#include "../client/settings/cache_settings.h" #include "../client/settings/cache_settings.h"
#include "../game_graphics/zones/select_zone.h"
#include "../game_graphics/zones/view_zone.h"
#include "../game_graphics/zones/view_zone_widget.h"
#include "board/card_item.h" #include "board/card_item.h"
#include "phases_toolbar.h" #include "phases_toolbar.h"
#include "player/player.h"
#include "player/player_graphics_item.h" #include "player/player_graphics_item.h"
#include "zones/view_zone.h" #include "player/player_logic.h"
#include "zones/view_zone_widget.h"
#include <QBasicTimer> #include <QBasicTimer>
#include <QDebug> #include <QDebug>
@ -54,8 +55,9 @@ GameScene::~GameScene()
*/ */
void GameScene::retranslateUi() void GameScene::retranslateUi()
{ {
for (ZoneViewWidget *view : zoneViews) for (ZoneViewWidget *view : zoneViews) {
view->retranslateUi(); view->retranslateUi();
}
} }
QList<CardItem *> GameScene::selectedCards() const QList<CardItem *> GameScene::selectedCards() const
@ -76,13 +78,30 @@ QList<CardItem *> GameScene::selectedCards() const
* *
* Connects to the player's sizeChanged signal to recompute layout on resize. * Connects to the player's sizeChanged signal to recompute layout on resize.
*/ */
void GameScene::addPlayer(Player *player) void GameScene::addPlayer(PlayerLogic *player)
{ {
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::addPlayer name=" << player->getPlayerInfo()->getName(); qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::addPlayer name=" << player->getPlayerInfo()->getName();
players << player->getGraphicsItem(); playerViews.insert(player->getPlayerInfo()->getId(), player->getGraphicsItem());
addItem(player->getGraphicsItem()); addItem(player->getGraphicsItem());
connect(player->getGraphicsItem(), &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange); connect(player->getGraphicsItem(), &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange);
connect(player, &PlayerLogic::concededChanged, this, [this](int id, bool conceded) {
if (conceded) {
clearArrowsForPlayer(id);
}
rearrange();
});
connect(player, &PlayerLogic::arrowDeleted, this, &GameScene::deleteArrow);
connect(player, &PlayerLogic::arrowCreateRequested, this, &GameScene::addArrow);
connect(player, &PlayerLogic::arrowDeleteRequested, this, &GameScene::requestArrowDeletion);
connect(player, &PlayerLogic::arrowsCleared, this,
[this, id = player->getPlayerInfo()->getId()]() { clearArrowsForPlayer(id); });
connect(player->getPlayerEventHandler(), &PlayerEventHandler::cardZoneChanged, this, &GameScene::onCardZoneChanged);
rearrange();
} }
/** /**
@ -91,17 +110,19 @@ void GameScene::addPlayer(Player *player)
* *
* Closes any zone views associated with the player and recomputes layout. * Closes any zone views associated with the player and recomputes layout.
*/ */
void GameScene::removePlayer(Player *player) void GameScene::removePlayer(PlayerLogic *player)
{ {
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::removePlayer name=" << player->getPlayerInfo()->getName(); qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::removePlayer name=" << player->getPlayerInfo()->getName();
clearArrowsForPlayer(player->getPlayerInfo()->getId());
for (ZoneViewWidget *zone : zoneViews) { for (ZoneViewWidget *zone : zoneViews) {
if (zone->getPlayer() == player) { if (zone->getPlayer() == player) {
zone->close(); zone->close();
} }
} }
players.removeOne(player->getGraphicsItem()); auto *view = playerViews.take(player->getPlayerInfo()->getId());
removeItem(player->getGraphicsItem()); removeItem(view);
rearrange(); rearrange();
} }
@ -176,14 +197,14 @@ void GameScene::processViewSizeChange(const QSize &newSize)
* *
* Used to determine rotation and layout order. * Used to determine rotation and layout order.
*/ */
QList<Player *> GameScene::collectActivePlayers(int &firstPlayerIndex) const QList<PlayerLogic *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
{ {
QList<Player *> activePlayers; QList<PlayerLogic *> activePlayers;
firstPlayerIndex = 0; firstPlayerIndex = 0;
bool firstPlayerFound = false; bool firstPlayerFound = false;
for (auto *pgItem : players) { for (auto *pgItem : playerViews.values()) {
Player *p = pgItem->getPlayer(); PlayerLogic *p = pgItem->getPlayer();
if (p && !p->getConceded()) { if (p && !p->getConceded()) {
activePlayers.append(p); activePlayers.append(p);
if (!firstPlayerFound && p->getPlayerInfo()->getLocal()) { if (!firstPlayerFound && p->getPlayerInfo()->getLocal()) {
@ -203,15 +224,17 @@ QList<Player *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
* *
* Applies rotation offset and ensures the list wraps correctly. * Applies rotation offset and ensures the list wraps correctly.
*/ */
QList<Player *> GameScene::rotatePlayers(const QList<Player *> &activePlayers, int firstPlayerIndex) const QList<PlayerLogic *> GameScene::rotatePlayers(const QList<PlayerLogic *> &activePlayers, int firstPlayerIndex) const
{ {
QList<Player *> rotated = activePlayers; QList<PlayerLogic *> rotated = activePlayers;
if (!rotated.isEmpty()) { if (!rotated.isEmpty()) {
int totalRotation = firstPlayerIndex + playerRotation; int totalRotation = firstPlayerIndex + playerRotation;
while (totalRotation < 0) while (totalRotation < 0) {
totalRotation += rotated.size(); totalRotation += rotated.size();
for (int i = 0; i < totalRotation; ++i) }
for (int i = 0; i < totalRotation; ++i) {
rotated.append(rotated.takeFirst()); rotated.append(rotated.takeFirst());
}
} }
return rotated; return rotated;
} }
@ -234,7 +257,7 @@ int GameScene::determineColumnCount(int playerCount)
* - Position players in columns with spacing. * - Position players in columns with spacing.
* - Mirror graphics for visual balance. * - Mirror graphics for visual balance.
*/ */
QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<Player *> &playersPlaying, int columns) QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &playersPlaying, int columns)
{ {
playersByColumn.clear(); playersByColumn.clear();
@ -242,7 +265,7 @@ QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<Player *> &players
qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing; qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing;
QList<int> columnWidth; QList<int> columnWidth;
QListIterator<Player *> playersIter(playersPlaying); QListIterator<PlayerLogic *> playersIter(playersPlaying);
for (int col = 0; col < columns; ++col) { for (int col = 0; col < columns; ++col) {
playersByColumn.append(QList<PlayerGraphicsItem *>()); playersByColumn.append(QList<PlayerGraphicsItem *>());
columnWidth.append(0); columnWidth.append(0);
@ -250,11 +273,12 @@ QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<Player *> &players
int rowsInColumn = rows - (playersPlaying.size() % columns) * col; // Adjust rows for uneven columns int rowsInColumn = rows - (playersPlaying.size() % columns) * col; // Adjust rows for uneven columns
for (int j = 0; j < rowsInColumn; ++j) { for (int j = 0; j < rowsInColumn; ++j) {
Player *player = playersIter.next(); PlayerLogic *player = playersIter.next();
if (col == 0) if (col == 0) {
playersByColumn[col].prepend(player->getGraphicsItem()); playersByColumn[col].prepend(player->getGraphicsItem());
else } else {
playersByColumn[col].append(player->getGraphicsItem()); playersByColumn[col].append(player->getGraphicsItem());
}
auto *pgItem = player->getGraphicsItem(); auto *pgItem = player->getGraphicsItem();
thisColumnHeight += pgItem->boundingRect().height() + playerAreaSpacing; thisColumnHeight += pgItem->boundingRect().height() + playerAreaSpacing;
@ -293,8 +317,9 @@ QList<qreal> GameScene::calculateMinWidthByColumn() const
QList<qreal> minWidthByColumn; QList<qreal> minWidthByColumn;
for (const auto &col : playersByColumn) { for (const auto &col : playersByColumn) {
qreal maxWidth = 0; qreal maxWidth = 0;
for (PlayerGraphicsItem *player : col) for (PlayerGraphicsItem *player : col) {
maxWidth = std::max(maxWidth, player->getMinimumWidth()); maxWidth = std::max(maxWidth, player->getMinimumWidth());
}
minWidthByColumn.append(maxWidth); minWidthByColumn.append(maxWidth);
} }
return minWidthByColumn; return minWidthByColumn;
@ -342,6 +367,99 @@ void GameScene::resizeColumnsAndPlayers(const QList<qreal> &minWidthByColumn, qr
} }
} }
void GameScene::addArrow(const ArrowData &data)
{
auto *startView = playerViews.value(data.startPlayerId);
auto *targetView = playerViews.value(data.targetPlayerId);
if (!startView || !targetView) {
return;
}
PlayerLogic *startLogic = startView->getPlayer();
auto *startZone = startLogic->getZones().value(data.startZone);
if (!startZone) {
return;
}
CardItem *startCard = startZone->getCard(data.startCardId);
if (!startCard) {
return;
}
ArrowTarget *targetItem = nullptr;
if (data.isPlayerTargeted()) {
targetItem = targetView->getPlayerTarget();
} else {
auto *zone = targetView->getPlayer()->getZones().value(data.targetZone);
if (zone) {
targetItem = zone->getCard(data.targetCardId);
}
}
if (!targetItem) {
return;
}
auto *arrow = new ArrowItem(startView->getPlayer(), data.id, startCard, targetItem, data.color);
addItem(arrow);
arrowRegistry.insert(data.id, arrow);
connect(arrow, &ArrowItem::requestDeletion, this, &GameScene::requestArrowDeletion);
}
void GameScene::deleteArrow(int arrowId)
{
if (arrowRegistry.contains(arrowId)) {
arrowRegistry.take(arrowId)->delArrow();
}
}
void GameScene::clearArrowsForPlayer(int playerId)
{
QList<int> toDelete;
for (auto i = arrowRegistry.cbegin(); i != arrowRegistry.cend(); ++i) {
auto *arrow = i.value();
if (arrow->getPlayer()->getPlayerInfo()->getId() == playerId) {
toDelete.append(i.key());
}
}
for (int arrowId : toDelete) {
arrowRegistry.take(arrowId)->delArrow();
}
}
void GameScene::requestArrowDeletion(int arrowId)
{
if (arrowRegistry.contains(arrowId)) {
emit arrowDeletionRequested(arrowId);
}
}
void GameScene::requestClearArrowsForPlayer(int playerId)
{
for (auto *arrow : arrowRegistry.values()) {
if (arrow->getPlayer()->getPlayerInfo()->getId() == playerId) {
emit requestArrowDeletion(arrow->getId());
}
}
}
void GameScene::onCardZoneChanged(CardItem *card, bool sameZone)
{
QList<ArrowItem *> toDelete;
for (auto *arrow : arrowRegistry.values()) {
if (arrow->getStartItem() == card || arrow->getTargetItem() == card) {
if (sameZone) {
arrow->updatePath();
} else {
toDelete.append(arrow);
}
}
}
for (auto *arrow : toDelete) {
deleteArrow(arrow->getId());
}
}
// ---------- Hover Handling ---------- // ---------- Hover Handling ----------
void GameScene::updateHover(const QPointF &scenePos) void GameScene::updateHover(const QPointF &scenePos)
@ -355,18 +473,38 @@ void GameScene::updateHover(const QPointF &scenePos)
void GameScene::updateHoveredCard(CardItem *newCard) void GameScene::updateHoveredCard(CardItem *newCard)
{ {
if (hoveredCard && (newCard != hoveredCard)) if (hoveredCard && (newCard != hoveredCard)) {
hoveredCard->setHovered(false); endCardHover(hoveredCard);
if (newCard && (newCard != hoveredCard)) }
newCard->setHovered(true); if (newCard && (newCard != hoveredCard)) {
beginCardHover(newCard);
}
hoveredCard = newCard; hoveredCard = newCard;
} }
void GameScene::beginCardHover(CardItem *card)
{
card->setHovered(true);
if (auto *zone = SelectZone::findOwningSelectZone(card)) {
zone->escapeClipForHover(card);
}
}
void GameScene::endCardHover(CardItem *card)
{
if (auto *zone = SelectZone::findOwningSelectZone(card)) {
zone->restoreClipAfterHover(card);
}
card->setHovered(false);
}
CardZone *GameScene::findTopmostZone(const QList<QGraphicsItem *> &items) CardZone *GameScene::findTopmostZone(const QList<QGraphicsItem *> &items)
{ {
for (QGraphicsItem *item : items) for (QGraphicsItem *item : items) {
if (auto *zone = qgraphicsitem_cast<CardZone *>(item)) if (auto *zone = qgraphicsitem_cast<CardZone *>(item)) {
return zone; return zone;
}
}
return nullptr; return nullptr;
} }
@ -377,14 +515,17 @@ CardItem *GameScene::findTopmostCardInZone(const QList<QGraphicsItem *> &items,
for (QGraphicsItem *item : items) { for (QGraphicsItem *item : items) {
CardItem *card = qgraphicsitem_cast<CardItem *>(item); CardItem *card = qgraphicsitem_cast<CardItem *>(item);
if (!card) if (!card) {
continue; continue;
}
if (card->getAttachedTo()) { if (card->getAttachedTo()) {
if (card->getAttachedTo()->getZone() != zone->getLogic()) if (card->getAttachedTo()->getZone() != zone->getLogic()) {
continue; continue;
} else if (card->getZone() != zone->getLogic()) }
} else if (card->getZone() != zone->getLogic()) {
continue; continue;
}
if (card->getRealZValue() > maxZ) { if (card->getRealZValue() > maxZ) {
maxZ = card->getRealZValue(); maxZ = card->getRealZValue();
@ -406,7 +547,7 @@ CardItem *GameScene::findTopmostCardInZone(const QList<QGraphicsItem *> &items,
* If an identical view exists, it is closed. Otherwise, a new ZoneViewWidget is created * If an identical view exists, it is closed. Otherwise, a new ZoneViewWidget is created
* and positioned based on zone type. * and positioned based on zone type.
*/ */
void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numberCards, bool isReversed) void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed)
{ {
for (auto &view : zoneViews) { for (auto &view : zoneViews) {
ZoneViewZone *temp = view->getZone(); ZoneViewZone *temp = view->getZone();
@ -423,12 +564,13 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView); connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
addItem(item); addItem(item);
if (zoneName == ZoneNames::GRAVE) if (zoneName == ZoneNames::GRAVE) {
item->setPos(360, 100); item->setPos(360, 100);
else if (zoneName == ZoneNames::EXILE) } else if (zoneName == ZoneNames::EXILE) {
item->setPos(380, 120); item->setPos(380, 120);
else } else {
item->setPos(340, 80); item->setPos(340, 80);
}
} }
/** /**
@ -438,7 +580,7 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb
* @param cardList List of cards to show. * @param cardList List of cards to show.
* @param withWritePermission Whether edits are allowed. * @param withWritePermission Whether edits are allowed.
*/ */
void GameScene::addRevealedZoneView(Player *player, void GameScene::addRevealedZoneView(PlayerLogic *player,
CardZoneLogic *zone, CardZoneLogic *zone,
const QList<const ServerInfo_Card *> &cardList, const QList<const ServerInfo_Card *> &cardList,
bool withWritePermission) bool withWritePermission)
@ -465,8 +607,9 @@ void GameScene::removeZoneView(ZoneViewWidget *item)
*/ */
void GameScene::clearViews() void GameScene::clearViews()
{ {
while (!zoneViews.isEmpty()) while (!zoneViews.isEmpty()) {
zoneViews.first()->close(); zoneViews.first()->close();
}
} }
/** /**
@ -474,8 +617,9 @@ void GameScene::clearViews()
*/ */
void GameScene::closeMostRecentZoneView() void GameScene::closeMostRecentZoneView()
{ {
if (!zoneViews.isEmpty()) if (!zoneViews.isEmpty()) {
zoneViews.last()->close(); zoneViews.last()->close();
}
} }
// ---------- View Transforms ---------- // ---------- View Transforms ----------
@ -494,8 +638,11 @@ QTransform GameScene::getViewportTransform() const
bool GameScene::event(QEvent *event) bool GameScene::event(QEvent *event)
{ {
if (event->type() == QEvent::GraphicsSceneMouseMove) if (event->type() == QEvent::GraphicsSceneMouseMove) {
updateHover(static_cast<QGraphicsSceneMouseEvent *>(event)->scenePos()); updateHover(static_cast<QGraphicsSceneMouseEvent *>(event)->scenePos());
} else if (event->type() == QEvent::Leave) {
updateHoveredCard(nullptr);
}
return QGraphicsScene::event(event); return QGraphicsScene::event(event);
} }
@ -505,25 +652,29 @@ void GameScene::timerEvent(QTimerEvent * /*event*/)
QMutableSetIterator<CardItem *> i(cardsToAnimate); QMutableSetIterator<CardItem *> i(cardsToAnimate);
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
if (!i.value()->animationEvent()) if (!i.value()->animationEvent()) {
i.remove(); i.remove();
}
} }
if (cardsToAnimate.isEmpty()) if (cardsToAnimate.isEmpty()) {
animationTimer->stop(); animationTimer->stop();
}
} }
void GameScene::registerAnimationItem(AbstractCardItem *card) void GameScene::registerAnimationItem(AbstractCardItem *card)
{ {
cardsToAnimate.insert(static_cast<CardItem *>(card)); cardsToAnimate.insert(static_cast<CardItem *>(card));
if (!animationTimer->isActive()) if (!animationTimer->isActive()) {
animationTimer->start(10, this); animationTimer->start(10, this);
}
} }
void GameScene::unregisterAnimationItem(AbstractCardItem *card) void GameScene::unregisterAnimationItem(AbstractCardItem *card)
{ {
cardsToAnimate.remove(static_cast<CardItem *>(card)); cardsToAnimate.remove(static_cast<CardItem *>(card));
if (cardsToAnimate.isEmpty()) if (cardsToAnimate.isEmpty()) {
animationTimer->stop(); animationTimer->stop();
}
} }
// ---------- Rubber Band ---------- // ---------- Rubber Band ----------

View file

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

View file

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

View file

@ -75,8 +75,9 @@ void GameView::resizeEvent(QResizeEvent *event)
QGraphicsView::resizeEvent(event); QGraphicsView::resizeEvent(event);
GameScene *s = dynamic_cast<GameScene *>(scene()); GameScene *s = dynamic_cast<GameScene *>(scene());
if (s) if (s) {
s->processViewSizeChange(event->size()); s->processViewSizeChange(event->size());
}
updateSceneRect(scene()->sceneRect()); updateSceneRect(scene()->sceneRect());
updateTotalSelectionCount(event->size()); updateTotalSelectionCount(event->size());
@ -89,8 +90,9 @@ void GameView::updateSceneRect(const QRectF &rect)
void GameView::startRubberBand(const QPointF &_selectionOrigin) void GameView::startRubberBand(const QPointF &_selectionOrigin)
{ {
if (!rubberBand) if (!rubberBand) {
return; return;
}
selectionOrigin = _selectionOrigin; selectionOrigin = _selectionOrigin;
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0))); rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
@ -99,8 +101,9 @@ void GameView::startRubberBand(const QPointF &_selectionOrigin)
void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount) void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
{ {
if (!rubberBand) if (!rubberBand) {
return; return;
}
constexpr int kLabelPaddingInPixels = 4; constexpr int kLabelPaddingInPixels = 4;
@ -145,8 +148,9 @@ void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
void GameView::stopRubberBand() void GameView::stopRubberBand()
{ {
if (!rubberBand) if (!rubberBand) {
return; return;
}
rubberBand->hide(); rubberBand->hide();
dragCountLabel->hide(); dragCountLabel->hide();

View file

@ -1,8 +1,8 @@
/** /**
* @file game_view.h * @file game_view.h
* @ingroup GameGraphics * @ingroup GameGraphics
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef GAMEVIEW_H #ifndef GAMEVIEW_H
#define GAMEVIEW_H #define GAMEVIEW_H

View file

@ -1,6 +1,6 @@
#include "hand_counter.h" #include "hand_counter.h"
#include "zones/card_zone.h" #include "../game_graphics/zones/card_zone.h"
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include <QPainter> #include <QPainter>

View file

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

View file

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

View file

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

View file

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

View file

@ -21,8 +21,9 @@ PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_
activeAnimationTimer = new QTimer(this); activeAnimationTimer = new QTimer(this);
connect(activeAnimationTimer, &QTimer::timeout, this, &PhaseButton::updateAnimation); connect(activeAnimationTimer, &QTimer::timeout, this, &PhaseButton::updateAnimation);
activeAnimationTimer->setSingleShot(false); activeAnimationTimer->setSingleShot(false);
} else } else {
activeAnimationCounter = 9; activeAnimationCounter = 9;
}
setCacheMode(DeviceCoordinateCache); setCacheMode(DeviceCoordinateCache);
} }
@ -63,8 +64,9 @@ void PhaseButton::setWidth(double _width)
void PhaseButton::setActive(bool _active) void PhaseButton::setActive(bool _active)
{ {
if ((active == _active) || !highlightable) if ((active == _active) || !highlightable) {
return; return;
}
active = _active; active = _active;
activeAnimationTimer->start(25); activeAnimationTimer->start(25);
@ -72,8 +74,9 @@ void PhaseButton::setActive(bool _active)
void PhaseButton::updateAnimation() void PhaseButton::updateAnimation()
{ {
if (!highlightable) if (!highlightable) {
return; return;
}
// the counter ticks up to 10 when active and down to 0 when inactive // the counter ticks up to 10 when active and down to 0 when inactive
if (active && activeAnimationCounter < 10) { if (active && activeAnimationCounter < 10) {
@ -99,8 +102,9 @@ void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
void PhaseButton::triggerDoubleClickAction() void PhaseButton::triggerDoubleClickAction()
{ {
if (doubleClickAction) if (doubleClickAction) {
doubleClickAction->trigger(); doubleClickAction->trigger();
}
} }
PhasesToolbar::PhasesToolbar(QGraphicsItem *parent) PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
@ -126,8 +130,9 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
buttonList << untapButton << upkeepButton << drawButton << main1Button << combatStartButton << combatAttackersButton buttonList << untapButton << upkeepButton << drawButton << main1Button << combatStartButton << combatAttackersButton
<< combatBlockersButton << combatDamageButton << combatEndButton << main2Button << cleanupButton; << combatBlockersButton << combatDamageButton << combatEndButton << main2Button << cleanupButton;
for (auto &i : buttonList) for (auto &i : buttonList) {
connect(i, &PhaseButton::clicked, this, &PhasesToolbar::phaseButtonClicked); connect(i, &PhaseButton::clicked, this, &PhasesToolbar::phaseButtonClicked);
}
nextTurnButton = new PhaseButton("nextturn", this, nullptr, false); nextTurnButton = new PhaseButton("nextturn", this, nullptr, false);
connect(nextTurnButton, &PhaseButton::clicked, this, &PhasesToolbar::actNextTurn); connect(nextTurnButton, &PhaseButton::clicked, this, &PhasesToolbar::actNextTurn);
@ -144,8 +149,9 @@ QRectF PhasesToolbar::boundingRect() const
void PhasesToolbar::retranslateUi() void PhasesToolbar::retranslateUi()
{ {
for (int i = 0; i < buttonList.size(); ++i) for (int i = 0; i < buttonList.size(); ++i) {
buttonList[i]->setToolTip(getLongPhaseName(i)); buttonList[i]->setToolTip(getLongPhaseName(i));
}
} }
QString PhasesToolbar::getLongPhaseName(int phase) const QString PhasesToolbar::getLongPhaseName(int phase) const
@ -187,8 +193,9 @@ const double PhasesToolbar::marginSize = 3;
void PhasesToolbar::rearrangeButtons() void PhasesToolbar::rearrangeButtons()
{ {
for (auto &i : buttonList) for (auto &i : buttonList) {
i->setWidth(symbolSize); i->setWidth(symbolSize);
}
nextTurnButton->setWidth(symbolSize); nextTurnButton->setWidth(symbolSize);
double y = marginSize; double y = marginSize;
@ -226,11 +233,13 @@ void PhasesToolbar::setHeight(double _height)
void PhasesToolbar::setActivePhase(int phase) void PhasesToolbar::setActivePhase(int phase)
{ {
if (phase >= buttonList.size()) if (phase >= buttonList.size()) {
return; return;
}
for (int i = 0; i < buttonList.size(); ++i) for (int i = 0; i < buttonList.size(); ++i) {
buttonList[i]->setActive(i == phase); buttonList[i]->setActive(i == phase);
}
} }
void PhasesToolbar::triggerPhaseAction(int phase) void PhasesToolbar::triggerPhaseAction(int phase)
@ -243,8 +252,9 @@ void PhasesToolbar::triggerPhaseAction(int phase)
void PhasesToolbar::phaseButtonClicked() void PhasesToolbar::phaseButtonClicked()
{ {
auto *button = qobject_cast<PhaseButton *>(sender()); auto *button = qobject_cast<PhaseButton *>(sender());
if (button->getActive()) if (button->getActive()) {
button->triggerDoubleClickAction(); button->triggerDoubleClickAction();
}
Command_SetActivePhase cmd; Command_SetActivePhase cmd;
cmd.set_phase(static_cast<google::protobuf::uint32>(buttonList.indexOf(button))); cmd.set_phase(static_cast<google::protobuf::uint32>(buttonList.indexOf(button)));

View file

@ -2,8 +2,8 @@
* @file phases_toolbar.h * @file phases_toolbar.h
* @ingroup GameGraphics * @ingroup GameGraphics
* @ingroup GameWidgets * @ingroup GameWidgets
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef PHASESTOOLBAR_H #ifndef PHASESTOOLBAR_H
#define PHASESTOOLBAR_H #define PHASESTOOLBAR_H
@ -21,7 +21,7 @@ namespace protobuf
class Message; class Message;
} }
} // namespace google } // namespace google
class Player; class PlayerLogic;
class GameCommand; class GameCommand;
class PhaseButton : public QObject, public QGraphicsItem class PhaseButton : public QObject, public QGraphicsItem

View file

@ -1,8 +1,8 @@
/** /**
* @file card_menu_action_type.h * @file card_menu_action_type.h
* @ingroup GameMenusPlayers * @ingroup GameMenusPlayers
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef COCKATRICE_CARD_MENU_ACTION_TYPE_H #ifndef COCKATRICE_CARD_MENU_ACTION_TYPE_H
#define COCKATRICE_CARD_MENU_ACTION_TYPE_H #define COCKATRICE_CARD_MENU_ACTION_TYPE_H

View file

@ -1,8 +1,8 @@
/** /**
* @file event_processing_options.h * @file event_processing_options.h
* @ingroup GameLogicPlayers * @ingroup GameLogicPlayers
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef COCKATRICE_EVENT_PROCESSING_OPTIONS_H #ifndef COCKATRICE_EVENT_PROCESSING_OPTIONS_H
#define COCKATRICE_EVENT_PROCESSING_OPTIONS_H #define COCKATRICE_EVENT_PROCESSING_OPTIONS_H

View file

@ -19,13 +19,13 @@ class AbstractPlayerComponent
public: public:
virtual ~AbstractPlayerComponent() = default; virtual ~AbstractPlayerComponent() = default;
/// Bind keyboard shortcuts. Called when this player gains focus. /** @brief Bind keyboard shortcuts. Called when this player gains focus. */
virtual void setShortcutsActive() = 0; virtual void setShortcutsActive() = 0;
/// Unbind keyboard shortcuts. Called when this player loses focus. /** @brief Unbind keyboard shortcuts. Called when this player loses focus. */
virtual void setShortcutsInactive() = 0; virtual void setShortcutsInactive() = 0;
/// Retranslate all user-visible strings. Called on language change. /** @brief Retranslate all user-visible strings. Called on language change. */
virtual void retranslateUi() = 0; virtual void retranslateUi() = 0;
}; };

View file

@ -3,23 +3,40 @@
#include "../../../client/settings/card_counter_settings.h" #include "../../../client/settings/card_counter_settings.h"
#include "../../../interface/widgets/tabs/tab_game.h" #include "../../../interface/widgets/tabs/tab_game.h"
#include "../../board/card_item.h" #include "../../board/card_item.h"
#include "../../zones/logic/view_zone_logic.h" #include "../../zones/view_zone_logic.h"
#include "../card_menu_action_type.h" #include "../card_menu_action_type.h"
#include "../player.h"
#include "../player_actions.h" #include "../player_actions.h"
#include "../player_logic.h"
#include "move_menu.h" #include "move_menu.h"
#include "pt_menu.h" #include "pt_menu.h"
#include <QPainter>
#include <libcockatrice/card/database/card_database_manager.h> #include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h> #include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/utility/zone_names.h> #include <libcockatrice/utility/zone_names.h>
CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive) /**
* @brief Creates a circular icon filled with the specified color.
*/
static QIcon createCircleIcon(const QColor &color)
{
QPixmap pixmap(32, 32);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(color);
painter.drawEllipse(pixmap.rect());
return QIcon(pixmap);
}
CardMenu::CardMenu(PlayerLogic *_player, const CardItem *_card, bool _shortcutsActive)
: player(_player), card(_card), shortcutsActive(_shortcutsActive) : player(_player), card(_card), shortcutsActive(_shortcutsActive)
{ {
auto playerActions = player->getPlayerActions(); auto playerActions = player->getPlayerActions();
const QList<Player *> &players = player->getGame()->getPlayerManager()->getPlayers().values(); const QList<PlayerLogic *> &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto playerToAdd : players) { for (auto playerToAdd : players) {
if (playerToAdd == player) { if (playerToAdd == player) {
@ -62,6 +79,9 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
aSelectColumn = new QAction(this); aSelectColumn = new QAction(this);
connect(aSelectColumn, &QAction::triggered, playerActions, &PlayerActions::actSelectColumn); connect(aSelectColumn, &QAction::triggered, playerActions, &PlayerActions::actSelectColumn);
aReduceLifeByPower = new QAction(this);
connect(aReduceLifeByPower, &QAction::triggered, playerActions, &PlayerActions::actReduceLifeByPower);
aPlay = new QAction(this); aPlay = new QAction(this);
connect(aPlay, &QAction::triggered, playerActions, &PlayerActions::actPlay); connect(aPlay, &QAction::triggered, playerActions, &PlayerActions::actPlay);
aHide = new QAction(this); aHide = new QAction(this);
@ -74,9 +94,21 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
mCardCounters = new QMenu; mCardCounters = new QMenu;
for (int i = 0; i < 6; ++i) { for (int i = 0; i < 6; ++i) {
QColor color = SettingsCache::instance().cardCounters().color(i);
QIcon circleIcon = createCircleIcon(color);
auto *tempAddCounter = new QAction(this); auto *tempAddCounter = new QAction(this);
tempAddCounter->setIconVisibleInMenu(true);
tempAddCounter->setIcon(circleIcon);
auto *tempRemoveCounter = new QAction(this); auto *tempRemoveCounter = new QAction(this);
tempRemoveCounter->setIconVisibleInMenu(true);
tempRemoveCounter->setIcon(circleIcon);
auto *tempSetCounter = new QAction(this); auto *tempSetCounter = new QAction(this);
tempSetCounter->setIconVisibleInMenu(true);
tempSetCounter->setIcon(circleIcon);
aAddCounter.append(tempAddCounter); aAddCounter.append(tempAddCounter);
aRemoveCounter.append(tempRemoveCounter); aRemoveCounter.append(tempRemoveCounter);
aSetCounter.append(tempSetCounter); aSetCounter.append(tempSetCounter);
@ -134,7 +166,7 @@ CardMenu::CardMenu(Player *_player, const CardItem *_card, bool _shortcutsActive
} }
} }
void CardMenu::removePlayer(Player *playerToRemove) void CardMenu::removePlayer(PlayerLogic *playerToRemove)
{ {
for (auto it = playersInfo.begin(); it != playersInfo.end();) { for (auto it = playersInfo.begin(); it != playersInfo.end();) {
if (it->second == playerToRemove->getPlayerInfo()->getId()) { if (it->second == playerToRemove->getPlayerInfo()->getId()) {
@ -153,6 +185,8 @@ void CardMenu::createTableMenu(bool canModifyCard)
addSeparator(); addSeparator();
addAction(aClone); addAction(aClone);
addSeparator(); addSeparator();
addAction(aReduceLifeByPower);
addSeparator();
addAction(aSelectAll); addAction(aSelectAll);
addAction(aSelectRow); addAction(aSelectRow);
addRelatedCardView(); addRelatedCardView();
@ -179,6 +213,8 @@ void CardMenu::createTableMenu(bool canModifyCard)
addMenu(new PtMenu(player)); addMenu(new PtMenu(player));
addAction(aSetAnnotation); addAction(aSetAnnotation);
addSeparator(); addSeparator();
addAction(aReduceLifeByPower);
addSeparator();
addAction(aSelectAll); addAction(aSelectAll);
addAction(aSelectRow); addAction(aSelectRow);
@ -463,6 +499,7 @@ void CardMenu::retranslateUi()
aUnattach->setText(tr("Unattac&h")); aUnattach->setText(tr("Unattac&h"));
aDrawArrow->setText(tr("&Draw arrow...")); aDrawArrow->setText(tr("&Draw arrow..."));
aSetAnnotation->setText(tr("&Set annotation...")); aSetAnnotation->setText(tr("&Set annotation..."));
aReduceLifeByPower->setText(tr("Reduce life by power"));
mCardCounters->setTitle(tr("Ca&rd counters")); mCardCounters->setTitle(tr("Ca&rd counters"));
@ -497,6 +534,7 @@ void CardMenu::setShortcutsActive()
aUnattach->setShortcuts(shortcuts.getShortcut("Player/aUnattach")); aUnattach->setShortcuts(shortcuts.getShortcut("Player/aUnattach"));
aDrawArrow->setShortcuts(shortcuts.getShortcut("Player/aDrawArrow")); aDrawArrow->setShortcuts(shortcuts.getShortcut("Player/aDrawArrow"));
aSetAnnotation->setShortcuts(shortcuts.getShortcut("Player/aSetAnnotation")); aSetAnnotation->setShortcuts(shortcuts.getShortcut("Player/aSetAnnotation"));
aReduceLifeByPower->setShortcuts(shortcuts.getShortcut("Player/aReduceLifeByPower"));
aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll")); aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll"));
aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow")); aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow"));

View file

@ -1,8 +1,8 @@
/** /**
* @file card_menu.h * @file card_menu.h
* @ingroup GameMenusCards * @ingroup GameMenusCards
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef COCKATRICE_CARD_MENU_H #ifndef COCKATRICE_CARD_MENU_H
#define COCKATRICE_CARD_MENU_H #define COCKATRICE_CARD_MENU_H
@ -10,14 +10,14 @@
#include <QMenu> #include <QMenu>
class CardItem; class CardItem;
class Player; class PlayerLogic;
class CardMenu : public QMenu class CardMenu : public QMenu
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit CardMenu(Player *player, const CardItem *card, bool shortcutsActive); explicit CardMenu(PlayerLogic *player, const CardItem *card, bool shortcutsActive);
void removePlayer(Player *playerToRemove); void removePlayer(PlayerLogic *playerToRemove);
void createTableMenu(bool canModifyCard); void createTableMenu(bool canModifyCard);
void createStackMenu(bool canModifyCard); void createStackMenu(bool canModifyCard);
void createGraveyardOrExileMenu(bool canModifyCard); void createGraveyardOrExileMenu(bool canModifyCard);
@ -36,11 +36,12 @@ public:
QAction *aFlip, *aPeek; QAction *aFlip, *aPeek;
QAction *aAttach, *aUnattach; QAction *aAttach, *aUnattach;
QAction *aSetAnnotation; QAction *aSetAnnotation;
QAction *aReduceLifeByPower;
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter; QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
private: private:
Player *player; PlayerLogic *player;
const CardItem *card; const CardItem *card;
QList<QPair<QString, int>> playersInfo; QList<QPair<QString, int>> playersInfo;
bool shortcutsActive; bool shortcutsActive;

View file

@ -1,13 +1,13 @@
#include "custom_zone_menu.h" #include "custom_zone_menu.h"
#include "../player.h" #include "../player_logic.h"
CustomZoneMenu::CustomZoneMenu(Player *_player) : player(_player) CustomZoneMenu::CustomZoneMenu(PlayerLogic *_player) : player(_player)
{ {
menuAction()->setVisible(false); menuAction()->setVisible(false);
connect(player, &Player::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu); connect(player, &PlayerLogic::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu);
connect(player, &Player::addViewCustomZoneActionToCustomZoneMenu, this, connect(player, &PlayerLogic::addViewCustomZoneActionToCustomZoneMenu, this,
&CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu); &CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu);
retranslateUi(); retranslateUi();

View file

@ -1,8 +1,8 @@
/** /**
* @file custom_zone_menu.h * @file custom_zone_menu.h
* @ingroup GameMenusZones * @ingroup GameMenusZones
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef COCKATRICE_CUSTOM_ZONE_MENU_H #ifndef COCKATRICE_CUSTOM_ZONE_MENU_H
#define COCKATRICE_CUSTOM_ZONE_MENU_H #define COCKATRICE_CUSTOM_ZONE_MENU_H
@ -11,12 +11,12 @@
#include <QMenu> #include <QMenu>
class Player; class PlayerLogic;
class CustomZoneMenu : public QMenu, public AbstractPlayerComponent class CustomZoneMenu : public QMenu, public AbstractPlayerComponent
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit CustomZoneMenu(Player *player); explicit CustomZoneMenu(PlayerLogic *player);
void retranslateUi() override; void retranslateUi() override;
void setShortcutsActive() override void setShortcutsActive() override
{ {
@ -26,7 +26,7 @@ public:
} }
private: private:
Player *player; PlayerLogic *player;
private slots: private slots:
void clearCustomZonesMenu(); void clearCustomZonesMenu();
void addViewCustomZoneActionToCustomZoneMenu(QString zoneName); void addViewCustomZoneActionToCustomZoneMenu(QString zoneName);

View file

@ -1,14 +1,14 @@
#include "grave_menu.h" #include "grave_menu.h"
#include "../../abstract_game.h" #include "../../abstract_game.h"
#include "../player.h"
#include "../player_actions.h" #include "../player_actions.h"
#include "../player_logic.h"
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <libcockatrice/utility/zone_names.h> #include <libcockatrice/utility/zone_names.h>
GraveyardMenu::GraveyardMenu(Player *_player, QWidget *parent) : TearOffMenu(parent), player(_player) GraveyardMenu::GraveyardMenu(PlayerLogic *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
{ {
createMoveActions(); createMoveActions();
createViewActions(); createViewActions();
@ -78,8 +78,9 @@ void GraveyardMenu::populateRevealRandomMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values(); const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) { for (auto *other : players) {
if (other == player) if (other == player) {
continue; continue;
}
QAction *a = mRevealRandomGraveyardCard->addAction(other->getPlayerInfo()->getName()); QAction *a = mRevealRandomGraveyardCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId()); a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &GraveyardMenu::onRevealRandomTriggered); connect(a, &QAction::triggered, this, &GraveyardMenu::onRevealRandomTriggered);

View file

@ -1,8 +1,8 @@
/** /**
* @file grave_menu.h * @file grave_menu.h
* @ingroup GameMenusZones * @ingroup GameMenusZones
* @brief TODO: Document this.
*/ */
//! \todo Document this file.
#ifndef COCKATRICE_GRAVE_MENU_H #ifndef COCKATRICE_GRAVE_MENU_H
#define COCKATRICE_GRAVE_MENU_H #define COCKATRICE_GRAVE_MENU_H
@ -13,7 +13,7 @@
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
class Player; class PlayerLogic;
class GraveyardMenu : public TearOffMenu, public AbstractPlayerComponent class GraveyardMenu : public TearOffMenu, public AbstractPlayerComponent
{ {
Q_OBJECT Q_OBJECT
@ -21,7 +21,7 @@ signals:
void newPlayerActionCreated(QAction *action); void newPlayerActionCreated(QAction *action);
public: public:
explicit GraveyardMenu(Player *player, QWidget *parent = nullptr); explicit GraveyardMenu(PlayerLogic *player, QWidget *parent = nullptr);
void createMoveActions(); void createMoveActions();
void createViewActions(); void createViewActions();
void populateRevealRandomMenuWithActivePlayers(); void populateRevealRandomMenuWithActivePlayers();
@ -40,7 +40,7 @@ public:
QAction *aMoveGraveToRfg = nullptr; QAction *aMoveGraveToRfg = nullptr;
private: private:
Player *player; PlayerLogic *player;
}; };
#endif // COCKATRICE_GRAVE_MENU_H #endif // COCKATRICE_GRAVE_MENU_H

View file

@ -2,16 +2,16 @@
#include "../../../client/settings/cache_settings.h" #include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h" #include "../../../client/settings/shortcuts_settings.h"
#include "../../../game_graphics/zones/hand_zone.h"
#include "../../abstract_game.h" #include "../../abstract_game.h"
#include "../../zones/hand_zone.h"
#include "../player.h"
#include "../player_actions.h" #include "../player_actions.h"
#include "../player_logic.h"
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <libcockatrice/utility/zone_names.h> #include <libcockatrice/utility/zone_names.h>
HandMenu::HandMenu(Player *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player) HandMenu::HandMenu(PlayerLogic *_player, PlayerActions *actions, QWidget *parent) : TearOffMenu(parent), player(_player)
{ {
if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) { if (player->getPlayerInfo()->local || player->getPlayerInfo()->judge) {
aViewHand = new QAction(this); aViewHand = new QAction(this);
@ -168,8 +168,9 @@ void HandMenu::populateRevealHandMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values(); const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) { for (auto *other : players) {
if (other == player) if (other == player) {
continue; continue;
}
QAction *a = mRevealHand->addAction(other->getPlayerInfo()->getName()); QAction *a = mRevealHand->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId()); a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealHandTriggered); connect(a, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
@ -186,8 +187,9 @@ void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
const auto &players = player->getGame()->getPlayerManager()->getPlayers().values(); const auto &players = player->getGame()->getPlayerManager()->getPlayers().values();
for (auto *other : players) { for (auto *other : players) {
if (other == player) if (other == player) {
continue; continue;
}
QAction *a = mRevealRandomHandCard->addAction(other->getPlayerInfo()->getName()); QAction *a = mRevealRandomHandCard->addAction(other->getPlayerInfo()->getName());
a->setData(other->getPlayerInfo()->getId()); a->setData(other->getPlayerInfo()->getId());
connect(a, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered); connect(a, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
@ -197,8 +199,9 @@ void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
void HandMenu::onRevealHandTriggered() void HandMenu::onRevealHandTriggered()
{ {
auto *action = qobject_cast<QAction *>(sender()); auto *action = qobject_cast<QAction *>(sender());
if (!action) if (!action) {
return; return;
}
const int targetId = action->data().toInt(); const int targetId = action->data().toInt();
player->getPlayerActions()->actRevealHand(targetId); player->getPlayerActions()->actRevealHand(targetId);
@ -207,8 +210,9 @@ void HandMenu::onRevealHandTriggered()
void HandMenu::onRevealRandomHandCardTriggered() void HandMenu::onRevealRandomHandCardTriggered()
{ {
auto *action = qobject_cast<QAction *>(sender()); auto *action = qobject_cast<QAction *>(sender());
if (!action) if (!action) {
return; return;
}
const int targetId = action->data().toInt(); const int targetId = action->data().toInt();
player->getPlayerActions()->actRevealRandomHandCard(targetId); player->getPlayerActions()->actRevealRandomHandCard(targetId);

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