§
    ,¼»j¶4  ã                  ó´   — d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
mZ ddlmZmZmZmZmZ ddlmZmZmZmZmZmZmZ ddlmZ  G d„ d	¦  «        Zdd„ZdS )u­  
Authoritative NPC, Dialogue Tree & Map-Quest Interconnection Engine for FreeExile.
Theme: Cá»” VÃ• HOANG DÃƒ & Háº®C Ã�M LÆ¯U Ä�Ã€Y (Grimdark Savage Primal Exile ARPG - 100% PoE2 Spirit).

Features:
1. Spatial NPC placement, zone indexing, and Euclidean proximity gating (Zero-Trust Anti-Cheat).
2. Grimdark Feral NPC archetypes: Outcast Scavengers, Bone Blacksmiths, Blood Shamans, Feral Trackers, Dune Savages.
3. Dynamic Dialogue Trees with brutal survival dialogues, branching choices, level/quest gating, and terminal states.
4. Reactive dialogue adaptation based on real-time QuestEngine states (Available, In-Progress, Completed, Claimed).
5. Bidirectional QuestEngine synchronization (Talk NPC, Deliver to NPC, Accept, Claim).
6. Hidden Quest serendipity triggers (CÆ¡ DuyÃªn Ä�Ã m Ä�áº¡o) through dialogue depth or blood/relic offerings.
7. Environmental & ZoneEngine linkage (Sandstorm, Miasma, and dynamic Secret Chamber gates).
é    )ÚannotationsN)ÚDictÚListÚOptionalÚSetÚTupleÚAny)ÚQuestEngineÚ	QuestTypeÚQuestStatusÚObjectiveTypeÚHiddenTriggerType)ÚNpcRoleÚNpcServiceTypeÚNpcDialogueChoiceÚNpcDialogueNodeÚNpcDialogueTreeÚNpcDefinitionÚPlayerDialogueSession)Úpopulate_canonical_npcsc                  ó¬   — e Zd ZdZd8d„Zd9d„Zd:d
„Zd;d„Zd<d„Z	 d=d>d„Z		 d?d@d„Z
dAd „ZdBd#„ZdCd$„Z	 	 	 dDdEd.„Z	 	 	 	 dFdGd/„Z	 	 	 	 dHdId3„Z	 	 dJdKd7„Zd&S )LÚ	NpcEnginezÆ
    Authoritative Feral NPC & Dialogue Engine.
    Enforces strict zero-trust distance limits, manages dialogue tree traversal,
    and synchronizes seamlessly with ZoneEngine and QuestEngine.
    ÚreturnÚNonec                ó>   — i | _         i | _        i | _        i | _        d S ©N)Ú_npc_registryÚ_dialogue_treesÚ_zone_npc_indexÚ_active_sessions)Úselfs    ú0C:\Projects\FreeExile\server\world\npc_engine.pyÚ__init__zNpcEngine.__init__.   s(   € Ø79ˆÔØ;=ˆÔà57ˆÔàBDˆÔÐÐó    Únpcr   c                óè   — || j         |j        <   |j        | j        vrg | j        |j        <   |j        | j        |j                 vr,| j        |j                                      |j        ¦  «         d S d S r   )r   Únpc_idÚzone_idr   Úappend)r!   r%   s     r"   Úregister_npczNpcEngine.register_npc6   su   € Ø),ˆÔ˜3œ:Ñ&ØŒ;˜dÔ2Ð2Ð2Ø02ˆDÔ  ¤Ñ-ØŒ:˜TÔ1°#´+Ô>Ð>Ð>ØÔ  ¤Ô-×4Ò4°S´ZÑ@Ô@Ð@Ð@Ð@ð ?Ð>r$   Útreer   c                ó$   — || j         |j        <   d S r   )r   Útree_id)r!   r+   s     r"   Úregister_dialogue_treez NpcEngine.register_dialogue_tree=   s   € Ø-1ˆÔ˜Tœ\Ñ*Ð*Ð*r$   r'   ÚstrúOptional[NpcDefinition]c                ó6   — | j                              |¦  «        S r   )r   Úget)r!   r'   s     r"   Úget_npczNpcEngine.get_npc@   s   € ØÔ!×%Ò% fÑ-Ô-Ð-r$   r(   úList[NpcDefinition]c                óV   ‡ — ‰ j                              |g ¦  «        }ˆ fd„|D ¦   «         S )Nc                ó<   •— g | ]}|‰j         v ¯‰j         |         ‘ŒS © )r   )Ú.0Únidr!   s     €r"   ú
