§
    €Æ½j/  ã                   ó2  — d Z ddlZddlmc mZ ddlZddlZddl	m
Z
  e
e¦  «                             ¦   «         j        j        j        Zedz  Z ee¦  «        ej        vr$ej                             d ee¦  «        ¦  «          ee¦  «        ej        vr$ej                             d ee¦  «        ¦  «         ddlmZ ddlmZmZ ddlmZ edz  d	z  Zed
z  dz  dz  Zed
z  dz  dz  Z G d„ dej        ¦  «        Zedk    r ej         ¦   «          dS dS )a|  
Unit and Integration Test Suite for FreeExile Milestone 4 Monster Poise, Stagger & Leashing:
- Monster poise recovery and safety reset (m.staggerTimer <= 0 && m.poise <= 0 -> m.poise = m.maxPoise)
- Stagger window attack cancellation (cancelTelegraph(m.id)) and action unlock
- Authoritative AI leashing persistent state (m.isLeashing latch)
- Leash return invulnerability and 30%/s HP regeneration
- Server MonsterAIEngine parity (30%/s regen, 1.5x speed, invulnerability, arrival reset)
- CombatSkills invulnerability protection against hitting leashing monsters
- Strict hygiene compliance (monster_system.js <= 500 lines hard cap)
é    N)ÚPathÚserver)ÚMonsterAIEngine)ÚMonsterRuntimeStateÚMonsterAIState)ÚMonsterProceduralEngineÚclientÚwebappÚjsÚenginezmonster_system.jszcombat_skills.jsc                   ó`   — e Zd Zed„ ¦   «         Zd„ Zd„ Zd„ Zd„ Zd„ Z	d„ Z
d„ Zd	„ Zd
„ Zd„ ZdS )ÚTestMonsterPoiseAndLeashc                 ó†   — t                                d¬¦  «        | _        t                               d¬¦  «        | _        d S )Nzutf-8)Úencoding)ÚMONSTER_SYSTEM_JSÚ	read_textÚmonster_system_contentÚCOMBAT_SKILLS_JSÚcombat_skills_content)Úclss    ú@C:\Projects\FreeExile\tests\unit\test_monster_poise_and_leash.pyÚ
setUpClassz#TestMonsterPoiseAndLeash.setUpClass!   s:   € å%6×%@Ò%@È'Ð%@Ñ%RÔ%RˆÔ"Ý$4×$>Ò$>ÈÐ$>Ñ$PÔ$PˆÔ!Ð!Ð!ó    c                 ó¨   — |                       d| j        ¦  «         |                       d| j        ¦  «         |                       d| j        ¦  «         dS )z^Verifies monster_system.js restores poise to maxPoise when staggerTimer expires or poise <= 0.z.if (m.staggerTimer <= 0) m.poise = m.maxPoise;zelse if (m.poise <= 0)zm.poise = m.maxPoise;N©ÚassertInr   ©Úselfs    r   Ú2test_monster_system_poise_recovery_on_timer_expiryzKTestMonsterPoiseAndLeash.test_monster_system_poise_recovery_on_timer_expiry'   sP   € à�ŠÐFÈÔHcÑdÔdÐdØ�ŠÐ.°Ô0KÑLÔLÐLØ�ŠÐ-¨tÔ/JÑKÔKÐKÐKÐKr   c                 ó<   — |                       d| j        ¦  «         dS )zQVerifies monster_system.js cancels active attack telegraph during stagger window.zcancelTelegraph(m.id)Nr   r   s    r   Ú4test_monster_system_stagger_cancels_active_telegraphzMTestMonsterPoiseAndLeash.test_monster_system_stagger_cancels_active_telegraph-   s    € à�ŠÐ-¨tÔ/JÑKÔKÐKÐKÐKr   c                 ó<   — |                       d| j        ¦  «         dS )z>Verifies monster animation action lock is released on stagger.zm.anim.isActionLocked = falseNr   r   s    r   Ú*test_monster_system_stagger_unlocks_actionzCTestMonsterPoiseAndLeash.test_monster_system_stagger_unlocks_action1   s    € à�ŠÐ5°tÔ7RÑSÔSÐSÐSÐSr   c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zRVerifies monster_system.js holds isLeashing state until reaching origin threshold.zm.isLeashingzdistToOrigin <= 0.6Nr   r   s    r   Ú1test_monster_system_leash_return_persistent_statezJTestMonsterPoiseAndLeash.test_monster_system_leash_return_persistent_state6   s7   € à�Š�n dÔ&AÑBÔBÐBØ�ŠÐ+¨TÔ-HÑIÔIÐIÐIÐIr   c                 ór   — |                       d| j        ¦  «         |                       d| j        ¦  «         dS )zYVerifies monster_system.js grants invulnerability and 30%/s HP regen during leash return.zm.isInvulnerable = truez	0.30 * dtNr   r   s    r   Ú=test_monster_system_leash_return_invulnerability_and_hp_regenzVTestMonsterPoiseAndLeash.test_monster_system_leash_return_invulnerability_and_hp_regen;   s7   € à�ŠÐ/°Ô1LÑMÔMÐMØ�Š�k 4Ô#>Ñ?Ô?Ð?Ð?Ð?r   c                 ó<   — |                       d| j        ¦  «         dS )zHVerifies active telegraph is cancelled when monster enters leash return.zAif (typeof cancelTelegraph === 'function') cancelTelegraph(m.id);Nr   r   s    r   Ú+test_monster_system_leash_cancels_telegraphzDTestMonsterPoiseAndLeash.test_monster_system_leash_cancels_telegraph@   s!   € à�ŠÐYÐ[_Ô[vÑwÔwÐwÐwÐwr   c                 ó<   — |                       d| j        ¦  «         dS )zGVerifies combat_skills.js guards against damaging invulnerable targets.ztarget.isInvulnerableN)r   r   r   s    r   Ú,test_combat_skills_invulnerable_target_guardzETestMonsterPoiseAndLeash.test_combat_skills_invulnerable_target_guardE   s    € à�ŠÐ-¨tÔ/IÑJÔJÐJÐJÐJr   c           	      óÒ  — t          ¦   «         }t          ¦   «                              dd¬¦  «        }|j        dz  }t	          |dd|ddt
          j        ¬¦  «        }|                     |dd	¬
¦  «        }|                      |j	        d¦  «         |  
                    |j        ¦  «         t          |j        ||j        dz  d	z  z   ¦  «        }|                      |j        |¦  «         dS )zJVerifies server MonsterAIEngine grants invulnerability and 30%/s HP regen.é   é
   ©Útarget_levelgš™™™™™É?ç      4@ç        ©ÚmonsterÚ	current_xÚ	current_yÚ
current_hpÚspawn_xÚspawn_yÚai_state)r1   r1   ç      ð?©Ú
player_posÚdtÚRETURN_TO_SPAWNg333333Ó?N)r   r   Úgenerate_monsterÚmax_hpr   r   ÚLEASH_RETURNÚupdateÚassertEqualÚaction_typeÚ
assertTrueÚis_invulnerableÚminÚassertAlmostEqualr7   )r   Ú	ai_enginer4   Ú
initial_hpÚstateÚactionÚexpected_hps          r   Ú<test_server_ai_leash_return_grants_invulnerability_and_regenzUTestMonsterPoiseAndLeash.test_server_ai_leash_return_grants_invulnerability_and_regenJ   sï   € å#Ñ%Ô%ˆ	Ý)Ñ+Ô+×<Ò<¸QÈRÐ<ÑPÔPˆØ”^ cÑ)ˆ
Ý#ØØØØ!ØØÝ#Ô0ð
ñ 
ô 
ˆð ×!Ò! %°LÀSÐ!ÑIÔIˆØ×Ò˜Ô+Ð->Ñ?Ô?Ð?Ø�Š˜Ô-Ñ.Ô.Ð.Ý˜'œ.¨*°w´~ÈÑ7LÈsÑ7RÑ*RÑSÔSˆØ×Ò˜uÔ/°Ñ=Ô=Ð=Ð=Ð=r   c           	      ó  — t          ¦   «         }t          ¦   «                              dd¬¦  «        }t          |dd|j        ddt
          j        ¬¦  «        }|                     |dd¬	¦  «        }|                      |j	        d
¦  «         |                      |j
        t
          j        ¦  «         |                      |j        ¦  «         |                      |j        d¦  «         |                      |j        d¦  «         dS )zbVerifies server MonsterAIEngine resets to IDLE and removes invulnerability when arriving at spawn.é   r.   r/   g      à?r2   r3   )ç      .@rR   r;   r<   ÚSTANDN)r   r   r@   r   rA   r   rB   rC   rD   rE   r:   ÚIDLEÚassertFalserG   r5   r6   )r   rJ   r4   rL   rM   s        r   Ú/test_server_ai_leash_return_arrival_resets_idlezHTestMonsterPoiseAndLeash.test_server_ai_leash_return_arrival_resets_idle^   sö   € å#Ñ%Ô%ˆ	Ý)Ñ+Ô+×<Ò<¸QÈRÐ<ÑPÔPˆÝ#ØØØØ”~ØØÝ#Ô0ð
ñ 
ô 
ˆð ×!Ò! %°LÀSÐ!ÑIÔIˆØ×Ò˜Ô+¨WÑ5Ô5Ð5Ø×Ò˜œ­Ô)<Ñ=Ô=Ð=Ø×Ò˜Ô.Ñ/Ô/Ð/Ø×Ò˜œ¨#Ñ.Ô.Ð.Ø×Ò˜œ¨#Ñ.Ô.Ð.Ð.Ð.r   c                 ó  — | j                              ¦   «         }|                      t          |¦  «        ddt          |¦  «        › d�¦  «         |                      t          |¦  «        ddt          |¦  «        › d�¦  «         dS )zTVerifies client/webapp/js/engine/monster_system.js is <= 490 lines (strict cap 500).iê  zmonster_system.js line count z exceeds 490 lines target!iô  z exceeds 500 hard cap!N)r   Ú
splitlinesÚassertLessEqualÚlen)r   Úliness     r   Ú3test_monster_system_line_count_within_hygiene_limitzLTestMonsterPoiseAndLeash.test_monster_system_line_count_within_hygiene_limits   s~   € àÔ+×6Ò6Ñ8Ô8ˆØ×Ò�S ™ZœZ¨Ð.tÍcÐRWÉjÌjÐ.tÐ.tÐ.tÑuÔuÐuØ×Ò�S ™ZœZ¨Ð.pÍcÐRWÉjÌjÐ.pÐ.pÐ.pÑqÔqÐqÐqÐqr   N)Ú__name__Ú
__module__Ú__qualname__Úclassmethodr   r   r!   r#   r%   r'   r)   r+   rO   rV   r\   © r   r   r   r       sà   € € € € € ØðQð Qñ „[ðQð
Lð Lð LðLð Lð LðTð Tð Tð
Jð Jð Jð
@ð @ð @ð
xð xð xð
Kð Kð Kð
>ð >ð >ð(/ð /ð /ð*rð rð rð rð rr   r   Ú__main__)!Ú__doc__ÚbuiltinsÚ@py_builtinsÚ_pytest.assertion.rewriteÚ	assertionÚrewriteÚ
@pytest_arÚsysÚunittestÚpathlibr   Ú__file__ÚresolveÚparentÚPROJECT_ROOTÚ
SERVER_DIRÚstrÚpathÚinsertÚworld.monster_ai_enginer   Úworld.monster_typesr   r   Úworld.monster_procedural_enginer   Ú
WEBAPP_DIRr   r   ÚTestCaser   r]   Úmainra   r   r   ú<module>r{      sÀ  ðð	ð 	ð € € € € € € € € € € € € €
€
€
€
Ø €€€Ø Ð Ð Ð Ð Ð àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$€
Ø€3€z�?„?˜#œ(Ð"Ð"Ø„H‡O‚O�A�s�s˜:‘”Ñ'Ô'Ð'Ø€3€|ÑÔ˜CœHÐ$Ð$Ø„H‡O‚O�A�s�s˜<Ñ(Ô(Ñ)Ô)Ð)à 3Ð 3Ð 3Ð 3Ð 3Ð 3Ø CÐ CÐ CÐ CÐ CÐ CÐ CÐ CØ CÐ CÐ CÐ CÐ CÐ Cà˜HÑ$ xÑ/€
Ø Ñ%¨Ñ0Ð3FÑFÐ Ø Ñ$ xÑ/Ð2DÑDÐ ðWrð Wrð Wrð Wrð Wr˜xÔ0ñ Wrô Wrð Wrðt ˆzÒÐØ€H„M�O„O€O€O€Oð Ðr   