§
    Ã½jnT  ã                   ó�  — d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	m
Z
 ddlZej                             ej                             ej                             e¦  «        d¦  «        ¦  «        Zeej        vrej                             de¦  «         ddlmZ ddlmZmZ ddlmZmZ dd	lmZmZ dd
lmZ ddl m!Z!m"Z"m#Z# ddl$m%Z% ddl&m'Z' ej(        defd„¦   «         Z)ej(        defd„¦   «         Z*ej(        de
eeef         fd„¦   «         Z+ G d„ d¦  «        Z, G d„ d¦  «        Z- G d„ d¦  «        Z. G d„ d¦  «        Z/dS )a4  
Comprehensive E2E Test Suite for FreeExile PoE2 Spatial Zoning & Encounter Systems.
Enforces 4-Tier Testing Methodology:
- Tier 1: Feature Coverage (>=5 test cases per feature area)
- Tier 2: Boundary & Corner Cases
- Tier 3: Cross-Feature Combinations
- Tier 4: Real-World End-to-End Application Scenarios
é    N)ÚPath)ÚDictÚListÚTuplez../../server©Ú
ZoneEngine)ÚZoneTypeÚZoneDefinition)ÚHideoutEngineÚ	AstralMap)ÚCombatEngineÚCombatActor)ÚFiveElements)ÚMonsterAIStateÚMonsterRuntimeStateÚMonsterGenus)ÚMonsterAIEngine)ÚMonsterProceduralEngineÚreturnc                  ó   — t          ¦   «         S ©Nr   © ó    úCC:\Projects\FreeExile\tests\e2e\test_poe2_zone_and_encounter_e2e.pyÚzone_enginer      s   € å‰<Œ<Ðr   c                  ó   — t          ¦   «         S r   )r   r   r   r   Úhideout_enginer   #   s   € å‰?Œ?Ðr   c                  óò   — t          ¦   «         } t          ddt          j        d¬¦  «        }t          ddt          j        dd¬¦  «        }|                      |¦  «         |                      |¦  «         | ||fS )	Né   u   QuÃ¡i Tinh Anhg     @U@)Úactor_idÚnameÚelementÚbase_attacké   u   LÆ°u Ä�Ã y Giáº£ç     @�@)r    r!   r"   Ú
current_hpÚmax_hp)r   r   r   ÚHOAÚKIMÚregister_actor)ÚengineÚattackerÚdefenders      r   Úcombat_setupr.   '   sy   € å‰^Œ^€FÝ AÐ,<ÅlÔFVÐdhÐiÑiÔi€HÝ AÐ,>ÍÔHXÐekÐtzÐ{Ñ{Ô{€HØ
×Ò˜(Ñ#Ô#Ð#Ø
×Ò˜(Ñ#Ô#Ð#Ø�8˜XÐ%Ð%r   c                   óª  — e Zd ZdZdeddfd„Zdeddfd„Zdeddfd„Zdeddfd„Zd)d	„Z	deddfd
„Z
deddfd„Zdeddfd„Zd)d„Zd)d„Zdeddfd„Zdeddfd„Zdeddfd„Zdeddfd„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d„Zd)d „Z d)d!„Z!d)d"„Z"d#e#ddfd$„Z$d#e#ddfd%„Z%d#e#ddfd&„Z&d#e#ddfd'„Z'd#e#ddfd(„Z(dS )*ÚTestTier1FeatureCoveragezQTier 1: Feature Coverage (>=5 test cases per feature area from ORIGINAL_REQUEST).r   r   Nc                 ó8   — |                      d¦  «        du sJ ‚dS )z+Sanctuary hub rejects hostile mob spawning.Úzone_boundless_sanctuaryFN©Úcan_spawn_hostile_monsters©Úselfr   s     r   Ú*test_safe_haven_sanctuary_hostile_rejectedzCTestTier1FeatureCoverage.test_safe_haven_sanctuary_hostile_rejected3   s)   € à×5Ò5Ð6PÑQÔQÐUZÐZÐZÐZÐZÐZÐZr   c                 ó8   — |                      d¦  «        du sJ ‚dS )z,Player hideout rejects hostile mob spawning.Úzone_player_hideoutFNr3   r5   s     r   Ú(test_safe_haven_hideout_hostile_rejectedzATestTier1FeatureCoverage.test_safe_haven_hideout_hostile_rejected6   s)   € à×5Ò5Ð6KÑLÔLÐPUÐUÐUÐUÐUÐUÐUr   c                 óZ   — |                      dd¬¦  «        \  }}|du rd|v sd|v sJ ‚dS dS )z8validate_monster_spawn rejects hostile mob in sanctuary.r2   F©Úis_dummyõ   An ToÃ nÚ	SanctuaryN©Úvalidate_monster_spawn©r6   r   ÚallowedÚreasons       r   Ú2test_safe_haven_sanctuary_validate_rejects_hostilezKTestTier1FeatureCoverage.test_safe_haven_sanctuary_validate_rejects_hostile9   sQ   € à%×<Ò<Ð=WÐbgÐ<ÑhÔh‰ˆ�Ø˜%ÐÐ Z°6Ð%9Ð%9¸[ÈFÐ=RÐ=RÐ=RÐSÐ%9Ð%9Ð=RÐ=Rr   c                 óZ   — |                      dd¬¦  «        \  }}|du rd|v sd|v sJ ‚dS dS )z6validate_monster_spawn rejects hostile mob in hideout.r9   Fr<   r>   ÚHideoutNr@   rB   s       r   Ú0test_safe_haven_hideout_validate_rejects_hostilezITestTier1FeatureCoverage.test_safe_haven_hideout_validate_rejects_hostile=   sQ   € à%×<Ò<Ð=RÐ]bÐ<ÑcÔc‰ˆ�Ø˜%ÐÐ Z°6Ð%9Ð%9¸YÈ&Ð=PÐ=PÐ=PÐQÐ%9Ð%9Ð=PÐ=Pr   c                 ó`   — t          d¦  «                             d¬¦  «        }d|vrd|vsJ ‚dS )zPClient monster_system.js must not spawn hostile hounds/skeletons in safe havens.ú)client/webapp/js/engine/monster_system.jsúutf-8©ÚencodingÚhellhound_sanctuaryÚskeleton_sanctuaryN©r   Ú	read_text©r6   Úcontents     r   Ú)test_safe_haven_client_js_no_hostile_mobszBTestTier1FeatureCoverage.test_safe_haven_client_js_no_hostile_mobsA   sE   € åÐBÑCÔC×MÒMÐW^ÐMÑ_Ô_ˆØ$¨GÐ3Ð3Ð8LÐT[Ð8[Ð8[Ð8[Ð[Ð8[Ð8[r   c                 óH   — |                      dd¬¦  «        d         du sJ ‚dS )z'Target Dummy is permitted in sanctuary.r2   Tr<   r   Nr@   r5   s     r   Útest_dummy_allowed_in_sanctuaryz8TestTier1FeatureCoverage.test_dummy_allowed_in_sanctuaryG   s5   € à×1Ò1Ð2LÐW[Ð1Ñ\Ô\Ð]^Ô_ÐcgÐgÐgÐgÐgÐgÐgr   c                 óH   — |                      dd¬¦  «        d         du sJ ‚dS )z%Target Dummy is permitted in hideout.r9   Tr<   r   Nr@   r5   s     r   Útest_dummy_allowed_in_hideoutz6TestTier1FeatureCoverage.test_dummy_allowed_in_hideoutJ   ó5   € à×1Ò1Ð2GÐRVÐ1ÑWÔWÐXYÔZÐ^bÐbÐbÐbÐbÐbÐbr   c                 óH   — |                      dd¬¦  «        d         du sJ ‚dS )z(Target Dummy is permitted in wilderness.Úzone_tang_kiem_nhaiTr<   r   Nr@   r5   s     r   Ú test_dummy_allowed_in_wildernessz9TestTier1FeatureCoverage.test_dummy_allowed_in_wildernessM   rY   r   c                 óh   — t          d¦  «                             d¬¦  «        }d|v rd|v rd|v sJ ‚dS )zQClient monster_system.js configures dummy with isDummy: true and isNeutral: true.rJ   rK   rL   Údummy_primal_shrinezisDummy: truezisNeutral: trueNrP   rR   s     r   Ú"test_dummy_configured_in_client_jsz;TestTier1FeatureCoverage.test_dummy_configured_in_client_jsP   sO   € åÐBÑCÔC×MÒMÐW^ÐMÑ_Ô_ˆØ$¨Ð/Ð/°OÀwÐ4NÐ4NÐSdÐhoÐSoÐSoÐSoÐoÐSoÐSor   c                 óT   — dt          d¦  «                             d¬¦  «        v sJ ‚dS )zEClient monster_system.js skips movement and attacks for target dummy.zif (m.isDummy) continue;rJ   rK   rL   NrP   ©r6   s    r   Ú"test_dummy_stationary_in_client_jsz;TestTier1FeatureCoverage.test_dummy_stationary_in_client_jsT   s4   € à)­TÐ2]Ñ-^Ô-^×-hÒ-hÐryÐ-hÑ-zÔ-zÐzÐzÐzÐzÐzÐzr   c                 ó8   — |                      d¦  «        du sJ ‚dS )z/Bone Strand wilderness map allows hostile mobs.r[   TNr3   r5   s     r   Ú*test_wilderness_bone_strand_allows_hostilezCTestTier1FeatureCoverage.test_wilderness_bone_strand_allows_hostileY   s)   € à×5Ò5Ð6KÑLÔLÐPTÐTÐTÐTÐTÐTÐTr   c                 ó8   — |                      d¦  «        du sJ ‚dS )z0Rotten Swamp wilderness map allows hostile mobs.Úzone_ancient_sword_barrowTNr3   r5   s     r   Ú+test_wilderness_rotten_swamp_allows_hostilezDTestTier1FeatureCoverage.test_wilderness_rotten_swamp_allows_hostile]   s)   € à×5Ò5Ð6QÑRÔRÐVZÐZÐZÐZÐZÐZÐZr   c                 ó8   — |                      d¦  «        du sJ ‚dS )z/Bone Wastes wilderness map allows hostile mobs.Úzone_boundless_sandstormTNr3   r5   s     r   Ú*test_wilderness_bone_wastes_allows_hostilezCTestTier1FeatureCoverage.test_wilderness_bone_wastes_allows_hostilea   s)   € à×5Ò5Ð6PÑQÔQÐUYÐYÐYÐYÐYÐYÐYr   c                 óH   — |                      dd¬¦  «        d         du sJ ‚dS )z<validate_monster_spawn permits hostile spawns in outer maps.r[   Fr<   r   TNr@   r5   s     r   Ú-test_wilderness_validate_spawn_allows_hostilezFTestTier1FeatureCoverage.test_wilderness_validate_spawn_allows_hostilee   s5   € à×1Ò1Ð2GÐRWÐ1ÑXÔXÐYZÔ[Ð_cÐcÐcÐcÐcÐcÐcr   c                 ó˜   — t          ¦   «                              dd¬¦  «        }|j        dk    r|j        dk    r|j        t
          v sJ ‚dS )zAProcedural monster generation generates valid wilderness enemies.é*   é   ©Útarget_levelr   N)r   Úgenerate_monsterr'   Úbase_damageÚgenusr   )r6   Úms     r   Ú-test_wilderness_procedural_monster_attributeszFTestTier1FeatureCoverage.test_wilderness_procedural_monster_attributesi   sO   € å#Ñ%Ô%×6Ò6°rÈÐ6ÑKÔKˆØŒx˜!Š|ˆ| ¤°Ò 1Ð 1°a´gÅÐ6MÐ6MÐ6MÐMÐ6MÐ6Mr   c                 ó²   — |\  }}}t          t          j        ¦   «         dz  ¦  «        }|                     |j        |¬¦  «        du sJ ‚|j        |k    sJ ‚dS )u=   Triggering Huyá»…n áº¢nh Bá»™ records last evasion timestamp.éè  )r    Útimestamp_msTN)ÚintÚtimeÚtrigger_phantom_evasionr    Úlast_evasion_timestamp_ms)r6   r.   r+   Ú_ÚdefnÚnow_mss         r   Ú$test_dodge_trigger_records_timestampz=TestTier1FeatureCoverage.test_dodge_trigger_records_timestampo   sg   € à&‰ˆ��4Ý•T”Y‘[”[ 4Ñ'Ñ(Ô(ˆØ×-Ò-°t´}ÐSYÐ-ÑZÔZÐ^bÐbÐbÐbÐbØÔ-°Ò7Ð7Ð7Ð7Ð7Ð7r   c                 ó  — |\  }}}t          t          j        ¦   «         dz  ¦  «        }|                     |j        |¦  «         |                     |j        |j        dt
          j        |¦  «        }|j        du r|j        dk    sJ ‚dS )z-Attack landing at t+0ms is completely evaded.rx   ç      Y@Tç        N©	rz   r{   r|   r    Úcalculate_damager   r(   Ú	is_evadedÚfinal_damage©r6   r.   r+   Úatkr   r€   Úress          r   Ú#test_dodge_iframe_active_at_zero_msz<TestTier1FeatureCoverage.test_dodge_iframe_active_at_zero_msv   s‡   € à(Ñˆ��TÝ•T”Y‘[”[ 4Ñ'Ñ(Ô(ˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÑcÔcˆØŒ} Ð$Ð$¨Ô)9¸SÒ)@Ð)@Ð)@Ð@Ð)@Ð)@r   c                 ó  — |\  }}}t          t          j        ¦   «         dz  ¦  «        }|                     |j        |¦  «         |                     |j        |j        dt
          j        |dz   ¦  «        }|j        du r|j        dk    sJ ‚dS )z/Attack landing at t+100ms is completely evaded.rx   rƒ   éd   Tr„   Nr…   r‰   s          r   Ú&test_dodge_iframe_active_at_hundred_msz?TestTier1FeatureCoverage.test_dodge_iframe_active_at_hundred_ms~   ó�   € à(Ñˆ��TÝ•T”Y‘[”[ 4Ñ'Ñ(Ô(ˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÐehÑ\hÑiÔiˆØŒ} Ð$Ð$¨Ô)9¸SÒ)@Ð)@Ð)@Ð@Ð)@Ð)@r   c                 ó  — |\  }}}t          t          j        ¦   «         dz  ¦  «        }|                     |j        |¦  «         |                     |j        |j        dt
          j        |dz   ¦  «        }|j        du r|j        dk    sJ ‚dS )z:Attack landing at t+249ms (inside 250ms window) is evaded.rx   rƒ   éù   Tr„   Nr…   r‰   s          r   Ú*test_dodge_iframe_active_at_boundary_249mszCTestTier1FeatureCoverage.test_dodge_iframe_active_at_boundary_249ms†   r�   r   c                 ó`   — t          d¦  «                             d¬¦  «        }d|v rd|v sJ ‚dS )z7Client combat_skills.js activates 0.25s i-frame window.ú(client/webapp/js/engine/combat_skills.jsrK   rL   zplayer.isIFrame = true;zplayer.iFrameTimer = 0.25;NrP   ©r6   Úcs     r   Ú'test_dodge_client_js_sets_iframe_windowz@TestTier1FeatureCoverage.test_dodge_client_js_sets_iframe_windowŽ   sE   € åÐ;Ñ<Ô<×FÒFÐPWÐFÑXÔXˆØ(¨AÐ-Ð-Ð2NÐRSÐ2SÐ2SÐ2SÐSÐ2SÐ2Sr   c                 ó`   — t          d¦  «                             d¬¦  «        }d|v rd|v sJ ‚dS )z<Monsters in monster_system.js initialize poise and maxPoise.rJ   rK   rL   zpoise: config.poise || 100zmaxPoise: config.poise || 100NrP   r–   s     r   Ú!test_poise_initialized_on_monsterz:TestTier1FeatureCoverage.test_poise_initialized_on_monster”   sE   € åÐ<Ñ=Ô=×GÒGÐQXÐGÑYÔYˆØ+¨qÐ0Ð0Ð5TÐXYÐ5YÐ5YÐ5YÐYÐ5YÐ5Yr   c                 ó`   — t          d¦  «                             d¬¦  «        }d|v rd|v sJ ‚dS )z2Monster AI loop pauses during active staggerTimer.rJ   rK   rL   zif (m.staggerTimer > 0)z+continue; // Stunned during stagger window!NrP   r–   s     r   Ú%test_stagger_state_stun_skips_actionsz>TestTier1FeatureCoverage.test_stagger_state_stun_skips_actions™   sE   € åÐ<Ñ=Ô=×GÒGÐQXÐGÑYÔYˆØ(¨AÐ-Ð-Ð2_ÐcdÐ2dÐ2dÐ2dÐdÐ2dÐ2dr   c                 ó`   — t          d¦  «                             d¬¦  «        }d|v rd|v sJ ‚dS )z1Boss stagger sets 4.0s timer in combat_skills.js.r•   rK   rL   zb.staggerTimer = 4.0;zb.poise = 0;NrP   r–   s     r   Ú&test_boss_stagger_four_second_durationz?TestTier1FeatureCoverage.test_boss_stagger_four_second_durationž   sC   € åÐ;Ñ<Ô<×FÒFÐPWÐFÑXÔXˆØ&¨!Ð+Ð+°À!Ð0CÐ0CÐ0CÐCÐ0CÐ0Cr   c                 ó¦   — |\  }}}|                      |j        |j        dt          j        d¦  «        }|j        dk    r|j        |j        k     sJ ‚dS )zBStaggered combat state integrates cleanly with damage calculation.ç      I@rx   r   N)r†   r    r   r(   rˆ   r&   r'   )r6   r.   r+   rŠ   r   r‹   s         r   Ú(test_stagger_combat_actor_evasion_intactzATestTier1FeatureCoverage.test_stagger_combat_actor_evasion_intact£   sY   € à(Ñˆ��TØ×%Ò% c¤l°D´MÀ4ÍÔIYÐ[_Ñ`Ô`ˆØÔ !Ò#Ð#¨¬¸$¼+Ò(EÐ(EÐ(EÐEÐ(EÐ(Er   c                 óL   — t          d¦  «                             ¦   «         sJ ‚dS )zBVerifies telegraph_renderer.js exists for warning cones & circles.z-client/webapp/js/engine/telegraph_renderer.jsN©r   Úexistsra   s    r   Ú'test_telegraph_renderer_module_baselinez@TestTier1FeatureCoverage.test_telegraph_renderer_module_baseline©   s)   € åÐCÑDÔD×KÒKÑMÔMÐMÐMÐMÐMÐMr   c                 ó  — t          ¦   «         t          ¦   «                              dd¬¦  «        }}t          |dddd|j        ¬¦  «        }|                     |dd¬¦  «        }|j        t          j        k    r|j	        dk    sJ ‚d	S )
