
    IiO              
       D   S r SSKJrJr  SSKJr  SSK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  SSKJrJrJr  SSKJr  SSKJr  SSKJr  SSKJrJr  SSKJrJr  SSK J!r!  SSK"J#r#  \ " S S\5      5       r$\ " S S\	5      5       r%\\ " S S\\\\5      5       5       r&g)z
1-4-24 (Midnight) Game Implementation for PlayPalace v11.

Dice game where players roll 6 dice trying to get a 1 and a 4.
The other 4 dice are summed for points (max 24). Highest score wins the round.
    )	dataclassfield)datetimeN   )GamePlayerGameOptions)register_game   )ActionGuardMixin)RoundBasedGameMixin)Action	ActionSet
Visibility)	BotHelperDiceSet)DiceGameMixin)
GameResultPlayerResult)	IntOptionoption_field)Localization)KeybindStatec                   \    \ rS rSr% Sr\" S S9r\\S'   Sr	\
\S'   Sr\
\S'   S	r\\S
'   Srg)MidnightPlayer   z(Player state for 1-4-24 (Midnight) game.c                      [        SSS9$ )N   num_dicesidesr        9c:\Users\dbart\PlayPalace11\server\games\midnight\game.py<lambda>MidnightPlayer.<lambda>   s    '1A2Nr$   default_factorydicer   round_score
round_winsF	qualifiedr#   N)__name__
__module____qualname____firstlineno____doc__r   r*   r   __annotations__r+   intr,   r-   bool__static_attributes__r#   r$   r%   r   r      s3    2*NOD'OKJItr$   r   c                   H    \ rS rSr% Sr\" \" SSSSSSS	S
95      r\\	S'   Sr
g)MidnightOptions$   z#Options for 1-4-24 (Midnight) game.         roundszmidnight-set-roundszmidnight-enter-roundszmidnight-option-changed-rounds)defaultmin_valmax_val	value_keylabelprompt
change_msgr#   N)r.   r/   r0   r1   r2   r   r   r=   r4   r3   r6   r#   r$   r%   r8   r8   $   s3    -'*7	

