§
    ê#¾j¤F  ã                  óB  — d Z ddlm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 ddlZddlZ ee¦  «                             ¦   «         j        j        j        Zedz  dz  Zedz  dz  Zed	z  d
z  Zg d¢Zdd„Z G d„ d¦  «        Z G d„ d¦  «        Z G d„ d¦  «        ZdS )zkUnit Test Suite for FreeExile Animation Atlas Frame Mapping, Pivot Bounding Box & Turn Inertia Snap Freeze.é    )ÚannotationsN)ÚPathÚclientÚwebappÚassetsÚ
animationsÚjsÚengine)Úchar_sword_masterÚchar_sword_maidenÚchar_feral_berserkerÚchar_wild_archerÚchar_glacial_lancerÚchar_shadow_assassinÚjs_codeÚstrÚreturnÚdictc                ó‚  — d| › d�}t          j        ddd|gt          t          ¦  «        dd¬¦  «        }|j        }d}||k    }|sÊt          j        d	|fd
||f¦  «        dt          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        ndt          j
        |¦  «        t          j
        |¦  «        dœz  }t          j        d|j        › d| › �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}}t          j        |j                             ¦   «         ¦  «        S )Nag  
    globalThis.window = globalThis;
    globalThis.document = { readyState: 'complete', addEventListener: () => {}, getElementById: () => null };
    const fs = await import('node:fs');
    new Function(fs.readFileSync('./client/webapp/js/engine/animation_engine.js', 'utf-8'))();
    const ae = window.AnimationEngine;
    globalThis.ASSETS = globalThis.ASSETS || {};
    globalThis.ASSETS['hero_anim_atlas'] = { complete: true, naturalWidth: 1280, naturalHeight: 960 };
    const makeCtx = () => {
        const captured = [];
        return {
            captured, save() {}, restore() {}, translate() {}, scale() {}, rotate() {},
            fillRect() {}, strokeRect() {}, fillText() {},
            drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh) { captured.push({ sx, sy, sw, sh, dx, dy, dw, dh }); }
        };
    };
    (async () => {
        try {
            zn
        } catch (err) {
            console.error(err);
            process.exit(1);
        }
    })();
    Únodez--input-type=modulez-eT)ÚcwdÚcapture_outputÚtextr   ©ú==)z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sÚres)Úpy0Úpy2Úpy5zNode script execution failed:
z
Code:
z
>assert %(py7)sÚpy7)Ú
subprocessÚrunr   ÚPROJECT_ROOTÚ
returncodeÚ
@pytest_arÚ_call_reprcompareÚ@py_builtinsÚlocalsÚ_should_repr_global_nameÚ	_safereprÚ_format_assertmsgÚstderrÚAssertionErrorÚ_format_explanationÚjsonÚloadsÚstdoutÚstrip)r   Úrunnerr   Ú@py_assert1Ú@py_assert4Ú@py_assert3Ú@py_format6Ú@py_format8s           úLC:\Projects\FreeExile\tests\unit\test_animation_frame_mapping_and_inertia.pyÚrun_node_jsr:      sl  € ðð$ ð%ð ð €Fõ2 Œ.˜&Ð"7¸¸vÐFÍCÕP\ÑL]ÔL]ÐnrÐy}Ð
~Ñ
~Ô
~€CØŒ>Ð`˜QÐ`ˆ>˜QÒÐ`Ð`Ð`Õ`Ô`Ð`Ð`Ð`Ð`ˆ>˜QÐ`Ñ`Ô`Ð`Õ`Ô`Ñ`Ô`Ð`Ð`Õ`Ô`ˆ3Ñ`Ô`Ð`Õ`Ô`ˆ3Ñ`Ô`Ð`Ð`Õ`Ô`ˆ>Ñ`Ô`Õ`Ô`˜QÑ`Ô`Ð`Ð`Ñ`Ð`Õ`Ô`Ð `À#Ä*Ð `Ð `ÐW^Ð `Ð `Ñ`Ô`Ð`Ñ`Ð`Ð`Ð`Ñ`Ð`Õ`Õ`Ô`Ð`Ñ`Ô`Ñ`Ô`Ð`Ð`Ð`Ð`Ð`Ð`Ð`ÝŒ:�c”j×&Ò&Ñ(Ô(Ñ)Ô)Ð)ó    c                  óú   — e Zd ZdZej                             de¦  «        ej                             dg d¢¦  «        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S )ÚTestAtlasFrameMappingz>Verifies R1: Exact atlas grid frame mapping and pivot reading.Úclass_idÚ	clip_name)Úidler"   Úattack_slashÚdodger   r   ÚNonec                ó&  — t          j        t          |› d�z                       d¬¦  «        ¦  «        }d|› d|› d|› d|› d|› d	|› d
�}t	          |¦  «        d         }|d         |         d         }t          |¦  «        }t          |¦  «        }||k    }	|	�sxt          j        d|	fd||f¦  «        dt          j	        ¦   «         v st          j
        t
          ¦  «        rt          j        t
          ¦  «        nddt          j	        ¦   «         v st          j
        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dt          j	        ¦   «         v st          j
        t
          ¦  «        rt          j        t
          ¦  «        nddt          j	        ¦   «         v st          j
        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }
dd|
iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}	}t          |¦  «        D �]i\  }}|d         |         }g }||         d         }|d         }||k    }	|	}|	r||         d         }|d         }||k    }|}|�st          j        d|	fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }
|                     |
¦  «         |	r`t          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd |iz  }|                     |¦  «         t          j        |d!¦  «        i z  }d"d#|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}	x}x}x}}�Œkd S )$Nz_anim_manifest.jsonúutf-8©Úencodingz
        globalThis.ASSETS['zŒ_anim_atlas'] = { complete: true, naturalWidth: 1280, naturalHeight: 960 };
        const ctx = makeCtx(), state = ae.createAnimationState('z!');
        state.currentClip = 'z&';
        const clip = ae.MANIFESTS['z']?.animations['z('] || ae.MANIFESTS['hero']?.animations['aL  '];
        const results = [];
        for (let f = 0; f < clip.frames.length; f++) {
            state.frameIndex = f; ctx.captured.length = 0;
            ae.drawEntityFrame(ctx, state, 100, 100, 1, 100, 125);
            results.push(ctx.captured[0] || null);
        }
        console.log(JSON.stringify({ results }));
        Úresultsr   Úframesr   )zN%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py8)s
{%(py8)s = %(py5)s(%(py6)s)
}ÚlenÚclip_frames)r   Úpy1Úpy3r   Úpy6Úpy8zassert %(py10)sÚpy10ÚsxÚxÚsyÚy©z%(py3)s == %(py6)s©rM   rN   ú%(py8)srO   ©z%(py11)s == %(py14)s©Úpy11Úpy14ú%(py16)sÚpy16r   úassert %(py19)sÚpy19)r/   r0   ÚANIM_DIRÚ	read_textr:   rJ   r%   r&   r'   r(   r)   r*   r-   r.   Ú	enumerateÚappendÚ_format_boolop)Úselfr>   r?   Úmanifest_datar   rH   rK   Ú@py_assert2Ú@py_assert7r5   Ú@py_format9Ú@py_format11ÚidxÚfkeyÚexpr4   Ú@py_assert5Ú@py_assert0Ú@py_assert10Ú@py_assert13Ú@py_assert12Ú@py_format7Ú@py_format15Ú@py_format17Ú@py_format18Ú@py_format20s                             r9   Ú+test_all_classes_match_manifest_coordinateszATestAtlasFrameMapping.test_all_classes_match_manifest_coordinates2   sV  € õ œ
¥H°(Ð/OÐ/OÐ/OÑ$O×#ZÒ#ZÐdkÐ#ZÑ#lÔ#lÑmÔmˆðØ$ðð àAIðð ð (ðð ð %-ð	ð ð ?Hð	ð ð r{ð	ð ð ˆõ ˜gÑ&Ô& yÔ1ˆØ# LÔ1°)Ô<¸XÔFˆÝ�7‰|Œ|Ð/�s ;Ñ/Ô/Ð/ˆ|Ð/Ò/Ð/Ð/Ñ/Õ/Ô/Ð/Ð/Ð/Ð/ˆ|Ð/Ð/Ñ/Ô/Ð/Õ/Ô/Ñ/Ô/Ð/Ð/Õ/Ô/�sÑ/Ô/Ð/Õ/Ô/�sÑ/Ô/Ð/Ð/Ð/Õ/Ô/Ñ/Ô/Ð/Ð/Õ/Ô/�7Ñ/Ô/Ð/Õ/Ô/�7Ñ/Ô/Ð/Ð/Õ/Ô/ˆ|Ñ/Ô/Ð/Õ/Ô/Ñ/Ô/Ð/Ð/Õ/Ô/�sÑ/Ô/Ð/Õ/Ô/�sÑ/Ô/Ð/Ð/Ð/Õ/Ô/Ñ/Ô/Ð/Ð/Õ/Ô/ ;Ñ/Ô/Ð/Õ/Ô/ ;Ñ/Ô/Ð/Ð/Õ/Ô/Ð/Ñ/Ô/Ð/Ð/Ñ/Ð/Ð/Ð/Ð/Ð/Ñ/Ð/Õ/Õ/Ô/Ð/Ñ/Ô/Ñ/Ô/Ð/Ð/Ð/Ð/Ð/Ð/Ð/Ý" ;Ñ/Ô/ð 	Uñ 	U‰IˆC�Ø Ô)¨$Ô/ˆCØTÐT�7˜3”< Ô%ÐT¨¨S¬ÐTÐ%¨Ò1ÐTÐTÐTÐTÐT°g¸c´lÀ4Ô6HÐTÈCÐPSÌHÐTÐ6HÈHÒ6TÐTÐTÐTÐTÑTÕTÔTÐTÐTÐTÐTÐ%¨ÐTÑTÔTÕTÔTÐ%ÑTÔTÕTÔT¨ÑTÔTÐTÐTÑTÐTÐTÐTÐTÐTÑTÐTÐT×TÒTÐTÑTÔTÐTÐTÐTÕTÔTÐTÐTÐTÐTÐ6HÈHÐTÑTÔTÕTÔTÐ6HÑTÔTÕTÔTÈHÑTÔTÐTÐTÑTÐTÐTÐTÐTÐTÑTÐTÐT×TÒTÐTÑTÔTÐTÕTÔTÐTÐTÑTÔTÐTÑTÐTÐTÐTÐTÐTÑTÐTÕTÕTÔTÐTÑTÔTÑTÔTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÐTÑTð	Uð 	Ur;   c                ó”  — d}t          |¦  «        }g }|d         d         }d}||k    }|}|r|d         d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        d	œz  }d
d|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	g }|d         d         }d}||k    }|}|r|d         d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        d	œz  }d
d|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	g }|d         d         }d}||k    }|}|r|d         d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        d	œz  }d
d|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	g }|d         d         }d}||k    }|}|r|d         d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        d	œz  }d
d|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	g }|d         d         }d}||k    }|}|r|d         d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        d	œz  }d
d|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	g }|d         d         }d}||k    }|}|r|d         d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        d	œz  }d
d|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )NaJ  
        const ctx = makeCtx(), state = ae.createAnimationState('hero');
        const checkClip = (clip) => {
            state.currentClip = clip; state.frameIndex = 0; ctx.captured.length = 0;
            ae.drawEntityFrame(ctx, state, 0, 0, 1, 100, 125);
            return ctx.captured[0];
        };
        console.log(JSON.stringify({
            thrust0: checkClip('attack_thrust'), slam0: checkClip('attack_slam'), bolt0: checkClip('attack_bolt'),
            whirlwind0: checkClip('skill_whirlwind'), dodge0: checkClip('dodge'), hurt0: checkClip('hurt')
        }));
        Úthrust0rQ   i€  rS   éÀ   r   rU   rV   rW   rO   rX   rY   r\   r]   r   r^   r_   Úslam0Úbolt0Ú
