
    Ii                     .   S r SSKJrJrJr  SSKJrJrJr  SSK	J
r
  SSKJrJrJrJr  SSKJr  \(       a  SS	KJrJr  \ " S
 S5      5       r\ " S S\5      5       r\ " S S\5      5       r\ " S S\5      5       r\ " S S\5      5       r\ " S S\5      5       r\ " S S5      5       r\ " S S\5      5       rS\S\4S jrS\S\4S jrSSSS .S\S!\S-  S"\ \\\/\!4   4   \"\ \\\/\!4   4      -  S-  S#\ \\\/\!4   \\!4   \"\ \\\/\!4   \\!4      -  S-  S\4
S$ jjr#S%\$S&\S\S-  4S' jr%S%\$S\&\\4   4S( jr'S%\$S\&\\4   4S) jr(S%\$S&\S\S-  4S* jr)S%\$S&\S\"\ \\\/\!4   4      S-  4S+ jr*\ " S, S-\
5      5       r+ " S. S/5      r,g)0a  
Declarative Options System for PlayPalace Games.

This module provides a way to define game options declaratively, reducing
boilerplate code for option handling, validation, and UI generation.

Usage:
    @dataclass
    class MyGameOptions(GameOptions):
        target_score: int = option_field(
            IntOption(default=50, min_val=10, max_val=1000,
                      label="game-set-target-score",
                      prompt="game-enter-target-score",
                      change_msg="game-option-changed-target"))
        team_mode: str = option_field(
            MenuOption(default="individual",
                       choices=["individual", "2v2"],
                       label="game-set-team-mode",
                       prompt="game-select-team-mode",
                       change_msg="game-option-changed-team"))
        show_hints: bool = option_field(
            BoolOption(default=False,
                       label="my-game-toggle-hints",
                       change_msg="my-game-option-changed-hints"))
    )	dataclassfieldfields)AnyCallableTYPE_CHECKING)DataClassJSONMixin   )Action	ActionSetEditboxInput	MenuInput   )Localization)GamePlayerc                       \ rS rSr% Sr\\S'   \\S'   \\S'   Sr\\S'   Sr	\\S'   S	\S
\S\4S jr
S
\S\\\4   4S jrS
\S\\\4   4S jrS\SSSSS\S	\S\4S jrS
\S\\\4   4S jrSrg)
OptionMeta'   a?  Base metadata for a game option.

Attributes:
    default: Default option value.
    label: Localization key for the option label.
    change_msg: Localization key for change announcements.
    prompt: Localization key for input prompt (if applicable).
    description: Human-readable description spoken via space key.
defaultlabel
change_msg promptdescriptionlocalevaluereturnc                     [         e)z8Get the localized label with current value interpolated.NotImplementedErrorselfr   r   s      8c:\Users\dbart\PlayPalace11\server\game_utils\options.py	get_labelOptionMeta.get_label9       !!    c                     [         e)z"Get kwargs for label localization.r    r#   r   s     r$   get_label_kwargsOptionMeta.get_label_kwargs=   r'   r(   c                     [         e)z+Get kwargs for change message localization.r    r*   s     r$   get_change_kwargsOptionMeta.get_change_kwargsA   r'   r(   option_namegamer   playerr   current_valuec                     [         e)z!Create an Action for this option.r    )r#   r0   r1   r2   r3   r   s         r$   create_actionOptionMeta.create_actionE   s
     "!r(   c                     [         e)zValidate and convert input string to the option's type.

Returns (success, converted_value). If success is False, converted_value
is the original string.
r    r*   s     r$   validate_and_convertOptionMeta.validate_and_convertP   s
     "!r(    N)__name__
__module____qualname____firstlineno____doc__r   __annotations__strr   r   r%   dictr+   r.   r   r5   tupleboolr8   __static_attributes__r:   r(   r$   r   r   '   s     LJOFCK" "C "C ""c "d38n ""s "tCH~ "	"	" 	" 		"
 	" 	" 
	""# "%c	2B "r(   r   c                       \ rS rSr% SrSr\\S'   Sr\\S'   Sr	\
\S'   S	\
S
\S\
4S jrS
\S\\
\4   4S jrS
\S\\
\4   4S jrS\
SSSSS\S	\
S\4S jrS
\
S\\\4   4S jrSrg)	IntOptionY   zInteger option with min/max validation.

Attributes:
    min_val: Minimum value (inclusive).
    max_val: Maximum value (inclusive).
    value_key: Localization placeholder key for the value.