<listcomp>z.NpcEngine.get_npcs_in_zone.<locals>.<listcomp>E   s.   ø€ ÐXÐXÐX¨C¸cÀTÔEWÐ>WÐ>W�Ô" 3Ô'Ð>WÐ>WÐ>Wr$   )r   r2   )r!   r(   Únpc_idss   `  r"   Úget_npcs_in_zonezNpcEngine.get_npcs_in_zoneC   s5   ø€ ØÔ&×*Ò*¨7°BÑ7Ô7ˆØXÐXÐXÐX°7ÐXÑXÔXÐXr$   ç      4@ÚxÚfloatÚyÚradiusc                ó¸   — |                       |¦  «        }g }||z  }|D ]:}|j        |z
  }	|j        |z
  }
|	|	z  |
|
z  z   |k    r|                     |¦  «         Œ;|S )zKSpatial query returning NPCs within euclidean radius in the specified zone.)r<   r>   r@   r)   )r!   r(   r>   r@   rA   Ú
candidatesÚnearbyÚ	radius_sqr%   ÚdxÚdys              r"   Úget_nearby_npcszNpcEngine.get_nearby_npcsG   sz   € ð ×*Ò*¨7Ñ3Ô3ˆ
Ø&(ˆØ˜V‘Oˆ	Øð 	#ð 	#ˆCØ”˜‘ˆBØ”˜‘ˆBØ�B‰w˜˜b™Ñ  IÒ-Ð-Ø—’˜cÑ"Ô"Ð"øØˆr$   ç      à?Úplayer_xÚplayer_yÚ	toleranceÚboolc                ó€   — |j         |z
  }|j        |z
  }t          j        ||z  ||z  z   ¦  «        }||j        |z   k    S )z9Zero-Trust server-authoritative Euclidean distance check.)r>   r@   ÚmathÚsqrtÚinteraction_radius)r!   r%   rJ   rK   rL   rF   rG   Údists           r"   Úvalidate_interaction_distancez'NpcEngine.validate_interaction_distanceU   sK   € ð ŒU�XÑˆØŒU�XÑˆÝŒy˜˜b™ 2¨¡7Ñ*Ñ+Ô+ˆØ˜Ô.°Ñ:Ò;Ð;r$   r-   úOptional[NpcDialogueTree]c                ó6   — | j                              |¦  «        S r   )r   r2   )r!   r-   s     r"   Úget_dialogue_treezNpcEngine.get_dialogue_tree^   s   € ØÔ#×'Ò'¨Ñ0Ô0Ð0r$   Ú	player_idúOptional[PlayerDialogueSession]c                ó6   — | j                              |¦  «        S r   )r    r2   ©r!   rW   s     r"   Úget_active_sessionzNpcEngine.get_active_sessiona   s   € ØÔ$×(Ò(¨Ñ3Ô3Ð3r$   c                ó,   — || j         v r