whirlwind0i@  i€  Údodge0i@  Úhurt0iÀ  ©r:   r%   r&   r*   rc   rd   r-   r.   ©re   r   Úoutr4   rg   rn   r5   ro   rp   rq   rr   rs   ri   rt   ru   rv   rw   s                    r9   Ú6test_aliased_attack_clips_do_not_skew_subsequent_clipszLTestAtlasFrameMapping.test_aliased_attack_clips_do_not_skew_subsequent_clipsJ   sp
  € ðˆõ ˜'Ñ"Ô"ˆØJÐJˆs�9Œ~˜dÔ#ÐJ sÐJÐ# sÒ*ÐJÐJÐJÐJÐJ¨s°9¬~¸dÔ/CÐJÀsÐJÐ/CÀsÒ/JÐJÐJÐJÐJÑJÕJÔJÐJÐJÐJÐJÐ# sÐJÑJÔJÕJÔJÐ#ÑJÔJÕJÔJ sÑJÔJÐJÐJÑJÐJÐJÐJÐJÐJÑJÐJÐJ×JÒJÐJÑJÔJÐJÐJÐJÕJÔJÐJÐJÐJÐJÐ/CÀsÐJÑJÔJÕJÔJÐ/CÑJÔJÕJÔJÀsÑJÔJÐJÐJÑJÐJÐJÐJÐJÐJÑJÐJÐJ×JÒJÐJÑJÔJÐJÕJÔJÐJÐJÑJÔJÐJÑJÐJÐJÐJÐJÐJÑJÐJÕJÕJÔJÐJÑJÔJÑJÔJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJØFÐFˆs�7Œ|˜DÔ!ÐF SÐFÐ! SÒ(ÐFÐFÐFÐFÐF¨S°¬\¸$Ô-?ÐFÀ3ÐFÐ-?À3Ò-FÐFÐFÐFÐFÑFÕFÔFÐFÐFÐFÐFÐ! SÐFÑFÔFÕFÔFÐ!ÑFÔFÕFÔF SÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÐFÐFÕFÔFÐFÐFÐFÐFÐ-?À3ÐFÑFÔFÕFÔFÐ-?ÑFÔFÕFÔFÀ3ÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÕFÔFÐFÐFÑFÔFÐFÑFÐFÐFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFØFÐFˆs�7Œ|˜DÔ!ÐF SÐFÐ! SÒ(ÐFÐFÐFÐFÐF¨S°¬\¸$Ô-?ÐFÀ3ÐFÐ-?À3Ò-FÐFÐFÐFÐFÑFÕFÔFÐFÐFÐFÐFÐ! SÐFÑFÔFÕFÔFÐ!ÑFÔFÕFÔF SÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÐFÐFÕFÔFÐFÐFÐFÐFÐ-?À3ÐFÑFÔFÕFÔFÐ-?ÑFÔFÕFÔFÀ3ÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÕFÔFÐFÐFÑFÔFÐFÑFÐFÐFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFØPÐPˆs�<Ô  Ô&ÐP¨#ÐPÐ&¨#Ò-ÐPÐPÐPÐPÐP°#°lÔ2CÀDÔ2IÐPÈSÐPÐ2IÈSÒ2PÐPÐPÐPÐPÑPÕPÔPÐPÐPÐPÐPÐ&¨#ÐPÑPÔPÕPÔPÐ&ÑPÔPÕPÔP¨#ÑPÔPÐPÐPÑPÐPÐPÐPÐPÐPÑPÐPÐP×PÒPÐPÑPÔPÐPÐPÐPÕPÔPÐPÐPÐPÐPÐ2IÈSÐPÑPÔPÕPÔPÐ2IÑPÔPÕPÔPÈSÑPÔPÐPÐPÑPÐPÐPÐPÐPÐPÑPÐPÐP×PÒPÐPÑPÔPÐPÕPÔPÐPÐPÑPÔPÐPÑPÐPÐPÐPÐPÐPÑPÐPÕPÕPÔPÐPÑPÔPÑPÔPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPÐPØFÐFˆs�8Œ}˜TÔ"ÐF aÐFÐ" aÒ'ÐFÐFÐFÐFÐF¨C°¬M¸$Ô,?ÐFÀ3ÐFÐ,?À3Ò,FÐFÐFÐFÐFÑFÕFÔFÐFÐFÐFÐFÐ" aÐFÑFÔFÕFÔFÐ"ÑFÔFÕFÔF aÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÐFÐFÕFÔFÐFÐFÐFÐFÐ,?À3ÐFÑFÔFÕFÔFÐ,?ÑFÔFÕFÔFÀ3ÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÕFÔFÐFÐFÑFÔFÐFÑFÐFÐFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFØFÐFˆs�7Œ|˜DÔ!ÐF SÐFÐ! SÒ(ÐFÐFÐFÐFÐF¨S°¬\¸$Ô-?ÐFÀ3ÐFÐ-?À3Ò-FÐFÐFÐFÐFÑFÕFÔFÐFÐFÐFÐFÐ! SÐFÑFÔFÕFÔFÐ!ÑFÔFÕFÔF SÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÐFÐFÕFÔFÐFÐFÐFÐFÐ-?À3ÐFÑFÔFÕFÔFÐ-?ÑFÔFÕFÔFÀ3ÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÕFÔFÐFÐFÑFÔFÐFÑFÐFÐFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFr;   c           	     ó²  — d}t          |¦  «        d         }g }t          j        }|d         }d}| }d} ||||¬¦  «        }	|	}