FC 
r$   r8   c            	       
  ^  \ rS rSr% SrS/r\" \S9r\\	   \
S'   \" \S9r\\
S'   \S\4S j5       r\S\4S	 j5       r\S\4S
 j5       r\S\4S j5       r\S\4S j5       rS5S\S\S\S\	4S jjrS\S\S\S-  4S jrS\S\S\4S jrS\S\S\4S jrS\S\S-  4S jrS\S\4S jrS\S\SS4S jrS\S\S-  4S jrS\S\4S jr S\S\SS4S jr!S\	SS4S jr"S\	S\#4S jr$S6U 4S  jjr%S\4S! jr&S\	SS4S" jr'S\	SS4S# jr(S\	SS4S$ jr)S6S% jr*S\	SS4S& jr+S6U 4S' jjr,S\	S\S-  4S( jr-S\	S\4S) jr.S\	S*\S\S-  4S+ jr/S\	S\S-  4S, jr0S\	S\4S- jr1S6S. jr2S6S/ jr3S\44S0 jr5S1\4S2\S\\   4S3 jr6S4r7U =r8$ )7MidnightGame5   a(  
1-4-24 (Midnight) dice game.

Players roll 6 dice and must keep at least one die after each roll.
Once kept, dice are locked and can't be changed.
To score, you need a 1 and a 4. The other 4 dice sum for points (max 24).
Highest score wins the round. First to win the most rounds wins the game.
dice_keeping_styler(   playersoptionsreturnc                     g)Nz1-4-24r#   clss    r%   get_nameMidnightGame.get_nameG   s    r$   c                     g)Nmidnightr#   rM   s    r%   get_typeMidnightGame.get_typeK   s    r$   c                     g)Nzcategory-dice-gamesr#   rM   s    r%   get_categoryMidnightGame.get_categoryO   s    $r$   c                     g)Nr   r#   rM   s    r%   get_min_playersMidnightGame.get_min_playersS       r$   c                     g)Nr   r#   rM   s    r%   get_max_playersMidnightGame.get_max_playersW   r[   r$   	player_idnameis_botc           
      0    [        UUU[        SSS9SSSS9$ )z1Create a new player with Midnight-specific state.r   r    r   F)idr`   ra   r*   r+   r,   r-   )r   r   )selfr_   r`   ra   s       r%   create_playerMidnightGame.create_player[   s+    !1-
 	
r$   player	die_indexNc                     U R                   S:w  a  gUR                  (       a  gU R                  U:w  a  gUnUR                  R                  (       d  gUR                  R                  U5      (       a  gg)z*Check if toggling die at index is enabled.playingaction-not-playingaction-spectatoraction-not-your-turnzmidnight-need-to-rollzdice-lockedN)statusis_spectatorcurrent_playerr*   
has_rolled	is_lockedrd   rg   rh   midnight_players       r%   _is_dice_toggle_enabled$MidnightGame._is_dice_toggle_enabledk   sb    ;;)#'%&()*0##..*)))44 r$   c                    U R                   S:w  a  [        R                  $ UR                  (       a  [        R                  $ U R                  U:w  a  [        R                  $ UnUR
                  R                  (       d  [        R                  $ UR
                  R                  U5      (       a  [        R                  $ [        R                  $ )zIDice toggles are visible when dice are rolled and die is not locked/kept.rj   )	rn   r   HIDDENro   rp   r*   rq   rr   VISIBLErs   s       r%   _is_dice_toggle_hidden#MidnightGame._is_dice_toggle_hidden{   s    ;;)#$$$$$$&($$$*0##..$$$)))44$$$!!!r$   c                 n   UnUR                   R                  (       a#  U[        UR                   R                  5      :  a  SUS-    3$ UR                   R                  U   nUR                   R	                  U5      (       a  U S3$ UR                   R                  U5      (       a  U S3$ [        U5      $ )z!Get label for dice toggle action.zDie r;   z	 (locked)z (kept))r*   rq   lenvaluesrr   is_keptstr)rd   rg   rh   rt   die_vals        r%   _get_dice_toggle_label#MidnightGame._get_dice_toggle_label   s    *0 ##..)s?CWCWC^C^?_2_)a-))!&&--i8)))44Yi((''	22Yg&&7|r$   c                 L   U R                  U5      nU(       a  U$ UnUR                  R                  (       a  UR                  R                  S:X  a  gUR                  R                  (       a  UR                  R                  (       a  gUR                  R
                  S:X  a  gg)z Check if roll action is enabled.r   zmidnight-must-keep-onezaction-not-availablezmidnight-no-dice-to-keepN)guard_turn_action_enabledr*   rq   kept_unlocked_countall_decidedunlocked_count)rd   rg   errorrt   s       r%   _is_roll_enabledMidnightGame._is_roll_enabled   s    ..v6L*0**/C/C/W/W[\/\+**/C/C/O/O)..!3-r$   c                     UnUR                   R                  =(       a    UR                   R                  (       + nU R                  XR                   R                  S:  =(       a    US9$ )z/Roll is visible during play for current player.r   )extra_condition)r*   rq   r   turn_action_visibilityr   )rd   rg   rt   
can_rerolls       r%   _is_roll_hiddenMidnightGame._is_roll_hidden   s^    *0)..99^o>R>R>^>^_
**$8$8$G$G!$K$ZPZ + 
 	