| j         |= d S d S r   )r    rZ   s     r"   Úclose_dialogue_sessionz NpcEngine.close_dialogue_sessiond   s)   € Ø˜Ô-Ð-Ð-ØÔ% iÐ0Ð0Ð0ð .Ð-r$   é   NÚplayer_levelÚintÚquest_engineúOptional[QuestEngine]ÚenvironmentúOptional[str]ú6Tuple[bool, str, Optional[NpcDialogueNode], List[str]]c	                óè  — |                       |¦  «        }	|	s
dd|› d�dg fS |	j        |k    rdd|	j        › d|› d�dg fS |                      |	||¦  «        sdd|	j        › d�dg fS ||	j        k     rdd	|	j        › d
|	j        › d�dg fS |	j        r"|	j        |k    rdd|	j        › d|	j        › d�dg fS |                      |	j        ¦  «        }
|
sdd|	j        › d�dg fS |
j        }|r`|
j	        rY|
j	         
                    ¦   «         D ]?\  }}|                     ||¦  «        }|r"|j        j        |v r||j        j                 } nŒ@|
j                             |¦  «        }|s'|
j                             |
j        ¦  «        }|sdddg fS t          t!          j        ¦   «         dz  ¦  «        }t#          |||j        ||¬¦  «        | j        |<   g }|r|                     ||¦  «        }dd|	j        › d�||fS )z”
        Authoritative interaction entry point. Validates map zone, euclidean distance,
        level gating, and sets up dialogue session.
        FúNPC 'u'   ' khÃ´ng tá»“n táº¡i trong Hoang Vá»±c!Nu%   ' khÃ´ng thuá»™c báº£n Ä‘á»“ (zone) 'z'!u,   Cá»± ly quÃ¡ xa! KhÃ´ng thá»ƒ tiáº¿p cáº­n 'u   ' Ä‘á»ƒ Ä‘á»‘i thoáº¡i.u/   Tu vi/cÄƒn cá»‘t chÆ°a Ä‘á»§ (YÃªu cáº§u Cáº¥p u   ) Ä‘á»ƒ diá»‡n kiáº¿n 'u4   MÃ´i trÆ°á»�ng hoang dÃ£ chÆ°a Ä‘á»§ dá»‹ tÆ°á»£ng (u   ) Ä‘á»ƒ gáº·p 'u   CÃ¢y há»™i thoáº¡i 'u   ' chÆ°a Ä‘Æ°á»£c Ä‘Äƒng kÃ½!u+   KhÃ´ng tÃ¬m tháº¥y nÃºt thoáº¡i há»£p lá»‡!éè  ©rW   r'   Úcurrent_node_idÚstarted_at_msÚlast_interact_msTu!   Báº¯t Ä‘áº§u Ä‘Ã m Ä‘áº¡o vá»›i 'ú')r3   r(   ÚnamerS   Úrequired_levelÚrequired_environmentrV   Údialogue_tree_idÚdefault_root_node_idÚquest_conditional_rootsÚitemsÚget_player_questÚstatusÚnodesr2   r`   Útimer   Únode_idr    Úrecord_talk_npc)r!   rW   r'   r(   rJ   rK   r_   ra   rc   r%   r+   Úselected_root_idÚq_idÚstatus_mappingÚactive_qÚ	root_nodeÚnow_msÚupdated_questss                     r"   Úinteract_with_npczNpcEngine.interact_with_npch   s  € ð �lŠl˜6Ñ"Ô"ˆØð 	\ØÐQ &ÐQÐQÐQÐSWÐY[Ð[Ð[ð Œ;˜'Ò!Ð!ØÐ\ #¤(Ð\Ð\ÐQXÐ\Ð\Ð\Ð^bÐdfÐfÐfð ×1Ò1°#°xÀÑJÔJð 	uØÐjÈÌÐjÐjÐjÐlpÐrtÐtÐtð ˜#Ô,Ò,Ð,Øð  DÈCÔL^ð  Dð  DÐwzÔwð  Dð  Dð  Dð  FJð  LNð  Nð  Nð Ô#ð 	Q¨Ô(@ÀKÒ(OÐ(OØð  GÐQTÔQið  Gð  GÐz}ô  {Cð  Gð  Gð  Gð  IMð  OQð  Qð  Qà×%Ò% cÔ&:Ñ;Ô;ˆØð 	nØÐc°Ô1EÐcÐcÐcÐeiÐkmÐmÐmð  Ô4ÐØð 	˜DÔ8ð 	Ø(,Ô(D×(JÒ(JÑ(LÔ(Lð ð Ñ$��nØ'×8Ò8¸ÀDÑIÔI�Øð  ¤Ô 4¸Ð FÐ FØ'5°h´oÔ6JÔ'KÐ$Ø�Eøà”J—N’NÐ#3Ñ4Ô4ˆ	Øð 	VØœ
Ÿš tÔ'@ÑAÔAˆIØð VØÐKÈTÐSUÐUÐUå•T”Y‘[”[ 4Ñ'Ñ(Ô(ˆÝ+@ØØØ%Ô-Ø Ø#ð,
ñ ,
ô ,
ˆÔ˜iÑ(ð %'ˆØð 	MØ)×9Ò9¸)ÀVÑLÔLˆNàÐD¸¼ÐDÐDÐDÀiÐQ_Ð_Ð_r$   c	           
     ó„   — |                       |¦  «        }	|�|n
|	r|	j        nd}
|                      |||
|||||¬¦  «        S )z(Convenience alias for interact_with_npc.NÚ )rW   r'   r(   rJ   rK   r_   ra   rc   )r3   r(   r‚   )r!   rW   r'   rJ   rK   r_   ra   rc   r(   r%   Úactual_zones              r"   Ústart_dialoguezNpcEngine.start_dialogue®   sd   € ð �lŠl˜6Ñ"Ô"ˆØ!(Ð!4�g�gÈ#Ð;U¸3¼;¸;ÐSUˆØ×%Ò%ØØØØØØ%Ø%Ø#ð &ñ 	
ô 	
ð 		
r$   Ú	choice_idrj   úTTuple[bool, str, Optional[NpcDialogueNode], Optional[NpcServiceType], Optional[str]]c                óx  — | j                              |¦  «        }|sH|rD|rBt          t          j        ¦   «         dz  ¦  «        }t	          |||||¬¦  «        }|| j         |<   ndS |p|j        }	|p|j        }
|                      |	¦  «        }|sdS |                      |j	        ¦  «        }|sdS |j
                             |
