
    IiW                        S r SSKJr  SSKJr  SSKJrJrJr  SSK	J
r
  SSKJr  SSKJr  \(       a  S	S
KJr   " S S5      rg)z
Mixin for dice-based games that use the DiceSet keep/lock mechanics.

Provides shared functionality for games like Threes and Yahtzee that have
dice toggling via 1-5/1-6 keys depending on user preferences.
    )annotations)TYPE_CHECKING   )Action	ActionSet
Visibility)KeybindState)DiceKeepingStyle)Localization   )Playerc                     \ rS rSrSrS,S-S jjrS,S.S jjrSS.S/S jjrSS.     S/S jjrS0S	 jr	S0S
 jr
S1S jrS2S jrS3S jrSS.S4S jjrSS.S4S jjrSS.S4S jjrSS.S4S jjrSS.S4S jjrSS.S4S jjrSS.S5S jjrSS.S5S jjrSS.S5S jjrSS.S5S jjrSS.S5S jjrSS.S5S jjrS0S jrS0S jrS0S jrS0S jrS0S jrS0S jrS6S  jr S7S! jr!S8S" jr"S9S# jr#S9S$ jr$S9S% jr%S:S& jr&S;S' jr'S<S( jr(S;S) jr)S;S* jr*S+r+g)=DiceGameMixin   a  Provide dice toggle actions for DiceSet-based games.

Supports two keeping styles:
    - Dice indexes: keys 1-5 toggle dice by index.
    - Dice values: keys 1-6 keep by face value; shift+1-6 reroll by value.

Expected Game attributes:
    get_user(player) -> User.
    get_action_set(player, name) -> ActionSet.
    rebuild_player_menu(player).
    Player objects with a `dice: DiceSet` attribute.

Required Game methods:
    _is_dice_toggle_enabled(player, die_index) -> str | None.
    _is_dice_toggle_hidden(player, die_index) -> Visibility.
    _get_dice_toggle_label(player, die_index) -> str.

Example:
    class MyGame(Game, DiceGameMixin):
        def create_turn_action_set(self, player):
            action_set = ActionSet(name="turn")
            self.add_dice_toggle_actions(action_set)
            return action_set

        def setup_keybinds(self):
            super().setup_keybinds()
            self.setup_dice_keybinds()