|	r+t          j        }|d         }d}| }d} ||||¬¦  «        }|}
|
�sÆd	d
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }|                     |¦  «         |	rÂdd
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }|                     |¦  «         t          j	        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}
x}x}x}x}x}x}x}	x}x}x}x}x}}d S )Nay  
        ae.MANIFESTS['custom_test'] = {
            texture_width: 1280, texture_height: 960, frame_width: 160, frame_height: 192,
            frames: { 'idle_0': { x: 0, y: 0, w: 160, h: 192, pivot: [0.4, 0.75] } },
            animations: { idle: { frames: ['idle_0'], fps: 6, loop: true } }
        };
        globalThis.ASSETS['custom_test_anim_atlas'] = { complete: true, naturalWidth: 1280, naturalHeight: 960 };
        const ctx = makeCtx(), state = ae.createAnimationState('custom_test');
        ae.drawEntityFrame(ctx, state, 100, 100, 1, 100, 200);
        console.log(JSON.stringify({ cap: ctx.captured[0] }));
        ÚcapÚdxg      D@çš™™™™™¹?©Úabs_tolÚdyg     Àb@z`%(py13)s
{%(py13)s = %(py4)s
{%(py4)s = %(py2)s.isclose
}(%(py6)s, -%(py8)s, abs_tol=%(py11)s)
}Úmath)r   Úpy4rN   rO   rZ   Úpy13ze%(py26)s
{%(py26)s = %(py17)s
{%(py17)s = %(py15)s.isclose
}(%(py19)s, -%(py21)s, abs_tol=%(py24)s)
})Úpy15Úpy17r_   Úpy21Úpy24Úpy26r   zassert %(py29)sÚpy29©r:   rŒ   Úiscloser'   r(   r%   r)   r*   rc   rd   r-   r.   )re   r   r†   r4   r6   rn   rh   Ú@py_assert9rp   rr   ro   Ú@py_assert16Ú@py_assert18Ú@py_assert20Ú@py_assert22Ú@py_assert23Ú@py_assert25Ú@py_format14Ú@py_format27Ú@py_format28Ú@py_format30s                        r9   Ú2test_pivot_bounding_box_reads_manifest_frame_pivotzHTestAtlasFrameMapping.test_pivot_bounding_box_reads_manifest_frame_pivot_   s¤  € ð
ˆõ ˜'Ñ"Ô" 5Ô)ˆØkÐk�tŒ|Ðk˜C œIÐk¨Ðk¨ uÐk°cÐkˆ|ˆ|˜I u°cÐ:Ñ:Ô:ÐkÐ:ÐkÐ:Ðk½t¼|ÐkÈCÐPTÌIÐkÐX]ÐkÐX]ÐW]ÐkÐgjÐk¸|¸|ÈIÐW]ÐgjÐ?kÑ?kÔ?kÐkÐ?kÐkÐkÑkÐkÐkÕkÔkÑkÔkÐkÐkÕkÔk�tÑkÔkÐkÕkÔk�tÑkÔkÐkÐkÕkÔkˆ|ÑkÔkÕkÔk˜IÑkÔkÕkÔk¨ÑkÔkÕkÔk°cÑkÔkÕkÔkÐ:ÑkÔkÐkÐkÑkÐkÐk×kÒkÐkÑkÔkÐkÐ:ÐkÐkÐkÕkÔkÑkÔkÐkÐkÕkÔk½tÑkÔkÐkÕkÔk½tÑkÔkÐkÐkÕkÔk¸|ÑkÔkÕkÔkÈIÑkÔkÕkÔkÐX]ÑkÔkÕkÔkÐgjÑkÔkÕkÔkÐ?kÑkÔkÐkÐkÑkÐkÐk×kÒkÐkÑkÔkÐkÕkÔkÐkÐkÑkÔkÐkÑkÐkÐkÐkÐkÐkÑkÐkÕkÕkÔkÐkÑkÔkÑkÔkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkÐkr;   c                óä  — d}t          |¦  «        d         }g }d }||u}|}|r&|d         }d}||k    }	|	}|	r|d         }
d}|
|k    }|}|�s�t          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }d	d
|iz  }|                     |¦  «         |rÂt          j        d|	fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         |	r`t          j        d|fd|
|f¦  «        t          j        |
¦  «        t          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j
        |¦  «        ¦  «        ‚d x}x}x}x}x}x}	x}x}
x}}d S )Na  
        const ctx = makeCtx(), state = ae.createAnimationState('hero');
        state.currentClip = 'nonexistent_test_action';
        ae.drawEntityFrame(ctx, state, 0, 0, 1, 100, 125);
        console.log(JSON.stringify({ cap: ctx.captured[0] }));
        r†   rQ   r   rS   ©úis not©z%(py2)s is not %(py5)s©r   r   ú%(py7)sr    r   )z%(py10)s == %(py13)s)rP   rŽ   z%(py15)sr�   )z%(py18)s == %(py21)s)Úpy18r‘   z%(py23)sÚpy23zassert %(py26)sr“   )r:   r%   r&   r'   r(   r)   r*   rc   rd   r-   r.   )re   r   r†   r4   r5   r6   ro   r—   rr   Ú@py_assert11Ú@py_assert17rš   Ú@py_assert19r7   r8   rž   Ú@py_format16Ú@py_format22Ú@py_format24Ú@py_format25rŸ   s                        r9   Ú=test_fallback_clip_on_unknown_animation_draws_idle_frame_zerozSTestAtlasFrameMapping.test_fallback_clip_on_unknown_animation_draws_idle_frame_zeron   s�  € ðˆõ ˜'Ñ"Ô" 5Ô)ˆØDÐD˜$ÐDˆs˜$ˆÐDÐDÐDÐDÐD 3 t¤9ÐD°ÐD 9°¢>ÐDÐDÐDÐDÐD°c¸$´iÐDÀ1ÐD°iÀ1²nÐDÐDÐDÐDÑDÕDÔDÐDÐDÐDÐDˆs˜$ÐDÑDÔDÐDÕDÔDÑDÔDÐDÐDÕDÔDˆsÑDÔDÐDÕDÔDˆsÑDÔDÐDÐDÕDÔD˜$ÑDÔDÐDÐDÑDÐDÐDÐDÐDÐDÑDÐDÐD×DÒDÐDÑDÔDÐDÐDÐDÕDÔDÐDÐDÐDÐD 9°ÐDÑDÔDÕDÔD 9ÑDÔDÕDÔD°ÑDÔDÐDÐDÑDÐDÐDÐDÐDÐDÑDÐDÐD×DÒDÐDÑDÔDÐDÐDÐDÕDÔDÐDÐDÐDÐD°iÀ1ÐDÑDÔDÕDÔD°iÑDÔDÕDÔDÀ1ÑDÔDÐDÐDÑDÐDÐDÐDÐDÐDÑDÐDÐD×DÒDÐDÑDÔDÐDÕDÔDÐDÐDÑDÔDÐDÑDÐDÐDÐDÐDÐDÑDÐDÕDÕDÔDÐDÑDÔDÑDÔDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDÐDr;   c                ó®  — d}t          |¦  «        d         }g }|d         }d}||k    }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        d	œz  }d