¦  «        }|sdS d}|j        D ]}|j        |k    r|} nŒ|sdd	|› d
�dddfS ||j        k     rdd|j        › d�dddfS |r=|j        r6|j        r/|                     ||j        ¦  «        }|r|j        |j        k    rdS |j        }|j        }|rV|                     |t*          j        |j        ||j        ¬¦  «         |t0          j        k    r|r|                     ||¦  «         |j        r|                      |¦  «         ddd||fS d}|j        rU|j
                             |j        ¦  «        }|r4|j        |_        t          t          j        ¦   «         dz  ¦  «        |_        dd|||fS )z³
        Executes a dialogue choice, updates session node, and triggers quest/services.
        Returns: (success, message, next_node, triggered_service, triggered_param)
        rh   ri   )Fu0   ChÆ°a má»Ÿ phiÃªn Ä‘á»‘i thoáº¡i vá»›i NPC nÃ o!NNN)Fu   NPC khÃ´ng há»£p lá»‡!NNN)Fu'   CÃ¢y Ä‘á»‘i thoáº¡i khÃ´ng tá»“n táº¡i!NNN)Fu,   NÃºt thoáº¡i hiá»‡n táº¡i khÃ´ng há»£p lá»‡!NNNNFu   Lá»±a chá»�n 'u-   ' khÃ´ng cÃ³ trong nÃºt thoáº¡i hiá»‡n táº¡i!u*   Cáº¥p Ä‘á»™ chÆ°a Ä‘á»§ (YÃªu cáº§u Cáº¥p u!   ) Ä‘á»ƒ chá»�n phÆ°Æ¡ng Ã¡n nÃ y!)FuL   Tráº¡ng thÃ¡i nhiá»‡m vá»¥ khÃ´ng thá»�a mÃ£n Ä‘iá»�u kiá»‡n Ä‘á»‘i thoáº¡i!NNN)rW   Útrigger_typer'   r‡   ÚzoneTu   Káº¿t thÃºc Ä‘á»‘i thoáº¡i.u   Chá»�n Ä‘Ã¡p Ã¡n thÃ nh cÃ´ng!) r    r2   r`   rx   r   r'   rj   r3   rV   rq   rw   Úchoicesr‡   ro   Úrequired_quest_idÚrequired_quest_statusÚget_active_questrv   Útrigger_serviceÚtrigger_paramÚtrigger_hidden_questr   ÚNPC_DIALOGUE_CHOICEr(   r   ÚQUEST_DISPATCHÚaccept_questÚis_terminalr]   Útarget_node_idry   rl   )r!   rW   r‡   r'   rj   ra   r_   Úsessionr€   Útarget_npc_idr—   r%   r+   Úcurrent_nodeÚmatched_choiceÚchÚqÚtriggered_serviceÚtriggered_payloadÚ	next_nodes                       r"   Úselect_dialogue_choicez NpcEngine.select_dialogue_choiceÇ   s$  € ð Ô'×+Ò+¨IÑ6Ô6ˆØð 	cØð c˜/ð cÝ�TœY™[œ[¨4Ñ/Ñ0Ô0�Ý/Ø'Ø!Ø$3Ø"(Ø%+ðñ ô �ð 4;�Ô% iÑ0Ð0àbÐbàÐ0 '¤.ˆØ(ÐC¨GÔ,Cˆà�lŠl˜=Ñ)Ô)ˆØð 	EØDÐDà×%Ò% cÔ&:Ñ;Ô;ˆØð 	VØUÐUà”z—~’~ nÑ5Ô5ˆØð 	[ØZÐZà6:ˆØÔ&ð 	ð 	ˆBØŒ|˜yÒ(Ð(Ø!#�Ø�ð )ð ð 	vØÐc¨9ÐcÐcÐcÐeiÐkoÐquÐuÐuà˜.Ô7Ò7Ð7Øð  HÀ~ÔGdð  Hð  Hð  Hð  JNð  PTð  VZð  Zð  Zàð 	˜NÔ<ð 	ÀÔAeð 	Ø×-Ò-¨i¸Ô9YÑZÔZˆAØð ˜œ NÔ$HÒHÐHØ~Ð~à*Ô:ÐØ*Ô8Ðð ð 		HØ×-Ò-Ø#Ý.ÔBØ”zØ#Ø”[ð .ñ ô ð ð !¥NÔ$AÒAÐAÐFWÐAØ×)Ò)¨)Ð5FÑGÔGÐGàÔ%ð 	cØ×'Ò'¨	Ñ2Ô2Ð2ØÐ6¸Ð>OÐQbÐbÐbà/3ˆ	ØÔ(ð 	CØœ
Ÿš ~Ô'DÑEÔEˆIØð CØ*3Ô*;�Ô'Ý+.­t¬y©{¬{¸TÑ/AÑ+BÔ+B�Ô(àÐ5°yÐBSÐUfÐfÐfr$   Úitem_idÚcountúTuple[bool, str, List[str]]c                óò   — |                       |¦  «        }|s	dd|› d�g fS g }|r@|                     |||¦  «        }|                     |t          j        |||j        ¬¦  «         dd|› d|› d|j        › d	�|fS )
z˜
        Delivers an item to an NPC, updating DELIVER_TO_NPC quest objectives
        and checking potential NPC_GIFT_OFFERING hidden triggers.
        Frg   u   ' khÃ´ng tá»“n táº¡i!)rW   rŠ   r'   r¢   r‹   Tu   NÃ©m zx 'z' cho 'u   ' thÃ nh cÃ´ng!)r3   Úrecord_deliver_npcr’   r   ÚNPC_GIFT_OFFERINGr(   rn   )r!   rW   r'   r¢   r£   ra   r%   r�   s           r"   Údeliver_item_to_npczNpcEngine.deliver_item_to_npc  s»   € ð �lŠl˜6Ñ"Ô"ˆØð 	DØÐ? &Ð?Ð?Ð?ÀÐCÐCà$&ˆØð 		Ø)×<Ò<¸YÈÐPUÑVÔVˆNà×-Ò-Ø#Ý.Ô@ØØØ”[ð .ñ ô ð ð ÐP˜UÐPÐP wÐPÐP°s´xÐPÐPÐPÐR`Ð`Ð`r$   )r   r   )r%   r   r   r   )r+   r   r   r   )r'   r/   r   r0   )r(   r/   r   r4   )r=   )
