§
    ~¹»jP  ã                   ó  — d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
mZ  ee¦  «                             ¦   «         j        j        j        Zedz  dz  Zedz  Z G d„ dej        ¦  «        Zed	k    r ej        ¦   «          dS dS )
aþ  
Unit tests for Character Animation State Machine and 3 Distinct Martial Skill VFX Systems in FreeExile.
Verifies:
1. Animation State Machine: automatic recovery from 'attack' and 'cast' back to 'idle'/'run' (zero freeze).
2. 8-directional isometric kinematics and velocity tilt/bobbing calculations.
3. 3 Distinct Martial Skill Systems:
   - Fire: Infernal Crescent Slash Wave (vfx_slashes, ground scorch, conflagration blast)
   - Thunder: Heavenly Lightning Bolt (vfx_lightnings, procedural branches, shockwave ring)
   - Frost: Sub-Zero Glacial Spikes Nova (vfx_spikes, crystal facets, frost shatter shards)
4. martial_skills_atlas asset registration and metadata loading.
5. Dynamic Screen Shake camera transformation and high-fidelity Ghost Trail afterimages.
é    N)ÚPathÚclientÚwebappz
index.htmlc                   ó`   — 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 )Ú"TestCharacterAnimationAndSkillsVFXc                 ó<  — |                       t                               ¦   «         d¦  «         g }t          t          dd¬¦  «        5 }|                     |                     ¦   «         ¦  «         d d d ¦  «         n# 1 swxY w Y   t          t          dz                       d¦  «        ¦  «        D ]S}t          |dd¬¦  «        5 }|                     |                     ¦   «         ¦  «         d d d ¦  «         n# 1 swxY w Y   ŒTt          t          dz                       d¦  «        ¦  «        D ]S}t          |dd¬¦  «        5 }|                     |                     ¦   «         ¦  «         d d d ¦  «         n# 1 swxY w Y   ŒTd	 	                    |¦  «        | _
        d S )
Nz#client/webapp/index.html must existÚrzutf-8)ÚencodingÚjsz**/*.jsÚcssz**/*.cssú
)Ú
assertTrueÚ
INDEX_HTMLÚexistsÚopenÚappendÚreadÚsortedÚ
WEBAPP_DIRÚglobÚjoinÚhtml)ÚclsÚpartsÚfÚjs_fileÚcss_files        úKC:\Projects\FreeExile\tests\unit\test_character_animation_and_skills_vfx.pyÚ
setUpClassz-TestCharacterAnimationAndSkillsVFX.setUpClass   s  € à�Š•z×(Ò(Ñ*Ô*Ð,QÑRÔRÐRàˆÝ•*˜c¨GÐ4Ñ4Ô4ð 	#¸Ø�LŠL˜Ÿš™œÑ"Ô"Ð"ð	#ð 	#ð 	#ñ 	#ô 	#ð 	#ð 	#ð 	#ð 	#ð 	#ð 	#øøøð 	#ð 	#ð 	#ð 	#å�z¨DÑ0×6Ò6°yÑAÔAÑBÔBð 	'ð 	'ˆGÝ�g˜s¨WÐ5Ñ5Ô5ð '¸Ø—’˜QŸVšV™XœXÑ&Ô&Ð&ð'ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'øå¥
¨UÑ 2×8Ò8¸ÑDÔDÑEÔEð 	'ð 	'ˆHÝ�h ¨gÐ6Ñ6Ô6ð '¸!Ø—’˜QŸVšV™XœXÑ&Ô&Ð&ð'ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'øà—9’9˜UÑ#Ô#ˆŒˆˆs6   Á(A;Á;A?ÂA?Ã(C8Ã8C<	Ã?C<	Å(E6Å6E:	Å=E:	c                 ót   — |                       d| j        d¦  «         |                       d| j        ¦  «         dS )z<martial_skills_atlas must be registered in ASSETS preloader.Úmartial_skills_atlasz;martial_skills_atlas must be registered in ASSETS assetListz(./assets/skills/martial_skills_atlas.pngN©ÚassertInr   ©Úselfs    r   Ú2test_martial_skills_atlas_registered_in_asset_listzUTestCharacterAnimationAndSkillsVFX.test_martial_skills_atlas_registered_in_asset_list(   s9   € à�ŠÐ,¨d¬iÐ9vÑwÔwÐwØ�ŠÐ@À$Ä)ÑLÔLÐLÐLÐLó    c                 óŽ   — d| j         v pd| j         v }|                      |d¦  «         |                      | j         dd¦  «         dS )zQAttack state must have an automatic recovery timer to prevent permanent freezing.ÚattackTimerÚattackDurationzJPlayer must have an attackTimer to automatically recover from attack stateziplayer\.animState\s*=\s*(mag\s*>\s*0\.05|\(?\w+\s*>\s*0\.05\)?)\s*\?\s*['\"]run['\"]\s*:\s*['\"]idle['\"]zYAttack state must automatically transition to 'run' or 'idle' when attack timer completesN)r   r   ÚassertRegex)r%   Úhas_attack_timers     r   Ú1test_animation_state_machine_attack_auto_recoveryzTTestCharacterAnimationAndSkillsVFX.test_animation_state_machine_attack_auto_recovery-   sc   € ð )¨D¬IÐ5ÐVÐ9IÈTÌYÐ9VÐØ�ŠÐ(Ð*vÑwÔwÐwð 	×ÒØŒIØxØgñ	
ô 	
ð 	
ð 	
ð 	
r'   c                 óÊ   — d| j         v pd| j         v pd| j         v }|                      |d¦  «         d| j         v pd| j         v pd| j         v }|                      |d¦  «         d	S )
zPMust calculate 8-directional isometric facing and body lean tilt during running.ÚfacingAngleÚheading8DirÚtargetAnglez9Must compute directional angle for 8-way isometric facingÚ	leanAngleÚfootstepÚfootstepDustz>Must implement dynamic body lean or footstep dust when runningN©r   r   )r%   Úhas_headingÚhas_tilt_or_dusts      r   Ú&test_directional_kinematics_and_facingzITestCharacterAnimationAndSkillsVFX.test_directional_kinematics_and_facing:   s†   € ð $ t¤yÐ0Ðl°MÀTÄYÐ4NÐlÐR_ÐcgÔclÐRlˆØ�Š˜Ð%`ÑaÔaÐað '¨$¬)Ð3Ðm°zÀTÄYÐ7NÐmÐR`ÐdhÔdmÐRmÐØ�ŠÐ(Ð*jÑkÔkÐkÐkÐkr'   c                 ó,  — d| j         v pd| j         v pd| j         v }|                      |d¦  «         d| j         v pd| j         v pd| j         v }|                      |d¦  «         d	| j         v pd
| j         v pd| j         v }|                      |d¦  «         dS )zUMust implement 3 completely distinct VFX systems for Fire, Thunder, and Frost skills.Úvfx_slashesÚspawnInfernalSlashÚcastFireSlashzGFire skill must spawn an Infernal Crescent Slash Wave, not generic dotsÚvfx_lightningsÚspawnLightningStrikeÚcastThunderSmitez?Thunder skill must spawn a Celestial Lightning Bolt from heavenÚ
vfx_spikesÚspawnGlacialSpikesÚcastFrostNovaz>Frost skill must spawn Glacial Spikes erupting from the groundNr5   )r%   Úhas_slash_waveÚhas_lightning_boltÚhas_glacial_spikess       r   Ú)test_three_distinct_martial_skill_systemszLTestCharacterAnimationAndSkillsVFX.test_three_distinct_martial_skill_systemsD   sÛ   € ð '¨$¬)Ð3ÐxÐ7KÈtÌyÐ7XÐxÐ\kÐosÔoxÐ\xˆØ�Š˜Ð(qÑrÔrÐrð .°´Ð:ð  EÐ>TÐX\ÔXaÐ>að  EÐewÐ{ô  |Eð  fEÐØ�ŠÐ*Ð,mÑnÔnÐnð *¨T¬YÐ6Ð{Ð:NÐRVÔR[Ð:[Ð{Ð_nÐrvÔr{Ð_{ÐØ�ŠÐ*Ð,lÑmÔmÐmÐmÐmr'   c                 óv   — |                       d| j        d¦  «         |                       d| j        d¦  «         dS )zPMust implement dynamic screen shake camera controller for impactful combat feel.ÚscreenShakez#Must have screenShake camera systemÚtriggerScreenShakez%Must have triggerScreenShake functionNr"   r$   s    r   Útest_screen_shake_camera_systemzBTestCharacterAnimationAndSkillsVFX.test_screen_shake_camera_systemR   s;   € à�Š�m T¤YÐ0UÑVÔVÐVØ�ŠÐ*¨D¬IÐ7^Ñ_Ô_Ð_Ð_Ð_r'   c                 óh   — d| j         v od| j         v pd| j         v }|                      |d¦  «         dS )z_Phantom evasion (dodge) must render character silhouette ghost trails, not simple colored dots.Ú	drawImageÚghostTrailsÚghostzMGhost trails must render sprite silhouette for authentic PoE2 phantom evasionNr5   )r%   Úhas_silhouettes     r   Útest_high_fidelity_ghost_trailszBTestCharacterAnimationAndSkillsVFX.test_high_fidelity_ghost_trailsW   sF   € ð %¨¬	Ð1Ðj°}ÈÌ	Ð7QÐ7iÐU\Ð`dÔ`iÐUiˆØ�Š˜Ð(wÑxÔxÐxÐxÐxr'   c                 óæ   — |                       d| j        d¦  «         |                       d| j        d¦  «         |                       d| j        d¦  «         |                       d| j        d¦  «         d	S )
zWCombat skills must calculate origin (caster) to target trajectory with flight progress.ÚoriginXzProjectiles must define originXÚtargetXzProjectiles must define targetXÚprogressz;Projectiles must interpolate with progress along trajectoryÚdurationz7Projectiles must have flight duration based on distanceNr"   r$   s    r   Ú0test_origin_target_flying_projectiles_trajectoryzSTestCharacterAnimationAndSkillsVFX.test_origin_target_flying_projectiles_trajectory]   sn   € ð 	�Š�i ¤Ð,MÑNÔNÐNØ�Š�i ¤Ð,MÑNÔNÐNØ�Š�j $¤)Ð-jÑkÔkÐkØ�Š�j $¤)Ð-fÑgÔgÐgÐgÐgr'   c                 óv   — |                       d| j        d¦  «         |                       d| j        d¦  «         dS )zdMonster impact damage and reactions must trigger upon projectile arrival at target, not immediately.zprogress >= 1.0z?Impact damage must trigger when projectile progress reaches 1.0ÚimpactTriggeredz.Must guard against duplicate impact triggeringNr"   r$   s    r   Ú%test_delayed_impact_damage_on_arrivalzHTestCharacterAnimationAndSkillsVFX.test_delayed_impact_damage_on_arrivale   s<   € à�ŠÐ'¨¬Ð4uÑvÔvÐvØ�ŠÐ'¨¬Ð4dÑeÔeÐeÐeÐer'   c                 óz   — d| j         v pd| j         v pd| j         v pd| j         v }|                      |d¦  «         dS )zTMonster must display distinct status reactions for burning, shock, and chill/freeze.zmonster.burnTimerzmonster.shockTimerzmonster.freezeTimerÚmonsterStatuszKMonster must react with distinct status VFX (burn, shock, freeze) to skillsNr5   )r%   Ú
has_statuss     r   Ú test_monster_status_vfx_feedbackzCTestCharacterAnimationAndSkillsVFX.test_monster_status_vfx_feedbackj   sw   € à(¨D¬IÐ5ð  aÐ9MÐQUÔQZÐ9Zð  aÐ^sÐw{ô  xAð  _Að  að  ETð  X\ô  Xað  Eaˆ
Ø�Š˜
Ð$qÑrÔrÐrÐrÐrr'   c                 ó®   — |                       d| j        d¦  «         |                       d| j        d¦  «         |                       d| j        d¦  «         dS )z\Character must be styled and named as Savage Exile, eliminating traditional wuxia swordsman.Úsavage_primal_exilez0savage_primal_exile must be registered in ASSETSu   Káº» Bá»‹ LÆ°u Ä�Ã yu-   Character name must be 'Káº» Bá»‹ LÆ°u Ä�Ã y'zThe Forsaken Exilez+Character name must be 'The Forsaken Exile'Nr"   r$   s    r   Ú4test_savage_primal_exile_character_assets_and_namingzWTestCharacterAnimationAndSkillsVFX.test_savage_primal_exile_character_assets_and_namingo   sX   € ð 	�ŠÐ+¨T¬YÐ8jÑkÔkÐkà�ŠÐ,¨d¬iÐ9hÑiÔiÐiØ�ŠÐ*¨D¬IÐ7dÑeÔeÐeÐeÐer'   N)Ú__name__Ú
__module__Ú__qualname__Úclassmethodr   r&   r-   r8   rF   rJ   rP   rV   rY   r]   r`   © r'   r   r   r      sà   € € € € € Øð$ð $ñ „[ð$ðMð Mð Mð

ð 
ð 
ðlð lð lðnð nð nð`ð `ð `ð
yð yð yðhð hð hðfð fð fð
sð sð sð
fð fð fð fð fr'   r   Ú__main__)Ú__doc__ÚbuiltinsÚ@py_builtinsÚ_pytest.assertion.rewriteÚ	assertionÚrewriteÚ
@pytest_arÚunittestÚosÚreÚpathlibr   Ú__file__ÚresolveÚparentÚPROJECT_ROOTr   r   ÚTestCaser   ra   Úmainre   r'   r   ú<module>rx      s÷   ððð ð € € € € € € € € € € € € €€€€Ø 	€	€	€	Ø 	€	€	€	Ø Ð Ð Ð Ð Ð àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$ xÑ/€
Ø˜,Ñ&€
ð]fð ]fð ]fð ]fð ]f¨Ô):ñ ]fô ]fð ]fð@ ˆzÒÐØ€H„M�O„O€O€O€Oð Ðr'   