d|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )Na  
        const ctx = makeCtx(), state = ae.createAnimationState('hero');
        state.currentClip = 'idle'; state.frameIndex = -1;
        ae.drawEntityFrame(ctx, state, 0, 0, 1, 100, 125);
        console.log(JSON.stringify({ cap: ctx.captured[0] }));
        r†   rQ   ià  rS   r   r   rU   rV   rW   rO   rX   rY   r\   r]   r^   r_   r�   )re   r   r†   r4   rg   rn   r5   ro   rp   rq   rr   rs   ri   rt   ru   rv   rw   s                    r9   Ú.test_negative_frame_index_wraps_modulo_cleanlyzDTestAtlasFrameMapping.test_negative_frame_index_wraps_modulo_cleanlyx   sÊ  € ðˆõ ˜'Ñ"Ô" 5Ô)ˆØ2Ð2ˆs�4ŒyÐ2˜CÐ2ˆy˜CÒÐ2Ð2Ð2Ð2Ð2 C¨¤IÐ2°Ð2 I°¢NÐ2Ð2Ð2Ð2Ñ2Õ2Ô2Ð2Ð2Ð2Ð2ˆy˜CÐ2Ñ2Ô2Õ2Ô2ˆyÑ2Ô2Õ2Ô2˜CÑ2Ô2Ð2Ð2Ñ2Ð2Ð2Ð2Ð2Ð2Ñ2Ð2Ð2×2Ò2Ð2Ñ2Ô2Ð2Ð2Ð2Õ2Ô2Ð2Ð2Ð2Ð2 I°Ð2Ñ2Ô2Õ2Ô2 IÑ2Ô2Õ2Ô2°Ñ2Ô2Ð2Ð2Ñ2Ð2Ð2Ð2Ð2Ð2Ñ2Ð2Ð2×2Ò2Ð2Ñ2Ô2Ð2Õ2Ô2Ð2Ð2Ñ2Ô2Ð2Ñ2Ð2Ð2Ð2Ð2Ð2Ñ2Ð2Õ2Õ2Ô2Ð2Ñ2Ô2Ñ2Ô2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2r;   c                ó(  — d}t          |¦  «        d         }d}||u }|slt          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }t	          t          j        |¦  «        ¦  «        ‚d x}x}}d S )	NzÁ
        const ctx = makeCtx(), state = ae.createAnimationState('mob_feral_hellhound');
        console.log(JSON.stringify({ drawn: ae.drawEntityFrame(ctx, state, 0, 0, 1, 80, 80) }));
        ÚdrawnF©Úis©z%(py1)s is %(py4)s©rL   r�   úassert %(py6)srN   ©r:   r%   r&   r*   r-   r.   ©re   r   ro   r6   rg   Ú@py_format5rs   s          r9   Ú(test_mob_atlas_does_not_draw_hero_spritez>TestAtlasFrameMapping.test_mob_atlas_does_not_draw_hero_sprite‚   sÂ   € ðˆõ ˜7Ñ#Ô# GÔ,Ð5°Ð5Ð,°Ð5Ð5Ð5Ð5Õ5Ô5Ð5Ð5Ð5Ð5Ð,°Ð5Ñ5Ô5Õ5Ô5Ð,Ñ5Ô5Õ5Ô5°Ñ5Ô5Ð5Ð5Ñ5Ð5Ð5Ð5Ð5Ð5Ñ5Ð5Õ5Õ5Ô5Ð5Ñ5Ô5Ñ5Ô5Ð5Ð5Ð5Ð5Ð5Ð5Ð5Ð5Ð5r;   c                ó(  — d}t          |¦  «        d         }d}||u }|slt          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }t	          t          j        |¦  «        ¦  «        ‚d x}x}}d S )	Na  
        ae.MANIFESTS['empty_test'] = {
            texture_width: 1280, texture_height: 960, frame_width: 160, frame_height: 192,
            animations: { empty_clip: { frames: [] } }
        };
        globalThis.ASSETS['empty_test_anim_atlas'] = { complete: true, naturalWidth: 1280, naturalHeight: 960 };
        const ctx = makeCtx(), state = ae.createAnimationState('empty_test');
        state.currentClip = 'empty_clip';
        console.log(JSON.stringify({ drawn: ae.drawEntityFrame(ctx, state, 0, 0, 1, 100, 100) }));
        r¶   Fr·   r¹   rº   r»   rN   r¼   r½   s          r9   Ú$test_empty_frames_clip_returns_falsez:TestAtlasFrameMapping.test_empty_frames_clip_returns_false‰   sÂ   € ð	ˆõ ˜7Ñ#Ô# GÔ,Ð5°Ð5Ð,°Ð5Ð5Ð5Ð5Õ5Ô5Ð5Ð5Ð5Ð5Ð,°Ð5Ñ5Ô5Õ5Ô5Ð,Ñ5Ô5Õ5Ô5°Ñ5Ô5Ð5Ð5Ñ5Ð5Ð5Ð5Ð5Ð5Ñ5Ð5Õ5Õ5Ô5Ð5Ñ5Ô5Ñ5Ô5Ð5Ð5Ð5Ð5Ð5Ð5Ð5Ð5Ð5r;   c                ó(  — d}t          |¦  «        d         }d}||u }|slt          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }t	          t          j        |¦  «        ¦  «        ‚d x}x}}d S )	NaÔ  
        ae.MANIFESTS['circular_cycle'] = {
            texture_width: 1280, texture_height: 960, frame_width: 160, frame_height: 192,
            animations: { loop_a: { atlas_clip: 'loop_b' }, loop_b: { atlas_clip: 'loop_a' } }
        };
        const ctx = makeCtx(), state = ae.createAnimationState('circular_cycle');
        state.currentClip = 'loop_a';
        console.log(JSON.stringify({ drawn: ae.drawEntityFrame(ctx, state, 0, 0, 1, 100, 100) }));
        r¶   Fr·   r¹   rº   r»   rN   r¼   r½   s          r9   Ú test_circular_alias_cycle_safetyz6TestAtlasFrameMapping.test_circular_alias_cycle_safety–   sÂ   € ðˆõ ˜7Ñ#Ô# GÔ,Ð5°Ð5Ð,°Ð5Ð5Ð5Ð5Õ5Ô5Ð5Ð5Ð5Ð5Ð,°Ð5Ñ5Ô5Õ5Ô5Ð,Ñ5Ô5Õ5Ô5°Ñ5Ô5Ð5Ð5Ñ5Ð5Ð5Ð5Ð5Ð5Ñ5Ð5Õ5Õ5Ô5Ð5Ñ5Ô5Ñ5Ô5Ð5Ð5Ð5Ð5Ð5Ð5Ð5Ð5Ð5r;   c           	     óê  — d}t          |¦  «        d         }g }d }||u}|}|rXt          j        }|d         }d}	|	 }
d} |||
|¬¦  «        }|}|r+t          j        }|d         }d}| }d} ||||¬¦  «        }|}|�sTt          j        d	|fd
||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }dd|iz  }| 	                    |¦  «         |�r†ddt          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        ndt          j        |¦  «        t          j        |¦  «        t          j        |	¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }| 	                    |¦  «         |rÂddt          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        ndt          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }| 	                    |¦  «         t          j
        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}	x}