z:Monster enters PURSUIT when player is inside aggro radius.é
   rp   r„   ©ÚmonsterÚ	current_xÚ	current_yÚspawn_xÚspawn_yr&   )g      @r„   çL7‰A`å ?©Ú
player_posÚdtÚMOVE_TOWARDSN)
r   r   rr   r   r'   ÚupdateÚai_stater   ÚPURSUITÚaction_type©r6   Úairu   ÚstÚacts        r   Útest_ai_pursuit_within_aggroz5TestTier1FeatureCoverage.test_ai_pursuit_within_aggro®   s‹   € åÑ!Ô!Õ#:Ñ#<Ô#<×#MÒ#MÈbÐ_aÐ#MÑ#bÔ#bˆAˆÝ ¨°cÀSÐRUÐ_bÐopÔowÐxÑxÔxˆØ�iŠi˜ z°eˆiÑ<Ô<ˆØŒ{�nÔ4Ò4Ð4¸¼ÈNÒ9ZÐ9ZÐ9ZÐZÐ9ZÐ9Zr   c                 ó  — t          ¦   «         t          ¦   «                              dd¬¦  «        }}t          |dddd|j        ¬¦  «        }|                     |dd¬¦  «        }|j        t          j        k    r|j	        dk    sJ ‚d	S )
z8Monster enters ATTACK when player is within melee range.r§   rp   r„   r¨   )gš™™™™™é?r„   r®   r¯   ÚATTACKN)
r   r   rr   r   r'   r³   r´   r   r½   r¶   r·   s        r   Útest_ai_attack_within_meleez4TestTier1FeatureCoverage.test_ai_attack_within_meleeµ   s‹   € åÑ!Ô!Õ#:Ñ#<Ô#<×#MÒ#MÈbÐ_aÐ#MÑ#bÔ#bˆAˆÝ ¨°cÀSÐRUÐ_bÐopÔowÐxÑxÔxˆØ�iŠi˜ z°eˆiÑ<Ô<ˆØŒ{�nÔ3Ò3Ð3¸¼È8Ò8SÐ8SÐ8SÐSÐ8SÐ8Sr   c                 ó  — t          ¦   «         t          ¦   «                              dd¬¦  «        }}t          |dddd|j        ¬¦  «        }|                     |dd¬¦  «        }|j        t          j        k    r|j	        d	k    sJ ‚d
S )z<Monster enters LEASH_RETURN when pulled beyond leash radius.r§   rp   ç      T@r„   r¨   ©g     @T@rÀ   r®   r¯   ÚRETURN_TO_SPAWNN)
r   r   rr   r   r'   r³   r´   r   ÚLEASH_RETURNr¶   r·   s        r   Ú%test_ai_leash_triggered_beyond_radiusz>TestTier1FeatureCoverage.test_ai_leash_triggered_beyond_radius¼   sŒ   € åÑ!Ô!Õ#:Ñ#<Ô#<×#MÒ#MÈbÐ_aÐ#MÑ#bÔ#bˆAˆÝ ¨°dÀdÐTWÐadÐqrÔqyÐzÑzÔzˆØ�iŠi˜ |¸ˆiÑ>Ô>ˆØŒ{�nÔ9Ò9Ð9¸c¼oÐQbÒ>bÐ>bÐ>bÐbÐ>bÐ>br   c                 óâ   — t          ¦   «         t          ¦   «                              dd¬¦  «        }}t          |dddd|j        ¬¦  «        }|                     |dd¬¦  «         |j        d	u sJ ‚d
S )z1Monster becomes invulnerable during LEASH_RETURN.r§   rp   rÀ   r„   r¨   rÁ   r®   r¯   TN)r   r   rr   r   r'   r³   Úis_invulnerable©r6   r¸   ru   r¹   s       r   Ú+test_ai_leash_return_grants_invulnerabilityzDTestTier1FeatureCoverage.test_ai_leash_return_grants_invulnerabilityÃ   s~   € åÑ!Ô!Õ#:Ñ#<Ô#<×#MÒ#MÈbÐ_aÐ#MÑ#bÔ#bˆAˆÝ ¨°dÀdÐTWÐadÐqrÔqyÐzÑzÔzˆØ
�	Š	�" °%ˆ	Ñ8Ô8Ð8ØÔ! TÐ)Ð)Ð)Ð)Ð)Ð)r   c           	      óL  — t          ¦   «         t          ¦   «                              dd¬¦  «        }}t          |dddd|j        dz  ¬¦  «        }|j        }|                     |dd¬	¦  «         |j        |k    sJ ‚t          j        |j        |z
  |j        d
z  d¬¦  «        sJ ‚dS )z3Monster regenerates 30% HP/sec during LEASH_RETURN.r§   rp   r    r„   gš™™™™™É?r¨   )g     €I@r    g      ð?r¯   g333333Ó?g{®Gáz„?)Úrel_tolN)	r   r   rr   r   r'   r&   r³   ÚmathÚisclose)r6   r¸   ru   r¹   Ú
initial_hps        r   Ú'test_ai_leash_return_regenerates_healthz@TestTier1FeatureCoverage.test_ai_leash_return_regenerates_healthÊ   s¾   € åÑ!Ô!Õ#:Ñ#<Ô#<×#MÒ#MÈbÐ_aÐ#MÑ#bÔ#bˆAˆÝ ¨°dÀdÐTWÐadÐqrÔqyÐ|Ñqð  Añ  Aô  AˆØ”]ˆ
Ø
�	Š	�" °#ˆ	Ñ6Ô6Ð6ØŒ}˜zÒ)Ð)Ð)Ð)ÝŒ|˜BœM¨JÑ6¸¼À4¹ÐQUÐVÑVÔVÐVÐVÐVÐVÐVr   r   c           	      óŒ   — |                      dt          dddd¦  «        ¦  «        \  }}}|du rt          |¦  «        dk    sJ ‚dS )	z9Astral Map Device opens exactly 6 portals for Tier 1 map.Úp1Úm1ÚT1r   r[   Té   N©Úactivate_map_devicer   Úlen©r6   r   Úokr~   Úportalss        r   Ú(test_map_device_activates_six_portals_t1zATestTier1FeatureCoverage.test_map_device_activates_six_portals_t1Ô   sS   € à'×;Ò;¸DÅ)ÈDÐRVÐXYÐ[pÑBqÔBqÑrÔr‰ˆˆAˆwØ�Tˆzˆz�c '™lœl¨aÒ/Ð/Ð/Ð/Ð/Ð/r   c           	      óŒ   — |                      dt          dddd¦  «        ¦  «        \  }}}|du rt          |¦  «        dk    sJ ‚dS )	z:Astral Map Device opens exactly 6 portals for Tier 16 map.rÐ   Úm16ÚT16é   Úzone_blood_scale_ruinsTrÓ   NrÔ   r×   s        r   Ú)test_map_device_activates_six_portals_t16zBTestTier1FeatureCoverage.test_map_device_activates_six_portals_t16Ù   sS   € à'×;Ò;¸DÅ)ÈEÐSXÐZ\Ð^vÑBwÔBwÑxÔx‰ˆˆAˆwØ�Tˆzˆz�c '™lœl¨aÒ/Ð/Ð/Ð/Ð/Ð/r   c           	      ó¨   — |                      dt          dddd¦  «        ¦  «         |                     d¦  «        \  }}}|du r|d         dk    sJ ‚dS )	z>Entering map portal consumes exactly 1 portal charge (6 -> 5).rÐ   Úm5ÚT5é   rf   TÚportals_remainingN)rÕ   r   Úenter_map_portal)r6   r   rØ   r~   r‹   s        r   Ú"test_map_portal_single_consumptionz;TestTier1FeatureCoverage.test_map_portal_single_consumptionÞ   se   € à×*Ò*¨4µ¸4ÀÀqÐJeÑ1fÔ1fÑgÔgÐgØ#×4Ò4°TÑ:Ô:‰
ˆˆAˆsØ�Tˆzˆz˜cÐ"5Ô6¸!Ò;Ð;Ð;Ð;Ð;Ð;r   c           	      óî   — |                      dt          dddd¦  «        ¦  «         t          d¦  «        D ]}|                     d¦  «         Œ|                     d¦  «        d         d         d	k    sJ ‚d
S )z2Entering map portal 6 times depletes charges to 0.rÐ   râ   rã   rä   rf   rÓ   Ú
map_devicerå   r   N)rÕ   r   Úrangeræ   Úget_hideout_summary)r6   r   r~   s      r   Ú&test_map_portal_full_depletion_to_zeroz?TestTier1FeatureCoverage.test_map_portal_full_depletion_to_zeroä   s„   € à×*Ò*¨4µ¸4ÀÀqÐJeÑ1fÔ1fÑgÔgÐgÝ�q‘”ð 	2ð 	2ˆAØ×+Ò+¨DÑ1Ô1Ð1Ð1Ø×1Ò1°$Ñ7Ô7¸ÔEÐFYÔZÐ^_Ò_Ð_Ð_Ð_Ð_Ð_r   c           	      óò   — |                      dt          dddd¦  «        ¦  «         t          d¦  «        D ]}|                     d¦  «         Œ|                     d¦  «        \  }}}|du rd|v sd	|v sJ ‚d
S d
S )z@Further portal entry attempts after 6 consumptions are rejected.rÐ   râ   rã   rä   rf   rÓ   Fz0/6u   háº¿t lÆ°á»£tN)rÕ   r   rê   ræ   )r6   r   r~   rØ   Úmsgs        r   Útest_map_device_sealed_at_zeroz7TestTier1FeatureCoverage.test_map_device_sealed_at_zeroë   s—   € à×*Ò*¨4µ¸4ÀÀqÐJeÑ1fÔ1fÑgÔgÐgÝ�q‘”ð 	2ð 	2ˆAØ×+Ò+¨DÑ1Ô1Ð1Ð1Ø#×4Ò4°TÑ:Ô:‰
ˆˆC�Ø�Uˆ{ˆ{ ¨  °À3Ð0FÐ0FÐ0FÐG  Ð0FÐ0Fr   ©r   N))Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r7   r:   rE   rH   rT   rV   rX   r\   r_   rb   rd   rg   rj   rl   rv   r�   rŒ   r�   r“   r˜   rš   rœ   rž   r¡   r¥   r»   r¾   rÄ   rÈ   rÎ   r   rÚ   rà   rç   rì   rï   r   r   r   r0   r0   0   sV  € € € € € Ø[Ð[ð[Àjð [ÐUYð [ð [ð [ð [ðVÀJð VÐSWð Vð Vð Vð VðTÈjð TÐ]að Tð Tð Tð TðRÈJð RÐ[_ð Rð Rð Rð Rð\ð \ð \ð \ðh¸:ð hÈ$ð hð hð hð hðc¸ð cÈð cð cð cð cðc¸Jð cÈ4ð cð cð cð cðpð pð pð pð{ð {ð {ð {ð
UÀjð UÐUYð Uð Uð Uð Uð[Àzð [ÐVZð [ð [ð [ð [ðZÀjð ZÐUYð Zð Zð Zð ZðdÈð dÐX\ð dð dð dð dðNð Nð Nð Nð8ð 8ð 8ð 8ðAð Að Að AðAð Að Að AðAð Að Að AðTð Tð Tð TðZð Zð Zð Zð
eð eð eð eð
Dð Dð Dð Dð
Fð Fð Fð FðNð Nð Nð Nð
[ð [ð [ð [ðTð Tð Tð Tðcð cð cð cð*ð *ð *ð *ðWð Wð Wð Wð0À}ð 0ÐY]ð 0ð 0ð 0ð 0ð
0Èð 0ÐZ^ð 0ð 0ð 0ð 0ð
<Àð <ÐSWð <ð <ð <ð <ð`À]ð `ÐW[ð `ð `ð `ð `ðH¸]ð HÈtð Hð Hð Hð Hð Hð Hr   r0   c                   óœ   — e Zd ZdZdeddfd„Zdd„Zdd„Zej	         
                    dg d	¢¦  «        d
ededdfd„¦   «         Zdeddfd„ZdS )ÚTestTier2BoundaryAndCornerCasesz Tier 2: Boundary & Corner Cases.r   r   Nc                 ój   — |                      d¦  «        du sJ ‚|                      d¦  «        du sJ ‚dS )z9Empty or unknown zone IDs reject hostile spawning safely.Ú FÚnonexistent_zone_999Nr3   r5   s     r   Ú-test_boundary_empty_and_unknown_zone_rejectedzMTestTier2BoundaryAndCornerCases.test_boundary_empty_and_unknown_zone_rejectedö   sH   € à×5Ò5°bÑ9Ô9¸UÐBÐBÐBÐBØ×5Ò5Ð6LÑMÔMÐQVÐVÐVÐVÐVÐVÐVr   c                 ó4  — t          ¦   «         t          ¦   «                              dd¬¦  «        }}t          |ddddd¬¦  «        }|                     |dd¬	¦  «         |j        t          j        k    r"t          j	        |j
        ¦  «        s	|j        d
u sJ ‚dS )zLMonsters dragged to extreme coordinates (5000m) handle leash return cleanly.rä   rp   ç     ˆ³@r„   rƒ   r¨   )g     ‰³@rü   r®   r¯   TN)r   r   rr   r   r³   r´   r   rÃ   rË   Úisnanrª   rÆ   rÇ   s       r   Ú7test_boundary_max_distance_leash_handles_extreme_coordszWTestTier2BoundaryAndCornerCases.test_boundary_max_distance_leash_handles_extreme_coordsû   sž   € åÑ!Ô!Õ#:Ñ#<Ô#<×#MÒ#MÈaÐ^_Ð#MÑ#`Ô#`ˆAˆÝ ¨°fÈÐX[ÐehÐuzÐ{Ñ{Ô{ˆØ
�	Š	�"Ð!1°eˆ	Ñ<Ô<Ð<ØŒ{�nÔ9Ò9Ð9Å$Ä*ÈRÌ\ÑBZÔBZÐ9Ð_aÔ_qÐuyÐ_yÐ_yÐ_yÐyÐ_yÐ_yr   c                 óØ   — |\  }}}d}|                      |j        |¦  «         |                     |j        |j        dt          j        |dz   ¦  «        }|j        du r|j        dk    sJ ‚dS )z>Attack landing at t+251ms (beyond 250ms window) is NOT evaded.i'  rƒ   éû   Fr„   N)r|   r    r†   r   r(   r‡   rˆ   r‰   s          r   Ú%test_boundary_iframe_expired_at_251mszETestTier2BoundaryAndCornerCases.test_boundary_iframe_expired_at_251ms  sz   € à(Ñˆ��TØˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÐehÑ\hÑiÔiˆØŒ} Ð%Ð%¨#Ô*:¸SÒ*@Ð*@Ð*@Ð@Ð*@Ð*@r   Úinvalid_tier)r   éÿÿÿÿé   éc   r   c           	      ó”   — |                      dt          dd|d¦  «        ¦  «        \  }}}|du rt          |¦  «        dk    rd|v sJ ‚dS )	z<Map tiers <1 or >16 must be rejected with informative error.rÐ   ÚbÚBr[   Fr   z	Tier 1-16NrÔ   )r6   r   r  rØ   rî   rÙ   s         r   Ú(test_boundary_invalid_map_tiers_rejectedzHTestTier2BoundaryAndCornerCases.test_boundary_invalid_map_tiers_rejected
  s`   € ð *×=Ò=¸dÅIÈcÐSVÐXdÐf{ÑD|ÔD|Ñ}Ô}ÑˆˆC�Ø�Uˆ{ˆ{�s 7™|œ|¨qÒ0Ð0°[ÀCÐ5GÐ5GÐ5GÐGÐ5GÐ5Gr   c                 óÀ   — |                      dddd¦  «         |                     ddd¦  «        d         du sJ ‚|                     ddd¦  «        \  }}|du rd	|v sJ ‚d
S )zAPlayer movement within zone half-extents succeeds; outside fails.Úp_mover2   r„   g     àu@r   Tg      |@Fu   VÆ°á»£t quÃ¡ ranh giá»›iN)Úspawn_playerÚupdate_player_position)r6   r   Úok_outrî   s       r   Ú-test_boundary_player_movement_bounds_clampingzMTestTier2BoundaryAndCornerCases.test_boundary_player_movement_bounds_clamping  s�   € à× Ò  Ð+EÀsÈCÑPÔPÐPØ×1Ò1°(¸EÀ5ÑIÔIÈ!ÔLÐPTÐTÐTÐTÐTØ!×8Ò8¸À5È#ÑNÔN‰ˆ�Ø˜ˆˆÐ#=ÀÐ#DÐ#DÐ#DÐDÐ#DÐ#Dr   rð   )rñ   rò   ró   rô   r   rú   rþ   r  ÚpytestÚmarkÚparametrizer   rz   r	  r  r   r   r   rö   rö   ô   só   € € € € € Ø*Ð*ðWÈð WÐX\ð Wð Wð Wð Wð
zð zð zð zðAð Að Að Að „[×Ò˜^¨_¨_¨_Ñ=Ô=ðHÀ}ð HÐdgð HÐlpð Hð Hð Hñ >Ô=ðHð
EÈð EÐX\ð Eð Eð Eð Eð Eð Er   rö   c                   ó:   — e Zd ZdZdeddfd„Zd	d„Zd	d„Zd	d„ZdS )
Ú!TestTier3CrossFeatureCombinationsz#Tier 3: Cross-Feature Combinations.r   r   Nc                 óÊ   — d}|                      |ddd¦  «         |                     |dd¬¦  «        \  }}}|du r|dk    sJ ‚|                     |¦  «        j        dk    sJ ‚d	S )
zWPlayer transitions through portal from Sanctuary to Wilderness, updating spatial state.Úcross_playerr2   r„   Úportal_sanctuary_to_tang_kiemrä   ©Úplayer_levelTr[   N)r  Útraverse_portalÚget_player_locationÚzone_id)r6   r   Úp_idrØ   Útarget_zoner~   s         r   Ú5test_portal_traversal_crosses_sanctuary_to_wildernesszWTestTier3CrossFeatureCombinations.test_portal_traversal_crosses_sanctuary_to_wilderness  sˆ   € àˆØ× Ò  Ð'AÀ3ÈÑLÔLÐLØ(×8Ò8¸Ð?^ÐmnÐ8ÑoÔoÑˆˆK˜Ø�Tˆzˆz˜kÐ-BÒBÐBÐBÐBØ×.Ò.¨tÑ4Ô4Ô<Ð@UÒUÐUÐUÐUÐUÐUr   c                 óâ   — |\  }}}d}|                      |j        |¦  «         |                     |j        |j        dt          j        |dz   ¦  «        }|j        du r|j        |j        k    sJ ‚dS )zPPlayer executing dodge roll during incoming monster attack avoids lethal damage.iPÃ  g     @o@éx   TN)r|   r    r†   r   r(   r‡   r&   r'   r‰   s          r   Ú'test_dodge_during_monster_attack_windupzITestTier3CrossFeatureCombinations.test_dodge_during_monster_attack_windup!  s{   € à(Ñˆ��TØˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×%Ò% c¤l°D´MÀ5Í,ÔJZÐ\bÐehÑ\hÑiÔiˆØŒ} Ð$Ð$¨¬¸D¼KÒ)GÐ)GÐ)GÐGÐ)GÐ)Gr   c           	      ó  — t          ¦   «         t          ¦   «                              dd¬¦  «        }}t          |dddd|j        dz  ¬¦  «        }|                     |dd	¬
¦  «         |j        t          j        k    r	|j	        du sJ ‚dS )zFMonster in LEASH_RETURN state possesses authoritative invulnerability.éM   é   rp   ç      ^@r„   g      à?r¨   )g     @^@r&  r®   r¯   TN)
r   r   rr   r   r'   r³   r´   r   rÃ   rÆ   rÇ   s       r   Ú(test_leash_invulnerability_blocks_damagezJTestTier3CrossFeatureCombinations.test_leash_invulnerability_blocks_damage)  s¥   € åÑ!Ô!Õ#:Ñ#<Ô#<×#MÒ#MÈbÐ_aÐ#MÑ#bÔ#bˆAˆÝ ¨°eÀuÐVYÐcfÐstÔs{ð  Bñ  tBð  Cñ  Cô  CˆØ
�	Š	�" °Eˆ	Ñ:Ô:Ð:ØŒ{�nÔ9Ò9Ð9¸bÔ>PÐTXÐ>XÐ>XÐ>XÐXÐ>XÐ>Xr   c                 óT   — dt          d¦  «                             d¬¦  «        v sJ ‚dS )zGStaggered monster timer prevents attack generation in AI state machine.zif (m.staggerTimer > 0) {rJ   rK   rL   NrP   ra   s    r   Ú+test_staggered_monster_cannot_damage_playerzMTestTier3CrossFeatureCombinations.test_staggered_monster_cannot_damage_player0  s4   € à*­dÐ3^Ñ._Ô._×.iÒ.iÐszÐ.iÑ.{Ô.{Ð{Ð{Ð{Ð{Ð{Ð{r   rð   )	rñ   rò   ró   rô   r   r  r"  r'  r)  r   r   r   r  r    sŽ   € € € € € Ø-Ð-ðVÐQ[ð VÐ`dð Vð Vð Vð VðHð Hð Hð HðYð Yð Yð Yð|ð |ð |ð |ð |ð |r   r  c                   ó>   — e Zd ZdZdededdfd„Zdeddfd„Zd	d„ZdS )
ÚTestTier4RealWorldScenariosz)Tier 4: Real-World Application Scenarios.r   r   r   Nc                 óž  — d}|                      |ddd¦  «        }|                     |j        ¦  «        du sJ ‚|                     |j        d¬¦  «        d         du sJ ‚|                     |j        d¬¦  «        d         du sJ ‚|                     |dd	¬
¦  «        \  }}}|du r|                     |¦  «        du sJ ‚t          ¦   «         }t          ddt          j        ddd¬¦  «        }	t          ddt          j	        ddd¬¦  «        }
| 
                    |	¦  «         | 
                    |