r   min_vald   max_valscore	value_keyr   r   r   c                 b    [         R                  " XR                  40 U R                  U5      D6$ N)r   getr   r+   r"   s      r$   r%   IntOption.get_labelg   s'    

Sd6K6KE6RSSr(   c                     U R                   U0$ 5Return label formatting kwargs for the current value.rM   r*   s     r$   r+   IntOption.get_label_kwargsj       &&r(   c                     U R                   U0$ 3Return change-message kwargs for the current value.rU   r*   s     r$   r.   IntOption.get_change_kwargsn   rW   r(   r0   r1   r   r2   r   r3   c                     [         R                  " XPR                  40 U R                  U5      D6n[	        SU 3USSSS[        U R                  [        U5      S9S9$ )z7Create an editbox action for setting an integer option.set__action_set_option_is_option_enabled_is_option_hiddenFr   r   idr   handler
is_enabled	is_hiddenshow_in_actions_menuinput_requestr   rP   r   r+   r   r   r   rA   r#   r0   r1   r2   r3   r   r   s          r$   r5   IntOption.create_actionr   e       \t7L7L]7[\k]#(+)!&&{{M*
 	
r(   c                      [        U5      n[        U R                  [        U R                  U5      5      nSU4$ ! [
         a    SU4s $ f = f)z!Validate and clamp integer input.TF)intmaxrI   minrK   
ValueError)r#   r   int_vals      r$   r8   IntOption.validate_and_convert   sN    	 %jG$,,DLL'(BCG=  	 %<	 s   8; AAr:   N)r;   r<   r=   r>   r?   rI   rn   r@   rK   rM   rA   r   r%   rB   r+   r.   r   r5   rC   rD   r8   rE   r:   r(   r$   rG   rG   Y   s     GSGSIsT TC TC T'c 'd38n ''s 'tCH~ '

 
 	

 
 
 

. #  %c	2B  r(   rG   c                       \ rS rSr% SrSr\\S'   Sr\\S'   Sr	\
\S'   S	r\\S
'   S	\S\\\4   4S jrS	\S\\\4   4S jrS\SSSSS\S\S\4S jrS	\S\\\4   4S jrSrg)FloatOption   zFloat option with min/max validation and rounding.

Attributes:
    min_val: Minimum value (inclusive).
    max_val: Maximum value (inclusive).
    decimal_places: Decimal places to round to.
    value_key: Localization placeholder key for the value.
g        rI   g      Y@rK   r
   decimal_placesr   rM   r   c                     U R                   U0$ rS   rU   r*   s     r$   r+   FloatOption.get_label_kwargs   rW   r(   c                     U R                   U0$ rY   rU   r*   s     r$   r.   FloatOption.get_change_kwargs   rW   r(   r0   r1   r   r2   r   r3   r   c                     [         R                  " XPR                  40 U R                  U5      D6n[	        SU 3USSSS[        U R                  [        U5      S9S9$ )z4Create an editbox action for setting a float option.r]   r^   r_   r`   Fra   rb   ri   rj   s          r$   r5   FloatOption.create_action   rl   r(   c                      [        U5      n[        U R                  [        U R                  U5      5      n[        X R                  5      nSU4$ ! [         a    SU4s $ f = f)zValidate and clamp float input.TF)floatro   rI   rp   rK   roundrw   rq   )r#   r   	float_vals      r$   r8    FloatOption.validate_and_convert   s^    	 eIDLL#dllI*FGIi)<)<=I?" 	 %<	 s   AA A! A!r:   N)r;   r<   r=   r>   r?   rI   r   r@   rK   rw   rn   rM   rA   r   rB   r+   r.   r   r5   rC   rD   r8   rE   r:   r(   r$   ru   ru      s     GUGUNCIs'c 'd38n ''s 'tCH~ '

 
 	

 
 
 

. #  %c	2B  r(   ru   c                   z   \ rS rSr% Sr\" \S9r\\   \	SS/\\   4   -  \
S'   Sr\\
S'   S	r\\\4   S	-  \
S
'   S\S\S\4S jrS\S\S\4S jrS\S\\\4   4S jrS\S\S\\\4   4S jrS\S\\\4   4S jrS\S\S\\\4   4S jrS\SSSSS\S\S\4S jrS\S\\\4   4S jrSSSSS\\   4S jrSrg	)
MenuOption   zMenu selection option.

Attributes:
    choices: Static list or callable to provide choices.
    value_key: Localization placeholder key for the value.
    choice_labels: Optional mapping of choice -> localization key.
default_factoryr   r   choicesmoderM   Nchoice_labelsr   r   r   c                 b    [         R                  " XR                  40 U R                  X!5      D6$ rO   )r   rP   r   get_label_kwargs_localizedr"   s      r$   r%   MenuOption.get_label   s/    JJ
"&"A"A%"P
 	
r(   c                     U R                   (       a2  XR                   ;   a#  [        R                  " X R                   U   5      $ U$ z2Get the localized display text for a choice value.r   r   rP   r#   r   r   s      r$   get_localized_choiceMenuOption.get_localized_choice   7    %+=+="=##F,>,>u,EFFr(   c                     U R                   U0$ rS   rU   r*   s     r$   r+   MenuOption.get_label_kwargs   rW   r(   c                 @    U R                  X5      nU R                  U0$ )z'Get kwargs with localized choice value.r   rM   r#   r   r   display_values       r$   r   %MenuOption.get_label_kwargs_localized   !    11%@..r(   c                     U R                   U0$ rY   rU   r*   s     r$   r.   MenuOption.get_change_kwargs   rW   r(   c                 @    U R                  X5      nU R                  U0$ )z:Get kwargs with localized choice value for change message.r   r   s       r$   get_change_kwargs_localized&MenuOption.get_change_kwargs_localized   r   r(   r0   r1   r2   r3   c                     [         R                  " XPR                  40 U R                  XE5      D6n[	        SU 3USSSS[        U R                  SU 3S9S9$ )	z8Create a menu action for selecting a value from choices.r]   r^   r_   r`   F_options_for_)r   optionsrb   )r   rP   r   r   r   r   r   rj   s          r$   r5   MenuOption.create_action   so       JJ
"&"A"A-"X
 k]#(+)!&#{{'}5
 	
r(   c                 
    SU4$ )z!Validate a menu option selection.Tr:   r*   s     r$   r8   MenuOption.validate_and_convert  s     U{r(   c                     [        U R                  5      (       a  U R                  X5      $ [        U R                  5      $ )z(Get the list of choices for this option.callabler   listr#   r1   r2   s      r$   get_choicesMenuOption.get_choices  s/    DLL!!<<--DLL!!r(   r:   )r;   r<   r=   r>   r?   r   r   r   rA   r   r@   rM   r   rB   r   r%   r   r+   r   r.   r   r   r5   rC   rD   r8   r   rE   r:   r(   r$   r   r      s    DIY]C^GT#Y68"4d3i"?@@^Is ,0M4S>D(/
 
C 
C 

# s s 'c 'd38n '/ /S /T#s(^ /
's 'tCH~ '/ /c /d3PS8n /


 
 	

 
 
 

6# %c	2B 
" " "T#Y "r(   r   c                   .    \ rS rSrSrS\S\S\4S jrSrg)	TeamModeOptioni!  zMenu option specialized for team modes.

Stores team modes in internal format ("individual", "2v2", "2v2v2") but
displays them in localized format ("Individual", "2 teams of 2").
r   r   r   c                 0    SSK Jn  UR                  X5      $ )z>Convert internal team mode format to localized display format.r
   )TeamManager)teamsr   format_team_mode_for_display)r#   r   r   r   s       r$   r   #TeamModeOption.get_localized_choice)  s    &77FFr(   r:   N)r;   r<   r=   r>   r?   rA   r   rE   r:   r(   r$   r   r   !  s%    G# Gs Gs Gr(   r   c                       \ rS rSr% SrSr\\S'   S\S\S\4S jr	S	 r
S\S\\\4   4S
 jrS\S\\\4   4S jrS\SSSSS\S\S\4S jrS\S\\\4   4S jrSrg)
BoolOptioni0  z_Boolean toggle option.

Attributes:
    value_key: Localization placeholder key for the value.
enabledrM   r   r   r   c                     U(       a  SOSn[         R                  " X5      n[         R                  " XR                  40 U R                  U0D6$ )N	option-on
option-off)r   rP   r   rM   )r#   r   r   
on_off_keyon_offs        r$   r%   BoolOption.get_label:  s>    $)[|
!!&5

Ot~~v6NOOr(   c                     SU l         g)z$Disable prompts for boolean toggles.r   Nr   r#   s    r$   __post_init__BoolOption.__post_init__?  s     r(   c                 2    U R                   U(       a  S0$ S0$ )rT   onoffrU   r*   s     r$   r+   BoolOption.get_label_kwargsD      99599r(   c                 2    U R                   U(       a  S0$ S0$ )rZ   r   r   rU   r*   s     r$   r.   BoolOption.get_change_kwargsH  r   r(   r0   r1   r   r2   r   r3   c           	          U(       a  SOSn[         R                  " XV5      n[         R                  " XPR                  40 U R                  U0D6n[	        SU 3USSSSS9$ )	z+Create a toggle action for boolean options.r   r   toggle__action_toggle_optionr_   r`   Frc   r   rd   re   rf   rg   )r   rP   r   rM   r   )	r#   r0   r1   r2   r3   r   r   r   r   s	            r$   r5   BoolOption.create_actionL  se     %2[|
!!&5  P7OP&++)!&
 	
r(   c                 ,    SUR                  5       S;   4$ )zValidate a boolean input value.T)true1yes)lowerr*   s     r$   r8   BoolOption.validate_and_convertc  s     U[[]&::::r(   r   N)r;   r<   r=   r>   r?   rM   rA   r@   r   r%   r   rB   r+   r.   r   r5   rC   rD   r8   rE   r:   r(   r$   r   r   0  s     IsP PC PC P

:c :d38n ::s :tCH~ :

 
 	

 
 
 

.;# ;%c	2B ;r(   r   c            
       B    \ rS rSr% Sr\\S'   S\SSSSS	\S
\4
S jrSr	g)OptionGroupMetaii  zyMetadata for an option group (sub-menu of options).

Attributes:
    label: Localization key for the group header label.
r   
group_namer1   r   r2   r   r   r   c           	      d    [         R                  " X@R                  5      n[        SU 3USSSSS9$ )z9Create an action that opens this option group's sub-menu.group__action_open_option_groupr_   r`   Fr   )r   rP   r   r   )r#   r   r1   r2   r   r   s         r$   r5   OptionGroupMeta.create_actions  s>       4
|$/+)!&
 	
r(   r:   N)
r;   r<   r=   r>   r?   rA   r@   r   r5   rE   r:   r(   r$   r   r   i  sC     J

 
 	

 
 

r(   r   c                      \ rS rSr% Sr\" \S9r\\   \	/ \\   4   -  \
S'   Sr\\
S'   Sr\\
S'   S	r\\\4   S	-  \
S
'   Sr\\
S'   S	r\\\\   4   \	/ \\\\   4   4   -  S	-  \
S'   S\\   4S jrS\\\\   4   S	-  4S jrS\S\S\4S jrS\S\\\4   4S jrS\S\\\4   4S jrS\SSSSS\S\S\4S jrS\S\\\4   4S jrSrg	)MultiSelectOptioni  a  Multi-select option where multiple choices can be toggled on/off.

Stores a list of selected choice strings. Displayed as a sub-menu of
boolean toggles.

Attributes:
    choices: Static list or no-arg callable returning available choices.
    min_selected: Minimum number of choices that must be selected.
    max_selected: Maximum number of choices that can be selected (0 = no limit).
    choice_labels: Optional mapping of choice -> localization key for display.
    show_bulk_actions: If True, show "Select all" / "Deselect all" in the toggle list.
    groups: Optional grouping of choices. When set, the top-level multi-select
        shows group names as navigable sub-menus instead of individual choices.
        Dict maps group name -> list of choice strings in that group.
r   r   r
   min_selectedr   max_selectedNr   Fshow_bulk_actionsgroupsr   c                     [        U R                  5      (       a  U R                  5       $ [        U R                  5      $ )z"Get the list of available choices.r   r   s    r$   r   MultiSelectOption.get_choices  s,    DLL!!<<>!DLL!!r(   c                     U R                   c  g[        U R                   5      (       a  U R                  5       $ [        U R                   5      $ )zGet the group mapping, if any.N)r   r   rB   r   s    r$   
get_groupsMultiSelectOption.get_groups  s9    ;;DKK  ;;= DKK  r(   r   r   c                     U R                   (       a2  XR                   ;   a#  [        R                  " X R                   U   5      $ U$ r   r   r   s      r$   r   &MultiSelectOption.get_localized_choice  r   r(   c                 z    [        U[        5      (       a  [        U5      OS[        U R                  5       5      S.$ )z<Return label formatting kwargs for the current value (list).r   counttotal
isinstancer   lenr   r*   s     r$   r+   "MultiSelectOption.get_label_kwargs  4     $.eT#:#:SZ))+,
 	
r(   c                 z    [        U[        5      (       a  [        U5      OS[        U R                  5       5      S.$ )rZ   r   r   r   r*   s     r$   r.   #MultiSelectOption.get_change_kwargs  r   r(   r0   r1   r   r2   r   r3   c           	          [        U[        5      (       a  [        U5      OSn[        R                  " XPR
                  40 U R                  U5      D6n[        SU 3USSSSS9$ )z6Create an action that opens the multi-select sub-menu.r   multiselect__action_open_multiselectr_   r`   Fr   )r   r   r   r   rP   r   r+   r   )r#   r0   r1   r2   r3   r   r   r   s           r$   r5   MultiSelectOption.create_action  sf     '1&E&EM"1  \t7L7L]7[\k]+.+)!&
 	
r(   c                 
    SU4$ )z=Not used for multi-select (toggles are handled individually).Tr:   r*   s     r$   r8   &MultiSelectOption.validate_and_convert  s    U{r(   r:   )r;   r<   r=   r>   r?   r   r   r   rA   r   r@   r   rn   r   r   rB   r   rD   r   r   r   r   r   r+   r.   r   r5   rC   r8   rE   r:   r(   r$   r   r     su     493NGT#Y"d3i-00NL#L#+/M4S>D(/#t#OSFDd3i 8BS$s)^0D,D#EELS"T#Y "!Dd3i047 !# s s 
c 
d38n 

s 
tCH~ 


 
 	

 
 
 

(# %c	2B r(   r   r   r   c                 ,    [        U S9n[        SSU0S9$ )zCreate a dataclass field for an option group (sub-menu header).

Args:
    label: Localization key for the group label.

Returns:
    Dataclass field with OptionGroupMeta in metadata.
)r   Noption_group_metar   metadata)r   r   )r   metas     r$   option_groupr     s!     'D)<d(CDDr(   r   c                     [        U R                  [        5      (       a  [        U R                  5      O/ n[        U4S jSU 0S9$ )zCreate a dataclass field for a multi-select option.

Args:
    meta: MultiSelectOption metadata instance.

Returns:
    Dataclass field configured for multi-select options.
c                     [        U 5      $ rO   )r   )ds    r$   <lambda>$multi_select_field.<locals>.<lambda>  s    d1gr(   option_meta)r   r   )r   r   r   r   )r   default_vals     r$   multi_select_fieldr    s?     )34<<(F(F$t||$BK!,5& r(   N)groupvisible_when
value_whenr	  r
  r  c                    SU 0nUb  XS'   Ub  [        U[        5      (       a  U/nX$S'   Ub  [        U[        5      (       a  U/nX4S'   [        U R                  US9$ )ar  Create a dataclass field with option metadata attached.

Args:
    meta: Option metadata instance.
    group: Name of the parent option group (None = top level).
    visible_when: One or more (option_name, predicate) tuples. The option
        is hidden when any predicate returns False for its referenced
        option's value (AND logic).
    value_when: One or more (option_name, predicate, forced_value, enforce)
        tuples. When predicate(ref_value) is True, this option is set to
        forced_value. If enforce is True, the option is also locked.

Returns:
    Dataclass field configured for declarative options.
r  r   r
  r  r   )r   rC   r   r   )r   r	  r
  r  r   s        r$   option_fieldr    sq    8 t$H#( lE**(>L#/ j%(($J!+99r(   options_class
field_namec                     [        U 5       H0  nUR                  U:X  d  M  UR                  R                  S5      s  $    g)z'Get OptionMeta for a field, if present.r  Nr   namer   rP   r  r  fs      r$   get_option_metar  #  s5    M"66Z::>>-00 # r(   c                     0 n[        U 5       H1  nUR                  R                  S5      nUc  M#  X1UR                  '   M3     U$ )z3Get all OptionMeta instances from an options class.r  r   r   rP   r  r  resultr  r   s       r$   get_all_option_metasr  +  s@    FM"zz~~m,!166N # Mr(   c                     0 n[        U 5       H1  nUR                  R                  S5      nUc  M#  X1UR                  '   M3     U$ )z8Get all OptionGroupMeta instances from an options class.r   r  r  s       r$   get_all_option_group_metasr  5  sA    FM"zz~~12!166N # Mr(   c                     [        U 5       H0  nUR                  U:X  d  M  UR                  R                  S5      s  $    g)z?Get the group name for an option field, if assigned to a group.r   Nr  r  s      r$   get_option_field_groupr  ?  s5    M"66Z::>>.11 # r(   c                     [        U 5       H0  nUR                  U:X  d  M  UR                  R                  S5      s  $    g)z@Get the visible_when conditions for an option field, if present.r
  Nr  r  s      r$   get_visibility_conditionsr   G  s7     M"66Z::>>.11 # r(   c            
           \ rS rSrSrS\\\4   4S jrS\S\	\   4S jr
S\\\4   4S jrS\S\4S	 jrS\S\4S
 jrS\SS4S jrSSSSS\	\   4S jrS\SSSSS\SS4
S jrSSSSS\4S jrSS jrSrg)GameOptionsiQ  zBase class for declarative game options.

Subclasses should use option_field() for options that need auto-generated
UI and handlers.
r   c                 *    [        [        U 5      5      $ )z2Get all option metadata for this options instance.)r  typer   s    r$   get_option_metasGameOptions.get_option_metasY  s    #DJ//r(   r   c                     / nU R                  5       R                  5        H0  u  p4[        X5      nUR                  UR	                  X5      5        M2     U$ )zGReturn a list of localized label strings for all current option values.)r%  itemsgetattrappendr%   )r#   r   linesr  r   r3   s         r$   format_options_summary"GameOptions.format_options_summary]  sK    //1779JD#D/MLL>? : r(   c                 *    [        [        U 5      5      $ )z8Get all option group metadata for this options instance.)r  r$  r   s    r$   get_option_group_metas"GameOptions.get_option_group_metase  s    )$t*55r(   r  c                     [        [        U 5      U5      nU(       d  gU H   u  p4[        XS5      nU" U5      (       a  M     g   g)zBCheck if an option passes all visible_when conditions (AND logic).TNF)r   r$  r)  )r#   r  
conditionsref_name	predicate	ref_values         r$   _is_option_visibleGameOptions._is_option_visiblei  sD    .tDz4@
#-H5IY'' $. r(   c                    [        U 5      n[        U5       Hj  nUR                  U:w  a  M  UR                  R	                  S5      nU(       d    gU H+  u  pVpxU(       d  M  [        XS5      n	U" U	5      (       d  M*      g     g   g)zCheck if an option's value is currently locked by value_when + enforce.

Returns True when any value_when entry has enforce=True and its
predicate is currently active.
r  FNT)r$  r   r  r   rP   r)  )
r#   r  r  r  	overridesr3  r4  _forced_valueenforcer5  s
             r$   _is_value_enforcedGameOptions._is_value_enforcedt  s|     T
&Avv~

|4I?H;]7 ' =I ++#	 @I
  ' r(   changed_optionNc                    [        U 5      n[        XS5      n[        U5       H_  nUR                  R	                  S5      nU(       d  M'  U H2  u  pgpXa:w  a  M  U" U5      (       d  M  [        XR                  U5        M4     Ma     g)zApply value_when overrides triggered by a change to changed_option.

Scans all option fields for value_when conditions referencing
changed_option. When the predicate matches, sets the dependent
option to the forced value.
Nr  )r$  r)  r   r   rP   setattrr  )
r#   r>  r  changed_valuer  r9  r3  r4  forced_value_enforces
             r$   _apply_value_overrides"GameOptions._apply_value_overrides  ss     T
d;&A

|4I?H;\-]++D&&,7	 @I	 'r(   r1   r   r2   r   c                 t    [        US5      (       a&  UR                  R                  UR                  / 5      $ / $ )z5Get the current options navigation path for a player._options_path)hasattrrG  rP   rc   r   s      r$   _get_options_pathGameOptions._get_options_path  s1    4))%%))&))R88	r(   
action_setc                  
  ^ U R                  X#5      n[        U 5      nU(       Ga  US   nUR                  S5      (       Ga  [        U5      S:  Ga  US   nUR	                  S5      n	[        Xh5      n
U
(       Ga^  [        U
[        5      (       GaH  U
R                  5       nU(       Ga0  X;   Ga*  X   n[        X/ 5      mU Hd  nUT;   nU(       a  SOSn[        R                  " XO5      nU
R                  X5      nU SU 3nUR                  [        SU S	U 3US
SSSS95        Mf     U
R                  (       aj  UR                  [        SU 3[        R                  " US5      SSSSS95        UR                  [        SU 3[        R                  " US5      SSSSS95        [        R                  " US5      nUR                  [        SUSSSSS95        g[        Xg5      n
U
(       Ga  [        U
[        5      (       Ga  [        X/ 5      mU
R                  5       nU(       ah  UR!                  5        HS  u  p[#        U4S jU 5       5      n[        U5      nU	 SU SU S3nUR                  [        SU S	U	 3USSSSS95        MU     OU
R%                  5       nU Hd  nUT;   nU(       a  SOSn[        R                  " XO5      nU
R                  X5      nU SU 3nUR                  [        SU S	U 3US
SSSS95        Mf     U
R                  (       aj  UR                  [        SU 3[        R                  " US5      SSSSS95        UR                  [        SU 3[        R                  " US5      SSSSS95        [        R                  " US5      nUR                  [        SUSSSSS95        gUnOSnU R'                  5       R!                  5        H<  u  n	n[)        Xi5      nUU:X  d  M  UR+                  XX45      nUR                  U5        M>     U R-                  5       R!                  5        H  u  nn
[)        UU5      nUU:w  a  M  U R/                  U5      (       d  M2  [        U U5      nU
R+                  UX#UU5      nU R1                  U5      (       a  S Ul        S!Ul        UR                  U5        M     U(       a5  [        R                  " US5      nUR                  [        SUSSSSS95        gg)"zBPopulate an action set with options for the player's current path.group:r   r   r   z: 	mstoggle___action_toggle_multiselectr_   r`   Fr   mselectall_zoption-select-all_action_select_all_multiselectmdeselectall_zoption-deselect-all _action_deselect_all_multiselectzoption-backoptions_back_action_options_backNc              3   6   >#    U  H  oT;   d  M
  S v   M     g7f)r
   Nr:   ).0ccurrent_selectionss     r$   	<genexpr>3GameOptions._populate_action_set.<locals>.<genexpr>  s     ,a1N`I`QQs   		z (z of z
 selected)msgroup__action_open_ms_group _action_options_back_multiselect_is_always_disabledzoption-locked)rI  r$  
startswithr   removeprefixr  r   r   r   r)  r   rP   r   addr   r   r(  sumr   r/  r  r5   r%  r6  r<  re   disabled_message)r#   rK  r1   r2   r   pathr  current_levelr0   r   r   r   group_choiceschoiceselectedr   r   displayr   
back_labelselected_counttotal_countr   target_group
group_metagroup_parentactionr  option_group_namer3   r\  s                                 @r$   _populate_action_set GameOptions._populate_action_set  s-    %%d3T
 HM ''11c$i1n"2h*77A
&}BJt->??!__.F*"6(.(:-4T-K*&3F'-1C'CH8@lJ%1%5%5f%IF&*&?&?&OG'.ir&$:E&NN &)2;-q'I*/,H/C.A9>!"	 '4"  11&NN &)4[M'B*6*:*:6CV*W,L/C.A9>!"	 'NN &)6{m'D*6*:*:6CX*Y,N/C.A9>!"	 &2%5%5fm%L
""#1&0(>+?*=5:	  #=@D
4):;;%,T"%E"*5;\\^1
),,a,a)a&)-&8#-,b0@[MQ[ \""%-m_Aj\#J&+(?+?*=5:		 6D  #..0G")#)-?#?4<[,
!-!1!1&!E"&";";F"K#*)2fX 6""%.}oQvh#G&+(D+?*=5:	 #*" --""%0#@&2&6&6v?R&S(H+?*=5:	 #"%2=/#B&2&6&6v?T&U(J+?*=5:	 *--fmD
)( B#7"5-2	  )L  L '+&A&A&C&I&I&K"J
1-LL|+#11*FSv& 'L //1779JD$ 6}d K L0**400#D$/M''dM6RF&&t,,$9!*9'NN6" :  %))&-@JNN%$231).	 r(   c                     UR                  U5      nU(       a  UR                  OSn[        SS9nU R                  XQX$5        U$ )zKCreate an ActionSet with options for the player's current navigation level.enr   r  )get_userr   r   rv  )r#   r1   r2   userr   rK  s         r$   create_options_action_set%GameOptions.create_options_action_sete  s=    }}V$ $$I.
!!*FCr(   c                 |   UR                    H  nUR                  US5      nU(       an  UR                  R                  5         UR                  R                  5         UR                  U5      nU(       a  UR                  OSnU R                  X1X%5        M  U R                  X5      nUR                  X&5        M     g)zUpdate options action sets for all players to reflect current values.

Updates the existing action set in-place to avoid duplicates.
r   ry  N)
playersget_action_set_actionsclear_orderr{  r   rv  r}  add_action_set)r#   r1   r2   existing_setr|  r   new_options_sets          r$   update_options_labels!GameOptions.update_options_labelsm  s    
 llF..vyAL%%++-##))+}}V,(,$)),fM"&"@"@"N##F< #r(   r:   )r1   r   r   N)r;   r<   r=   r>   r?   rB   rA   r   r%  r   r,  r   r/  rD   r6  r<  rD  rI  r   rv  r}  r  rE   r:   r(   r$   r"  r"  Q  s    0$sJ"7 0S T#Y 6S/-A(B 6	s 	t 	s t *8S 8T 8&f h 49 A#A+1A;CAMPA	AFf h 9 =r(   r"  c            	         ^  \ rS rSrSrSSS\4S jrSSS\4U 4S jjrSSS\	4S jr
S	\S
\SS4S jrS	\SS4S jrSSS
\S\SS4S jrSSS\SS4S jrSSS\SS4S jrSSS\SS4S jrSSS\SS4S jrSSS\SS4S jrSSS\SS4S jrSSS\SS4S jrSSS	\SSS\\   4S jrSSS\SS4S jrSSS\SS4S jrSSS\S\4S jrSrU =r$ )OptionsHandlerMixini  zHandle declarative options for games.

Expected Game attributes:
    options: GameOptions instance.
    get_user(player) -> User | None.
    rebuild_all_menus().
    _options_path: dict[str, list[str]] (player_id -> navigation stack).
r2   r   r   c                     [        U S5      (       a.  [        U R                  R                  UR                  5      5      $ g)z8Check if a player is navigated into an options sub-menu.rG  F)rH  rD   rG  rP   rc   r#   r2   s     r$   _is_in_options_submenu*OptionsHandlerMixin._is_in_options_submenu  s2    4))**..vyy9::r(   c                    > U R                  U5      (       a,  U R                  US5      nU(       a  UR                  X5      $ / $ [        TU ]  U5      $ )zGet visible actions, filtering to only options when in a sub-menu.

When a player is inside an options group or multi-select, only the
options action set is shown (no lobby/turn actions cluttering the menu).
r   )r  r  get_visible_actionssuperget_all_visible_actions)r#   r2   options_set	__class__s      r$   r  +OptionsHandlerMixin.get_all_visible_actions  sQ     &&v..--fi@K"66tDDIw.v66r(   c                     [        U R                  S5      (       a  U R                  R                  X5      $ [        SS9$ )zCreate the options action set for a player.

If the game's options class uses declarative options (option_field),
this will auto-generate the action set. Otherwise, subclasses should
override this method.
r}  r   rz  )rH  r   r}  r   r  s     r$   r}  -OptionsHandlerMixin.create_options_action_set  s6     4<<!<==<<99$GGi((r(   r0   r   Nc                 v   [        [        U R                  5      U5      nU(       d  gUR                  U5      u  pEU(       d  g[	        U R                  X5        U R                  R                  U5        [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g)z6Handle a declarative option change (int/menu options).Nr  )	r  r$  r   r8   r@  rD  rH  r  rebuild_all_menus)r#   r0   r   r   success	converteds         r$   _handle_option_change)OptionsHandlerMixin._handle_option_change  s    tDLL1;?!66u= 	k5++K8 4<<!899LL..t4 r(   c                 z   [        [        U R                  5      U5      nU(       d  g[        U R                  U5      nU(       + n[	        U R                  X5        U R                  R                  U5        [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g)z+Handle a declarative boolean option toggle.Nr  )	r  r$  r   r)  r@  rD  rH  r  r  )r#   r0   r   current	new_values        r$   _handle_option_toggle)OptionsHandlerMixin._handle_option_toggle  s    tDLL1;? $,,4K	k5++K8 4<<!899LL..t4 r(   	action_idc                 H    UR                  S5      nU R                  XB5        g)zGeneric handler for setting an option value.

Extracts the option name from action_id (e.g., "set_total_rounds" -> "total_rounds")
and delegates to _handle_option_change.
r]   N)rd  r  )r#   r2   r   r  r0   s        r$   r^   &OptionsHandlerMixin._action_set_option  s"      ,,V4"";6r(   c                 H    UR                  S5      nU R                  U5        g)zGeneric handler for toggling a boolean option.

Extracts the option name from action_id (e.g., "toggle_show_hints" -> "show_hints")
and delegates to _handle_option_toggle.
r   N)rd  r  )r#   r2   r  r0   s       r$   r   )OptionsHandlerMixin._action_toggle_option  s"      ,,Y7"";/r(   c                 P   UR                  S5      n[        U S5      (       d  0 U l        U R                  R                  UR                  / 5      nUR                  U5        [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g)zkOpen an option group's sub-menu.

Pushes the group name onto the player's options path and rebuilds menus.
r   rG  r  N	rd  rH  rG  
setdefaultrc   r*  r   r  r  )r#   r2   r  r   rh  s        r$   r   -OptionsHandlerMixin._action_open_option_group  s    
 ++H5
t_--!#D!!,,VYY;J4<<!899LL..t4 r(   c                 P   UR                  S5      n[        U S5      (       d  0 U l        U R                  R                  UR                  / 5      nUR                  U5        [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g)zrOpen a multi-select option's sub-menu.

Pushes the option name onto the player's options path and rebuilds menus.
r   rG  r  Nr  )r#   r2   r  r0   rh  s        r$   r   ,OptionsHandlerMixin._action_open_multiselect  s    
  ,,^<t_--!#D!!,,VYY;K 4<<!899LL..t4 r(   c                 ,   [        U S5      (       a=  U R                  R                  UR                  / 5      nU(       a  UR	                  5         [        U R
                  S5      (       a  U R
                  R                  U 5        U R                  5         g)zuGo back one level in the options navigation.

Pops the last group from the player's options path and rebuilds menus.
rG  r  N)rH  rG  rP   rc   popr   r  r  )r#   r2   r  rh  s       r$   rX  (OptionsHandlerMixin._action_options_back  si    
 4))%%))&))R8D