x}x}x}x}x}x}x}}d S )Naw  
        ae.MANIFESTS['nan_pivot'] = {
            texture_width: 1280, texture_height: 960, frame_width: 160, frame_height: 192,
            frames: { 'idle_0': { x: 0, y: 0, w: 160, h: 192, pivot: [NaN, Infinity] } },
            animations: { idle: { frames: ['idle_0'], fps: 6, loop: true } }
        };
        globalThis.ASSETS['nan_pivot_anim_atlas'] = { complete: true, naturalWidth: 1280, naturalHeight: 960 };
        const ctx = makeCtx(), state = ae.createAnimationState('nan_pivot');
        ae.drawEntityFrame(ctx, state, 100, 100, 1, 100, 200);
        console.log(JSON.stringify({ cap: ctx.captured[0] }));
        r†   r‡   g      I@rˆ   r‰   r‹   g     €f@r¤   r¦   r§   r¨   r    zd%(py20)s
{%(py20)s = %(py11)s
{%(py11)s = %(py9)s.isclose
}(%(py13)s, -%(py15)s, abs_tol=%(py18)s)
}rŒ   )Úpy9rZ   rŽ   r�   r©   Úpy20ze%(py33)s
{%(py33)s = %(py24)s
{%(py24)s = %(py22)s.isclose
}(%(py26)s, -%(py28)s, abs_tol=%(py31)s)
})Úpy22r’   r“   Úpy28Úpy31Úpy33r   zassert %(py36)sÚpy36)r:   rŒ   r–   r%   r&   r'   r(   r)   r*   rc   rd   r-   r.   )re   r   r†   r4   r5   r6   ro   rp   rr   Ú@py_assert14r˜   r¬   r­   rœ   r�   Ú@py_assert27Ú@py_assert29Ú@py_assert30Ú@py_assert32r7   r8   Ú@py_format21Ú@py_format34Ú@py_format35Ú@py_format37s                            r9   Ú$test_nan_and_infinite_pivot_fallbackz:TestAtlasFrameMapping.test_nan_and_infinite_pivot_fallback¢   su  € ð
ˆõ ˜'Ñ"Ô" 5Ô)ˆØÐ˜$Ðˆs˜$ˆÐÐÐÐÐ¥4¤<Ð°°D´	Ð¸DÐ¸D¸5ÐÈ#Ð < <°	¸5È#Ð#NÑ#NÔ#NÐÐ#NÐÐ#NÐÕSWÔS_ÐÐ`cÐdhÔ`iÐÐlqÐÐlqÐkqÐÐ{~ÐÐS_ÐS_Ð`iÐkqÐ{~ÐSÑSÔSÐÐSÐÐÑÕÔÐÐÐÐˆs˜$ÐÑÔÐÕÔÑÔÐÐÕÔˆsÑÔÐÕÔˆsÑÔÐÐÕÔ˜$ÑÔÐÐÑÐÐÐÐÐÑÐÐ×ÒÐÑÔÐÐÑÐÐÕÔÑÔÐÐÕÔ¥4ÑÔÐÕÔ¥4ÑÔÐÐÕÔ <ÑÔÕÔ°	ÑÔÕÔ¸DÑÔÕÔÈ#ÑÔÕÔÐ#NÑÔÐÐÑÐÐ×ÒÐÑÔÐÐ#NÐÐÐÕÔÑÔÐÐÕÔÕSWÑÔÐÕÔÕSWÑÔÐÐÕÔÐS_ÑÔÕÔÐ`iÑÔÕÔÐlqÑÔÕÔÐ{~ÑÔÕÔÐSÑÔÐÐÑÐÐ×ÒÐÑÔÐÕÔÐÐÑÔÐÑÐÐÐÐÐÑÐÕÕÔÐÑÔÑÔÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐr;   c           	     óž  — d}t          |¦  «        d         }g }t          j        }|d         }d}d} ||||¬¦  «        }|}	|r(t          j        }
|d         }d}d} |
|||¬¦  «        }|}	|	�sÆd	d
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }|                     |¦  «         |rÂdd
t          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nd
t          j        |
¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }|                     |¦  «         t          j	        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}	x}x}x}x}x}x}x}
x}x}x}}dS )zFNegative frame pivots calculate proper offset coordinates without NaN.aa  
        ae.MANIFESTS['neg_pivot'] = {
            texture_width: 1280, texture_height: 960, frame_width: 160, frame_height: 192,
            frames: { 'i0': { x: 0, y: 0, w: 160, h: 192, pivot: [-0.25, -0.5] } },
            animations: { idle: { frames: ['i0'], fps: 6 } }
        };
        globalThis.ASSETS['neg_pivot_anim_atlas'] = { complete: true, naturalWidth: 1280, naturalHeight: 960 };
        const ctx = makeCtx(), state = ae.createAnimationState('neg_pivot');
        ae.drawEntityFrame(ctx, state, 100, 100, 1, 100, 200);
        console.log(JSON.stringify({ cap: ctx.captured[0] }));
        r†   r‡   g      9@rˆ   r‰   r‹   g      Y@z_%(py12)s
{%(py12)s = %(py4)s
{%(py4)s = %(py2)s.isclose
}(%(py6)s, %(py8)s, abs_tol=%(py10)s)
}rŒ   )r   r�   rN   rO   rP   Úpy12zd%(py24)s
{%(py24)s = %(py16)s
{%(py16)s = %(py14)s.isclose
}(%(py18)s, %(py20)s, abs_tol=%(py22)s)
})r[   r]   r©   rÆ   rÇ   r’   r   úassert %(py27)sÚpy27Nr•   )re   r   r†   r4   r6   rn   rh   r—   r«   ro   Ú@py_assert15r¬   r­   Ú@py_assert21rœ   Ú@py_format13r±   Ú@py_format26r    s                      r9   Ú"test_negative_frame_pivot_handlingz8TestAtlasFrameMapping.test_negative_frame_pivot_handling±   s‡  € ð
ˆõ ˜'Ñ"Ô" 5Ô)ˆØiÐi�tŒ|Ði˜C œIÐi tÐi°SÐiˆ|ˆ|˜I t°SÐ9Ñ9Ô9ÐiÐ9ÐiÐ9Ði½d¼lÐiÈ3ÈtÌ9ÐiÐV[ÐiÐehÐi¸l¸lÈ9ÐV[ÐehÐ>iÑ>iÔ>iÐiÐ>iÐiÐiÑiÐiÐiÕiÔiÑiÔiÐiÐiÕiÔi�tÑiÔiÐiÕiÔi�tÑiÔiÐiÐiÕiÔiˆ|ÑiÔiÕiÔi˜IÑiÔiÕiÔi tÑiÔiÕiÔi°SÑiÔiÕiÔiÐ9ÑiÔiÐiÐiÑiÐiÐi×iÒiÐiÑiÔiÐiÐ9ÐiÐiÐiÕiÔiÑiÔiÐiÐiÕiÔi½dÑiÔiÐiÕiÔi½dÑiÔiÐiÐiÕiÔi¸lÑiÔiÕiÔiÈ9ÑiÔiÕiÔiÐV[ÑiÔiÕiÔiÐehÑiÔiÕiÔiÐ>iÑiÔiÐiÐiÑiÐiÐi×iÒiÐiÑiÔiÐiÕiÔiÐiÐiÑiÔiÐiÑiÐiÐiÐiÐiÐiÑiÐiÕiÕiÔiÐiÑiÔiÑiÔiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐir;   c                ó®  — d}t          |¦  «        }g }|d         }d}||u }|}|r2|d         d         }d}	||	k    }
|
}|
r|d         d         }d}||k    }|}|�sdt          j        d|fd	||f¦  «        t          j        |¦  «        t          j        |¦  «        d
œz  }dd|iz  }|                     |¦  «         |rÂt          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         |
r`t          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}x}x}
x}	x}x}}dS )zOFrames with non-finite or zero dimensions safely fallback to manifest defaults.a}  
        ae.MANIFESTS['malformed_frame'] = {
            texture_width: 1280, texture_height: 960, frame_width: 160, frame_height: 192,
            frames: { 'bad0': { x: NaN, y: Infinity, w: 0, h: -10 } },
            animations: { idle: { frames: ['bad0'], fps: 6 } }
        };
        globalThis.ASSETS['malformed_frame_anim_atlas'] = { complete: true, naturalWidth: 1280, naturalHeight: 960 };
        const ctx = makeCtx(), state = ae.createAnimationState('malformed_frame');
        const drawn = ae.drawEntityFrame(ctx, state, NaN, 100, 1, 100, 200);
        console.log(JSON.stringify({ drawn, cap: ctx.captured[0] }));
        r¶   Tr†   rQ   r   rS   r·   ©z%(py3)s is %(py6)srV   rW   rO   r   rX   rY   r\   r]   )z%(py19)s == %(py22)s)r_   rÇ   z%(py24)sr’   rØ   rÙ   Nr�   )re   r   r   r4   rg   rn   r5   ro   rp   rq   rr   r™   rÛ   rš   rs   ri   rt   ru   Ú@py_format23r±   rÝ   r    s                         r9   Ú(test_malformed_frame_dimensions_fallbackz>TestAtlasFrameMapping.test_malformed_frame_dimensions_fallbackÁ   s„  € ð
ˆõ ˜'Ñ"Ô"ˆØWÐWˆs�7Œ|ÐW˜tÐWˆ|˜tÐ#ÐWÐWÐWÐWÐW¨¨E¬
°4Ô(8ÐW¸AÐWÐ(8¸AÒ(=ÐWÐWÐWÐWÐWÀ#ÀeÄ*ÈTÔBRÐWÐVWÐWÐBRÐVWÒBWÐWÐWÐWÐWÑWÕWÔWÐWÐWÐWÐWˆ|˜tÐWÑWÔWÕWÔWˆ|ÑWÔWÕWÔW˜tÑWÔWÐWÐWÑWÐWÐWÐWÐWÐWÑWÐWÐW×WÒWÐWÑWÔWÐWÐWÐWÕWÔWÐWÐWÐWÐWÐ(8¸AÐWÑWÔWÕWÔWÐ(8ÑWÔWÕWÔW¸AÑWÔWÐWÐWÑWÐWÐWÐWÐWÐWÑWÐWÐW×WÒWÐWÑWÔWÐWÐWÐWÕWÔWÐWÐWÐWÐWÐBRÐVWÐWÑWÔWÕWÔWÐBRÑWÔWÕWÔWÐVWÑWÔWÐWÐWÑWÐWÐWÐWÐWÐWÑWÐWÐW×WÒWÐWÑWÔWÐWÕWÔWÐWÐWÑWÔWÐWÑWÐWÐWÐWÐWÐWÑWÐWÕWÕWÔWÐWÑWÔWÑWÔWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWr;   c                óš  — d}t          |¦  «        }g }|d         }d }||u }|}|r|d         }d }	||	u }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         |r`t          j        d|
fd	||	f¦  «        t          j        |¦  «        t          j        |	¦  «        d
œz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )NaX  
        const ctx = makeCtx();
        let errUpdate = null, errDraw = null;
        try { ae.updateAnimation(null, 0.0, 0.016); } catch (e) { errUpdate = e.message; }
        try { ae.drawEntityFrame(ctx, undefined, 0, 0, 1, 100, 100); } catch (e) { errDraw = e.message; }
        console.log(JSON.stringify({ errUpdate, errDraw }));
        Ú	errUpdateÚerrDrawr·   rà   rV   rW   rO   ©z%(py11)s is %(py14)srY   r\   r]   r   r^   r_   r�   r‚   s                    r9   Ú)test_null_and_undefined_anim_state_safetyz?TestAtlasFrameMapping.test_null_and_undefined_anim_state_safetyÑ   sÊ  € ðˆõ ˜'Ñ"Ô"ˆØBÐBˆs�;ÔÐB 4ÐBÐ 4Ð'ÐBÐBÐBÐBÐB¨C°	¬NÐB¸dÐB¨N¸dÐ,BÐBÐBÐBÐBÑBÕBÔBÐBÐBÐBÐBÐ 4ÐBÑBÔBÕBÔBÐÑBÔBÕBÔB 4ÑBÔBÐBÐBÑBÐBÐBÐBÐBÐBÑBÐBÐB×BÒBÐBÑBÔBÐBÐBÐBÕBÔBÐBÐBÐBÐB¨N¸dÐBÑBÔBÕBÔB¨NÑBÔBÕBÔB¸dÑBÔBÐBÐBÑBÐBÐBÐBÐBÐBÑBÐBÐB×BÒBÐBÑBÔBÐBÕBÔBÐBÐBÑBÔBÐBÑBÐBÐBÐBÐBÐBÑBÐBÕBÕBÔBÐBÑBÔBÑBÔBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBÐBr;   N)r>   r   r?   r   r   rC   ©r   rC   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚpytestÚmarkÚparametrizeÚCLASSESrx   r„   r¢   r²   r´   r¿   rÁ   rÃ   rÕ   rÞ   râ   rç   © r;   r9   r=   r=   /   sn  € € € € € ØHÐHà„[×Ò˜Z¨Ñ1Ô1Ø„[×Ò˜[Ð*RÐ*RÐ*RÑSÔSðUð Uð Uñ TÔSñ 2Ô1ðUð,Gð Gð Gð Gð*lð lð lð lðEð Eð Eð Eð3ð 3ð 3ð 3ð6ð 6ð 6ð 6ð6ð 6ð 6ð 6ð
6ð 
6ð 
6ð 
6ð@ð @ð @ð @ðjð jð jð jð Xð Xð Xð Xð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cr;   r=   c                  óZ   — e Zd Z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S )ÚTestTurnInertiaSnapFreezezZVerifies R2: Smooth turn inertia freezes immediately on release without residual rotation.r   rC   c                óº  — d}t          |¦  «        }g }|d         }|d         }||k    }|}|r|d         }|d         }	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }|                     |¦  «         |r`t          j        d|
fd
||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )Na9  
        const state = ae.createAnimationState('hero'), moveDir = { x: 0.707, y: -0.707 };
        for (let i = 0; i < 10; i++) ae.updateAnimation(state, 4.2, 0.016, moveDir);
        const movingAngle = state.smoothAngle, stoppedFacing = { x: 1, y: 0 };
        ae.updateAnimation(state, 0.0, 0.016, stoppedFacing);
        const stoppedAngle1 = state.smoothAngle;
        for (let i = 0; i < 20; i++) ae.updateAnimation(state, 0.0, 0.016, stoppedFacing);
        console.log(JSON.stringify({ movingAngle, stoppedAngle1, stoppedAngle20: state.smoothAngle }));
        ÚstoppedAngle1ÚmovingAngleÚstoppedAngle20r   rU   rV   rW   rO   rX   rY   r\   r]   r   r^   r_   r�   r‚   s                    r9   Ú;test_smooth_angle_stops_lerp_immediately_when_velocity_zerozUTestTurnInertiaSnapFreeze.test_smooth_angle_stops_lerp_immediately_when_velocity_zeroà   sá  € ðˆõ ˜'Ñ"Ô"ˆØiÐiˆs�?Ô#Ði s¨=Ô'9ÐiÐ#Ð'9Ò9ÐiÐiÐiÐiÐi¸cÐBRÔ>SÐiÐWZÐ[hÔWiÐiÐ>SÐWiÒ>iÐiÐiÐiÐiÑiÕiÔiÐiÐiÐiÐiÐ#Ð'9ÐiÑiÔiÕiÔiÐ#ÑiÔiÕiÔiÐ'9ÑiÔiÐiÐiÑiÐiÐiÐiÐiÐiÑiÐiÐi×iÒiÐiÑiÔiÐiÐiÐiÕiÔiÐiÐiÐiÐiÐ>SÐWiÐiÑiÔiÕiÔiÐ>SÑiÔiÕiÔiÐWiÑiÔiÐiÐiÑiÐiÐiÐiÐiÐiÑiÐiÐi×iÒiÐiÑiÔiÐiÕiÔiÐiÐiÑiÔiÐiÑiÐiÐiÐiÐiÐiÑiÐiÕiÕiÔiÐiÑiÔiÑiÔiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐir;   c                ó–  — d}t          |¦  «        }g }|d         }d}||k    }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }|                     |¦  «         |r`t          j        d|
