   	                                  Ьм РЬЬЭЬмэЬЬмэЬЬнэЭнньанЭ юю ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџяџџџџџџџџџџџџџџџџџџџџџџџџџџџџююююўџџџўџџџўџџџўџџџўџџџўџџџўџџџююююџџџџџџџџџџџџџџџџџџџџџџџџџџџџююююџџџяџџџяџџџяџџџяџџџяџџџяџџџя                                                                                                                                                                                                                                                                                                                                                                џџџџџџџџџџџџџџџџџџџџџџџџџџџџўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџяўџџџўџџџўџџџўџџџўџџџўџџџўџџџўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџяџџџяџџџяџџџяџџџяџџџяџџџяџџџя                                                                                                                                   р   р   ў   ў  рџ  рџ  ўџ  ўџ      я   я   џ  џ  џя  џя                                                                                                                                                                                                                                  ўџџџўџџџўџџџўџџџўџџџўџџџўџџџююююџџџџџџџџџџџџџџџџџџџџџџџџџџџџююююџџџяџџџяџџџяџџџяџџџяџџџяџџџяюююю                   ю  юџ юџџюџџџ   ю  юџ юџџюџџџџџџџџџџџџџџџџџџџю   џю  џџю џџџюџџџџџџџџџџџџџџџџ                ю   џю  џџю џџџю рџџ рџџ ўџџ ўџџрџџџрџџџўџџџўџџџџџ џџ џџя џџя џџџџџџџџџяџџџя   р   ў  рџ  ўџ рџџ ўџџрџџџўџџџ   я   џ  џя  џџ џџя џџџџџџя                                                                                                                                                                                                                                                                юџџџ юџџ  юџ   ю                џџџџџџџџџџџџџџџџюџџџ юџџ  юџ   юџџџџџџџџџџџџџџџџџџџюџџю џю  ю   џџџюџџю џю  ю                   ўџџџўџџџрџџџрџџџ ўџџ ўџџ рџџ рџџџџџяџџџяџџџџџџџџя џџя џџ џџ ўџџџрџџџ ўџџ рџџ  ўџ  рџ   ў   рџџџяџџџџџя џџ џя  џ  я                                                                                                                                                                                                                                                                                                                                                                                                        ўџ  ўџ  рџ  рџ   ў   ў   р   рџя  џя  џ  џ  я   я       %%%%%%%%%%%%%%                                                                                                                                                                                                                             789:  =%>                                                                                                                                                                                                                               =>                                                                                                                                                                                                                                        ;<                                                                                                                                                                                                                                         KL                                                                                                                                                                                                                                          =%>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       )*                                                                                                                                                                                                                                           )*                       +                                                                                                                                                                                                                  .                                                                                                                                                                                                                                       .                   +                                                                                                                                                                                                                  =%>      -.         -                                                                                                                                                                                                                    ,            -                                                                                                                                                                                                                        +,     '(                                                                                                                                                                                                                  . -,   -.  '(                                                                                                                                                                                                                  	>                                                                O                                  @         	 !A            @Р? џџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџяююююююююююююююююююююююююююююююююююююююююююююџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџююююююююџџџџџџџџџџџџююююўџџџџџџя                                            юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџю        ўџџџџџџџџџџя    ўџџџџџџя                                             юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџю         рџџџџџџџџџџ    ўџџџџџџя                                              юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџю           ўџџџџџџџџя     ўџџџџџџя                                               юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџю            рџџџџџџџџ     ўџџџџџџя                                                юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџю              ўџџџџџџя      ўџџџџџџя                                                 юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџю               рџџџџџџ      ўџџџџџџя    рюююю    рюююю   юююююю   юююююю              юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџю                 ўџџџџя       ўџџџџџџя    рюююю    рюююю   юююююю   юююююю               юџџџџџџџџџџџџџџџџџџџџџџџџџџџџю                  рюююю       ўџџџџџџя    рюююю    рюююю   юююююю   юююююю                ўџџџџџџџџџџџџџџџџџџџџџџџџџџя                                ўџџџџџџя   ююю   ю ююю   ю ююю   ю ююю   ю              рџџџџџџџџџџџџџџџџџџџџџџџџџџ                                ўџџџџџџя   ююю   ю ююю   ю ююю   ю ююю   ю               ўџџџџџџџџџџџџџџџџџџџџџџџџя                                 ўџџџџџџя   ююю   ю ююю   ю ююю   ю ююю   ю               рџџџџџџџџџџџџџџџџџџџџџџџџ                                 ўџџџџџџя   ююю   ю ююю   ю юююююю   юююююю                  ўџџџџџџџџџџџџџџџџџџџџџџя                                  ўџџџџџџя   ююю   ю ююю   ю юююююю   юююююю                  рџџџџџџџџџџџџџџџџџџџџџџ                                  ўџџџџџџя   ююю   ю ююю   ю юююююю   юююююю                   ўџџџџџџџџџџџџџџџџџџџџя                                   ўџџџџџџя   ююююююю ююююююю ююю   ю ююю   ю                 рџџџџџџџџџџџџџџџџџџџџ                                   ўџџџџџџя   ююююююю ююююююю ююю   ю ююю   ю                  ўџџџџџџџџџџџџџџџџџџя                                    ўџџџџџџя   ююююююю ююююююю ююю   ю ююю   ю                  ўџџџџџџџџџџџџџџџџџџя                                    ўџџџџџџя   ююю   ю ююю   ю юююююю   юююююю                    рџџџџџџџџџџџџџџџџџџ                                    ўџџџџџџя   ююю   ю ююю   ю юююююю   юююююю                    рџџџџџџџџџџџџџџџџџџ                                    ўџџџџџџя   ююю   ю ююю   ю юююююю   юююююю                     ўџџџџџџџџџџџџџџџџя                                     ўџџџџџџя                                                         ўџџџџџџџџџџџџџџџџя                                     ўџџџџџџя                                                         рџџџџџџџџџџџџџџџџ                                     ўџџџџџџя                                                         рџџџџџџџџџџџџџџџџ                                     ўџџџџџџя    рююююю ююю       рюююю   юююююю   ююююююю  рююююю  ўџџџџџџџџџџџџџџя    ююю   ю юююююю         юююю     ўџџџџџџя    рююююю ююю       рюююю   юююююю   ююююююю  рююююю  ўџџџџџџџџџџџџџџя    ююю   ю юююююю         юююю     ўџџџџџџя    рююююю ююю       рюююю   юююююю   ююююююю  рююююю  рџџџџџџџџџџџџџџ    ююю   ю юююююю         юююю     ўџџџџџџя   юююю    ююю      ююю   ю ююю   ю ююю      юююю     рџџџџџџџџџџџџџџ    ююю   ю     рюю     рюю ююю    ўџџџџџџя   юююю    ююю      ююю   ю ююю   ю ююю      юююю      ўџџџџџџџџџџџџя     ююю   ю     рюю     рюю ююю    ўџџџџџџя   юююю    ююю      ююю   ю ююю   ю ююю      юююю      ўџџџџџџџџџџџџя     ююю   ю     рюю     рюю ююю    ўџџџџџџя    рюююю   ююю      ююю   ю ююю   ю юююююю    рюююю     рџџџџџџџџџџџџ     ююю   ю  рюююю       рюююю рю    ўџџџџџџя    рюююю   ююю      ююю   ю ююю   ю юююююю    рюююю     рџџџџџџџџџџџџ     ююю   ю  рюююю       рюююю рю    ўџџџџџџя    рюююю   ююю      ююю   ю ююю   ю юююююю    рюююю      ўџџџџџџџџџџя      ююю   ю  рюююю       рюююю рю    ўџџџџџџя      юююю ююю      ююю   ю юююююю   ююю         юююю    рџџџџџџџџџџ       рюююю   ююю      ююю рюю  рю    ўџџџџџџя      юююю ююю      ююю   ю юююююю   ююю         юююю     ўџџџџџџџџя        рюююю   ююю      ююю рюю  рю    ўџџџџџџя      юююю ююю      ююю   ю юююююю   ююю         юююю     рџџџџџџџџ        рюююю   ююю      ююю рюю  рю    ўџџџџџџя   юююююю   ююююююю  рюююю   ююю      ююююююю юююююю        ўџџџџџџя           ю    ююююююю ююю   юююю     ўџџџџџџя   юююююю   ююююююю  рюююю   ююю      ююююююю юююююю        рџџџџџџ           ю    ююююююю ююю   юююю     ўџџџџџџя   юююююю   ююююююю  рюююю   ююю      ююююююю юююююю         ўџџџџя            ю    ююююююю ююю   юююю     ўџџџџџџя                                                               рюююю                                           ўџџџџџџя                                                                                                                ўџџџџџџя                                                                                                                ўџџџџџџя                                                                                                                ўџџџџџџя                                                                                                                ўџџџџџџя   №џ    џ      џ№ џ           џ  №џ           џ№        џџ                                                 ўџџџџџџя   џ џ№  џџ  №№№   џ№џ џ џџ  №№ џ№№№џ џџ  џџ №џ   џ №џ џ№                                          ўџџџџџџя   џ №џ џ№џ №џ№№№ џ№ џ№№№џ№ џ  №џ№№№№№№№ џ№џ №џџџ џ №џ                                           ўџџџџџџя   џџ№џ џ №џ  №џџ№ џ№џџ№№№џ № џ  №№№№№№№№№ џ№џ џџ  џ џ №џ                                           ўџџџџџџя   џ џ№џ№џ  №№ џџ  џ№№ џ џџ  №џ џ џ№№ џџ№џ  №  џџ №џ џ№                                          ўџџџџџџя                       џ                               №џ                                                      ўџџџџџџя         џ № џ   №              џ џ №             џ            №                                            ўџџџџџџя   №џ№џ џ №   џџ  №џ џџ №џ    №џџ№џ   џџ№№ џџ№џџ џ№   џџ№ №џ џџ №џ №џ                               ўџџџџџџя   џ џ џ № џ№џ №џ џ џ   џ џ №№  №џ №№№џ  џ №№№џџ  №џ № џ џ џ№џ                                ўџџџџџџя   џ џ џ № џ №џ№џ џ  џ  џџџ џ №№  №џ №№ №џ џ №№№№№   №џ№ џ џ џ  џ                               ўџџџџџџя   №џ№џ №џ џџ№џ№№џ џ џџ   џ№џ №џ№№   џџ џ№џ №џ џ№№№  №џ џ№џ џџ №џ џџ                                ўџџџџџџя                                                                        џ                                       ўџџџџџџџю                                                                                                              рџџџџџџџџџю                                                                                                             рџџџџџџџџџџю                                                                                                            ўџџџџџџџџџџџю                                                                                                           ўџџџџџџџџџџџџю                                                                                                         рџџџџџџџџџџџџџџю                                                                                                        рџџџџџџџџџџџџџџџю                                                                                                       ўџџџџџџџџџџџџџџџџю                                                                                                      ўџџџџџџџџџџџџџџџџџю                                                                                                    рџџџџџџџџџџџџџџџџџџџю                                                                                                   рџџџџџџџџџџџџџџџџџџџџю                                                                                                  ўџџџџџџџџџџџџџџџџџџџџџю                                                                                                 ўџџџџџџџџџџџџџџџџџџџџџџю                                                                                               рџџџџџџџџџџџџџџџџџџџџџџџџю                                                                                              рџџџџџџџџџџџџџџџџџџџџџџџџџю                                                                                             ўџџџџџџџџџџџџџџџџџџџџџџџџџџю                                                                                            ўџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                                                                          рџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                                                                          рџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                                                                         ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                                                                         ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                                                                       рџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                                                                       рџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                                                                      ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                                                                      ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                    Ьм                                              рџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                   РЬЬ                                             рџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                  ЭЬмэ                                             ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                  ЬЬмэ                                             ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                 ЬЬнэ                                            рџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                 Эннь                                            рџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ                                анЭ                                            ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя                                 юю                                             ўџџџџџџџџџџџџџџџџџџяўџџџџџџџџџџяўџџџџџџџ                              рюююю                                          рџџџџџџџџџџџџџџџџџџџярџџџџџџџџџџўџџџџџџџ                              ўџџџџя                                          ўџџџџџџџџџџџџџџџџџџџя ўџџџџџџџџя ўџџџџџџџя                             рџџџџџџ                                        рџџџџџџџџџџџџџџџџџџџџя рџџџџџџџџ ўџџџџџџџя                             ўџџџџџџя                                        ўџџџџџџџџџџџџџџџџџџџџя  ўџџџџџџя  ўџџџџџџџџ                           рџџџџџџџџ                                      рџџџџџџџџџџџџџџџџџџџџџя  рџџџџџџ  ўџџџџџџџџ                           ўџџџџџџџџя                                      ўџџџџџџџџџџџџџџџџџџџџџя   ўџџџџя   ўџџџџџџџџя                          рџџџџџџџџџџ                                    рџџџџџџџџџџџџџџџџџџџџџџя   рюююю   ўџџџџџџџџя                          ўџџџџџџџџџџя                                    ўџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџ                        рџџџџџџџџџџџџ                                  рџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџ                        рџџџџџџџџџџџџ                                  ўџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџя                        ўџџџџџџџџџџџџя                                 рџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџя                        ўџџџџџџџџџџџџя                                 ўџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџџ                      рџџџџџџџџџџџџџџ                               рџџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџџ                      рџџџџџџџџџџџџџџ                               ўџџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџџя                      ўџџџџџџџџџџџџџџя                              рџџџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџџя                      ўџџџџџџџџџџџџџџя                              ўџџџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџџџ                    рџџџџџџџџџџџџџџџџ                            юџџџџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџџџ                    рџџџџџџџџџџџџџџџџ                           юџџџџџџџџџџџџџџџџџџџџџџџџџџџџя            ўџџџџџџџџџџџя                    ўџџџџџџџџџџџџџџџџя                          юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя       Ьм   ўџџџџџџџџџџџя                    ўџџџџџџџџџџџџџџџџя                         юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя   Ьм РЬЬ  ўџџџџџџџџџџџџ                  рџџџџџџџџџџџџџџџџџџ                       юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя  РЬЬЭЬмэ  ўџџџџџџџџџџџџ                  рџџџџџџџџџџџџџџџџџџ                      юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя  ЭЬмэЬЬмэ  ўџџџџџџџџџџџџя                  ўџџџџџџџџџџџџџџџџџџя                     юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя  ЬЬмэЬЬнэ  ўџџџџџџџџџџџџя                  ўџџџџџџџџџџџџџџџџџџя                    юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ ЬЬнэЭннь рџџџџџџџџџџџџџџ         Ьм     рџџџџџџџџџџџџџџџџџџџџ      РЬ         юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя ЭнньанЭ ўџџџџџџџџџџџџџџ        РЬЬ    ўџџџџџџџџџџџџџџџџџџџџя      ЬЬм        юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџанЭ юю рџџџџџџџџџџџџџџџя        ЭЬмэ   рџџџџџџџџџџџџџџџџџџџџџџ    аЬЬн      юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя юю     ўџџџџџџџџџџџџџџџя        ЬЬмэ   ўџџџџџџџџџџџџџџџџџџџџџџя    РЬЬн     юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ      рџџџџџџџџџџџџџџџџџ       ЬЬнэ  рџџџџџџџџџџџџџџџџџџџџџџџџ   РЬмн    юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя      ўџџџџџџџџџџџџџџџџџ       Эннь  ўџџџџџџџџџџџџџџџџџџџџџџџџя   амнЭ   юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ    рџџџџџџџџџџџџџџџџџџя       анЭ рџџџџџџџџџџџџџџџџџџџџџџџџџџ   ннм   юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџя    ўџџџџџџџџџџџџџџџџџџя        юю  ўџџџџџџџџџџџџџџџџџџџџџџџџџџя   рю  юџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџююююџџџџџџџџџџџџџџџџџџџџююююююююююююџџџџџџџџџџџџџџџџџџџџџџџџџџџџююююююююџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ? ;; title:   AABB Slopes v2.0
;; author:  Andrey Listopadov
;; desc:    Making slopes wiht AABB collisions
;; site:    andreyor.st
;; license: MIT License (change this to your license of choice)
;; version: 2.0
;; script:  fennel
;; strict:  true

(set package.preload.bump
  (fn []
    (local bump
      {:_VERSION "bump v3.1.7"
       :_URL "https://github.com/kikito/bump.lua"
       :_DESCRIPTION "A collision detection library for Lua (fennel port)"
       :_LICENSE "https://github.com/kikito/bump.lua/blob/master/MIT-LICENSE.txt"})

    ;; Auxiliary functions

    (local DELTA 1e-10)               ; floating-point margin of error

    (local {: abs : floor : ceil : min : max} math)

    (fn sign [x]
      (if (> x 0) 1
          (= x 0) 0
          -1))

    (fn nearest [x a b]
      (if (< (abs (- a x)) (abs (- b x))) a b))

    (fn assert-type [desired-type value name]
      (when (not= (type value) desired-type)
        (error (.. name " must be a " desired-type ", but was " (tostring value)
                   "(a " (type value) ")"))))

    (fn assert-is-positive-number [value name]
      (when (or (not= (type value) :number) (<= value 0))
        (error (.. name " must be a positive integer, but was " (tostring value)
                   "(" (type value) ")"))))

    (fn assert-is-rect [x y w h]
      (assert-type :number x :x)
      (assert-type :number y :y)
      (assert-is-positive-number w :w)
      (assert-is-positive-number h :h))

    (fn default-filter []
      :slide)

    ;; Rectangle functions

    (fn rect-get-nearest-corner [x y w h px py]
      (values (nearest px x (+ x w)) (nearest py y (+ y h))))

    ;; This is a generalized implementation of the liang-barsky algorithm, which also returns
    ;; the normals of the sides where the segment intersects.
    ;; Returns nil if the segment never touches the rect
    ;; Notice that normals are only guaranteed to be accurate when initially ti1, ti2 == -math.huge, math.huge
    (fn rect-get-segment-intersection-indices [x y w h x1 y1 x2 y2 ti1 ti2]
      (let [(dx dy) (values (- x2 x1) (- y2 y1))]
        (var (nx1 ny1 nx2 ny2 ret?) (values 0 0 0 0 true))
        (var (ti1 ti2) (values (or ti1 0) (or ti2 1)))
        (var (nx ny p q r) nil)
        (for [side 1 4 :until (not ret?)]
          (if (= side 1) (set (nx ny p q) (values (- 1) 0 (- dx) (- x1 x))) ; left
              (= side 2) (set (nx ny p q) (values 1 0 dx (- (+ x w) x1))) ; right
              (= side 3) (set (nx ny p q) (values 0 (- 1) (- dy) (- y1 y))) ; top
              (set (nx ny p q) (values 0 1 dy (- (+ y h) y1)))) ; bottom
          (if (= p 0)
              (when (<= q 0)
                (set ret? false))
              (do
                (set r (/ q p))
                (if (< p 0)
                    (if (> r ti2)
                        (set ret? false)
                        (> r ti1)
                        (set (ti1 nx1 ny1) (values r nx ny)))
                    ;; p > 0
                    (if (< r ti1)
                        (set ret? false)
                        (< r ti2)
                        (set (ti2 nx2 ny2) (values r nx ny)))))))
        (when ret?
          (values ti1 ti2 nx1 ny1 nx2 ny2))))

    ;; Calculates the minkowsky difference between 2 rects, which is another rect
    (fn rect-get-diff [x1 y1 w1 h1 x2 y2 w2 h2]
      (values (- (- x2 x1) w1) (- (- y2 y1) h1) (+ w1 w2) (+ h1 h2)))

    (fn rect-contains-point [x y w h px py]
      (and (> (- px x) DELTA)
           (> (- py y) DELTA)
           (> (- (+ x w) px) DELTA)
           (> (- (+ y h) py) DELTA)))

    (fn rect-is-intersecting [x1 y1 w1 h1 x2 y2 w2 h2]
      (and (< x1 (+ x2 w2))
           (< x2 (+ x1 w1))
           (< y1 (+ y2 h2))
           (< y2 (+ y1 h1))))

    (fn rect-get-square-distance [x1 y1 w1 h1 x2 y2 w2 h2]
      (let [dx (+ (- x1 x2) (/ (- w1 w2) 2))
            dy (+ (- y1 y2) (/ (- h1 h2) 2))]
        (+ (* dx dx) (* dy dy))))

    (fn rect-detect-collision [x1 y1 w1 h1 x2 y2 w2 h2 goal-x goal-y]
      (let [goal-x (or goal-x x1)
            goal-y (or goal-y y1)
            (dx dy) (values (- goal-x x1) (- goal-y y1))
            (x y w h) (rect-get-diff x1 y1 w1 h1 x2 y2 w2 h2)]
        (var (overlaps ti nx ny) nil)
        (if (rect-contains-point x y w h 0 0) ; item was intersecting other
            (let [(px py) (rect-get-nearest-corner x y w h 0 0)
                  (wi hi) (values (min w1 (abs px)) (min h1 (abs py)))] ; area of intersection
              (set ti (* (- wi) hi)) ; ti is the negative area of intersection
              (set overlaps true))
            (let [(ti1 ti2 nx1 ny1)
                  (rect-get-segment-intersection-indices
                   x y w h 0
                   0 dx dy
                   (- math.huge)
                   math.huge)]
              ;; item tunnels into other
              (when (and ti1
                         (< ti1 1)
                         (>= (abs (- ti1 ti2)) DELTA)
                         (or (< 0 (+ ti1 DELTA))
                             (and (= 0 ti1)
                                  (> ti2 0))))
                (set (ti nx ny) (values ti1 nx1 ny1))
                (set overlaps false))))
        (when ti
          (var (tx ty ret?) (values nil nil true))
          (if overlaps
              (if (and (= dx 0) (= dy 0))
                  (do ; intersecting and not moving - use minimum displacement vector
                    (var (px py) (rect-get-nearest-corner x y w h 0 0))
                    (if (< (abs px) (abs py)) (set py 0) (set px 0))
                    (set (nx ny) (values (sign px) (sign py)))
                    (set (tx ty) (values (+ x1 px) (+ y1 py))))
                  (do ; intersecting and moving - move in the opposite direction
                    (var (ti1 _) nil)
                    (set (ti1 _ nx ny)
                      (rect-get-segment-intersection-indices
                       x y w h 0 0 dx dy
                       (- math.huge) 1))
                    (when (not ti1)
                      (set ret? false))
                    (set (tx ty) (values (+ x1 (* dx ti1)) (+ y1 (* dy ti1))))))
              ;; tunnel
              (set (tx ty) (values (+ x1 (* dx ti)) (+ y1 (* dy ti)))))
          (when ret?
            {: overlaps
             : ti
             :move {:x dx :y dy}
             :normal {:x nx :y ny}
             :touch {:x tx :y ty}
             :itemRect {:h h1 :w w1 :x x1 :y y1}
             :otherRect {:h h2 :w w2 :x x2 :y y2}}))))

    ;; Grid functions

    (fn grid-to-world [cell-size cx cy]
      (values (* (- cx 1) cell-size) (* (- cy 1) cell-size)))

    (fn grid-to-cell [cell-size x y]
      (values (+ (floor (/ x cell-size)) 1) (+ (floor (/ y cell-size)) 1)))

    ;; grid_traverse* functions are based on "A Fast Voxel Traversal Algorithm for Ray Tracing",
    ;; by John Amanides and Andrew Woo - http://www.cse.yorku.ca/~amana/research/grid.pdf
    ;; It has been modified to include both cells when the ray "touches a grid corner",
    ;; and with a different exit condition

    (fn grid-traverse-init-step [cell-size ct t1 t2]
      (let [v (- t2 t1)]
        (if (> v 0) (values 1 (/ cell-size v) (/ (- (* (+ ct v) cell-size) t1) v))
            (< v 0)
            (values (- 1) (/ (- cell-size) v)
                    (/ (- (* (- (+ ct v) 1) cell-size) t1) v))
            (values 0 math.huge math.huge))))

    (fn grid-traverse [cell-size x1 y1 x2 y2 f]
      (let [(cx cy) (grid-to-cell cell-size x1 y1)
            (cx2 cy2) (grid-to-cell cell-size x2 y2)
            (step-x dx tx) (grid-traverse-init-step cell-size cx x1 x2)
            (step-y dy ty) (grid-traverse-init-step cell-size cy y1 y2)]
        (var (tx ty cx cy) (values tx ty cx cy))
        (f cx cy)
        ;; The default implementation had an infinite loop problem when
        ;; approaching the last cell in some occassions. We finish iterating
        ;; when we are *next* to the last cell
        (while (> (+ (abs (- cx cx2)) (abs (- cy cy2))) 1)
          (if (< tx ty) (do
                          (set (tx cx) (values (+ tx dx) (+ cx step-x)))
                          (f cx cy))
              (do
                (when (= tx ty) (f (+ cx step-x) cy))
                (set (ty cy) (values (+ ty dy) (+ cy step-y)))
                (f cx cy))))
        ;; If we have not arrived to the last cell, use it
        (when (or (not= cx cx2) (not= cy cy2))
          (f cx2 cy2))))

    (fn grid-to-cell-rect [cell-size x y w h]
      (let [(cx cy) (grid-to-cell cell-size x y)
            (cr cb) (values (ceil (/ (+ x w) cell-size))
                            (ceil (/ (+ y h) cell-size)))]
        (values cx cy (+ (- cr cx) 1) (+ (- cb cy) 1))))

    ;; Responses

    (fn touch [_world col _x _y _w _h _goal-x _goal-y _filter]
      (values col.touch.x col.touch.y {} 0))

    (fn cross [world col x y w h goal-x goal-y filter]
      (let [(cols len) (world:project col.item x y w h goal-x goal-y filter)]
        (values goal-x goal-y cols len)))

    (fn slide [world col x y w h goal-x goal-y filter]
      (var (x y) (values x y))
      (var goal-x (or goal-x x))
      (var goal-y (or goal-y y))
      (local (tch move) (values col.touch col.move))
      (when (or (not= move.x 0) (not= move.y 0))
        (if (not= col.normal.x 0)
            (set goal-x tch.x)
            (set goal-y tch.y)))
      (set col.slide {:x goal-x :y goal-y})
      (set (x y) (values tch.x tch.y))
      (local (cols len) (world:project col.item x y w h goal-x goal-y filter))
      (values goal-x goal-y cols len))

    (fn bounce [world col x y w h goal-x goal-y filter]
      (var (x y) (values x y))
      (var goal-x (or goal-x x))
      (var goal-y (or goal-y y))
      (local (tch move) (values col.touch col.move))
      (local (tx ty) (values tch.x tch.y))
      (var (bx by) (values tx ty))
      (when (or (not= move.x 0) (not= move.y 0))
        (var (bnx bny) (values (- goal-x tx) (- goal-y ty)))
        (if (= col.normal.x 0) (set bny (- bny)) (set bnx (- bnx)))
        (set (bx by) (values (+ tx bnx) (+ ty bny))))
      (set col.bounce {:x bx :y by})
      (set (x y) (values tch.x tch.y))
      (set (goal-x goal-y) (values bx by))
      (local (cols len) (world:project col.item x y w h goal-x goal-y filter))
      (values goal-x goal-y cols len))

    ;; World

    (local World {})
    (local World-mt {:__index World})

    ;; Private functions and methods

    (fn sort-by-weight [a b] (< a.weight b.weight))

    (fn sort-by-ti-and-distance [a b]
      (if (= a.ti b.ti)
          (let [ir a.itemRect
                ar a.otherRect
                br b.otherRect
                ad (rect-get-square-distance
                    ir.x ir.y ir.w ir.h ar.x ar.y ar.w ar.h)
                bd (rect-get-square-distance
                    ir.x ir.y ir.w ir.h br.x br.y br.w br.h)]
            (< ad bd))
          (< a.ti b.ti)))

    (fn add-item-to-cell [self item cx cy]
      (tset self.rows cy (or (. self.rows cy) (setmetatable {} {:__mode :v})))
      (local row (. self.rows cy))
      (tset row cx (or (. row cx) {:itemCount 0
                                   :items (setmetatable {} {:__mode :k})
                                   :x cx
                                   :y cy}))
      (local cell (. row cx))
      (tset self.nonEmptyCells cell true)
      (when (not (. cell.items item)) (tset cell.items item true)
            (set cell.itemCount (+ cell.itemCount 1))))

    (fn remove-item-from-cell [self item cx cy]
      (let [row (. self.rows cy)]
        (if (or (not row)
                (not (. row cx))
                (not (. (. (. row cx) :items) item)))
            false
            (let [cell (. row cx)]
              (tset cell.items item nil)
              (set cell.itemCount (- cell.itemCount 1))
              (when (= cell.itemCount 0) (tset self.nonEmptyCells cell nil))
              true))))

    (fn get-dict-items-in-cell-rect [self cl ct cw ch]
      (let [items-dict {}]
        (for [cy ct (- (+ ct ch) 1)]
          (local row (. self.rows cy))
          (when row
            (for [cx cl (- (+ cl cw) 1)]
              (local cell (. row cx))
              (when (and cell (> cell.itemCount 0)) ; no cell.itemCount > 1 because tunneling
                (each [item _ (pairs cell.items)] (tset items-dict item true))))))
        items-dict))

    (fn get-cells-touched-by-segment [self x1 y1 x2 y2]
      (let [cells {} visited {}]
        (var cells-len 0)
        (grid-traverse
         self.cellSize x1 y1 x2 y2
         (fn [cx cy]
           (let [row (. self.rows cy)]
             (when row
               (let [cell (. row cx)]
                 (when (not (or (not cell) (. visited cell)))
                   (tset visited cell true)
                   (set cells-len (+ cells-len 1))
                   (tset cells cells-len cell)))))))
        (values cells cells-len)))

    (fn get-info-about-items-touched-by-segment [self x1 y1 x2 y2 filter]
      (let [(cells len) (get-cells-touched-by-segment self x1 y1 x2 y2)
            visited {} item-info {}]
        (var (item-info-len cell rect l t w h ti1 ti2 tii0 tii1) 0)
        (for [i 1 len]
          (set cell (. cells i))
          (each [item (pairs cell.items)]
            (when (not (. visited item))
              (tset visited item true)
              (when (or (not filter) (filter item))
                (set rect (. self.rects item))
                (set (l t w h) (values rect.x rect.y rect.w rect.h))
                (set (ti1 ti2)
                  (rect-get-segment-intersection-indices l t w h x1 y1 x2 y2 0 1))
                (when (and ti1
                           (or (and (< 0 ti1) (< ti1 1)) (and (< 0 ti2) (< ti2 1))))
                  ;; the sorting is according to the t of an infinite line, not the segment
                  (set (tii0 tii1)
                    (rect-get-segment-intersection-indices l t w h x1 y1 x2 y2
                                                           (- math.huge)
                                                           math.huge))
                  (set item-info-len (+ item-info-len 1))
                  (tset item-info item-info-len
                        {: item : ti1 : ti2 :weight (min tii0 tii1)}))))))
        (table.sort item-info sort-by-weight)
        (values item-info item-info-len)))

    (fn get-response-by-name [self name]
      (let [response (. self.responses name)]
        (when (not response)
          (error (: "Unknown collision type: %s (%s)" :format name (type name))))
        response))

    ;; -- Misc Public Methods

    (fn World.addResponse [self name response]
      (tset self.responses name response))

    (fn World.project [self item x y w h goal-x goal-y filter]
      (assert-is-rect x y w h)
      (let [goal-x (or goal-x x)
            goal-y (or goal-y y)
            filter (or filter default-filter)
            visited {}
            collisions {}]
        (var len 0)
        (when (not= item nil)
          (tset visited item true))
        ;; This could probably be done with less cells using a polygon raster over the cells instead of a
        ;; bounding rect of the whole movement. Conditional to building a queryPolygon method
        (let [(tl tt) (values (min goal-x x) (min goal-y y))
              (tr tb) (values (max (+ goal-x w) (+ x w)) (max (+ goal-y h) (+ y h)))
              (tw th) (values (- tr tl) (- tb tt))
              (cl ct cw ch) (grid-to-cell-rect self.cellSize tl tt tw th)
              dict-items-in-cell-rect (get-dict-items-in-cell-rect self cl ct cw ch)]
          (each [other _ (pairs dict-items-in-cell-rect)]
            (when (not (. visited other))
              (tset visited other true)
              (local response-name (filter item other))
              (when response-name
                (local (ox oy ow oh) (self:getRect other))
                (local col (rect-detect-collision x y w h ox oy ow oh goal-x goal-y))
                (when col (set col.other other) (set col.item item)
                      (set col.type response-name)
                      (set len (+ len 1))
                      (tset collisions len col)))))
          (table.sort collisions sort-by-ti-and-distance)
          (values collisions len))))

    (fn World.countCells [self]
      (var count 0)
      (each [_ row (pairs self.rows)]
        (each [_ _ (pairs row)]
          (set count (+ count 1))))
      count)

    (fn World.hasItem [self item]
      (not (not (. self.rects item))))

    (fn World.getItems [self]
      (let [items {}]
        (var len 0)
        (each [item _ (pairs self.rects)]
          (set len (+ len 1)) (tset items len item))
        (values items len)))

    (fn World.countItems [self]
      (var len 0)
      (each [_ (pairs self.rects)]
        (set len (+ len 1)))
      len)

    (fn World.getRect [self item]
      (let [rect (. self.rects item)]
        (when (not rect)
          (error (.. "Item " (tostring item)
                     " must be added to the world before getting its rect. Use world:add(item, x,y,w,h) to add it first.")))
        (values rect.x rect.y rect.w rect.h)))

    (fn World.toWorld [self cx cy]
      (grid-to-world self.cellSize cx cy))

    (fn World.toCell [self x y]
      (grid-to-cell self.cellSize x y))

    ;; Query methods

    (fn World.queryRect [self x y w h filter]
      (assert-is-rect x y w h)
      (let [(cl ct cw ch) (grid-to-cell-rect self.cellSize x y w h)
            dict-items-in-cell-rect (get-dict-items-in-cell-rect self cl ct cw ch)
            items {}]
        (var (len rect) 0)
        (each [item _ (pairs dict-items-in-cell-rect)]
          (set rect (. self.rects item))
          (when (and (or (not filter) (filter item))
                     (rect-is-intersecting x y w h rect.x rect.y rect.w rect.h))
            (set len (+ len 1))
            (tset items len item)))
        (values items len)))

    (fn World.queryPoint [self x y filter]
      (let [(cx cy) (self:toCell x y)
            dict-items-in-cell-rect (get-dict-items-in-cell-rect self cx cy 1 1)
            items {}]
        (var (len rect) 0)
        (each [item _ (pairs dict-items-in-cell-rect)]
          (set rect (. self.rects item))
          (when (and (or (not filter) (filter item))
                     (rect-contains-point rect.x rect.y rect.w rect.h x y))
            (set len (+ len 1))
            (tset items len item)))
        (values items len)))

    (fn World.querySegment [self x1 y1 x2 y2 filter]
      (let [(item-info len) (get-info-about-items-touched-by-segment self x1 y1 x2
                                                                     y2 filter)
            items {}]
        (for [i 1 len]
          (tset items i (. (. item-info i) :item)))
        (values items len)))

    (fn World.querySegmentWithCoords [self x1 y1 x2 y2 filter]
      (let [(item-info len) (get-info-about-items-touched-by-segment self x1 y1 x2
                                                                     y2 filter)
            (dx dy) (values (- x2 x1) (- y2 y1))]
        (var (info ti1 ti2) nil)
        (for [i 1 len]
          (set info (. item-info i))
          (set ti1 info.ti1)
          (set ti2 info.ti2)
          (set info.weight nil)
          (set info.x1 (+ x1 (* dx ti1)))
          (set info.y1 (+ y1 (* dy ti1)))
          (set info.x2 (+ x1 (* dx ti2)))
          (set info.y2 (+ y1 (* dy ti2))))
        (values item-info len)))

    ;; Main methods

    (fn World.add [self item x y w h]
      (let [rect (. self.rects item)]
        (when rect
          (error (.. "Item " (tostring item) " added to the world twice.")))
        (assert-is-rect x y w h)
        (tset self.rects item {: h : w : x : y})
        (local (cl ct cw ch) (grid-to-cell-rect self.cellSize x y w h))
        (for [cy ct (- (+ ct ch) 1)]
          (for [cx cl (- (+ cl cw) 1)]
            (add-item-to-cell self item cx cy)))
        item))

    (fn World.remove [self item]
      (let [(x y w h) (self:getRect item)]
        (tset self.rects item nil)
        (local (cl ct cw ch) (grid-to-cell-rect self.cellSize x y w h))
        (for [cy ct (- (+ ct ch) 1)]
          (for [cx cl (- (+ cl cw) 1)]
            (remove-item-from-cell self item cx cy)))))

    (fn World.update [self item x2 y2 w2 h2]
      (let [(x1 y1 w1 h1) (self:getRect item)
            (w2 h2) (values (or w2 w1) (or h2 h1))]
        (assert-is-rect x2 y2 w2 h2)
        (when (or (not= x1 x2)
                  (not= y1 y2)
                  (not= w1 w2)
                  (not= h1 h2))
          (let [cell-size self.cellSize
                (cl1 ct1 cw1 ch1) (grid-to-cell-rect cell-size x1 y1 w1 h1)
                (cl2 ct2 cw2 ch2) (grid-to-cell-rect cell-size x2 y2 w2 h2)]
            (when (or (not= cl1 cl2)
                      (not= ct1 ct2)
                      (not= cw1 cw2)
                      (not= ch1 ch2))
              (let [(cr1 cb1) (values (- (+ cl1 cw1) 1) (- (+ ct1 ch1) 1))
                    (cr2 cb2) (values (- (+ cl2 cw2) 1) (- (+ ct2 ch2) 1))]
                (var cy-out nil)
                (for [cy ct1 cb1]
                  (set cy-out (or (< cy ct2) (> cy cb2)))
                  (for [cx cl1 cr1]
                    (when (or cy-out
                              (< cx cl2)
                              (> cx cr2))
                      (remove-item-from-cell self item cx cy))))
                (for [cy ct2 cb2]
                  (set cy-out (or (< cy ct1) (> cy cb1)))
                  (for [cx cl2 cr2]
                    (when (or cy-out
                              (< cx cl1)
                              (> cx cr1))
                      (add-item-to-cell self item cx cy))))))
            (local rect (. self.rects item))
            (set (rect.x rect.y rect.w rect.h) (values x2 y2 w2 h2))))))

    (fn World.move [self item goal-x goal-y filter]
      (let [(actual-x actual-y cols len)
            (self:check item goal-x goal-y filter)]
        (self:update item actual-x actual-y)
        (values actual-x actual-y cols len)))

    (fn World.check [self item goal-x goal-y filter]
      (let [filter (or filter default-filter)
            visited {item true}
            cols {}]
        (fn visited-filter [itm other]
          (if (. visited other)
              false
              (filter itm other)))
        (var (len goal-x goal-y) (values 0 goal-x goal-y))
        (let [(x y w h) (self:getRect item)]
          (var (projected-cols projected-len) (self:project item x y w h goal-x goal-y visited-filter))
          (while (> projected-len 0)
            (let [col (. projected-cols 1)]
              (set len (+ len 1))
              (tset cols len col)
              (tset visited col.other true)
              (local response (get-response-by-name self col.type))
              (set (goal-x goal-y projected-cols projected-len)
                (response self col x y w h goal-x goal-y visited-filter))))
          (values goal-x goal-y cols len))))

    ;; Public library functions

    (fn bump.newWorld [cell-size]
      (let [cell-size (or cell-size 64)
            world (setmetatable
                   {:cellSize cell-size
                    :nonEmptyCells {}
                    :rects {}
                    :responses {}
                    :rows {}}
                   World-mt)]
        (assert-is-positive-number cell-size :cellSize)
        (world:addResponse :touch touch)
        (world:addResponse :cross cross)
        (world:addResponse :slide slide)
        (world:addResponse :bounce bounce)
        world))

    (set bump.rect
      {:getNearestCorner rect-get-nearest-corner
       :getSegmentIntersectionIndices rect-get-segment-intersection-indices
       :getDiff rect-get-diff
       :containsPoint rect-contains-point
       :isIntersecting rect-is-intersecting
       :getSquareDistance rect-get-square-distance
       :detectCollision rect-detect-collision})

    (set bump.responses
      {: touch
       : cross
       : slide
       : bounce})

    bump))

(local bump (require :bump))

(local {:min m/min
        :max m/max
        :random m/random
        :sqrt m/sqrt}
  math)

(local world (bump.newWorld 24))

(macro id-at [x y]
  `(mget (// ,x 8) (// ,y 8)))

(macro clamp [low x high]
  `(m/min (m/max ,low ,x) ,high))

(macro lerp [a b t]
  `(let [t# ,t] (+ (* (- 1 t#) ,a) (* t# ,b))))

(fn slope-normal [x0 y0 x1 y1 slope-type]
  "Calculate a normal vector for the given `slope-type`."
  (let [dx (- x1 x0)
        dy (- y1 y0)
        len (m/sqrt (+ (* dx dx) (* dy dy)))
        nx (/ (- dy) len)
        ny (/ dx len)]
    (if (or (and (= slope-type :floor) (> ny 0))
            (and (= slope-type :ceiling) (< ny 0)))
        (values (- nx) (- ny))
        (values nx ny))))

(fn make-slope [x y x0 y0 x1 y1 slope-type]
  "Creates a slope object with specified dimensions at given coordinates."
  (let [(nx ny) (slope-normal x0 y0 x1 y1 slope-type)]
    {:slope slope-type
     :surface #(+ y0 (/ (* (- y1 y0) (- (clamp x0 $ x1) x0)) (- x1 x0)))
     : x : y : nx : ny
     :h (m/max y0 y1) :w (m/max x0 x1)}))

(fn slope-response [world col x y w h goal-x goal-y filter]
  "Bump's collision resolution logic for right-angle triangular slopes."
  (let [goal-x (or goal-x x)
        {: surface :slope slope-type : nx : ny} col.other
        {:x ox :y oy} col.otherRect
        {:y touch-y} col.touch]
    (var goal-y (or goal-y y))
    (case slope-type
      :floor (let [surf-y (m/min (+ oy (surface (- goal-x ox)))
                                 (+ oy (surface (- (+ goal-x w) ox))))]
               (if (> (+ goal-y h) surf-y)
                   (if (> col.normal.y 0)
                       (set goal-y touch-y)
                       (set [goal-y col.normal.x col.normal.y] [(- surf-y h) nx ny]))
                   (set [col.normal.x col.normal.y] [0 0])))
      :ceiling (let [surf-y (m/max (+ oy (surface (- goal-x ox)))
                                   (+ oy (surface (- (+ goal-x w) ox))))]
                 (if (< goal-y surf-y)
                     (if (< col.normal.y 0)
                         (set goal-y touch-y)
                         (set [goal-y col.normal.x col.normal.y] [surf-y nx ny]))
                     (set [col.normal.x col.normal.y] [0 0])))
      _ (error (.. "unknown slope type: " (tostring _))))
    (set col.slide {:x goal-x :y goal-y})
    (local (cols len) (world:project col.item x y w h goal-x goal-y filter))
    (values goal-x goal-y cols len)))

(world:addResponse :slope slope-response)

(fn roll-response [world col x y w h goal-x goal-y filter]
  "Bump's collision resolution for ball interactions."
  (let [item col.item
        other col.other
        (gx gy cols len) (bump.responses.slide world col x y w h goal-x goal-y filter)]
    (if item.prev-x
        (do
          (set other.xvel (+ other.xvel (- gx x)))
          (set other.yvel (+ other.yvel (- gy y))))
        (do
          (set other.xvel (/ (+ other.xvel item.xvel) 2))
          (set other.yvel (/ (+ other.yvel item.yvel) 2))
          (set item.xvel (/ item.xvel 2))
          (set item.yvel (/ item.yvel 2))
          (when (= col.normal.y -1)
            (if (< item.x other.x)
                (do (set item.xvel (- item.xvel 0.5))
                    (set other.xvel (+ other.xvel 0.5)))
                (do (set item.xvel (+ item.xvel 0.5))
                    (set other.xvel (- other.xvel 0.5)))))))
    (values gx gy cols len)))

(world:addResponse :roll roll-response)

;; Balls

(fn collision-filter [_ other]
  (if other.slope :slope
      other.ball :roll
      :slide))

(var grabbed nil)

(local balls
  (->> {:__index
        {:draw (fn [self]
                 (each [ball (pairs self)]
                   (spr 1 ball.x ball.y 0)))
         :update (fn [self]
                   (local (mx my is-pressed) (mouse))
                   (if (and is-pressed (not grabbed))
                       (case (next (world:queryPoint mx my (fn [obj] obj.ball)) nil)
                         (_ item) (set grabbed item))
                       (not is-pressed)
                       (do
                         (when grabbed
                           (doto grabbed
                             (tset :xvel (- grabbed.x grabbed.prev-x))
                             (tset :yvel (- grabbed.y grabbed.prev-y))
                             (tset :prev-x nil)
                             (tset :prev-y nil)))
                         (set grabbed nil)))
                   (each [ball (pairs self)]
                     (match ball
                       grabbed (let [x (lerp ball.x (- mx 4) 0.3)
                                     y (lerp ball.y (- my 4) 0.3)]
                                 (doto ball
                                   (tset :prev-x ball.x)
                                   (tset :prev-y ball.y))
                                 (let [(x y) (world:move ball x y collision-filter)]
                                   (doto ball
                                     (tset :x x)
                                     (tset :y y))))
                       _ (let [xvel (lerp ball.xvel 0 0.03)
                               yvel (lerp ball.yvel 5 0.075)]
                           (let [(x y cols len) (world:move ball (+ ball.x xvel) (+ ball.y yvel) collision-filter)]
                             (doto ball
                               (tset :x x)
                               (tset :y y)
                               (tset :xvel xvel)
                               (tset :yvel yvel))
                             (for [i 1 len]
                               (let [col (. cols i)]
                                 (if col.other.slope
                                     (let [n col.normal
                                           vn (+ (* ball.xvel n.x) (* ball.yvel n.y))]
                                       (when (< vn 0)
                                         (doto ball
                                           (tset :xvel (- ball.xvel (* 1.5 vn n.x)))
                                           (tset :yvel (- ball.yvel (* 1.5 vn n.y))))))
                                     (do
                                       (when (not= col.normal.y 0)
                                         (doto ball
                                           (tset :yvel (- (* ball.yvel 0.9)))
                                           (tset :xvel (* ball.xvel 0.75))))
                                       (when (not= col.normal.x 0)
                                         (set ball.xvel (- (* ball.xvel 0.9)))))))))))))}}
       (setmetatable {})))

;; Map loading

(fn ball? [id x y]
  (when (fget id 1)
    (let [ball {:h 8 :ball true :w 8 : x :xvel (- (m/random 5) 2.5) : y :yvel (- (m/random 5))}]
      (tset balls ball true)
      ball)))

(fn solid? [id x y]
  (when (fget id 0)
    {:h 8 :w 8 : x : y}))

(fn floor-low-r? [id x y]
  (when (and (fget id 2) (not (fget id 0)))
    (make-slope x y 0 8 16 0 :floor)))

(fn floor-low-l? [id x y]
  (when (and (fget id 3) (not (fget id 0)))
    (make-slope x y 0 0 16 8 :floor)))

(fn floor-high-r? [id x y]
  (when (and (fget id 4) (not (fget id 0)))
    (make-slope x y 0 16 8 0 :floor)))

(fn floor-high-l? [id x y]
  (when (and (fget id 5) (not (fget id 0)))
    (make-slope x y 0 0 8 16 :floor)))

(fn floor-45-r? [id x y]
  (when (and (fget id 6) (not (fget id 0)))
    (make-slope x y 0 8 8 0 :floor)))

(fn floor-45-l? [id x y]
  (when (and (fget id 7) (not (fget id 0)))
    (make-slope x y 0 0 8 8 :floor)))

(fn ceil-low-r? [id x y]
  (when (and (fget id 2) (fget id 0))
    (make-slope x y 0 0 16 8 :ceiling)))

(fn ceil-low-l? [id x y]
  (when (and (fget id 3) (fget id 0))
    (make-slope x y 0 8 16 0 :ceiling)))

(fn ceil-high-r? [id x y]
  (when (and (fget id 4) (fget id 0))
    (make-slope x y 0 0 8 16 :ceiling)))

(fn ceil-high-l? [id x y]
  (when (and (fget id 5) (fget id 0))
    (make-slope x y 0 16 8 0 :ceiling)))

(fn ceil-45-r? [id x y]
  (when (and (fget id 6) (fget id 0))
    (make-slope x y 0 0 8 8 :ceiling)))

(fn ceil-45-l? [id x y]
  (when (and (fget id 7) (fget id 0))
    (make-slope x y 0 8 8 0 :ceiling)))

(fn is-obj [x y]
  (let [id (id-at x y)]
    (or (floor-low-r? id x y)
        (floor-low-l? id x y)
        (floor-high-r? id x y)
        (floor-high-l? id x y)
        (floor-45-r? id x y)
        (floor-45-l? id x y)
        (ceil-low-r? id x y)
        (ceil-low-l? id x y)
        (ceil-high-r? id x y)
        (ceil-high-l? id x y)
        (ceil-45-r? id x y)
        (ceil-45-l? id x y)
        (solid? id x y)
        (ball? id x y))))

(fn load-map []
  (for [x 0 (* 240 8) 8]
    (for [y 0 (* 136 8) 8]
      (case (is-obj x y)
        obj (world:add obj obj.x obj.y obj.w obj.h)))))

(fn _G.BOOT [] (load-map))

(fn _G.TIC []
  (cls 0)
  (print "AABB\nSLOPES" 14 14 14 true 3)
  (print "\nV2.0" 164 14 14 false 3)
  (print "Axis-Aligned Bounding-Box\ncollisions with custom slopes" 14 52 15 false 1)
  (balls:update)
  (balls:draw)
  (map 0 0 31 18 0 0 0 1 #(if (= $ 1) 0 $)))