¦  «         d}|                     |
j        |¦  «         |                     |	j        |
j        |	j        |	j        |dz   ¦  «        }|j        du r|
j        dk    sJ ‚|                     |
j        |	j        |
j        |
j        |dz   ¦  «        }|j        du r|j        dk    sJ ‚t'          dddd¦  «        }|                     ||¦  «        \  }}}|du rt+          |¦  «        dk    sJ ‚|                     |¦  «        \  }}}|du r|d         dk    sJ ‚dS ) zhComplete E2E simulation: Sanctuary -> Wilderness -> Combat -> Dodge -> Victory -> Hideout -> Map Device.Úhero_e2e_journeyr2   r„   Fr<   r   Tr  r§   r  ée   u   Cuá»“ng Khuyá»ƒng     Àr@g     €Q@)r&   r'   r#   éf   ÚHeror%   g     Àb@i † é2   i,  g     €f@Úmap_endgame_t14u   Pháº¿ TÃ­ch Xáº» Thá»‹té   rß   rÓ   rå   rä   N)r  r4   r  rA   r  r   r   r   r(   ÚTHUYr*   r|   r    r†   r#   r"   r‡   r&   rˆ   r   rÕ   rÖ   ræ   )r6   r   r   Ú	player_idÚlocrØ   Úw_zoner~   ÚcombatÚmobÚheror€   Úevaded_strikeÚcounter_strikeÚ
astral_mapÚok_devrÙ   Úok_enterr‹   s                      r   Ú&test_e2e_full_player_journey_lifecyclezBTestTier4RealWorldScenarios.test_e2e_full_player_journey_lifecycle6  s   € à&ˆ	à×&Ò& yÐ2LÈcÐSVÑWÔWˆØ×5Ò5°c´kÑBÔBÀeÐKÐKÐKÐKØ×1Ò1°#´+ÈÐ1ÑNÔNÈqÔQÐUZÐZÐZÐZÐZØ×1Ò1°#´+ÈÐ1ÑMÔMÈaÔPÐTXÐXÐXÐXÐXà#×3Ò3°IÐ?^ÐmoÐ3ÑpÔp‰ˆˆF�AØ�Tˆzˆz˜k×DÒDÀVÑLÔLÐPTÐTÐTÐTÐTå‘”ˆÝ˜#Ð1µ<Ô3CÐPUÐ^cÐquÐvÑvÔvˆÝ˜3 ­Ô(9ÀfÐU[ÐinÐoÑoÔoˆØ×Ò˜cÑ"Ô"Ð"Ø×Ò˜dÑ#Ô#Ð#ØˆØ×&Ò& t¤}°fÑ=Ô=Ð=Ø×/Ò/°´¸d¼mÈSÌ_Ð^aÔ^iÐkqÐtvÑkvÑwÔwˆØÔ&¨$Ð.Ð.°4´?ÀfÒ3LÐ3LÐ3LÐLØ×0Ò0°´ÀÄÈdÔN^Ð`dÔ`lÐntÐwzÑnzÑ{Ô{ˆØÔ'¨5Ð0Ð0°^Ô5PÐT_Ò5_Ð5_Ð5_Ð_åÐ0Ð2KÈRÐQiÑjÔjˆ
Ø+×?Ò?À	È:ÑVÔVÑˆ��7Ø˜ˆ~ˆ~¥# g¡,¤,°!Ò"3Ð"3Ð"3Ð3Ø)×:Ò:¸9ÑEÔEÑˆ�!�SØ˜4ÐÐ CÐ(;Ô$<ÀÒ$AÐ$AÐ$AÐAÐ$AÐ$Ar   c                 ób   — |                      d¦  «        }|�|j        t          j        k    sJ ‚dS )zJVerifies zone_player_hideout is registered in ZoneEngine without KeyError.r9   N)Úget_zoneÚ	zone_typer	   Ú	SANCTUARY)r6   r   Úzones      r   Ú0test_e2e_canonical_hideout_registration_baselinezLTestTier4RealWorldScenarios.test_e2e_canonical_hideout_registration_baselineT  s7   € à×#Ò#Ð$9Ñ:Ô:ˆØÐ D¤NµhÔ6HÒ$HÐ$HÐ$HÐHÐ$HÐ$Hr   c                 óL   — t          d¦  «                             ¦   «         sJ ‚dS )zFVerifies target_dummy_telemetry.js exists for combo and DPS telemetry.z1client/webapp/js/engine/target_dummy_telemetry.jsNr£   ra   s    r   Ú$test_dummy_telemetry_module_baselinez@TestTier4RealWorldScenarios.test_dummy_telemetry_module_baselineY  s)   € åÐGÑHÔH×OÒOÑQÔQÐQÐQÐQÐQÐQr   rð   )	rñ   rò   ró   rô   r   r   r@  rF  rH  r   r   r   r+  r+  4  s�   € € € € € Ø3Ð3ðBÀ*ð BÐ^kð BÐptð Bð Bð Bð Bð<IÈJð IÐ[_ð Ið Ið Ið Ið
Rð Rð Rð Rð Rð Rr   r+  )0rô   rË   ÚosÚsysr{   Úpathlibr   Útypingr   r   r   r  ÚpathÚabspathÚjoinÚdirnameÚ__file__Ú
SERVER_DIRÚinsertÚserver.world.zone_enginer   Úserver.world.zone_typesr	   r
   Úserver.world.hideout_enginer   r   Úserver.world.combat_enginer   r   Úserver.world.martial_matrixr   Úserver.world.monster_typesr   r   r   Úserver.world.monster_ai_enginer   Ú&server.world.monster_procedural_enginer   Úfixturer   r   r.   r0   rö   r  r+  r   r   r   ú<module>r]     sË  ððð ð €€€Ø 	€	€	€	Ø 