fd
||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	g }|d         }d}||k    }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }|                     |¦  «         |r`t          j        d|
fd
||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	g }|d         }d}||k    }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }|                     |¦  «         |r`t          j        d|
fd
||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )NaY  
        const state = ae.createAnimationState('hero');
        state.currentClip = 'run';
        ae.updateAnimation(state, 4.2, 0.016, { x: 1, y: 0 });
        const movingClip = state.currentClip, movingPhase = state.kineticPhase;
        ae.updateAnimation(state, 0.0, 0.016, { x: 1, y: 0 });
        const stoppedClip = state.currentClip, stoppedPhase = state.kineticPhase;
        ae.updateAnimation(state, 4.2, 0.016, { x: 1, y: 0 });
        console.log(JSON.stringify({ movingClip, movingPhase, stoppedClip, stoppedPhase, resClip: state.currentClip, resPhase: state.kineticPhase }));
        Ú
movingClipr"   ÚmovingPhaser   rU   rV   rW   rO   rX   rY   r\   r]   r   r^   r_   ÚstoppedClipr@   ÚstoppedPhaseÚresClipÚresPhaser�   r‚   s                    r9   Ú+test_transition_run_to_idle_in_single_framezETestTurnInertiaSnapFreeze.test_transition_run_to_idle_in_single_frameí   s&  € ð	ˆõ ˜'Ñ"Ô"ˆØIÐIˆs�<Ô ÐI EÐIÐ  EÒ)ÐIÐIÐIÐIÐI¨c°-Ô.@ÐIÀEÐIÐ.@ÀEÒ.IÐIÐIÐIÐIÑIÕIÔIÐIÐIÐIÐIÐ  EÐIÑIÔIÕIÔIÐ ÑIÔIÕIÔI EÑIÔIÐIÐIÑIÐIÐIÐIÐIÐIÑIÐIÐI×IÒIÐIÑIÔIÐIÐIÐIÕIÔIÐIÐIÐIÐIÐ.@ÀEÐIÑIÔIÕIÔIÐ.@ÑIÔIÕIÔIÀEÑIÔIÐIÐIÑIÐIÐIÐIÐIÐIÑIÐIÐI×IÒIÐIÑIÔIÐIÕIÔIÐIÐIÑIÔIÐIÑIÐIÐIÐIÐIÐIÑIÐIÕIÕIÔIÐIÑIÔIÑIÔIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIÐIØMÐMˆs�=Ô!ÐM VÐMÐ! VÒ+ÐMÐMÐMÐMÐM°°NÔ0CÐMÀvÐMÐ0CÀvÒ0MÐMÐMÐMÐMÑMÕMÔMÐMÐMÐMÐMÐ! VÐMÑMÔMÕMÔMÐ!ÑMÔMÕMÔM VÑMÔMÐMÐMÑMÐMÐMÐMÐMÐMÑMÐMÐM×MÒMÐMÑMÔMÐMÐMÐMÕMÔMÐMÐMÐMÐMÐ0CÀvÐMÑMÔMÕMÔMÐ0CÑMÔMÕMÔMÀvÑMÔMÐMÐMÑMÐMÐMÐMÐMÐMÑMÐMÐM×MÒMÐMÑMÔMÐMÕMÔMÐMÐMÑMÔMÐMÑMÐMÐMÐMÐMÐMÑMÐMÕMÕMÔMÐMÑMÔMÑMÔMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMÐMØCÐCˆs�9Œ~ÐC ÐCˆ~ Ò&ÐCÐCÐCÐCÐC¨3¨z¬?ÐC¸eÐC¨?¸eÒ+CÐCÐCÐCÐCÑCÕCÔCÐCÐCÐCÐCˆ~ ÐCÑCÔCÕCÔCˆ~ÑCÔCÕCÔC ÑCÔCÐCÐCÑCÐCÐCÐCÐCÐCÑCÐCÐC×CÒCÐCÑCÔCÐCÐCÐCÕCÔCÐCÐCÐCÐC¨?¸eÐCÑCÔCÕCÔC¨?ÑCÔCÕCÔC¸eÑCÔCÐCÐCÑCÐCÐCÐCÐCÐCÑCÐCÐC×CÒCÐCÑCÔCÐCÕCÔCÐCÐCÑCÔCÐCÑCÐCÐCÐCÐCÐCÑCÐCÕCÕCÔCÐCÑCÔCÑCÔCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCÐCr;   c                ó¢  — d}t          |¦  «        }g }|d         }d}||k    }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }|                     |¦  «         |r`t          j        d|
fd
||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )NzÝ
        const state = ae.createAnimationState('hero');
        ae.updateAnimation(state, -4.2, 0.016, { x: 1, y: 0 });
        console.log(JSON.stringify({ clip: state.currentClip, phase: state.kineticPhase }));
        Úclipr"   Úphaser   rU   rV   rW   rO   rX   rY   r\   r]   r   r^   r_   r�   r‚   s                    r9   Ú)test_negative_velocity_magnitude_handlingzCTestTurnInertiaSnapFreeze.test_negative_velocity_magnitude_handlingý   sÆ  € ðˆõ
 ˜'Ñ"Ô"ˆØ=Ð=ˆs�6Œ{Ð=˜eÐ=ˆ{˜eÒ#Ð=Ð=Ð=Ð=Ð=¨¨G¬Ð=¸Ð=¨¸Ò(=Ð=Ð=Ð=Ð=Ñ=Õ=Ô=Ð=Ð=Ð=Ð=ˆ{˜eÐ=Ñ=Ô=Õ=Ô=ˆ{Ñ=Ô=Õ=Ô=˜eÑ=Ô=Ð=Ð=Ñ=Ð=Ð=Ð=Ð=Ð=Ñ=Ð=Ð=×=Ò=Ð=Ñ=Ô=Ð=Ð=Ð=Õ=Ô=Ð=Ð=Ð=Ð=¨¸Ð=Ñ=Ô=Õ=Ô=¨Ñ=Ô=Õ=Ô=¸Ñ=Ô=Ð=Ð=Ñ=Ð=Ð=Ð=Ð=Ð=Ñ=Ð=Ð=×=Ò=Ð=Ñ=Ô=Ð=Õ=Ô=Ð=Ð=Ñ=Ô=Ð=Ñ=Ð=Ð=Ð=Ð=Ð=Ñ=Ð=Õ=Õ=Ô=Ð=Ñ=Ô=Ñ=Ô=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=Ð=r;   c                óž  — d}t          |¦  «        }g }|d         }d}||k    }|}|r|d         }d}	||	u }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }d	d
