
    Iiv                    &   S r SSKJr  SSKrSSKJr  SSKJrJrJ	r	J
r
  SSKJrJrJrJr  \(       a  SSKJrJr  S"S	 jr      S#S
 jr        S$S jr          S%S jrS&S jrS'S jr  S(             S)S jjrS*S jrS+S jr      S,S jr                    S-S jr            S.S jr            S/S jrS0S jr S1S jr!S2S jr"S3S jr#S4S jr$S3S jr%S'S jr&S'S jr'S3S jr(S3S jr)S3S  jr*S3S! jr+g)5z$Combat/War system for Age of Heroes.    )annotationsN)TYPE_CHECKING   )CardCardType	EventTypeget_card_name)WarStateWarGoalget_war_goal_nameget_tribe_name)AgeOfHeroesGameAgeOfHeroesPlayerc                    UR                   (       d  gUR                   R                  5       n[        S UR                   5       5      nUS:  a  US:  a  g[	        X5      (       d  gg)zACheck if a player can declare war. Returns error message or None.zNo tribe statec              3     #    U  HG  nUR                   [        R                  :X  d  M#  UR                  [        R
                  :X  d  MC  S v   MI     g7fr   N	card_typer   EVENTsubtyper   HERO.0cards     >c:\Users\dbart\PlayPalace11\server\games\ageofheroes\combat.py	<genexpr>"can_declare_war.<locals>.<genexpr>   >      D>>X^^+ 	
04	0N 	
   "AA	Ar   zageofheroes-war-no-armyzNo valid targetsN)tribe_stateget_available_armiessumhandget_valid_war_targets)gameplayeravailable_armies
hero_counts       r   can_declare_warr)      sf     ))>>@ KK J !
Q( !..!    c                0   / nU R                  5       nUR                  U5      n[        U5       Hc  u  pVXT:X  a  M  [        US5      (       a  UR                  (       d  M0  UR                  R                  5       (       a  MQ  UR                  XV45        Me     U$ )z5Get list of valid war targets (player_index, player).r    )get_active_playersindex	enumeratehasattrr    is_eliminatedappend)r%   r&   targetsactive_playersplayer_indexips          r   r$   r$   *   s     G,,.N!''/L.)q-((==&&(( 	v * Nr*   c                   / nUR                   (       d  U$ UR                   R                  S:  a/  U R                  S:  a  UR                  [        R
                  5        [        UR                  5      S:  a  UR                  [        R                  5        UR                   R                  S:  a  UR                  [        R                  5        U$ )z8Get list of valid war goals against a specific defender.r      )r    citiescurrent_dayr1   r   CONQUESTlenr#   PLUNDERmonument_progressDESTRUCTION)r%   attackerdefendergoalss       r   get_valid_war_goalsrC   A   s     E ""Q&4+;+;q+@W%%& 8==AW__% --1W(()Lr*   c                   U R                  5       nUS:  d  U[        U5      :  a  gUR                  U5      nXB   n[        US5      (       a  UR                  (       d  g[        UUUS9U l        U R                  S5        U R                   HZ  nU R                  U5      nU(       d  M  UR                  n	[        X95      n
UR                  SUR                  UR                  U
S9  M\     g)	zDeclare war on another player.r   Fr    )attacker_indexdefender_indexgoalzgame_ageofheroes/war.oggzageofheroes-war-declare)r@   rA   rG   T)r,   r<   r-   r/   r    r
   	war_state
play_soundplayersget_userlocaler   speak_lname)r%   r@   rF   rG   r3   rE   rA   r6   userrL   	goal_names              r   declare_warrQ   [   s     ,,.N^s>/BB#))(3N-H8]++83G3G %%DN 	OO./\\}}Q4[[F)$7ILL)!!	    r*   c                z   U R                  5       nU R                  nUR                  S:  d  UR                  [        U5      :  a  gXR                     n[	        US5      (       d  gUR
                   HE  nUR                  [        R                  :X  d  M#  UR                  [        R                  :X  d  MC  Us  $    g)z7Check if defender has Olympic Games card to cancel war.r   Nr#   )r,   rH   rF   r<   r/   r#   r   r   r   r   r   OLYMPICS)r%   r3   warrA   r   s        r   check_olympics_defenserU      s    ,,.N
..C
A!3!3s>7J!J001H8V$$ >>X^^+	@R@R0RO  r*   c                   [        UR                  5       H  u  p#UR                  [        R                  :X  d  M%  UR
                  [        R                  :X  d  ME  UR                  R                  U5      nU R                  R                  U5        SU R                  l        U R                  S5        U R                  SUR                  S9    g   g)z Use Olympic Games to cancel war.Tzgame_ageofheroes/olympics.oggzageofheroes-olympics-cancelrN   F)r.   r#   r   r   r   r   r   rS   popdiscard_piler1   rH   cancelled_by_olympicsrI   broadcast_lrN   r%   r&   r5   r   removeds        r   use_olympicsr^      s     V[[)>>X^^+	@R@R0Rkkooa(G$$W- 48DNN0OO;<:M * r*   c                   UR                   (       d  gU R                  5       nUR                  U5      nU R                  nUR                   R	                  5       n	UR                   R                  5       n
[        S UR                   5       5      nXE-   nX:  a  gX):  a  gX::  a  gXxR                  :X  a   X(l	        X8l
        XHl        XXl        SUl        O0XxR                  :X  a   X(l        X8l        XHl        XXl        SUl        Og[)        U5       H  n[+        UR                  5       H|  u  pUR,                  [.        R0                  :X  d  M%  UR2                  [4        R6                  :X  d  ME  UR                  R9                  U5      nU R:                  R=                  U5          M     M     U R?                  U5      nU(       a  URA                  SX$-   X5-   SS9  g)zPrepare forces for battle.Fc              3     #    U  HG  nUR                   [        R                  :X  d  M#  UR                  [        R
                  :X  d  MC  S v   MI     g7fr   r   r   s     r   r   !prepare_forces.<locals>.<genexpr>   r   r   Tzageofheroes-war-preparedr   )armiesgeneralsheroes)!r    r,   r-   rH   r!   get_available_generalsr"   r#   rE   attacker_armiesattacker_generalsattacker_heroesattacker_hero_generalsattacker_preparedrF   defender_armiesdefender_generalsdefender_heroesdefender_hero_generalsdefender_preparedranger.   r   r   r   r   r   r   rX   rY   r1   rK   rM   )r%   r&   rb   rc   rd   hero_generalsr3   r4   rT   r'   available_generals
hero_cardstotal_heroes_used_r5   r   r]   rO   s                     r   prepare_forcesrv      s    ,,.N!''/L
..C ))>>@++BBD  KK J .% $ )))$ ($%2" $	++	+$ ($%2" $ $% -GA~~/DLLINN4R ++//!,!!((1	 . & == D&?-	 	 	
 r*   c                   U R                   nU R                  5       nUR                  U5      n[        R                  " SS5      nXBR
                  :X  a  XRl        U/Ul        OXBR                  :X  a  XRl	        U/Ul
        U R                  S5        U R                  U5      nU(       a  UR                  SUS9  U R                   H?  nXq:w  d  M
  U R                  U5      nU(       d  M$  UR                  SUR                  US9  MA     U$ )zAPlayer clicks to roll dice for war. Returns the roll value (1d6).r      zgame_pig/dice.oggzageofheroes-war-roll-you)rollzageofheroes-war-roll-other)r&   ry   )rH   r,   r-   randomrandintrE   attacker_rollattacker_dicerF   defender_rolldefender_dicerI   rK   rM   rJ   rN   )	r%   r&   rT   r3   r4   die_rollrO   r6   
other_users	            r   player_roll_war_dicer      s    
..C,,.N!''/L ~~a#H )))$%J	++	+$%J 	OO'( == D/h? \\;q)Jz""0!;;! # 	  Or*   c                    U R                   nU R                  5       n[        X5      u  nnnnnnn	n
[        U U	U
UUUUUU5	        [	        X	XU5      u  pn[        XU5        XU4$ )zResolve one round of battle using already-rolled dice. Returns (winner, attacker_losses, defender_losses).

Winner is 'attacker', 'defender', or 'draw'.
NOTE: In Pascal, draws cause NO losses (unlike Risk-style games).
)rH   r,   _calculate_war_totals_announce_war_bonuses_resolve_war_outcomeapply_battle_losses)r%   rT   r3   attacker_totaldefender_totalatt_gen_bonusatt_fort_bonusdef_gen_bonusdef_fort_bonusr@   rA   winnerattacker_lossesdefender_lossess                 r   resolve_battle_roundr     s     ..C,,.N 	c2	 
 0D.0,F_
 ?O33r*   c                    U R                   nU R                  nU R                  5       S:  a  SOSnU R                  5       S:  a  SOSnSnU R                  nU[        U5      :  a<  X   n[        US5      (       a'  UR                  (       a  UR                  R                  nSn	XI-   n
XV-   nX*-   nX;-   nU R                  [        U5      :  a  XR                     OSnU R                  [        U5      :  a  XR                     OSnUUUU	UUUU4$ )zACompute dice totals, bonuses, and participant references for war.r      r    N)
r|   r~   get_attacker_total_generalsget_defender_total_generalsrF   r<   r/   r    
fortressesrE   )rT   r3   att_dice_totaldef_dice_totalr   r   r   rF   defender_playerr   att_total_bonusdef_total_bonusr   r   r@   rA   s                   r   r   r   F  s.    &&N&&N 88:Q>AAM88:Q>AAMN''NN++(8?M227R7R,88CCNN#4O#4O#5N#5N /2.@.@3~CV.V))*\`  /2.@.@3~CV.V))*\` 
 		 	r*   c	                    U(       a  X4-   S:  a  [        U UUUU5        U(       a  XV-   S:  a  [        U UUUU5        ggg)z8Announce bonuses for attacker and defender when present.r   N)_announce_war_bonus_for_side)	r%   r@   rA   r   r   r   r   r   r   s	            r   r   r   |  sU     ]3q8$	
 ]3q8$	
 9xr*   c           	         U R                    HS  nU R                  U5      nU(       d  M  XQ:X  a  UR                  SUUUS9  M6  UR                  SUR                  UUUS9  MU     g )Nzageofheroes-war-bonuses-you)generalfortresstotalzageofheroes-war-bonuses-other)r&   r   r   r   )rJ   rK   rM   rN   )r%   participant	gen_bonus