c                F   [        U5       H7  nUR                  [        SU 3SUS-    3SSU S3SU S3SU S	3S
S
S95        M9     [        SS5       HK  nUR                  [        SU 3SU 3SSSSSS95        UR                  [        SU 3SU 3SSSSSS95        MM     g)a  
Add dice toggle actions to an action set.

Adds both index-based toggle actions (for menu items) and
keybind-triggered actions that respect user preferences.

Args:
    action_set: The ActionSet to add actions to.
    num_dice: Number of dice (default 5).
toggle_die_Die r   _action_toggle_die_is_toggle_die__enabled_hidden_get_toggle_die__labelF)idlabelhandler
is_enabled	is_hidden	get_labelshow_in_actions_menushow_disabled_label   	dice_key_	Dice key _action_dice_key_is_dice_key_enabled_is_dice_key_hidden_get_dice_key_labelT)r   r   r   r   r   r   r    dice_unkeep_zUnkeep _action_dice_unkeep_is_dice_unkeep_enabled_get_dice_unkeep_labelN)rangeaddr   )self
action_setnum_diceivs        @c:\Users\dbart\PlayPalace11\server\game_utils\dice_game_mixin.pyadd_dice_toggle_actions%DiceGameMixin.add_dice_toggle_actions3   s     xANN$QC( Q.0!08< /s': 06:).(-	 !  q!ANN"1#%aS/.533)-
 NN%aS)#A3-1836)-
     c                    [        SS5       H]  nU R                  [        U5      SU 3SU 3/[        R                  S9  U R                  SU 3SU 3SU 3/[        R                  S9  M_     g	)
z
Set up keybinds for dice toggling.

Defines keybinds for both styles:
- Keys 1-6 trigger dice_key_X (style determines behavior)
- Shift+1-6 trigger dice_unkeep_X (dice values style only)

Args:
    num_dice: Number of dice (default 5).
r   r"   r$   r#   )statezshift+zUnkeep dice r)   N)r-   define_keybindstrr	   ACTIVE)r/   r1   r3   s      r4   setup_dice_keybinds!DiceGameMixin.setup_dice_keybindsh   s     q!AAA3QC!"))	    qc"s#$"))	    r7   N)	action_idc               0   U R                   S:w  a  gU(       d  gU R                  U5      nU(       a(  UR                  R                  SU R	                  5       S9O[
        R                  n [        UR                  S5      S   5      n[        US	5      (       aI  U[
        R                  :X  a  XQR                  R                  :  a  gOXQR                  R                  :  a  gU[
        R                  :X  a;  U R                  XS
S9nUc  g[        U S5      (       a  U R!                  X5      nUb  gg[        U S5      (       aE  US-
  n[        US	5      (       a  XaR                  R                  :  a  gU R!                  X5      nUb  gg! [         a     gf = f)zBEnable dice keybind actions based on game state and keeping style.playingaction-not-playingNdice_keeping_style	game_type_action-not-availablediceF	want_kept_is_dice_toggle_enabledr   )statusget_userpreferencesget_effectiveget_typer
   
PLAYPALACEintsplit
ValueErrorhasattr	QUENTIN_CrI   sidesr1   _find_value_die_indexrL   r/   playerr?   userstylekey_num	die_indextoggle_reasons           r4   r&   "DiceGameMixin._is_dice_key_enabled   s}   ;;)#'}}V$  **+?4==?*[!,, 	
	*)//#.r23G 66""(222[[...1 /;;///-$...226e2TI -t677 $ < <V O ,14233!Ivv&&98L8L+L- 88KM(-1  	*)	*s   +F 
FFc               &   U R                   S:w  a  gU R                  U5      nU(       a(  UR                  R                  SU R	                  5       S9O[
        R                  nU[
        R                  :w  a  gU(       d  g [        UR                  S5      S   5      n[        US5      (       a  XQR                  R                  :  a  gU R                  XS	S
9nUc  g[        U S5      (       a  U R                  X5      nUb  gg! [         a     gf = f)z2Only enable unkeep keybinds for dice values style.rA   rB   rC   rD   rH   rF   rG   rI   TrJ   NrL   )rM   rN   rO   rP   rQ   r
   rR   rW   rS   rT   rU   rV   rI   rX   rY   rL   rZ   s           r4   r+   %DiceGameMixin._is_dice_unkeep_enabled   s
    ;;)#'}}V$  **+?4==?*[!,, 	
 $...))	*)//#.r23G 66""w1B1B'B)..v$.O	)4233 88KM(-  	*)	*s    D 
DDc                    [        UR                  S5      S   5      nU R                  U5      nU(       a(  UR                  R                  SU R                  5       S9O[        R                  nU[        R                  :X  a^  [        US5      (       aM  US-
  nXaR                  R                  :  a  SU 3$ UR                  R                  U5      (       a  SU 3$ SU 3$ S	U 3$ ! [         a    Us $ f = f)
z/Label for dice_key actions in the actions menu.rF   rG   rC   rD   rI   r   z	Keep die zReroll die zKeep )rS   rT   rU   rN   rO   rP   rQ   r
   rR   rV   rI   r1   is_kept)r/   r[   r?   r^   r\   r]   r_   s          r4   r(   !DiceGameMixin._get_dice_key_label   s    	)//#.r23G }}V$  **+?4==?*[!,, 	
 $///GFF4K4K!IKK000"7),,{{""9--$WI..wi((wi    		s   C& &C54C5c                l     [        UR                  S5      S   5      nSU 3$ ! [         a    Us $ f = f)z2Label for dice_unkeep actions in the actions menu.rF   rG   zReroll )rS   rT   rU   r/   r[   r?   r^   s       r4   r,   $DiceGameMixin._get_dice_unkeep_label   sE    	)//#.r23G 	""  		s   $ 33c                    g)zHook for values mode defaults after roll.

Keep state now follows each game's normal roll behavior so both dice
styles remain consistent.
N r/   r[   s     r4   _apply_dice_values_defaults)DiceGameMixin._apply_dice_values_defaults   s     	r7   c                  [        US5      (       d  gUR                  nUR                  (       d  g[        UR                  5       Hv  nUR                  U5      (       a  M  UR                  U5      U:w  a  M2  U(       a  UR                  U5      (       a  Us  $ U(       a  M\  UR                  U5      (       a  Mt  Us  $    g)z@Find a matching unlocked die index by face value and kept state.rI   N)rV   rI   
has_rolledr-   r1   	is_locked	get_valuere   )r/   r[   valuerK   rI   r2   s         r4   rY   #DiceGameMixin._find_value_die_index   s    vv&&{{t}}%A~~a  ~~a E)T\\!__9T\\!__ & r7   c                "    [         R                  $ )z6Dice keybind actions are always hidden (keybind only).)r   HIDDENrl   s     r4   r'   !DiceGameMixin._is_dice_key_hidden  s       r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z9Check if toggling die 0 is enabled (via generic handler).rF   rG   r   rS   rT   rL   r/   r[   r?   r_   s       r4   _is_toggle_die_0_enabled&DiceGameMixin._is_toggle_die_0_enabled  /    5>C	,R01A	++F>>r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z9Check if toggling die 1 is enabled (via generic handler).rF   rG   r   ry   rz   s       r4   _is_toggle_die_1_enabled&DiceGameMixin._is_toggle_die_1_enabled  r}   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z9Check if toggling die 2 is enabled (via generic handler).rF   rG   r   ry   rz   s       r4   _is_toggle_die_2_enabled&DiceGameMixin._is_toggle_die_2_enabled  r}   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z9Check if toggling die 3 is enabled (via generic handler).rF   rG      ry   rz   s       r4   _is_toggle_die_3_enabled&DiceGameMixin._is_toggle_die_3_enabled  r}   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z9Check if toggling die 4 is enabled (via generic handler).rF   rG      ry   rz   s       r4   _is_toggle_die_4_enabled&DiceGameMixin._is_toggle_die_4_enabled!  r}   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z9Check if toggling die 5 is enabled (via generic handler).rF   rG      ry   rz   s       r4   _is_toggle_die_5_enabled&DiceGameMixin._is_toggle_die_5_enabled&  r}   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z.Check if die 0 toggle action should be hidden.rF   rG   r   rS   rT   _is_dice_toggle_hiddenrz   s       r4   _is_toggle_die_0_hidden%DiceGameMixin._is_toggle_die_0_hidden+  /    5>C	,R01A	**6==r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z.Check if die 1 toggle action should be hidden.rF   rG   r   r   rz   s       r4   _is_toggle_die_1_hidden%DiceGameMixin._is_toggle_die_1_hidden0  r   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z.Check if die 2 toggle action should be hidden.rF   rG   r   r   rz   s       r4   _is_toggle_die_2_hidden%DiceGameMixin._is_toggle_die_2_hidden5  r   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z.Check if die 3 toggle action should be hidden.rF   rG   r   r   rz   s       r4   _is_toggle_die_3_hidden%DiceGameMixin._is_toggle_die_3_hidden:  r   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z.Check if die 4 toggle action should be hidden.rF   rG   r   r   rz   s       r4   _is_toggle_die_4_hidden%DiceGameMixin._is_toggle_die_4_hidden?  r   r7   c               p    U(       a  [        UR                  S5      S   5      OSnU R                  X5      $ )z.Check if die 5 toggle action should be hidden.rF   rG   r   r   rz   s       r4   _is_toggle_die_5_hidden%DiceGameMixin._is_toggle_die_5_hiddenD  r   r7   c                ^    [        UR                  S5      S   5      nU R                  X5      $ )z-Return the label for the die 0 toggle action.rF   rG   rS   rT   _get_dice_toggle_labelrz   s       r4   _get_toggle_die_0_label%DiceGameMixin._get_toggle_die_0_labelI  +    	,R01	**6==r7   c                ^    [        UR                  S5      S   5      nU R                  X5      $ )z-Return the label for the die 1 toggle action.rF   rG   r   rz   s       r4   _get_toggle_die_1_label%DiceGameMixin._get_toggle_die_1_labelN  r   r7   c                ^    [        UR                  S5      S   5      nU R                  X5      $ )z-Return the label for the die 2 toggle action.rF   rG   r   rz   s       r4   _get_toggle_die_2_label%DiceGameMixin._get_toggle_die_2_labelS  r   r7   c                ^    [        UR                  S5      S   5      nU R                  X5      $ )z-Return the label for the die 3 toggle action.rF   rG   r   rz   s       r4   _get_toggle_die_3_label%DiceGameMixin._get_toggle_die_3_labelX  r   r7   c                ^    [        UR                  S5      S   5      nU R                  X5      $ )z-Return the label for the die 4 toggle action.rF   rG   r   rz   s       r4   _get_toggle_die_4_label%DiceGameMixin._get_toggle_die_4_label]  r   r7   c                ^    [        UR                  S5      S   5      nU R                  X5      $ )z-Return the label for the die 5 toggle action.rF   rG   r   rz   s       r4   _get_toggle_die_5_label%DiceGameMixin._get_toggle_die_5_labelb  r   r7   c                    U R                   S:w  a  gU R                  U:w  a  g[        US5      (       d  gUR                  R                  (       d  gUR                  R                  U5      (       a  gg)	zBCheck if toggling die at index is enabled. Override in game class.rA   rB   zaction-not-your-turnrI   zdice-no-dicezdice-not-rolleddice-lockedN)rM   current_playerrV   rI   rp   rq   r/   r[   r_   s      r4   rL   %DiceGameMixin._is_dice_toggle_enabledh  s]    ;;)#'&()vv&&!{{%%$;;  ++ r7   c                :   U R                   S:w  a  [        R                  $ U R                  U:w  a  [        R                  $ [	        US5      (       d  [        R                  $ UR
                  R                  (       d  [        R                  $ [        R                  $ )z=Check if die toggle action is hidden. Override in game class.rA   rI   )rM   r   rv   r   rV   rI   rp   VISIBLEr   s      r4   r   $DiceGameMixin._is_dice_toggle_hiddenv  sr    ;;)#$$$&($$$vv&&$$${{%%$$$!!!r7   c                   [        US5      (       d  SUS-    3$ UR                  R                  U5      nUc  SUS-    3$ U R                  U5      nU(       a  UR                  OSnUR                  R                  U5      (       a  [        R                  " US5      nU SU S3$ UR                  R                  U5      (       a  [        R                  " US5      nU SU S3$ [        U5      $ )	z8Get label for die toggle action. Override in game class.rI   r   r   enzdice-status-lockedz ()zdice-status-kept)
rV   rI   rr   rN   localerq   r   getre   r;   )r/   r[   r_   die_valr\   r   rM   s          r4   r   $DiceGameMixin._get_dice_toggle_label  s    vv&&)a-))++''	2?)a-))}}V$ $$;;  ++!%%f.BCFYb**;;y))!%%f.@AFYb**7|r7   c                `    [        UR                  S5      S   5      nU R                  X5        g)zBHandle toggle_die_X action by extracting die index from action ID.rF   rG   N)rS   rT   _toggle_dierz   s       r4   r    DiceGameMixin._action_toggle_die  s*     	,R01	+r7   c                `    [        UR                  S5      S   5      nU R                  X5        g)zAHandle dice_key_X action by extracting key number from action ID.rF   rG   N)rS   rT   _handle_dice_keyrh   s       r4   r%   DiceGameMixin._action_dice_key  s*     iooc*2./f.r7   c                `    [        UR                  S5      S   5      nU R                  X5        g)z?Handle dice_unkeep_X action by extracting value from action ID.rF   rG   N)rS   rT   _handle_dice_unkeep)r/   r[   r?   rs   s       r4   r*   !DiceGameMixin._action_dice_unkeep  s*     IOOC(,-  /r7   c                V   U R                  U5      nU(       d  gUR                  R                  SU R                  5       S9nU[        R
                  :X  aC  US-
  n[        US5      (       a,  XQR                  R                  :  a  U R                  X5        gggU R                  X5        g)z
Handle a dice key press (1-6).

Behavior depends on user's dice keeping style preference:
- Dice indexes: Toggle die at index (key_num - 1)
- Dice values: Keep first unkept die with face value key_num
NrC   rD   r   rI   )rN   rO   rP   rQ   r
   rR   rV   rI   r1   r   _keep_by_value)r/   r[   r^   r\   r]   r_   s         r4   r   DiceGameMixin._handle_dice_key  s     }}V$  ../Ct}}._$///!Ivv&&9{{7K7K+K  3 ,L& 0r7   c                    U R                  U5      nU(       d  gUR                  R                  SU R                  5       S9nU[        R
                  :X  a  U R                  X5        gg)zp
Handle shift+key press for rerolling by value.

Only works in dice values style. Silent in dice indexes style.
NrC   rD   )rN   rO   rP   rQ   r
   rW   _unkeep_by_value)r/   r[   rs   r\   r]   s        r4   r   !DiceGameMixin._handle_dice_unkeep  s\     }}V$  ../Ct}}._$...!!&0 /r7   c                |   [        US5      (       d  gU R                  U5      nUR                  R                  U5      nUc  U(       a  UR	                  S5        gUR                  R                  U5      nU(       a  U(       a  UR	                  SUS9  OU(       a  UR	                  SUS9  U R                  U5        g)z
Toggle keeping a die by index.

Handles the common logic for toggling dice in games using DiceSet.
Speaks the appropriate message (keeping/rerolling/locked).
rI   Nr   dice-keepingrs   dice-rerolling)rV   rN   rI   toggle_keepspeak_lrr   rebuild_player_menu)r/   r[   r_   r\   resultr   s         r4   r   DiceGameMixin._toggle_die  s     vv&&}}V$((3>]+++''	2^7; -W=  (r7   c                   [        US5      (       d  gU R                  U5      nUR                  n[        UR                  5       H  nUR                  U5      (       a  M  UR                  U5      (       a  M3  UR                  U5      U:X  d  MJ  UR                  U5        U(       a  UR                  SUS9  U R                  U5          g   g)z
Keep the first unkept die with the given face value.

Used in dice values style. Silent if no unkept die with that value exists.
rI   Nr   r   )rV   rN   rI   r-   r1   rq   re   rr   keepr   r   r/   r[   rs   r\   rI   r2   s         r4   r   DiceGameMixin._keep_by_value  s     vv&&}}V${{ t}}%A>>!$$T\\!__>>!$-IIaL^5A,,V4 &r7   c                   [        US5      (       d  gU R                  U5      nUR                  n[        UR                  5       H  nUR                  U5      (       d  M  UR                  U5      (       a  M3  UR                  U5      U:X  d  MJ  UR                  U5        U(       a  UR                  SUS9  U R                  U5          g   g)z
Unkeep the first kept die with the given face value.

Used in dice values style. Silent if no kept die with that value exists.
rI   Nr   r   )rV   rN   rI   r-   r1   re   rq   rr   unkeepr   r   r   s         r4   r   DiceGameMixin._unkeep_by_value  s     vv&&}}V${{ t}}%A||At~~a'8'8>>!$-KKN%5UC,,V4 &r7   rk   )r   )r0   r   r1   rS   returnNone)r1   rS   r   r   )r[   r   r?   
str | Noner   r   )r[   r   r?   r;   r   r;   )r[   r   r   r   )r[   r   rs   rS   rK   boolr   z
int | None)r[   r   r   r   )r[   r   r?   r;   r   r   )r[   r   r?   r;   r   r   )r[   r   r_   rS   r   r   )r[   r   r_   rS   r   r   )r[   r   r_   rS   r   r;   )r[   r   r?   r;   r   r   )r[   r   r^   rS   r   r   )r[   r   rs   rS   r   r   )r[   r   r_   rS   r   r   ),__name__
__module____qualname____firstlineno____doc__r5   r=   r&   r+   r(   r,   rm   rY   r'   r{   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rL   r   r   r   r%   r*   r   r   r   r   r   __static_attributes__rk   r7   r4   r   r      s?   :3j> OS &R :>,6	>!*#$! LP ?
 LP ?
 LP ?
 LP ?
 LP ?
 LP ?
 KO >
 KO >
 KO >
 KO >
 KO >
 KO >
>
>
>
>
>
>
"$,/01.1 )>0r7   r   N)r   
__future__r   typingr   actionsr   r   r   server.core.ui.keybindsr	   server.core.users.preferencesr
   server.messages.localizationr   
games.baser   r   rk   r7   r4   <module>r      s3    #   2 2 0 : 5#E Er7   