|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )Na  
        const state = ae.createAnimationState('hero');
        ae.playAction(state, 'attack_slash');
        ae.updateAnimation(state, 0.0, 0.016, { x: 1, y: 0 });
        console.log(JSON.stringify({ clip: state.currentClip, locked: state.isActionLocked }));
        r  rA   ÚlockedTr   rU   rV   rW   rO   r·   ræ   rY   r\   r]   r   r^   r_   r�   r‚   s                    r9   Ú8test_action_locked_animation_not_overwritten_by_velocityzRTestTurnInertiaSnapFreeze.test_action_locked_animation_not_overwritten_by_velocity  sÆ  € ðˆõ ˜'Ñ"Ô"ˆØFÐFˆs�6Œ{ÐF˜nÐFˆ{˜nÒ,ÐFÐFÐFÐFÐF°°X´ÐFÀ$ÐF°À$Ð1FÐFÐFÐFÐFÑFÕFÔFÐFÐFÐFÐFˆ{˜nÐFÑFÔFÕFÔFˆ{ÑFÔFÕFÔF˜nÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÐFÐFÕFÔFÐFÐFÐFÐF°À$ÐFÑFÔFÕFÔF°ÑFÔFÕFÔFÀ$ÑFÔFÐFÐFÑFÐFÐFÐFÐFÐFÑFÐFÐF×FÒFÐFÑFÔFÐFÕFÔFÐFÐFÑFÔFÐFÑFÐFÐFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFÐFr;   c                óº  — d}t          |¦  «        }g }|d         }|d         }||k    }|}|r|d         }|d         }	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }|                     |¦  «         |r`t          j        d|
fd
||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚d x}x}x}x}x}x}x}
}	d S )Naº  
        const state = ae.createAnimationState('hero');
        const p = { wx: 0, wy: 0, speed: 4.2, anim: state, destination: { wx: 10, wy: 5 } };
        const dx = p.destination.wx - p.wx, dy = p.destination.wy - p.wy, dist = Math.hypot(dx, dy);
        ae.updateAnimation(state, p.speed, 0.016, { x: (dx/dist - dy/dist)*0.5, y: (dx/dist + dy/dist)*0.25 });
        const movingAngle = state.smoothAngle;
        ae.updateAnimation(state, 0.0, 0.016, null);
        const arrivalAngle = state.smoothAngle;
        for (let i = 0; i < 10; i++) ae.updateAnimation(state, 0.0, 0.016, null);
        console.log(JSON.stringify({ movingAngle, arrivalAngle, postAngle: state.smoothAngle }));
        ÚarrivalAnglerö   Ú	postAngler   rU   rV   rW   rO   rX   rY   r\   r]   r   r^   r_   r�   r‚   s                    r9   Ú*test_click_to_move_heading_and_snap_freezezDTestTurnInertiaSnapFreeze.test_click_to_move_heading_and_snap_freeze  sà  € ð
ˆõ ˜'Ñ"Ô"ˆØcÐcˆs�>Ô"Ðc c¨-Ô&8ÐcÐ"Ð&8Ò8ÐcÐcÐcÐcÐc¸SÀÔ=MÐcÐQTÐUbÔQcÐcÐ=MÐQcÒ=cÐcÐcÐcÐcÑcÕcÔcÐcÐcÐcÐcÐ"Ð&8ÐcÑcÔcÕcÔcÐ"ÑcÔcÕcÔcÐ&8ÑcÔcÐcÐcÑcÐcÐcÐcÐcÐcÑcÐcÐc×cÒcÐcÑcÔcÐcÐcÐcÕcÔcÐcÐcÐcÐcÐ=MÐQcÐcÑcÔcÕcÔcÐ=MÑcÔcÕcÔcÐQcÑcÔcÐcÐcÑcÐcÐcÐcÐcÐcÑcÐcÐc×cÒcÐcÑcÔcÐcÕcÔcÐcÐcÑcÔcÐcÑcÐcÐcÐcÐcÐcÑcÐcÕcÕcÔcÐcÑcÔcÑcÔcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcÐcr;   c                ó,  — d}t          |¦  «        d         }d}||k    }|slt          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }t	          t          j        |¦  «        ¦  «        ‚d x}x}}d S )	Na•  
        const state = ae.createAnimationState('hero'), dt = 1.0 / 120.0, dir = { x: 0.8, y: 0.6 };
        ae.updateAnimation(state, 4.2, dt, dir);
        const angles = [];
        for (let f = 0; f < 120; f++) {
            const mag = (f % 2 === 0) ? 0.04 : 0.06;
            ae.updateAnimation(state, (mag >= 0.05) ? 4.2 : 0, dt, (mag >= 0.05) ? dir : null);
            angles.push(state.smoothAngle);
        }
        let flutterCount = 0;
        for (let f = 1; f < angles.length; f += 2) {
            if (f + 1 < angles.length && angles[f + 1] !== angles[f]) flutterCount++;
        }
        console.log(JSON.stringify({ flutterCount }));
        ÚflutterCountr   r   )z%(py1)s == %(py4)srº   r»   rN   r¼   r½   s          r9   Ú+test_rapid_120hz_analog_boundary_no_flutterzETestTurnInertiaSnapFreeze.test_rapid_120hz_analog_boundary_no_flutter  sÂ   € ðˆõ ˜7Ñ#Ô# NÔ3Ð8°qÐ8Ð3°qÒ8Ð8Ð8Ð8Õ8Ô8Ð8Ð8Ð8Ð8Ð3°qÐ8Ñ8Ô8Õ8Ô8Ð3Ñ8Ô8Õ8Ô8°qÑ8Ô8Ð8Ð8Ñ8Ð8Ð8Ð8Ð8Ð8Ñ8Ð8Õ8Õ8Ô8Ð8Ñ8Ô8Ñ8Ô8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ð8r;   c                ó(  — d}t          |¦  «        d         }d }||u }|slt          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }t	          t          j        |¦  «        ¦  «        ‚d x}x}}d S )Naš  
        ae.MANIFESTS['no_kin'] = { texture_width: 1280, texture_height: 960, frame_width: 160, frame_height: 192, animations: { idle: { frames: ['i0'], fps: 6 } } };
        const state = ae.createAnimationState('no_kin');
        let error = null;
        try { ae.updateAnimation(state, 2.0, 0.016, { x: 1, y: 0 }); } catch (e) { error = e.message; }
        console.log(JSON.stringify({ error }));
        Úerrorr·   r¹   rº   r»   rN   r¼   r½   s          r9   Ú%test_manifest_without_kinematics_safez?TestTurnInertiaSnapFreeze.test_manifest_without_kinematics_safe1  sÂ   € ðˆõ ˜7Ñ#Ô# GÔ,Ð4°Ð4Ð,°Ð4Ð4Ð4Ð4Õ4Ô4Ð4Ð4Ð4Ð4Ð,°Ð4Ñ4Ô4Õ4Ô4Ð,Ñ4Ô4Õ4Ô4°Ñ4Ô4Ð4Ð4Ñ4Ð4Ð4Ð4Ð4Ð4Ñ4Ð4Õ4Õ4Ô4Ð4Ñ4Ô4Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4r;   c                ó  — d}t          |¦  «        }g }|d         }d}||u }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }d	d