r$   	action_idc                 V  ^	 Um	T	R                   R                  n[        T	R                   R                  5      n[        T	R                   R                  5      nU(       a>  [        T	R                   R                  5       Vs/ s H  nXd;  d  M
  Xe;  d  M  UPM     nnO([        [        T	R                   R                  5      5      nU R                  S5        T	R                   R                  SSS9  U R                  T	5        SR                  U	4S jU 5       5      nU R                  USSUS9  T	R                   R                  S	::  a  U R                  T	5        g
UR                  (       a*  [         R"                  " U[$        R&                  " SS5      S9  U R)                  5         g
s  snf )zHandle roll action.zgame_pig/roll.oggT)	lock_kept
clear_keptz, c              3   h   >#    U  H'  n[        TR                  R                  U   5      v   M)     g 7fN)r   r*   r~   ).0irt   s     r%   	<genexpr>,MidnightGame._action_roll.<locals>.<genexpr>   s*     \^O$8$8$?$?$B C C^s   /2zmidnight-you-rolledzmidnight-player-rolled)r*   r;   N
   r<   ticks)r*   rq   setlockedkeptranger!   list
play_soundroll_apply_dice_values_defaultsjoinbroadcast_personal_lr   _score_turnra   r   jolt_botrandomrandintrebuild_all_menus)
rd   rg   r   
had_rolledlocked_beforekept_beforer   rolled_indicesresult_textrt   s
            @r%   _action_rollMidnightGame._action_roll   ss   *0$))44
O00778/..334 33<<==A) ./.B =  N "%(<(<(E(E"FGN+, 	!!DT!B((9 ii\^\\ 	!!)+C+ 	" 	

 ..!3_- ==vV^^B-CD ?s    	F&F&F&c                     U R                   S:w  a  gUR                  (       a  gU R                  U:w  a  gUnUR                  R                  (       d  gUR                  R
                  (       d  gg)z Check if bank action is enabled.rj   rk   rl   rm   zmidnight-must-roll-firstzmidnight-keep-all-firstN)rn   ro   rp   r*   rq   r   rd   rg   rt   s      r%   _is_bank_enabledMidnightGame._is_bank_enabled   sZ    ;;)#'%&()*0##..-##//,r$   c                 >   U R                   S:w  a  [        R                  $ UR                  (       a  [        R                  $ U R                  U:w  a  [        R                  $ UnUR
                  R                  (       d  [        R                  $ [        R                  $ )z@Bank is visible during play for current player after first roll.rj   )rn   r   rx   ro   rp   r*   rq   ry   r   s      r%   _is_bank_hiddenMidnightGame._is_bank_hidden   su    ;;)#$$$$$$&($$$*0##..$$$!!!r$   c                 *    UnU R                  U5        g)zBank score and end turn.N)r   )rd   rg   r   rt   s       r%   _action_bankMidnightGame._action_bank   s    *0)r$   c                 P   SUR                   R                  ;   nSUR                   R                  ;   nU(       a  U(       a  UR                   R                  R                  5       nUR                  S5        UR                  S5        [	        U5      Ul        SUl        U R                  S5        U R                  USSUR
                  S9  O!SUl        S	Ul        U R                  US
S5        [        R                  " U [        R                  " SS5      S9  U R                  5         g)zCalculate and apply turn score.r;      Tgame_pig/bank.oggzmidnight-you-scoredzmidnight-scored)scorer   Fzmidnight-you-disqualifiedzmidnight-player-disqualifiedr<      r   N)r*   r~   copyremovesumr+   r-   r   r   r   	jolt_botsr   r   _on_turn_end)rd   rg   has_onehas_fourvalues_copys        r%   r   MidnightGame._score_turn  s     v{{)))***x !++,,113Kq!q!!$[!1F#FOO/0%%%!((	 &  "#F$F%%35S
 	Dr2(>?r$   c           
      H   U R                  U5      nU(       a  UR                  OSn[        SS9nU R                  USS9  UR	                  [        S[        R                  " US5      SS	S
S95        UR	                  [        S[        R                  " US5      SSSS95        U$ )z(Create the turn action set for a player.enturn)r`   r   r!   r   zmidnight-rollr   r   r   )rc   rB   handler
is_enabled	is_hiddenbankzmidnight-bankr   r   r   )get_userlocaler   add_dice_toggle_actionsaddr   r   get)rd   rg   userr   
action_sets        r%   create_turn_action_set#MidnightGame.create_turn_action_set.  s    }}V$ $$F+
 	$$Z!$< 	"&&v?&-+	
 	"&&v?&-+	
 r$   c                    > [         TU ]  5         U R                  SS9  U R                  SSS/[        R
                  S9  U R                  SSS	/[        R
                  S9  g
)z!Define all keybinds for the game.r   r   rzRoll the dicer   )statebBankr   N)supersetup_keybindssetup_dice_keybindsdefine_keybindr   ACTIVErd   	__class__s    r%   r   MidnightGame.setup_keybindsP  se     	  	  ! , 	C6(,BUBUV 	C&9L9LMr$   c                     g)NTr#   )rd   s    r%   should_reset_all_scores$MidnightGame.should_reset_all_scores^  s    r$   c                 b    UR                   R                  5         SUl        SUl        SUl        g Nr   F)r*   resetr+   r,   r-   rd   rg   s     r%   _reset_player_for_game#MidnightGame._reset_player_for_gamea  s*     r$   c                 T    UR                   R                  5         SUl        SUl        g r   r*   r   r+   r-   r   s     r%   _reset_player_for_round$MidnightGame._reset_player_for_roundg  "     r$   c                 T    UR                   R                  5         SUl        SUl        g r   r   r   s     r%   _reset_player_for_turn#MidnightGame._reset_player_for_turnl  r   r$   c                 Z    U R                  S5        U R                  SUR                  S9  g )Nzgame_pig/turn.oggzmidnight-turn-startrg   )r   broadcast_lr`   r   s     r%   _announce_turn_start!MidnightGame._announce_turn_startq  s'    +,.v{{Cr$   c                 V    UR                   (       a  [        R                  " US5        g g )N   )ra   r   
set_targetr   s     r%   _setup_bot_for_turn MidnightGame._setup_bot_for_turnu  s    ==  , r$   c                 r   > [         TU ]  5         U R                  (       d  g[        R                  " U 5        g)z!Called every tick. Handle bot AI.N)r   on_tickgame_activer   r   s    r%   r  MidnightGame.on_ticky  s'    $r$   c                     U R                  U5      (       a  gU R                  US5      nU(       a  U$ U R                  US5      nU(       a  U$ U R                  U5      nU(       a  U$ U R                  U5      $ )z,Bot AI decision making. Called by BotHelper.r   r;   r   )_should_bot_roll_bot_lock_target_value_bot_lock_highest_available_bot_finalize_turn)rd   rg   decisions      r%   	bot_thinkMidnightGame.bot_think  ss      ((..vq9O..vq9O33F;O&&v..r$   c                 r    UR                   R                  (       d  gUR                   R                  S:  a  gg)NTr   F)r*   rq   r   r   s     r%   r  MidnightGame._should_bot_roll  s*    {{%%;;**Q.r$   targetc                 B   UR                   R                   Vs/ s H  o1R                   R                  U   PM     nnX$;   a  g [        S5       HI  nUR                   R	                  U5      (       a  M%  UR                   R                  U   U:X  d  MD  SU 3s  $    g s  snf )Nr   toggle_die_)r*   r   r~   r   rr   )rd   rg   r  r   locked_valuess        r%   r  #MidnightGame._bot_lock_target_value  s    8>8J8JK8J1++A.8JK"qA;;((++0B0B10E0O$QC((   Ls   "Bc                 B   SnSn[        S5       H  nUR                  R                  U5      (       a  M%  UR                  R                  U5      (       a  MG  UR                  R                  U   U:  d  Mf  UR                  R                  U   nUnM     US:  a  SU 3$ g )Nr   r   r  )r   r*   rr   r   r~   )rd   rg   
best_index
best_valuer   s        r%   r  (MidnightGame._bot_lock_highest_available  s    

qA;;((++FKK4G4G4J4J;;%%a(:5!'!3!3A!6J!"J	 
 ? --r$   c                     UR                   R                   Vs/ s H  o!R                   R                  U   PM     nnSU;   nSU;   nU(       a  U(       a  gUR                   R                  S:X  a  ggs  snf )Nr;   r   r   r   r   )r*   r   r~   r   )rd   rg   r   r  r   r   s         r%   r  MidnightGame._bot_finalize_turn  si    8>8J8JK8J1++A.8JK}$%x;;**a/ Ls   "A2c                 "   U R                  5       nU Vs/ s H  o"R                  (       d  M  UPM     nnU(       d  U R                  S5        GOm[        S U 5       5      nU Vs/ s H  o"R                  U:X  d  M  UPM     nn[        U5      S:X  al  US   nU=R                  S-  sl        U R                  R                  UR                  S5        U R                  S5        U R                  SUR                  S9  OU Vs/ s H  owR                  PM     nnU H>  nU=R                  S-  sl        U R                  R                  UR                  S5        M@     U R                   HN  n	U R                  U	5      n
U
(       d  M  [        R                  " U
R                  U5      nU
R!                  SUS	9  MP     U R"                  U R$                  R&                  :  a  U R)                  5         g
U R+                  5         g
s  snf s  snf s  snf )zHandle end of a round.zmidnight-all-disqualifiedc              3   8   #    U  H  oR                   v   M     g 7fr   )r+   r   ps     r%   r   -MidnightGame._on_round_end.<locals>.<genexpr>  s     F4Eq]]4E   r;   r   r   zmidnight-round-winnerr   zmidnight-round-tie)rI   N)get_active_playersr-   r   maxr+   r}   r,   _team_manageradd_to_team_scorer`   r   rI   r   r   format_list_andr   speak_lroundrJ   r=   	_end_game_start_round)rd   active_playersr#  qualified_players
high_scorewinnerswinnerwnamesrg   r   	names_strs               r%   _on_round_endMidnightGame._on_round_end  s   002 )7F1++QF 89F4EFFJ"3S"3Q}}
7Rq"3GS7|q  !!Q&!""44V[[!D 34  !8 M *11A1 ALLA%L&&88C ! #llF==0Dt$0$@$@e$T	%99M	 + ::,,,NN E G T 2s   HH%H<HHc                 4   U R                  5       n[        S U 5       5      nU Vs/ s H  o3R                  U:X  d  M  UPM     nn[        U5      S:X  a0  U R	                  S5        U R                  SUS   R                  US9  OzU Vs/ s H  oUR                  PM     nnU R                   HO  nU R                  U5      nU(       d  M  [        R                  " UR                  U5      n	UR                  SXSS	9  MQ     U R                  5         g
s  snf s  snf )z*End the game and determine overall winner.c              3   8   #    U  H  oR                   v   M     g 7fr   r,   r"  s     r%   r   )MidnightGame._end_game.<locals>.<genexpr>  s     <^||^r%  r;   zgame_pig/win.oggzmidnight-game-winnerr   )rg   winszmidnight-game-tietable)rI   r=  bufferN)r&  r'  r,   r}   r   r   r`   rI   r   r   r*  r   r+  finish_game)
rd   r/  max_winsr#  r2  r4  r5  rg   r   r6  s
             r%   r-  MidnightGame._end_game  s    002 <^<<,In0H1nIw<1OO./3GAJOORZ[ &--WVVWE-,,}}V,4 , < <T[[% PILL+YV] ! 	 ' 	# J .s   DD	Dc                 N   U R                  5       n[        US SS9nU(       a  US   OSn0 nU H  nUR                  XER                  '   M     [	        U R                  5       [        R                  " 5       R                  5       U R                  U Vs/ s H8  n[        UR                  UR                  UR                  [        USS5      S9PM:     snU(       a  UR                  OSU(       a  UR                  OSUU R                  U R                  R                   S	.S
9$ s  snf )z2Build the game result with Midnight-specific data.c                     U R                   $ r   r;  )r#  s    r%   r&   0MidnightGame.build_game_result.<locals>.<lambda>  s    allr$   T)keyreverser   Nis_virtual_botF)r_   player_namera   rH  )winner_namewinner_roundsfinal_standingsrounds_playedtotal_rounds)	game_type	timestampduration_ticksplayer_resultscustom_data)r&  sortedr,   r`   r   rS   r   now	isoformatsound_scheduler_tickr   rc   ra   getattrr,  rJ   r=   )rd   r/  sorted_playersr3  rL  rg   r#  s          r%   build_game_resultMidnightGame.build_game_result   s   0024JTXY&4"$ $F+1+<+<OKK( % mmolln..044 ( (A dd !88#*1.>#F	 ( /5v{{$6<!2!2!#2!% $ 3 3
 	
s   ?D"resultr   c           	          [         R                  " US5      /nUR                  R                  S0 5      n[        UR	                  5       S5       H"  u  nu  pgUR                  U SU SU S35        M$     U$ )z(Format the end screen for Midnight game.zgame-final-scoresrL  r;   z. z: z round wins)r   r   rS  	enumerateitemsappend)rd   r\  r   linesrL  r   r`   r=  s           r%   format_end_screenMidnightGame.format_end_screen!  sx    !!&*=>? ,,001BBG()>)>)@!DOA|LLA3bbk:;  E r$   r#   )F)rK   N)9r.   r/   r0   r1   r2   relevant_preferencesr   r   rI   r   r3   r8   rJ   classmethodr   rO   rS   rV   r4   rY   r]   r5   re   r   ru   r   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r  r7  r-  r   rZ  rb  r6   __classcell__)r   s   @r%   rF   rF   5   s    11 %*$$?GT.!?$_EG_E      %S % %      

s 

# 

t 

P^ 

 f  t  "V " "
 " V   *v #* 
f 
 
'!6 '!c '!d '!Zv #* "f " "*6 *c *d *
#. #T #R ^  	  DN !^ ! !!n ! !
!^ ! !
D-. -T - / /3: /&~ $ ^ S SSWZ 
. 
S4Z 
 C ' R2
: 
B
 C DI  r$   rF   )'r2   dataclassesr   r   r   r   baser   r   r	   registryr
   game_utils.action_guard_mixinr   !game_utils.round_based_game_mixinr   game_utils.actionsr   r   r   game_utils.bot_helperr   game_utils.dicer   game_utils.dice_game_mixinr   game_utils.game_resultr   r   game_utils.optionsr   r   messages.localizationr   server.core.ui.keybindsr   r   r8   rF   r#   r$   r%   <module>rt     s    )   , , $ = D ? ? . & 7 > 9 1 0 V   k    r#%8$ r  rr$   