4<<!899LL..t4 r(   c                 >   UR                  S5      nU R                  R                  5       R                  5        H  u  pE[	        U[
        5      (       d  M  UR                  US-   5      (       d  M7  U[        U5      S-   S n[        U S5      (       d  0 U l	        U R                  R                  UR                  / 5      nUR                  SU 35        [        U R                  S5      (       a  U R                  R                  U 5        U R                  5           g   g)zOpen a multi-select group's sub-menu.

Action ID format: msgroup_{option_name}_{group_name}
Pushes 'group:{name}' onto the player's options path.
r_  rQ  r
   NrG  rN  r  )rd  r   r%  r(  r   r   rc  r   rH  rG  r  rc   r*  r  r  )r#   r2   r  	remainderr  r   r   rh  s           r$   r`  )OptionsHandlerMixin._action_open_ms_group  s     **:6	,,779??AJD$ 122y7K7KDSVJ7W7W&s4y1}7
t_55)+D&))44VYYCfZL124<<)@AALL66t<&&( Br(   c                 f   UR                  S5      n[        [        U R                  5      U5      nU(       a  [	        U[
        5      (       d  g[        [        U R                  U/ 5      5      nU R                  XU5      nSnU H   nX;  d  M
  UR                  U5        US-  nM"     [        U R                  X55        US:  a(  U R                  U5      n	U	(       a  U	R                  SUS9  [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g)z|Select all choices in the current multi-select view.

Scoped to current group if inside one. Announces how many were added.
rS  Nr   r
   zoption-selected-countr   r  )rd  r  r$  r   r   r   r   r)  _get_scoped_choicesr*  r@  r{  speak_lrH  r  r  )
r#   r2   r  r0   r   current_listr   addedrk  r|  s
             r$   rT  2OptionsHandlerMixin._action_select_all_multiselect   s    
  ,,];tDLL1;?:d,=>>GDLL+rBC**6EF)##F+
 
 	k819==(D4EB4<<!899LL..t4 r(   c                 f   UR                  S5      n[        [        U R                  5      U5      nU(       a  [	        U[
        5      (       d  g[        [        U R                  U/ 5      5      nU R                  XU5      nSnU H   nX;   d  M
  UR                  U5        US-  nM"     [        U R                  X55        US:  a(  U R                  U5      n	U	(       a  U	R                  SUS9  [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g)zDeselect all choices in the current multi-select view.

Scoped to current group if inside one. Announces how many were removed.
rU  Nr   r
   zoption-deselected-countr  r  )rd  r  r$  r   r   r   r   r)  r  remover@  r{  r  rH  r  r  )
r#   r2   r  r0   r   r  r   removedrk  r|  s
             r$   rV  4OptionsHandlerMixin._action_deselect_all_multiselect>  s    
  ,,_=tDLL1;?:d,=>>GDLL+rBC**6EF%##F+1 
 	k8Q;==(D6gF4<<!899LL..t4 r(   r   r   c                 8   [        U S5      (       az  U R                  R                  UR                  / 5      nU(       aM  US   R	                  S5      (       a4  US   R                  S5      nUR                  5       nU(       a	  XV;   a  Xe   $ UR                  5       $ )zGet the choices scoped to the current view (group or all).

If the player is inside a group, returns only that group's choices.
Otherwise returns all choices.
rG  rM  rN  )rH  rG  rP   rc   rc  rd  r   r   )r#   r2   r0   r   rh  r   r   s          r$   r  'OptionsHandlerMixin._get_scoped_choices\  s     4))%%))&))R8DR++H55!"X228<
*j2!--!!r(   c                    [        U S5      (       Ga  U R                  R                  UR                  / 5      nU(       Ga|  US   nUR	                  S5      (       aW  UR                  5         [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g[        [        U R                  5      U5      nU(       a  [        U[        5      (       a  [        U R                  U/ 5      n[        U5      UR                  :  a3  U R!                  U5      nU(       a  UR#                  SUR                  S9  gUR$                  S:  aL  [        U5      UR$                  :  a3  U R!                  U5      nU(       a  UR#                  S	UR$                  S9  gUR                  5         [        U R                  S5      (       a  U R                  R                  U 5        U R                  5         g)
z=Go back from a multi-select menu, validating selection count.rG  rM  rN  r  Nzoption-min-selectedr  r   zoption-max-selected)rH  rG  rP   rc   rc  r  r   r  r  r  r$  r   r   r)  r   r   r{  r  r   )r#   r2   r  rh  r  r   r  r|  s           r$   ra  4OptionsHandlerMixin._action_options_back_multiselectm  s}   4))%%))&))R8Dr(%%h//HHJt||-DEE::4@**,&tDLL'97CJt->??#*4<<"#EL<(4+<+<<#}}V4 LL)>dFWFWLX((1,\1BTEVEV1V#}}V4 LL)>dFWFWLX
4<<!899LL..t4 r(   c                    UR                  S5      n[        U R                  5      nSnSnU R                  R                  5       R	                  5        HJ  u  px[        U[        5      (       d  M  UR                  US-   5      (       d  M7  UnU[        U5      S-   S n  O   U(       a  Uc  g[        XE5      nU(       a  [        U[        5      (       d  g[        [        U R                  U/ 5      5      n	Xi;   a  U	R                  U5        OU	R                  U5        [        U R                  XY5        [        U R                  S5      (       a  U R                  R!                  U 5        U R#                  5         g)z]Toggle a choice in a multi-select option.

Action ID format: mstoggle_{option_name}_{choice}
rP  NrQ  r
   r  )rd  r$  r   r%  r(  r   r   rc  r   r  r   r)  r  r*  r@  rH  r  r  )
r#   r2   r  r  r  r0   rk  r  r   r  s
             r$   rR  .OptionsHandlerMixin._action_toggle_multiselect  s.    **;7	T\\*,,779??AJD$ 122y7K7KDSVJ7W7W""3t9q=?3	 B
 fn}::d,=>>GDLL+rBC!''k84<<!899LL..t4 r(   menu_item_idc                 B   SnS H,  nUR                  U5      (       d  M  UR                  U5      n  O   Uc  g[        [        U R                  5      U5      nUb  UR
                  (       d  gU R                  U5      nU(       a  UR                  UR
                  5        g)zSpeak the description for an option when space is pressed.

Extracts the option name from the action ID and looks up its
description. Returns True if a description was spoken.
N)r]   r   r   r   FT)rc  rd  r  r$  r   r   r{  r  )r#   r2   r  r0   prefixr   r|  s          r$   _speak_option_description-OptionsHandlerMixin._speak_option_description  s     CF&&v..*77? D tDLL1;?<t//}}V$LL))*r(   )rG  )r;   r<   r=   r>   r?   rD   r  r   r  r   r}  rA   r  r  r^   r   r   r   rX  r`  rT  rV  r  ra  rR  r  rE   __classcell__)r  s   @r$   r  r    s   X $ 7h 74 7
) 
)Y 
)! !S !T !&! ! !&7 7# 7# 7RV 70H 0 0 0! !S !T !!x !C !D !!8 ! ! !H   (!X !# !RV !<!x !C !TX !<""-0"8K"	c""!x !C !TX !@!! !!c !!d !!F  PT  r(   r  )-r?   dataclassesr   r   r   typingr   r   r   mashumaro.mixins.jsonr	   actionsr   r   r   r   messages.localizationr   
games.baser   r   r   rG   ru   r   r   r   r   r   rA   r   r  rC   rD   r   r  r$  r  rB   r  r  r  r   r"  r  r:   r(   r$   <module>r     s  4 1 0 / / 4 ? ? 0) ." ." ."b 6 
 6  6 r 6 * 6  6 r P" P" P"f GZ G G 5; 5; 5;p 
 
 
8 P
 P Pf
E 
E 
E. 3 &  	
 	):
): :):
 	c8SE4K(()DsHcUD[<Q7Q1R,SSVZZ): 	c8SE4K(#t34
uS(C5$;/d:;
<	=
	): 	):X4 S Z$=N  c:o1F d tC<P7Q $ C C$J %(	%XseTk**
+,t3 j=$ j= j=Z	D Dr(   