|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}x}x}
}	g }|d         }d}||u }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }d	d
|iz  }|                     |¦  «         |r`t          j        d|
fd||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}x}x}
}	dS )zJInfinity velocity or dt safely falls back without creating NaN frameIndex.a¦  
        const state1 = ae.createAnimationState('hero'), state2 = ae.createAnimationState('hero');
        ae.updateAnimation(state1, Infinity, 0.016);
        ae.updateAnimation(state2, 4.2, Infinity);
        console.log(JSON.stringify({
            idx1: state1.frameIndex, finite1: Number.isFinite(state1.frameTime),
            idx2: state2.frameIndex, finite2: Number.isFinite(state2.frameTime)
        }));
        Úfinite1TÚidx1r   r·   rà   rV   rW   rO   r   rX   rY   r\   r]   r^   r_   NÚfinite2Úidx2r�   r‚   s                    r9   Ú+test_infinite_velocity_and_dt_finite_safetyzETestTurnInertiaSnapFreeze.test_infinite_velocity_and_dt_finite_safety;  sn  € ðˆõ ˜'Ñ"Ô"ˆØ:Ð:ˆs�9Œ~Ð: Ð:ˆ~ Ð%Ð:Ð:Ð:Ð:Ð:¨#¨f¬+Ð:¸Ð:¨+¸Ò*:Ð:Ð:Ð:Ð:Ñ:Õ:Ô:Ð:Ð:Ð:Ð:ˆ~ Ð:Ñ:Ô:Õ:Ô:ˆ~Ñ:Ô:Õ:Ô: Ñ:Ô:Ð:Ð:Ñ:Ð:Ð:Ð:Ð:Ð:Ñ:Ð:Ð:×:Ò:Ð:Ñ:Ô:Ð:Ð:Ð:Õ:Ô:Ð:Ð:Ð:Ð:¨+¸Ð:Ñ:Ô:Õ:Ô:¨+Ñ:Ô:Õ:Ô:¸Ñ:Ô:Ð:Ð:Ñ:Ð:Ð:Ð:Ð:Ð:Ñ:Ð:Ð:×:Ò:Ð:Ñ:Ô:Ð:Õ:Ô:Ð:Ð:Ñ:Ô:Ð:Ñ:Ð:Ð:Ð:Ð:Ð:Ñ:Ð:Õ:Õ:Ô:Ð:Ñ:Ô:Ñ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ø:Ð:ˆs�9Œ~Ð: Ð:ˆ~ Ð%Ð:Ð:Ð:Ð:Ð:¨#¨f¬+Ð:¸Ð:¨+¸Ò*:Ð:Ð:Ð:Ð:Ñ:Õ:Ô:Ð:Ð:Ð:Ð:ˆ~ Ð:Ñ:Ô:Õ:Ô:ˆ~Ñ:Ô:Õ:Ô: Ñ:Ô:Ð:Ð:Ñ:Ð:Ð:Ð:Ð:Ð:Ñ:Ð:Ð:×:Ò:Ð:Ñ:Ô:Ð:Ð:Ð:Õ:Ô:Ð:Ð:Ð:Ð:¨+¸Ð:Ñ:Ô:Õ:Ô:¨+Ñ:Ô:Õ:Ô:¸Ñ:Ô:Ð:Ð:Ñ:Ð:Ð:Ð:Ð:Ð:Ñ:Ð:Ð:×:Ò:Ð:Ñ:Ô:Ð:Õ:Ô:Ð:Ð:Ñ:Ô:Ð:Ñ:Ð:Ð:Ð:Ð:Ð:Ñ:Ð:Õ:Õ:Ô:Ð:Ñ:Ô:Ñ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:r;   c                ó¢  — d}t          |¦  «        }g }|d         }d}||k    }|}|r|d         }d}	||	k    }
|
}|�st          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd	|iz  }|                     |¦  «         |r`t          j        d|
fd
||	f¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}x}x}
}	dS )z/Non-finite degrees safely default to S heading.ziconsole.log(JSON.stringify({ h1: ae.get8DirectionHeading(NaN), h2: ae.get8DirectionHeading(Infinity) }));Úh1ÚSÚh2r   rU   rV   rW   rO   rX   rY   r\   r]   r   r^   r_   Nr�   r‚   s                    r9   Ú'test_non_finite_heading_degree_fallbackzATestTurnInertiaSnapFreeze.test_non_finite_heading_degree_fallbackJ  sÂ  € à}ˆÝ˜'Ñ"Ô"ˆØ4Ð4ˆs�4ŒyÐ4˜CÐ4ˆy˜CÒÐ4Ð4Ð4Ð4Ð4 C¨¤IÐ4°Ð4 I°Ò$4Ð4Ð4Ð4Ð4Ñ4Õ4Ô4Ð4Ð4Ð4Ð4ˆy˜CÐ4Ñ4Ô4Õ4Ô4ˆyÑ4Ô4Õ4Ô4˜CÑ4Ô4Ð4Ð4Ñ4Ð4Ð4Ð4Ð4Ð4Ñ4Ð4Ð4×4Ò4Ð4Ñ4Ô4Ð4Ð4Ð4Õ4Ô4Ð4Ð4Ð4Ð4 I°Ð4Ñ4Ô4Õ4Ô4 IÑ4Ô4Õ4Ô4°Ñ4Ô4Ð4Ð4Ñ4Ð4Ð4Ð4Ð4Ð4Ñ4Ð4Ð4×4Ò4Ð4Ñ4Ô4Ð4Õ4Ô4Ð4Ð4Ñ4Ô4Ð4Ñ4Ð4Ð4Ð4Ð4Ð4Ñ4Ð4Õ4Õ4Ô4Ð4Ñ4Ô4Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4r;   Nrè   )ré   rê   rë   rì   rø   r   r  r  r  r  r  r  r  rñ   r;   r9   ró   ró   Ý   sÞ   € € € € € ØdÐdðjð jð jð jðDð Dð Dð Dð >ð >ð >ð >ðGð Gð Gð Gðdð dð dð dð9ð 9ð 9ð 9ð$5ð 5ð 5ð 5ð;ð ;ð ;ð ;ð5ð 5ð 5ð 5ð 5ð 5r;   ró   c                  ó"   — e Zd ZdZdd„Zdd„ZdS )ÚTestCodeQualityAndDebugOverlayz)Verifies R3 and Code Quality constraints.r   rC   c                óü  — t          t          dz                       d¬¦  «                             ¦   «         ¦  «        }d}||k    }|s°t	          j        d|fd||f¦  «        dt          j        ¦   «         v st	          j        |¦  «        rt	          j	        |¦  «        ndt	          j	        |¦  «        dœz  }t	          j
        d	|› d
�¦  «        dz   d|iz  }t          t	          j        |¦  «        ¦  «        ‚d x}}d S )Nzanimation_engine.jsrE   rF   i^  )ú<=)z%(py0)s <= %(py3)sÚlines)r   rM   zanimation_engine.js line count z exceeds soft cap of 350z
>assert %(py5)sr   )rJ   Ú
ENGINE_DIRra   Ú
splitlinesr%   r&   r'   r(   r)   r*   r+   r-   r.   )re   r!  rg   r4   Ú@py_format4r7   s         r9   Ú1test_animation_engine_line_cap_strictly_under_350zPTestCodeQualityAndDebugOverlay.test_animation_engine_line_cap_strictly_under_350T  s  € Ý•ZÐ"7Ñ7×BÒBÈGÐBÑTÔT×_Ò_ÑaÔaÑbÔbˆØÐ^ˆu˜Š|Ð^Ð^Ð^Õ^Ô^Ð^Ð^Ð^Ð^ˆu˜Ð^Ñ^Ô^Ð^Õ^Ô^Ñ^Ô^Ð^Ð^Õ^Ô^ˆuÑ^Ô^Ð^Õ^Ô^ˆuÑ^Ô^Ð^Ð^Õ^Ô^˜Ñ^Ô^Ð^Ð^Ñ^Ð^Õ^Ô^Ð^¸uÐ^Ð^Ð^Ñ^Ô^Ð^Ñ^Ð^Ð^Ð^Ñ^Ð^Õ^Õ^Ô^Ð^Ñ^Ô^Ñ^Ô^Ð^Ð^Ð^Ð^Ð^Ð^Ð^r;   c                ó(  — d}t          |¦  «        d         }d}||u }|slt          j        d|fd||f¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }dd|iz  }t	          t          j        |¦  «        ¦  «        ‚d x}x}}d S )	NzBconsole.log(JSON.stringify({ debugAnim: window.__DEBUG_ANIM__ }));Ú	debugAnimFr·   r¹   rº   r»   rN   r¼   r½   s          r9   Ú$test_debug_overlay_hidden_by_defaultzCTestCodeQualityAndDebugOverlay.test_debug_overlay_hidden_by_defaultX  s¾   € ØVˆÝ˜7Ñ#Ô# KÔ0Ð9°EÐ9Ð0°EÐ9Ð9Ð9Ð9Õ9Ô9Ð9Ð9Ð9Ð9Ð0°EÐ9Ñ9Ô9Õ9Ô9Ð0Ñ9Ô9Õ9Ô9°EÑ9Ô9Ð9Ð9Ñ9Ð9Ð9Ð9Ð9Ð9Ñ9Ð9Õ9Õ9Ô9Ð9Ñ9Ô9Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9Ð9Ð9Ð9r;   Nrè   )ré   rê   rë   rì   r%  r(  rñ   r;   r9   r  r  Q  sF   € € € € € Ø3Ð3ð_ð _ð _ð _ð:ð :ð :ð :ð :ð :r;   r  )r   r   r   r   )rì   Ú
__future__r   Úbuiltinsr'   Ú_pytest.assertion.rewriteÚ	assertionÚrewriter%   r/   rŒ   Úpathlibr   r!   rí   Ú__file__ÚresolveÚparentr#   Ú
WEBAPP_DIRr`   r"  rð   r:   r=   ró   r  rñ   r;   r9   ú<module>r3     sƒ  ðØ qÐ qØ "Ð "Ð "Ð "Ð "Ð "Ø  € € € € € € € € € € € € €€€€Ø €€€Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ø €€€àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø˜HÑ$ xÑ/€
Ø˜Ñ  <Ñ/€Ø˜$Ñ Ñ)€
ð Pð  Pð  P€ð*ð *ð *ð *ð>kCð kCð kCð kCð kCñ kCô kCð kCð\q5ð q5ð q5ð q5ð q5ñ q5ô q5ð q5ðh	:ð 	:ð 	:ð 	:ð 	:ñ 	:ô 	:ð 	:ð 	:ð 	:r;   