r(   r/   r>   r?   r@   r?   rA   r?   r   r4   )rI   )
r%   r   rJ   r?   rK   r?   rL   r?   r   rM   )r-   r/   r   rT   )rW   r/   r   rX   )rW   r/   r   r   )r^   NN)rW   r/   r'   r/   r(   r/   rJ   r?   rK   r?   r_   r`   ra   rb   rc   rd   r   re   )r^   NNN)rW   r/   r'   r/   rJ   r?   rK   r?   r_   r`   ra   rb   rc   rd   r(   rd   r   re   )NNNr^   )rW   r/   r‡   r/   r'   rd   rj   rd   ra   rb   r_   r`   r   rˆ   )r^   N)rW   r/   r'   r/   r¢   r/   r£   r`   ra   rb   r   r¤   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r#   r*   r.   r3   r<   rH   rS   rV   r[   r]   r‚   r†   r¡   r¨   r7   r$   r"   r   r   '   sº  € € € € € ðð ðEð Eð Eð EðAð Að Að Að2ð 2ð 2ð 2ð.ð .ð .ð .ðYð Yð Yð Yð
 AEðð ð ð ð ð X[ð<ð <ð <ð <ð <ð1ð 1ð 1ð 1ð4ð 4ð 4ð 4ð1ð 1ð 1ð 1ð Ø.2Ø%)ðD`ð D`ð D`ð D`ð D`ðX Ø.2Ø%)Ø!%ð
ð 
ð 
ð 
ð 
ð: !%Ø)-Ø.2ØðVgð Vgð Vgð Vgð Vgðz Ø.2ðað að að að að að ar$   r   r   c                 ó@   — t          ¦   «         } t          | ¦  «         | S )z©
    Factory creating an NpcEngine populated with FreeExile's Grimdark Feral NPCs
    across Outcast Camp, Bone-Cliff Chasm, Ancient Barrow, Dune Desert, and Ruins.
    )r   r   )Úengines    r"   Úcreate_canonical_npc_enginer¯   >  s    € õ
 ‰[Œ[€FÝ˜FÑ#Ô#Ð#Ø€Mr$   )r   r   )r¬   Ú
__future__r   rO   rx   Útypingr   r   r   r   r   r	   Úserver.world.quest_enginer
   r   r   r   r   Úserver.world.npc_typesr   r   r   r   r   r   r   Úserver.world.npc_catalogr   r   r¯   r7   r$   r"   ú<module>rµ      sp  ððð ð #Ð "Ð "Ð "Ð "Ð "Ø €€€Ø €€€Ø 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8ðð ð ð ð ð ð ð ð ð ð ð ð ð ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð =Ð <Ð <Ð <Ð <Ð <ðTað Tað Tað Tað Tañ Taô Tað Taðnð ð ð ð ð r$   