€
€
€
Ø €€€Ø Ð Ð Ð Ð Ð Ø $Ð $Ð $Ð $Ð $Ð $Ð $Ð $Ð $Ð $Ø €€€àŒW�_Š_˜RœWŸ\š\¨"¬'¯/ª/¸(Ñ*CÔ*CÀ^ÑTÔTÑUÔU€
Ø�S”XÐÐØ„H‡O‚O�A�zÑ"Ô"Ð"à /Ð /Ð /Ð /Ð /Ð /Ø <Ð <Ð <Ð <Ð <Ð <Ð <Ð <Ø @Ð @Ð @Ð @Ð @Ð @Ð @Ð @Ø @Ð @Ð @Ð @Ð @Ð @Ð @Ð @Ø 4Ð 4Ð 4Ð 4Ð 4Ð 4Ø XÐ XÐ XÐ XÐ XÐ XÐ XÐ XÐ XÐ XØ :Ð :Ð :Ð :Ð :Ð :Ø JÐ JÐ JÐ JÐ JÐ Jà„ð�Zð ð ð ñ „ðð „ð˜ð ð ð ñ „ðð „ð&�e˜L¨+°{ÐBÔCð &ð &ð &ñ „ð&ðAHð AHð AHð AHð AHñ AHô AHð AHðH!Eð !Eð !Eð !Eð !Eñ !Eô !Eð !EðF|ð |ð |ð |ð |ñ |ô |ð |ð:'Rð 'Rð 'Rð 'Rð 'Rñ 'Rô 'Rð 'Rð 'Rð 'Rr   