fort_bonusr   r6   rO   s          r   r   r     sq     \\}}QLL-!#	   LL/"''!#   r*   c                   X4:  aK  U R                  S5        U R                  SU(       a  UR                  OSU(       a  UR                  OSUUS9  gXC:  aK  U R                  S5        U R                  SU(       a  UR                  OSU(       a  UR                  OSUUS9  g	U R                  S
U(       a  UR                  OSU(       a  UR                  OSUS9  g)z6Determine winner, announce outcome, and return losses.zgame_ageofheroes/attack_win.oggzageofheroes-round-attacker-winsAttackerDefender)r@   rA   	att_total	def_total)r@   r   r   zgame_ageofheroes/defend_win.oggzageofheroes-round-defender-wins)rA   r   r   zageofheroes-round-draw)r@   rA   r   )drawr   r   )rI   r[   rN   )r%   r@   rA   r   r   s        r   r   r     s     &9:-&.X]]J&.X]]J$$ 	 	
  &9:-&.X]]J&.X]]J$$ 	 	
   "*
"*
	   r*   c                   U R                   nU R                  5       nUS:  a  UR                  [        U5      :  a  XCR                     n[	        US5      (       a  UR
                  (       a  [        XR                  5      nU=R                  U-  sl        X-  nUS:  a^  [        XR                  5      nU=R                  U-  sl        UR
                  =R                  U-  sl	        U =R                  U-  sl
        US:  a  UR                  [        U5      :  a  XCR                     n[	        US5      (       a  UR
                  (       a  [        X#R                  5      nU=R                  U-  sl        X&-  nUS:  a_  [        X#R                  5      nU=R                  U-  sl        UR
                  =R                  U-  sl	        U =R                  U-  sl
        gggggg)zApply army losses from battle.r   r    N)rH   r,   rE   r<   r/   r    minrh   rf   rb   army_supplyrF   rm   rk   )	r%   r   r   rT   r3   r@   heroes_lostarmies_lostrA   s	            r   r   r     s   
..C,,.N s11C4GG!"4"458]++0D0Do/B/BCK;.*O "!/3F3FG##{2#$$++{:+  K/  s11C4GG!"4"458]++0D0Do/B/BCK;.*O "!/3F3FG##{2#$$++{:+  K/ 	 # 1E+  Hr*   c                |    U R                   nUR                  5       nUR                  5       nUS:*  =(       d    US:*  $ )z:Check if the battle is over (one side has no armies left).r   )rH   get_attacker_total_armiesget_defender_total_armiesr%   rT   rf   rk   s       r   is_battle_overr     s<    
..C335O335Oa7?a#77r*   c                    [        U 5      (       d  gU R                  nUR                  5       nUR                  5       nUS:  a  US::  a  gUS:  a  US::  a  gg)z2Get the winner of the battle, or None if not over.Nr   r@   rA   )r   rH   r   r   r   s       r   get_battle_winnerr     s^    $
..C335O335O!3	1	A!5 r*   c                &   U R                   n[        U 5      nU R                  5       nUS:w  a  [        U 5        gUR                  [        U5      :  a  gUR                  [        U5      :  a  gX1R                     nX1R                     n[        US5      (       a  UR                  (       d  g[        US5      (       a  UR                  (       d  gUR                  UR                  -   nUR                  [        R                  :X  a  US:  a  SnOUS:  a  SnOSn[        XuR                  R                  5      nUS:  au  UR                  =R                  U-  sl        UR                  =R                  U-  sl        U R!                  SUR"                  UR"                  US	9  U R%                  S
5        GOUR                  [        R&                  :X  Ga  [        SU-  [        UR(                  5      5      nUS:  a  / n	[+        U5       H  n
UR(                  (       d  M  [,        R.                  " S[        UR(                  5      S-
  5      nUR(                  R1                  U5      nUR(                  R3                  U5        U	R3                  U5        M     U R!                  SUR"                  [        U	5      UR"                  S9  U R%                  S5        OUR                  [        R4                  :X  a  US:  a  SnOUS:  a  SnOSn[        XR                  R6                  5      nUS:  aV  UR                  =R6                  U-  sl        U R!                  SUR"                  UR"                  US	9  U R%                  S5        [        U 5        g)z/Apply the outcome of the war based on the goal.r@   Nr    r8   r   r   r   zageofheroes-conquest-success)r@   rA   countzgame_ageofheroes/conquest.oggzageofheroes-plunder-success)r@   r   rA   zgame_ageofheroes/plunder.oggzageofheroes-destruction-successz game_ageofheroes/destruction.ogg)rH   r   r,   return_surviving_forcesrE   r<   rF   r/   r    rf   rh   rG   r   r;   r   r9   r[   rN   rI   r=   r#   rp   rz   r{   rX   r1   r?   r>   )r%   rT   r   r3   r@   rA   attacker_strengthcities_to_takecards_to_stealstolenru   idxr   resources_to_destroys                 r   apply_war_outcomer      s   
..Ct$F,,.N% S00
S00001H001H8]++83G3G8]++83G3G ++c.A.AA
xx7### !N!#NN^-A-A-H-HIA  ''>9'  ''>9'.!!$	   OO;<	W__	$Q!22C4FGAF>*=== ..C,>,BCC#==,,S1DMM((.MM$' + -!&k!	   OO:;	W((	( !#$ !##$ #$ "#79M9M9_9_`!#  226JJ21!!*	   OO>?D!r*   c                   U R                  5       nU[        U5      :  d  U[        U5      :  a  gX1   nX2   n[        US5      (       a  UR                  (       d  g[        US5      (       a  UR                  (       d  g[        U5      nUS-   U-  U:X  a3  UR                  R                  =(       a    UR                  R
                  $ US-
  U-  U:X  a3  UR                  R
                  =(       a    UR                  R                  $ g)z9Check if two players have a road connection between them.Fr    r   )r,   r<   r/   r    
road_right	road_left)r%   player1_indexplayer2_indexr3   player1player2num_playerss          r   has_road_connectionr     s    ,,.NN++}N@S/S+G+G7M**'2E2E7M**'2E2E n%K 	[(M9""--O'2E2E2O2OO 	[(M9"",,O1D1D1O1OOr*   c                F   U R                   nU R                  5       nUR                  [        U5      :  Ga@  X!R                     n[	        US5      (       Ga   UR
                  (       Ga  UR                  nUR                  nUS:  d  US:  a  [        XR                  UR                  5      nU(       ay  UR
                  =R                  U-  sl
        UR
                  =R                  U-  sl        U R                  U5      nU(       a  UR                  S5        U R                  S5        OJXCR
                  l        XSR
                  l        U R                  U5      nU(       a  UR                  SXE-   S9  UR                  [        U5      :  a  X!R                     n[	        US5      (       ac  UR
                  (       aR  UR
                  =R                  UR"                  -  sl
        UR
                  =R                  UR$                  -  sl        UR'                  5         g)z%Return surviving armies after battle.r    r   zageofheroes-army-return-roadzgame_ageofheroes/backarmy.oggzageofheroes-army-return-delayed)r   N)rH   r,   rE   r<   r/   r    rf   rg   r   rF   rb   rc   rK   rM   rI   returning_armiesreturning_generalsrk   rl   reset)	r%   rT   r3   r@   surviving_armiessurviving_generalshas_roadrO   rA   s	            r   r   r     s   
..C,,.N C//!"4"458]++0D0D0D"22!$!6!6!#'9A'=.t5G5GI[I[\((//3CC/((115GG1==2D%CDOO$CD =M((9>P((;==2D="2"G %  C//!"4"458]++0D0D  ''3+>+>>'  ))S-B-BB) IIKr*   c                    UR                    HC  nUR                  [        R                  :X  d  M#  UR                  [
        R                  :X  d  MC    g   g)z,Check if player has Fortune card for reroll.TF)r#   r   r   r   r   r   FORTUNE)r%   r&   r   s      r   check_fortune_rerollr     s9    >>X^^+	@Q@Q0Q  r*   c                   [        UR                  5       H  u  p#UR                  [        R                  :X  d  M%  UR
                  [        R                  :X  d  ME  UR                  R                  U5      nU R                  R                  U5        U R                  SUR                  S9  U R                  S5          g   g)z Use Fortune card to reroll dice.zageofheroes-fortune-rerollrW   zgame_ageofheroes/fortune.oggTF)r.   r#   r   r   r   r   r   r   rX   rY   r1   r[   rN   rI   r\   s        r   use_fortune_rerollr     s    V[[)>>X^^+	@Q@Q0Qkkooa(G$$W-9LOO:; * r*   c                   U R                  5       nU R                  nUR                  [        U5      :  a=  XR                     nUR                  (       a  UR
                  S:X  a  SUl        SUl        UR                  [        U5      :  a@  XR                     nUR                  (       a   UR                  S:X  a  SUl        SUl        gggg)z%Jolt bot players to roll dice in war.r   Nr   )
r,   rH   rE   r<   is_botr|   bot_pending_actionbot_think_ticksrF   r~   r%   r3   rT   r@   rA   s        r   jolt_war_botsr     s    ,,.N
..C
C//!"4"45??s00A5*.H''(H$
C//!"4"45??s00A5*.H''(H$  6? 0r*   c                   [        U 5        [        U 5      (       a  [        U 5        gU R                  R	                  5         U R                  5         U R                  5       nU R                  nUR                  [        U5      :  a-  XR                     nUR                  (       a  SUl
        SUl        UR                  [        U5      :  a/  XR                     nUR                  (       a  SUl
        SUl        ggg)z?Resolve one round of war battle after both players have rolled.r   N)r   r   finish_war_battlerH   reset_round_rollsrebuild_all_menusr,   rE   r<   r   r   r   rF   r   s        r   resolve_war_roundr     s      d$ 	((*  002nnN 33%&8&89H+,(.2+N 33%&8&89H+,(.2+  4r*   c                V   SSK Jn  U R                  5       nU R                  nUR                  [        U5      :  a|  UR                  [        U5      :  ac  X#R                     nX#R                     nUR                  5       nUR                  5       nU R                  SUR                  UR                  UUS9  [        U 5      (       a  [        U 5        gUR                  U l        SUl        UR!                  5         U R#                  5         U R                  5       nUR                  [        U5      :  a-  X#R                     nUR$                  (       a  SUl        SUl        UR                  [        U5      :  a/  X#R                     nUR$                  (       a  SUl        SUl        ggg)zStart the interactive war battle after both sides have prepared forces.

Players will now click to roll dice each round instead of automatic resolution.
r   )PlaySubPhasezageofheroes-battle-start)r@   rA   
att_armies
def_armiesNTr   )stater   r,   rH   rE   r<   rF   r   r   r[   rN   r   r   
WAR_BATTLE	sub_phasebattle_in_progressr   r   r   r   r   )r%   r   r3   rT   r@   rA   r   r   s           r   execute_war_battler     s|   
 $ ,,.N
..C
C//C4F4F^I\4\!"4"45!"4"45224
224
 	&]]]]!! 	 	
 d$ ",,DN!C 	 ,,.N
C//!"4"45??'(H$*.H'
C//!"4"45??'(H$*.H'  0r*   c                b   U R                  5       nU R                  n[        U 5      nUR                  nSnSnUR                  [        U5      :  aM  UR                  [        U5      :  a4  XR                     nXR                     nUR                  nUR                  n[        U 5        U(       dO  U(       aH  U(       aA  US:X  a  U R                  SUUS9  O)US:X  a  U R                  SUUS9  OU R                  SUUS9  UR                  [        U5      :  a  XR                     nU R                  U5        UR                  [        U5      :  a  XR                     nU R                  U5        UR                  n	UR                  5         U	[        U5      :  a  X   nU R                  U5        gg)z(Finish the war battle and apply outcome.Nr@   z#ageofheroes-battle-victory-attacker)r@   rA   rA   z#ageofheroes-battle-victory-defenderz ageofheroes-battle-mutual-defeat)r,   rH   r   r   rE   r<   rF   rN   r   r[   _check_eliminationr   _end_action)
r%   r3   rT   r   
had_roundsattacker_namedefender_namer@   rA   attacker_idxs
             r   r   r   L  s   ,,.N
..C t$F''JMM
C//C4F4F^I\4\!"4"45!"4"45   d
 -MZ5&&  
 z!5&&   2&&   C//!"4"45)
C//!"4"45) %%LIIKc.))!/" *r*   )r%   r   r&   r   return
str | None)r%   r   r&   r   r   z#list[tuple[int, AgeOfHeroesPlayer]])r%   r   r@   r   rA   r   r   z	list[str])
r%   r   r@   r   rF   intrG   strr   bool)r%   r   r   AgeOfHeroesPlayer | None)r%   r   r&   r   r   r   )r   r   )r%   r   r&   r   rb   r   rc   r   rd   r   rq   r   r   r   )r%   r   r&   r   r   r   )r%   r   r   tuple[str, int, int])rT   r
   r3   zlist[AgeOfHeroesPlayer]r   zWtuple[int, int, int, int, int, int, AgeOfHeroesPlayer | None, AgeOfHeroesPlayer | None])r%   r   r@   r   rA   r   r   r   r   r   r   r   r   r   r   r   r   r   r   None)r%   r   r   r   r   r   r   r   r   r   r   r   )r%   r   r@   r   rA   r   r   r   r   r   r   r   )r%   r   r   r   r   r   r   r   )r%   r   r   r   )r%   r   r   r   )r%   r   r   r   )r%   r   r   r   r   r   r   r   ),__doc__
__future__r   rz   typingr   cardsr   r   r   r	   r   r
   r   r   r   r%   r   r   r)   r$   rC   rQ   rU   r^   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r*   r   <module>r      sW   * "    ; ;  8.
#4(.
   	4(
(( ( 	(
 
(V(. F
FF F 	F
 F F 
FR$N'4T3	3#:3	3l


&
 '
 	

 
 
 
 
 
 

>
"  	
  
8$
$&$ '$ 	$
 $ $N#0L8$^"B<.b	)(3:4/n:#r*   