Compare commits
1932 Commits
Author | SHA1 | Date |
---|---|---|
Zeno Rogue | bb14c55997 | |
Zeno Rogue | b74b77463c | |
Zeno Rogue | 1e6793fa0a | |
Zeno Rogue | 78585f7ec2 | |
Zeno Rogue | b86eaa5693 | |
Zeno Rogue | 046deb799c | |
Zeno Rogue | 59fe423728 | |
Zeno Rogue | 2fccfdf0c5 | |
Zeno Rogue | 93dcc68acb | |
Zeno Rogue | 94c02b5082 | |
Zeno Rogue | 05309e3272 | |
Zeno Rogue | d059eb028c | |
Jacob Mandelson | 56cb3618d4 | |
Zeno Rogue | c80b34140f | |
Zeno Rogue | 078d16a4e4 | |
Zeno Rogue | 520314c2c5 | |
Zeno Rogue | 6a086e9764 | |
Zeno Rogue | 13ff317948 | |
Zeno Rogue | c5cc8be04f | |
Zeno Rogue | f80492f365 | |
Zeno Rogue | 70747f938d | |
Zeno Rogue | 00644cb2ef | |
Zeno Rogue | d4cb90fe1c | |
Zeno Rogue | 7cfda649be | |
Zeno Rogue | 4f868faee4 | |
Zeno Rogue | 22e0d8264f | |
Zeno Rogue | cd11bc2332 | |
Zeno Rogue | 43f998453e | |
Zeno Rogue | 0c0dcaba45 | |
Zeno Rogue | 20ce218bec | |
Zeno Rogue | 249dff7382 | |
Zeno Rogue | df5deaba4b | |
Zeno Rogue | 517f540800 | |
Zeno Rogue | 5877690cce | |
Zeno Rogue | c9b7e0ac1d | |
Zeno Rogue | 226881020d | |
Zeno Rogue | 809351e6a5 | |
Zeno Rogue | 99564ddfc9 | |
Zeno Rogue | 59c52a8176 | |
Zeno Rogue | 7af403490a | |
Zeno Rogue | 2314eaba29 | |
Zeno Rogue | 5d34760290 | |
Zeno Rogue | 50d70097cb | |
Zeno Rogue | c16c064b21 | |
Zeno Rogue | 448397ab1d | |
Zeno Rogue | b482dabb84 | |
Zeno Rogue | 478be692de | |
Zeno Rogue | dda979ad14 | |
Zeno Rogue | 9485495e48 | |
Zeno Rogue | d4a610c2b6 | |
Zeno Rogue | 003ca36ee5 | |
Zeno Rogue | 9752cdede1 | |
Zeno Rogue | fbd2cc6b9d | |
Zeno Rogue | 5324d3d068 | |
Zeno Rogue | d34070f709 | |
Zeno Rogue | 5d576c3344 | |
Zeno Rogue | c6c040eead | |
Zeno Rogue | aec2463f2f | |
Zeno Rogue | ba44e111ca | |
Zeno Rogue | 43d1fd3db8 | |
Zeno Rogue | 727ae8a260 | |
Zeno Rogue | 99bc842c57 | |
Zeno Rogue | a9d6def718 | |
Zeno Rogue | 0d5723dd69 | |
Zeno Rogue | ab0ca74328 | |
Zeno Rogue | e66f071521 | |
Zeno Rogue | b7bfe746cb | |
Zeno Rogue | 093044ba83 | |
Zeno Rogue | 3c29b987ce | |
Zeno Rogue | a755f26075 | |
Zeno Rogue | c1bacb0695 | |
Zeno Rogue | e2c81eeae7 | |
Zeno Rogue | fcc3cae938 | |
Zeno Rogue | 3b3e9e2de6 | |
Zeno Rogue | 5901d9598d | |
Zeno Rogue | 6bf198946c | |
Zeno Rogue | a3261b21da | |
Zeno Rogue | 3da7e4c020 | |
Zeno Rogue | ce09e4910e | |
Zeno Rogue | 95d7ffee08 | |
Zeno Rogue | 82a7077019 | |
Zeno Rogue | 1cc90a6f76 | |
Zeno Rogue | 1323ec446a | |
Zeno Rogue | 8db11dc683 | |
Zeno Rogue | 502469a54a | |
Zeno Rogue | 0df75589ca | |
Zeno Rogue | 358554d60e | |
Zeno Rogue | c594aea40e | |
Zeno Rogue | 03c549b010 | |
Zeno Rogue | 937a291485 | |
Zeno Rogue | 0e09775669 | |
Zeno Rogue | 5c03f9c7fe | |
Zeno Rogue | 8321751cb0 | |
Zeno Rogue | bfacda7207 | |
Zeno Rogue | 4f761c70cb | |
Zeno Rogue | 3ca75bec8e | |
Zeno Rogue | 54443e365d | |
Zeno Rogue | 6ca2051c96 | |
Zeno Rogue | e5e89c4800 | |
Zeno Rogue | bb6df35bf2 | |
Zeno Rogue | ba05c94d7b | |
Zeno Rogue | 90c7f6e927 | |
Zeno Rogue | e6417951de | |
Zeno Rogue | f823a53f84 | |
Zeno Rogue | 83575d9d7d | |
Zeno Rogue | d381caba1f | |
Zeno Rogue | 78cd26f456 | |
Zeno Rogue | 96be05484a | |
Zeno Rogue | 4d57041c9f | |
Zeno Rogue | 5022b76d75 | |
Zeno Rogue | 8caf343390 | |
Zeno Rogue | 203c11f6e1 | |
Zeno Rogue | 322b21e999 | |
Zeno Rogue | f445d02707 | |
Zeno Rogue | 888a34dea6 | |
Zeno Rogue | a20158ab65 | |
Zeno Rogue | a703448144 | |
Zeno Rogue | 480916e4db | |
Zeno Rogue | 998a74800c | |
Zeno Rogue | f4796a10f4 | |
Zeno Rogue | aa4bf4d818 | |
Zeno Rogue | ff8bb20a55 | |
Zeno Rogue | 57691737f0 | |
Zeno Rogue | a4b9b9b0a5 | |
Zeno Rogue | 1c74774bfa | |
Zeno Rogue | a80a73458a | |
Zeno Rogue | d7bde6f175 | |
Zeno Rogue | 9f711627f1 | |
Zeno Rogue | 89763be7d2 | |
Zeno Rogue | 03b89f053b | |
Zeno Rogue | 441f825566 | |
Zeno Rogue | f2d8b4d95e | |
Zeno Rogue | 73dbccbb0e | |
Jacob Mandelson | efc2ce90e0 | |
Zeno Rogue | 7b3d2c2626 | |
Zeno Rogue | 126f45a714 | |
Jacob Mandelson | 11837d9614 | |
Zeno Rogue | 64569f1818 | |
Jacob Mandelson | cd2152ffad | |
Zeno Rogue | eee39b0340 | |
Zeno Rogue | 937c830571 | |
Zeno Rogue | 4ec627b1a1 | |
Zeno Rogue | 1a70e54e24 | |
Zeno Rogue | a70a9dc663 | |
Zeno Rogue | 879549ca5d | |
Zeno Rogue | 7982ea0e58 | |
Zeno Rogue | 7b99248c06 | |
Zeno Rogue | dc136cc937 | |
Jacob Mandelson | 3f78c11e6c | |
Jacob Mandelson | 1dd4da5135 | |
Jacob Mandelson | 601274e67a | |
Zeno Rogue | 7581ba887b | |
Zeno Rogue | 6b03aca3c0 | |
Zeno Rogue | 80df589bd2 | |
Zeno Rogue | 159b47e72a | |
Zeno Rogue | 9a33e63f53 | |
Zeno Rogue | 10184f9087 | |
Zeno Rogue | 6b0dd547bd | |
Zeno Rogue | 542e2520c1 | |
Zeno Rogue | f2d81746a7 | |
Zeno Rogue | a130fbbc50 | |
Zeno Rogue | 2097fde609 | |
Zeno Rogue | bc5e1d78c9 | |
Zeno Rogue | e324ae07f3 | |
Zeno Rogue | 215be1ea17 | |
Zeno Rogue | 53461e6c5a | |
Zeno Rogue | 7a81b6b0de | |
Zeno Rogue | 723422e137 | |
Zeno Rogue | 50881f519f | |
Zeno Rogue | df67249ec0 | |
Zeno Rogue | 0a9714e657 | |
Zeno Rogue | 5eb7cfc17a | |
Zeno Rogue | 000bfd4b97 | |
Zeno Rogue | 0b0ad4abe3 | |
Zeno Rogue | 305d546ae1 | |
Zeno Rogue | c369c08bc9 | |
Zeno Rogue | 52f9cc820b | |
Zeno Rogue | 4c81c0cc5d | |
Zeno Rogue | 51ecd882e1 | |
Zeno Rogue | 9ba9797068 | |
Zeno Rogue | ba972ea8d8 | |
Zeno Rogue | e4b0ebbd89 | |
Zeno Rogue | 35ddcf6fe1 | |
Zeno Rogue | 7c2aca91a4 | |
Zeno Rogue | 43702b82a1 | |
Zeno Rogue | 43a3e8f030 | |
Zeno Rogue | ce825db2c0 | |
Zeno Rogue | b8a7e6e093 | |
Zeno Rogue | 962efb3152 | |
Zeno Rogue | 84666ade8c | |
Zeno Rogue | 9aa15f96e1 | |
Zeno Rogue | bc22d17a16 | |
Zeno Rogue | d9a03ab1d3 | |
Zeno Rogue | 5ae3bc02d1 | |
Zeno Rogue | aafced83aa | |
Zeno Rogue | 33aacfa289 | |
Zeno Rogue | d074606cae | |
Zeno Rogue | 6aecf921bf | |
Zeno Rogue | fa99e83019 | |
Zeno Rogue | 1003808999 | |
Zeno Rogue | 5085853fb4 | |
Zeno Rogue | 9372ecb8f8 | |
Zeno Rogue | 690b2164db | |
Zeno Rogue | 16e3daeab5 | |
Zeno Rogue | 0a16e53561 | |
Zeno Rogue | 443be1acda | |
Zeno Rogue | ba9c41bed2 | |
Zeno Rogue | 329ad76c3c | |
Zeno Rogue | de20daf708 | |
Zeno Rogue | f229c489cd | |
Zeno Rogue | 1e3347590b | |
Zeno Rogue | fd1960191e | |
Zeno Rogue | 942fd9dafb | |
Zeno Rogue | f1e91a1614 | |
Zeno Rogue | e71ddf1140 | |
Zeno Rogue | a0ba84d70c | |
Zeno Rogue | 404b964f28 | |
Jacob Mandelson | b56d2d21bf | |
Zeno Rogue | 27fb2d92d7 | |
Zeno Rogue | ec9be47a83 | |
Jacob Mandelson | 14519dc258 | |
Jacob Mandelson | c3ef9c2733 | |
Jacob Mandelson | c29517b5b0 | |
Zeno Rogue | e91c11ffb7 | |
Zeno Rogue | 7d3d3a0869 | |
Tokarak | d0d4b24f91 | |
Tokarak | 2659d08b78 | |
Tokarak | 45db9977a0 | |
Tokarak | aa78aacdf3 | |
Tokarak | fd128d24c6 | |
Jacob Mandelson | d756224f8d | |
Zeno Rogue | fbea2d91ce | |
Zeno Rogue | d4f449d994 | |
Zeno Rogue | 9807b1b3ba | |
Zeno Rogue | 4d761385ac | |
Zeno Rogue | 05b6cdea3e | |
Zeno Rogue | 10646933db | |
Zeno Rogue | 521b452436 | |
Zeno Rogue | 0323e4100e | |
Zeno Rogue | 0708c0e2bc | |
Zeno Rogue | b7db56812e | |
Zeno Rogue | 7fc90f116b | |
Zeno Rogue | 824fa9a732 | |
Zeno Rogue | 92603dddcc | |
Zeno Rogue | 32d329d81e | |
Zeno Rogue | b9608dcd4c | |
Zeno Rogue | 977bd8ca9d | |
Zeno Rogue | 869c63cb88 | |
Zeno Rogue | 5377147b1a | |
Zeno Rogue | e83d38e267 | |
Zeno Rogue | 1fc02631c8 | |
Zeno Rogue | edff317759 | |
Jacob Mandelson | b8de8155da | |
Zeno Rogue | 9bc4e21f10 | |
Zeno Rogue | a328568ee5 | |
Zeno Rogue | 494fc4ec11 | |
Zeno Rogue | 6f7e5b4d6a | |
Zeno Rogue | ccea416237 | |
Zeno Rogue | 4a908273d0 | |
Zeno Rogue | 5efacd787d | |
Zeno Rogue | b07987b2f4 | |
Zeno Rogue | 84ada5184f | |
Zeno Rogue | 14b68f0b64 | |
Zeno Rogue | 960485ec8e | |
Zeno Rogue | e032e619c0 | |
Zeno Rogue | 57f6fb5f71 | |
Zeno Rogue | d2cd6fa2c1 | |
Zeno Rogue | 8a407f4505 | |
Zeno Rogue | 6abb82174e | |
Zeno Rogue | dea9fea67f | |
Zeno Rogue | d618b10889 | |
Zeno Rogue | d250abf1a4 | |
Zeno Rogue | 89563ebde9 | |
Zeno Rogue | 445c240c79 | |
Zeno Rogue | 15b711e099 | |
Zeno Rogue | 8002f42d71 | |
Zeno Rogue | 79f2940683 | |
Zeno Rogue | 0ec4e46bf0 | |
Zeno Rogue | c55550de57 | |
Zeno Rogue | 886a7ff43e | |
Zeno Rogue | deb207e4c3 | |
Zeno Rogue | 819d815d59 | |
Zeno Rogue | b20288557e | |
Zeno Rogue | 4a8eb08340 | |
Zeno Rogue | 007a111eab | |
Zeno Rogue | 65e9f68bc7 | |
Zeno Rogue | 3e30a7ded1 | |
Zeno Rogue | 5f8d250940 | |
Zeno Rogue | dee90f8d7c | |
Zeno Rogue | d43b19625e | |
Zeno Rogue | f32a2708b4 | |
Zeno Rogue | be27fc0fce | |
Zeno Rogue | 61720cec5e | |
Zeno Rogue | 7cf1643c5d | |
Zeno Rogue | 3791daf9e3 | |
Zeno Rogue | e9941d29d3 | |
Zeno Rogue | afd4a3f4e3 | |
Zeno Rogue | 66a79fe2cd | |
Zeno Rogue | 350963852c | |
Zeno Rogue | a650fe7faf | |
Zeno Rogue | fdf83820f2 | |
Zeno Rogue | 6b723977dd | |
Zeno Rogue | 1b3aecc10c | |
Zeno Rogue | e762da439c | |
Zeno Rogue | 7f023b2459 | |
Zeno Rogue | 2a9ae3071d | |
Zeno Rogue | de21375f40 | |
Zeno Rogue | 7bc2715a43 | |
Zeno Rogue | 04c15fc9c6 | |
Zeno Rogue | 9430c26970 | |
Zeno Rogue | 616607dc8e | |
Zeno Rogue | 86f5a040c9 | |
Zeno Rogue | 37b498203c | |
Zeno Rogue | 77a4bb4160 | |
Zeno Rogue | 5bdade94b6 | |
Zeno Rogue | 0b526cbdfb | |
Zeno Rogue | a82d9b2266 | |
Zeno Rogue | 0e018df878 | |
Zeno Rogue | 1c5709a3c9 | |
Zeno Rogue | c230e03a0a | |
Zeno Rogue | b71cd1e44d | |
Zeno Rogue | ef936d7b0e | |
Zeno Rogue | 97f8c5ed72 | |
Zeno Rogue | 94bf06f7dc | |
Zeno Rogue | 261800d765 | |
Zeno Rogue | 2b2cc4e8a9 | |
Zeno Rogue | cbccf4936d | |
Zeno Rogue | 68f5ad6e92 | |
Zeno Rogue | 9f44f98b0a | |
Zeno Rogue | 5bb4b69c23 | |
Zeno Rogue | 9cc370a2d2 | |
Zeno Rogue | 26e61783b2 | |
Zeno Rogue | d0d354b53a | |
Zeno Rogue | 78a1615c6c | |
Zeno Rogue | 125b271889 | |
Zeno Rogue | c85b4d2f2b | |
Zeno Rogue | 424186b10d | |
Zeno Rogue | 4421143ae5 | |
Jacob Mandelson | ee293310b6 | |
Jacob Mandelson | a40e72f1d8 | |
Jacob Mandelson | 3bd67f466a | |
Zeno Rogue | ddb9fbd58e | |
Zeno Rogue | b152bac377 | |
Jacob Mandelson | a626ede2bf | |
Jacob Mandelson | 1f2692a4fb | |
Jacob Mandelson | e31c9dc263 | |
Jacob Mandelson | 7d04b0c717 | |
Jacob Mandelson | 0f84812d15 | |
Jacob Mandelson | 80f90dec52 | |
Zeno Rogue | e840e39ba0 | |
Zeno Rogue | fa9c2da41d | |
Zeno Rogue | f291bbb1d1 | |
Zeno Rogue | 2de61962f9 | |
Zeno Rogue | 43fc692b47 | |
Zeno Rogue | 87ac19febe | |
Zeno Rogue | 2379228ab4 | |
Zeno Rogue | 5aac5fd2a3 | |
Zeno Rogue | 46eaee44ef | |
Zeno Rogue | 21d3f8bec4 | |
Zeno Rogue | c2d06dc05b | |
Zeno Rogue | 21a782cd28 | |
Zeno Rogue | bf512e39ce | |
Zeno Rogue | de5ddc3034 | |
Zeno Rogue | b4b00baa5e | |
Zeno Rogue | 648dd67dc7 | |
Zeno Rogue | 30f6fbc16c | |
Zeno Rogue | 00b5fe3a22 | |
Zeno Rogue | 55493cc364 | |
Zeno Rogue | 3b1918535f | |
Zeno Rogue | 650108bad3 | |
Zeno Rogue | 79e74e8d53 | |
Zeno Rogue | 3ed43b8c7d | |
Zeno Rogue | 5508fb7183 | |
Zeno Rogue | 6c682510bc | |
Zeno Rogue | 6d9f7e791b | |
Zeno Rogue | e343ed9c3f | |
Zeno Rogue | 8af2a43f5e | |
Zeno Rogue | e33f26d51f | |
Zeno Rogue | 60980bcb8b | |
Zeno Rogue | bcc026173e | |
Zeno Rogue | d86f70886d | |
Zeno Rogue | 2a7e2e96ca | |
Zeno Rogue | a91f74c86c | |
Zeno Rogue | 285c71e10f | |
Zeno Rogue | a28c62416f | |
Zeno Rogue | bfd1945d7b | |
Zeno Rogue | f271ba6b4d | |
Zeno Rogue | f87a7c5f1c | |
Zeno Rogue | 9ce5c63708 | |
Jacob Mandelson | 56c8838101 | |
Zeno Rogue | 9a590ecc42 | |
Zeno Rogue | eb1488b24f | |
Zeno Rogue | 26328f5493 | |
Zeno Rogue | 52081a916a | |
Jacob Mandelson | 08a774dfd4 | |
Jacob Mandelson | acd88377a9 | |
Zeno Rogue | 51f59cc2fa | |
Zeno Rogue | 5f552799e5 | |
Zeno Rogue | f883322ecd | |
Zeno Rogue | 8c06e184c8 | |
Zeno Rogue | b8a5c7528b | |
Zeno Rogue | 11aa7d5216 | |
Zeno Rogue | 0ea461fa7e | |
Zeno Rogue | bdd2b5e9fd | |
Zeno Rogue | 8ce805372d | |
Zeno Rogue | 072041db06 | |
Zeno Rogue | 4c6c44cc26 | |
Zeno Rogue | 31471fc6c5 | |
Zeno Rogue | 7ad46d8e80 | |
Zeno Rogue | 34ab44d1e1 | |
Zeno Rogue | 66a3a3df6c | |
Zeno Rogue | 0c34e9fd34 | |
Zeno Rogue | cb8a3f5424 | |
Zeno Rogue | fc808d448b | |
Zeno Rogue | 7ad955dcff | |
Zeno Rogue | 17b84bb4fb | |
Zeno Rogue | 902986d473 | |
Zeno Rogue | 9bc978ce16 | |
Zeno Rogue | 6f81743488 | |
Zeno Rogue | f4607b63f4 | |
Zeno Rogue | 6e3be8a92c | |
Zeno Rogue | 02efdec4b7 | |
Zeno Rogue | 18247ec98f | |
Zeno Rogue | eb4b7177f3 | |
Zeno Rogue | 517f4af193 | |
Zeno Rogue | 2f1bb092b8 | |
Zeno Rogue | ffda562f7c | |
Zeno Rogue | c5a4cc2255 | |
Zeno Rogue | dbc51d2f94 | |
Zeno Rogue | 3da65f4cd5 | |
Zeno Rogue | 0c7aa7cbe3 | |
Zeno Rogue | 79527688cf | |
Zeno Rogue | 364a563423 | |
Zeno Rogue | a6b30fa564 | |
Zeno Rogue | eb3406d7dc | |
Zeno Rogue | 95ed035180 | |
Zeno Rogue | 3d01ce808f | |
Zeno Rogue | 558b8d7aff | |
Zeno Rogue | 0de012923a | |
Zeno Rogue | 7a352ccf43 | |
Zeno Rogue | 98831aff7e | |
Zeno Rogue | 17c254e2b4 | |
Zeno Rogue | 4fbce2ae5a | |
Zeno Rogue | cdc1696929 | |
Zeno Rogue | 2fc42cb114 | |
Zeno Rogue | 73884482aa | |
Zeno Rogue | 8c57e8b746 | |
Zeno Rogue | f5c5a5f876 | |
Jacob Mandelson | 12c464eb99 | |
Zeno Rogue | 8e31c51bc9 | |
Zeno Rogue | 71cbc8e221 | |
Zeno Rogue | bce07e5914 | |
Zeno Rogue | ed8b7d5d1d | |
Zeno Rogue | 5c24213092 | |
Zeno Rogue | a282ac314e | |
Zeno Rogue | 5ab9bf8f11 | |
Zeno Rogue | 61303fcab6 | |
Zeno Rogue | 517f4a833c | |
Jacob Mandelson | 27db11064c | |
Zeno Rogue | 062fb577b2 | |
Zeno Rogue | 4338ec2b43 | |
Zeno Rogue | cd7af38e2e | |
Zeno Rogue | 24c196db15 | |
Zeno Rogue | 548e2609ce | |
Zeno Rogue | d2d6167eb9 | |
Zeno Rogue | 86402cf979 | |
Zeno Rogue | 38825f3a31 | |
Zeno Rogue | 560cc91e95 | |
Zeno Rogue | ffc06b981f | |
Zeno Rogue | 0cdd6f8d5d | |
Zeno Rogue | c63969a21b | |
Zeno Rogue | 7802194248 | |
Zeno Rogue | a79a7f63a1 | |
Zeno Rogue | 928ab73fff | |
Zeno Rogue | ac33354358 | |
Zeno Rogue | 39ddc3dc33 | |
Zeno Rogue | 68a3d20d83 | |
Zeno Rogue | 6ef4a8a5e9 | |
Zeno Rogue | 16cb1090e8 | |
Zeno Rogue | 176ea28a24 | |
Zeno Rogue | 9bebbd8f4e | |
Zeno Rogue | 4ca8a7e394 | |
Zeno Rogue | 8946317475 | |
Zeno Rogue | 9ca0993d6f | |
Zeno Rogue | 2a892012b2 | |
Zeno Rogue | 53b0701d95 | |
Zeno Rogue | 439040c90c | |
Zeno Rogue | a840b96104 | |
Zeno Rogue | fe7e122613 | |
Zeno Rogue | 2dccf0d3ab | |
Zeno Rogue | c69bed4d12 | |
Zeno Rogue | c94e927929 | |
Zeno Rogue | 2dd4ef868b | |
Zeno Rogue | 34d3d67ace | |
Zeno Rogue | 2add515fbf | |
Zeno Rogue | 79165ae014 | |
Zeno Rogue | 9d4d085973 | |
Zeno Rogue | 45a9e0c85a | |
Zeno Rogue | c336e9d385 | |
Zeno Rogue | 8984cd8cd2 | |
Zeno Rogue | f76ccef90f | |
Zeno Rogue | 858db697d8 | |
Zeno Rogue | 8185657768 | |
Zeno Rogue | 0c6d286fa8 | |
Zeno Rogue | 76c6195d19 | |
Zeno Rogue | 95dc72a582 | |
Zeno Rogue | c91dc341ae | |
Zeno Rogue | b84e751d96 | |
Zeno Rogue | ed9081cfd5 | |
Zeno Rogue | da0bf9a035 | |
Zeno Rogue | 6030402441 | |
Zeno Rogue | 4b97f300ff | |
Zeno Rogue | 0c0bf1dd84 | |
Zeno Rogue | 1926fd8434 | |
Zeno Rogue | 6b8adfde9e | |
Zeno Rogue | 85fc2773b1 | |
Zeno Rogue | 669814efce | |
Zeno Rogue | 1f6bee5701 | |
Zeno Rogue | b2c8bb96d6 | |
Zeno Rogue | 87f7b2a593 | |
Zeno Rogue | f7a25ff2d1 | |
Zeno Rogue | a163c80ba1 | |
Zeno Rogue | b3b1611f33 | |
Zeno Rogue | 89a46a8cd1 | |
Zeno Rogue | a50a87f095 | |
Zeno Rogue | 33060a884c | |
Zeno Rogue | 9caa4daa62 | |
Zeno Rogue | 8e55cc9ebd | |
Zeno Rogue | 4e134c56b6 | |
Zeno Rogue | 8129cfd726 | |
Zeno Rogue | 3645a9b85e | |
Zeno Rogue | b0d117e646 | |
Zeno Rogue | 4f82c3eb8e | |
Zeno Rogue | c36da1985c | |
Zeno Rogue | e8ecccdf53 | |
Zeno Rogue | 11869c796b | |
Zeno Rogue | a012e6103a | |
Zeno Rogue | ddc7cddb91 | |
Zeno Rogue | daebe28d4f | |
Zeno Rogue | 3ef09bded2 | |
Zeno Rogue | f99a473720 | |
Zeno Rogue | dd37a1c6c7 | |
Zeno Rogue | 41e28c34b2 | |
Zeno Rogue | 9da8206a9f | |
Zeno Rogue | a233d3a7a6 | |
Zeno Rogue | 3a35d351c4 | |
Zeno Rogue | 079094799d | |
Zeno Rogue | 4ddccfed8e | |
Zeno Rogue | 44265f6d61 | |
Zeno Rogue | ddb06573df | |
Zeno Rogue | 1924a03d7a | |
Zeno Rogue | 33d48a76b3 | |
Zeno Rogue | f3398e70c3 | |
Zeno Rogue | c81e2bf7e8 | |
Zeno Rogue | e5458c5f80 | |
Zeno Rogue | e6a4d987bb | |
Zeno Rogue | f8fb7d5950 | |
Zeno Rogue | 7e46b4b5bb | |
Zeno Rogue | 845237c756 | |
Zeno Rogue | 9f5b13dfab | |
Zeno Rogue | 63b6576eb6 | |
Jacob Mandelson | db72295775 | |
Jacob Mandelson | 36bdc5d3f0 | |
Zeno Rogue | 5fb0099fbb | |
Zeno Rogue | ff19ceb438 | |
Zeno Rogue | 99f4b8698b | |
Zeno Rogue | 67a77befb9 | |
Zeno Rogue | 1c0bf5def3 | |
Zeno Rogue | 0ab6974cd9 | |
Zeno Rogue | fb1f3d8f13 | |
Zeno Rogue | 72029b3fbe | |
Zeno Rogue | c63eebc15f | |
Zeno Rogue | b9d8aaee13 | |
Zeno Rogue | ef93305313 | |
Zeno Rogue | fb5e4d25bb | |
Zeno Rogue | 2c171f7be4 | |
Zeno Rogue | 64a89e732f | |
Zeno Rogue | 7b3532a594 | |
Zeno Rogue | 70b7e24e96 | |
Zeno Rogue | 9326220310 | |
Zeno Rogue | c2f1f4371c | |
Zeno Rogue | 9e4c883001 | |
Zeno Rogue | eeb6373338 | |
Zeno Rogue | 6db4adb91c | |
Zeno Rogue | ec4b02d754 | |
Zeno Rogue | d4247e7b13 | |
Zeno Rogue | a74cdeeacc | |
Zeno Rogue | 2239d72bc8 | |
Zeno Rogue | 4d680e13c4 | |
Zeno Rogue | 23423e4016 | |
Zeno Rogue | 7a7af2a536 | |
Zeno Rogue | 9fbc73025e | |
Zeno Rogue | 66ea0804cf | |
Zeno Rogue | cab3cfe2f9 | |
Zeno Rogue | f62fcc12fc | |
Zeno Rogue | 9031b32cf4 | |
Zeno Rogue | 5076343223 | |
Zeno Rogue | dd5e9dbc6e | |
Zeno Rogue | 1d4dac0a50 | |
Zeno Rogue | 4aa707f197 | |
Zeno Rogue | 3670be5700 | |
Zeno Rogue | 78b75baf3a | |
Zeno Rogue | b617bc12a7 | |
Zeno Rogue | 6e695b5262 | |
Zeno Rogue | 2668841e5a | |
Zeno Rogue | 283fe020fc | |
Zeno Rogue | e1a78fe1ac | |
Zeno Rogue | f9b8551529 | |
Zeno Rogue | 8ac3bb29ab | |
Zeno Rogue | 8568f6489c | |
Zeno Rogue | 49ca18aef3 | |
Zeno Rogue | 3b341bb34b | |
Zeno Rogue | 77e5efa28f | |
Zeno Rogue | 50e5cc2c5a | |
Zeno Rogue | 0293680ea1 | |
Zeno Rogue | f3d28c9105 | |
Arthur O'Dwyer | 62629f3e70 | |
Zeno Rogue | b70b339f52 | |
Zeno Rogue | 529e27ea2f | |
Zeno Rogue | c89d98e832 | |
Zeno Rogue | 089db20356 | |
Zeno Rogue | 572866b67a | |
Zeno Rogue | b2668e4cf5 | |
Zeno Rogue | 01ede9681e | |
Zeno Rogue | bb22d363c8 | |
Zeno Rogue | fd1be4beb8 | |
Zeno Rogue | 04f31aa637 | |
Arthur O'Dwyer | 28880f2985 | |
Arthur O'Dwyer | 10d0ed8900 | |
Arthur O'Dwyer | ced3bbcad4 | |
Zeno Rogue | a250a4d430 | |
Zeno Rogue | c1584e9ece | |
Zeno Rogue | e3357c9b26 | |
Zeno Rogue | 29d50a9f21 | |
Zeno Rogue | 0b2aee0b40 | |
Zeno Rogue | 4b5a1621e8 | |
Zeno Rogue | 6a9ed169eb | |
Zeno Rogue | 838b34762e | |
Zeno Rogue | 18d042b9eb | |
Zeno Rogue | 0e1d7c024e | |
Zeno Rogue | 73e98644d3 | |
Zeno Rogue | 9e999ef30f | |
Zeno Rogue | b7f55e9f87 | |
Zeno Rogue | 01748ac77b | |
Zeno Rogue | 610d64d22a | |
Zeno Rogue | a5ada45164 | |
Zeno Rogue | 442a7d3c74 | |
Zeno Rogue | b123900b52 | |
Zeno Rogue | 37d558944e | |
Zeno Rogue | 56b5d52534 | |
Zeno Rogue | 42c47d0388 | |
Zeno Rogue | 36607319fd | |
Zeno Rogue | f37c4ba165 | |
Zeno Rogue | b9eac3f6ae | |
Zeno Rogue | 933361d394 | |
Zeno Rogue | 83b49caa5f | |
Zeno Rogue | f2f62cf296 | |
Zeno Rogue | 27bedb19ed | |
Zeno Rogue | 27b572a44a | |
Zeno Rogue | cfa01d878c | |
Zeno Rogue | 937da384e7 | |
Zeno Rogue | f3a0855df2 | |
Zeno Rogue | e22c34b343 | |
Zeno Rogue | b018582f44 | |
Zeno Rogue | ccb5068964 | |
Zeno Rogue | 63fc2c9c92 | |
Zeno Rogue | 53324a9eeb | |
Zeno Rogue | 1b76ab495e | |
Zeno Rogue | 97be7618e6 | |
Zeno Rogue | 74f1a93dc3 | |
Zeno Rogue | 246034f4cb | |
Zeno Rogue | 260c30c218 | |
Zeno Rogue | 394f8052b4 | |
Zeno Rogue | 44e9c3e317 | |
Zeno Rogue | 000726f450 | |
Zeno Rogue | 535d86a1c8 | |
Zeno Rogue | a70940b3ee | |
Zeno Rogue | 590d8021c6 | |
Zeno Rogue | 07857e612a | |
Zeno Rogue | beb679ccab | |
Zeno Rogue | 67d38feabd | |
Zeno Rogue | 3e1228b7c7 | |
Zeno Rogue | dff8db44b0 | |
Zeno Rogue | 757579fb18 | |
Zeno Rogue | 3eb2813667 | |
Zeno Rogue | cb05649732 | |
Zeno Rogue | 3069dbd316 | |
Zeno Rogue | a7cf3c4d1c | |
Zeno Rogue | e4562be1f5 | |
Zeno Rogue | d9d92bfd84 | |
Zeno Rogue | b98ac1c487 | |
Zeno Rogue | 6806a0e7e3 | |
Zeno Rogue | ea193d23b1 | |
Zeno Rogue | 9ab2b2bbd8 | |
Zeno Rogue | 3a3317d0be | |
Zeno Rogue | e666faba31 | |
Zeno Rogue | 392d3c075f | |
Zeno Rogue | c9a9a38188 | |
Zeno Rogue | f50964d576 | |
Zeno Rogue | 22636060dc | |
Zeno Rogue | b4e280c43f | |
Zeno Rogue | dc95d4c3e6 | |
Zeno Rogue | d8f64b62ac | |
Zeno Rogue | 5cc7a4e527 | |
Zeno Rogue | fe6d7abec2 | |
Zeno Rogue | f212f6173b | |
Zeno Rogue | 8a124f6890 | |
Zeno Rogue | 563d16c9c1 | |
Zeno Rogue | 4668321e4e | |
Zeno Rogue | b6f13b953b | |
Zeno Rogue | 4d4874f7ac | |
Zeno Rogue | 234a691ab6 | |
Zeno Rogue | 5057f10358 | |
Zeno Rogue | a13ba9bdbe | |
Zeno Rogue | c914bf86e0 | |
Zeno Rogue | e658a471da | |
Zeno Rogue | a088d46e6d | |
Zeno Rogue | 1554caa7b4 | |
Zeno Rogue | c896b3ecd6 | |
Zeno Rogue | debdcae057 | |
Zeno Rogue | 22947c7fd1 | |
Zeno Rogue | 522436ba96 | |
Zeno Rogue | 4ca3d41ad5 | |
Zeno Rogue | 7a09ab2cb0 | |
Zeno Rogue | c42a06772b | |
Zeno Rogue | 4c59d87a34 | |
Zeno Rogue | fb3b526ae6 | |
Zeno Rogue | 301236d154 | |
Zeno Rogue | d2c601834a | |
Zeno Rogue | 097ded1bd0 | |
Zeno Rogue | 07aa843f18 | |
Zeno Rogue | 0cdbb0f8f4 | |
Zeno Rogue | b31ceaf3df | |
Zeno Rogue | 108f4fb437 | |
Zeno Rogue | 38baf6605a | |
Zeno Rogue | 861543b9e5 | |
Zeno Rogue | 1211de5603 | |
Zeno Rogue | bcc86e7b30 | |
Zeno Rogue | 9e46638733 | |
Zeno Rogue | ec5e774613 | |
Zeno Rogue | c75f7b9cd4 | |
Zeno Rogue | 919725eabb | |
Zeno Rogue | 9ecd621fe8 | |
Zeno Rogue | 56be838b40 | |
Zeno Rogue | 32911e2b67 | |
Zeno Rogue | 4b61d63ef5 | |
Zeno Rogue | a830fa73b3 | |
Zeno Rogue | 0167e284cc | |
Zeno Rogue | 9a9ecd3c8c | |
Zeno Rogue | 286f98fb49 | |
Zeno Rogue | 2c0afce4ca | |
Zeno Rogue | dfb3626568 | |
Zeno Rogue | 34574ad050 | |
Zeno Rogue | 0168e4c7a8 | |
Zeno Rogue | 92cf27a056 | |
Zeno Rogue | ac336f7035 | |
Zeno Rogue | aebcabb99c | |
Zeno Rogue | 754e774bcf | |
Zeno Rogue | c6ccee56f9 | |
Zeno Rogue | 554e9c5cfc | |
Zeno Rogue | a041016446 | |
Zeno Rogue | f972170869 | |
Zeno Rogue | e218b0b19f | |
Zeno Rogue | 901521631f | |
Zeno Rogue | 41fda7545e | |
Zeno Rogue | aa729c912c | |
Zeno Rogue | 59dd09173a | |
Zeno Rogue | e68cd6736e | |
Zeno Rogue | 31976a1994 | |
Zeno Rogue | 51fc7b6573 | |
Zeno Rogue | 965996b3fb | |
Zeno Rogue | 5054b12b93 | |
Zeno Rogue | 61610282ca | |
Zeno Rogue | 2153626309 | |
Zeno Rogue | 03b0a80be0 | |
Zeno Rogue | 3850d8dbeb | |
Zeno Rogue | 20546133c3 | |
Zeno Rogue | e069a2cd46 | |
Zeno Rogue | d587f29a91 | |
Zeno Rogue | 3e8dd6f549 | |
Zeno Rogue | 3fdd6d4967 | |
Zeno Rogue | 09a43c5646 | |
Zeno Rogue | 6aed2c58e8 | |
Zeno Rogue | b808d78e7f | |
Zeno Rogue | c6b27c5b27 | |
Zeno Rogue | da687e8874 | |
Zeno Rogue | d179976281 | |
Zeno Rogue | bde2025ce3 | |
Zeno Rogue | 9658950e6a | |
Zeno Rogue | a5e327f67f | |
Zeno Rogue | ccf9abc2b6 | |
Zeno Rogue | d1d06b9941 | |
Zeno Rogue | 02d1fbd1e7 | |
Zeno Rogue | 949ee1b382 | |
Zeno Rogue | 2d74cfe6c4 | |
Zeno Rogue | f2cb72aaeb | |
Zeno Rogue | 24cd670de0 | |
Zeno Rogue | c03e9cfeb4 | |
Zeno Rogue | d9f01c67d1 | |
Zeno Rogue | 4bcd23af08 | |
Zeno Rogue | 71d49b7198 | |
Zeno Rogue | 1f834d3def | |
Zeno Rogue | 9932a034fc | |
Zeno Rogue | c95395f574 | |
Zeno Rogue | 494a65d16e | |
Zeno Rogue | 1359784e65 | |
Zeno Rogue | fd3cc72508 | |
Zeno Rogue | a70e799081 | |
Zeno Rogue | a9d76c861c | |
Zeno Rogue | 56916e8bc6 | |
Zeno Rogue | b76db976f0 | |
Zeno Rogue | 60d7d1da7e | |
Zeno Rogue | e6738f6c20 | |
Zeno Rogue | 2e1e14c1a2 | |
Zeno Rogue | f22abb7def | |
Zeno Rogue | c77a5cef22 | |
Zeno Rogue | a0aeb6f792 | |
Zeno Rogue | 37fa49aab8 | |
Zeno Rogue | 17fc76c0eb | |
Zeno Rogue | d5064db846 | |
Zeno Rogue | fccf07a07d | |
Zeno Rogue | 542ce23b76 | |
Zeno Rogue | 97c24d7dfe | |
Zeno Rogue | 58a1b085c7 | |
Zeno Rogue | 3692ef68b9 | |
Zeno Rogue | 894252caf2 | |
Zeno Rogue | 07c6a596e0 | |
Zeno Rogue | 227b4a15f7 | |
Zeno Rogue | 882fecf792 | |
Zeno Rogue | a6c3ea03e4 | |
Zeno Rogue | cca6b1b721 | |
Zeno Rogue | 043fc38dc6 | |
Zeno Rogue | cad46dc16f | |
Zeno Rogue | f9a951a2d1 | |
Zeno Rogue | 9c462b2334 | |
Zeno Rogue | f9b0dcf8a0 | |
Zeno Rogue | 557166c561 | |
Zeno Rogue | 3541a39119 | |
Zeno Rogue | 7dc21f32de | |
Zeno Rogue | 8ede45cb12 | |
Zeno Rogue | b49a52d6af | |
Zeno Rogue | d4e71b78c6 | |
Zeno Rogue | 3f1dc8a4c4 | |
Zeno Rogue | 0410f54d43 | |
Zeno Rogue | 782b6ab4f8 | |
Zeno Rogue | 921ec7ff8d | |
Zeno Rogue | 6a1601becf | |
Zeno Rogue | a8b75c317a | |
Zeno Rogue | 9f85af3068 | |
Zeno Rogue | f57157435e | |
Zeno Rogue | 0c473559f3 | |
Zeno Rogue | e63feddb7c | |
Zeno Rogue | 804c3897b8 | |
Zeno Rogue | 70842eb6e9 | |
Zeno Rogue | 1271c9162a | |
Zeno Rogue | d389a40bd9 | |
Zeno Rogue | 5a4f6595e1 | |
Zeno Rogue | 9832285260 | |
Zeno Rogue | 31cce8aa2c | |
Zeno Rogue | b5343d5696 | |
Zeno Rogue | 79cde326af | |
Zeno Rogue | a02cfe2062 | |
Zeno Rogue | 3ded56524d | |
Zeno Rogue | 5b47779028 | |
Zeno Rogue | e9c2278e8e | |
Zeno Rogue | a471025346 | |
Zeno Rogue | 3b2c87838d | |
Zeno Rogue | 8760ac4cfb | |
Zeno Rogue | 3e81697164 | |
Zeno Rogue | 0b6be1caff | |
Zeno Rogue | d5e7f22073 | |
Zeno Rogue | e93187a81f | |
Zeno Rogue | decdfc7806 | |
Zeno Rogue | dfcfee087d | |
Zeno Rogue | 7806f1cb70 | |
Zeno Rogue | 1c2dbcc7d9 | |
Zeno Rogue | 2576918b8a | |
Zeno Rogue | 2a05642198 | |
Zeno Rogue | d04a015bd0 | |
Zeno Rogue | 5a33967711 | |
Zeno Rogue | f0b52b7034 | |
Zeno Rogue | 14aaa7ecea | |
Zeno Rogue | 7dbb60d3f8 | |
Zeno Rogue | 25fb183059 | |
Zeno Rogue | f822d5b215 | |
Zeno Rogue | 0a9141d940 | |
Zeno Rogue | d1813b5ad1 | |
Zeno Rogue | 8c3b073e0e | |
Zeno Rogue | d4e264bc9b | |
Zeno Rogue | f99e95b914 | |
Zeno Rogue | a9b6452d25 | |
Zeno Rogue | 511ffe8498 | |
Zeno Rogue | 121df0d9c7 | |
Zeno Rogue | e3a4ca5aa7 | |
Zeno Rogue | 86838ac307 | |
Zeno Rogue | 1dac5c731b | |
Zeno Rogue | 3baf09be25 | |
Zeno Rogue | 014f88132a | |
Zeno Rogue | e906cb985b | |
Zeno Rogue | 7e023e8092 | |
Zeno Rogue | eaaeac8624 | |
Zeno Rogue | 610338329b | |
Zeno Rogue | 3793bb00c3 | |
Zeno Rogue | 06d250e6a5 | |
Zeno Rogue | a0343f6108 | |
Zeno Rogue | e61321aea3 | |
Zeno Rogue | 968dfb1aac | |
Zeno Rogue | e2c5420c96 | |
Zeno Rogue | 17579d8301 | |
Zeno Rogue | b085426f2c | |
Zeno Rogue | 342c7c4484 | |
Zeno Rogue | fe4786d768 | |
Zeno Rogue | 759de3274a | |
Zeno Rogue | a47dbc5dd5 | |
Zeno Rogue | a3c861ec9e | |
Zeno Rogue | f8b6b28c75 | |
Zeno Rogue | d13c939ff6 | |
Zeno Rogue | 314a7af3fd | |
Zeno Rogue | cd391412aa | |
Zeno Rogue | 08bf3fe3d6 | |
Zeno Rogue | 7e79661ce0 | |
Zeno Rogue | 4c10fd6aae | |
Zeno Rogue | 44454c479a | |
Zeno Rogue | defeaf2cc6 | |
Zeno Rogue | 56ca00df82 | |
Zeno Rogue | fa9365466c | |
Zeno Rogue | 9fa2ba72fe | |
Zeno Rogue | 15623fd84d | |
Zeno Rogue | a0f91faf67 | |
Zeno Rogue | 1e68511d46 | |
Zeno Rogue | d3da7dddc9 | |
Zeno Rogue | 2ec531e056 | |
Zeno Rogue | 9d483b1442 | |
Zeno Rogue | 39dcaa9e15 | |
Zeno Rogue | e1ec1ef5b9 | |
Zeno Rogue | 1a97becdf0 | |
Zeno Rogue | 8dfa0efbcf | |
Zeno Rogue | 8efec97b24 | |
Jacob Mandelson | 7470b6996d | |
Zeno Rogue | de0e51412c | |
Zeno Rogue | 3faedc295b | |
Zeno Rogue | de6f5ba97a | |
Zeno Rogue | 3416f09381 | |
Zeno Rogue | bf6220913c | |
Zeno Rogue | 9c0ff85a98 | |
Zeno Rogue | 76d432aa9c | |
Zeno Rogue | 426c350a59 | |
Zeno Rogue | b854f68a88 | |
Zeno Rogue | acfa454114 | |
Zeno Rogue | 732d80965f | |
Zeno Rogue | f9d28371b7 | |
Zeno Rogue | 15540e91e6 | |
Zeno Rogue | 1b7f4b869e | |
Zeno Rogue | 02f0b1e714 | |
Zeno Rogue | 4bface6860 | |
Zeno Rogue | 2527398a3e | |
Zeno Rogue | 5986f02025 | |
Zeno Rogue | a434f3b063 | |
Zeno Rogue | 631e44f871 | |
Zeno Rogue | 2370084b11 | |
Zeno Rogue | eb867ecccc | |
Zeno Rogue | 2a45504580 | |
Zeno Rogue | 12a9ba163f | |
Zeno Rogue | c862a94e46 | |
Zeno Rogue | e0e1182d97 | |
Zeno Rogue | e898c61921 | |
Zeno Rogue | b6503f0059 | |
Zeno Rogue | b8f916df3a | |
Zeno Rogue | 0f9b30f51b | |
Zeno Rogue | ef556185db | |
Zeno Rogue | 7bd5abbdd6 | |
Zeno Rogue | 5473c1645c | |
Zeno Rogue | ad90aecee7 | |
Zeno Rogue | 2a354786e4 | |
Zeno Rogue | b8059c0528 | |
Zeno Rogue | 66671145a9 | |
Jacob Mandelson | 9982f88a41 | |
Zeno Rogue | 999b26e818 | |
Zeno Rogue | fa528e75d2 | |
Zeno Rogue | cf90d4e3c4 | |
Zeno Rogue | 16e1e0d516 | |
Zeno Rogue | b708391dd2 | |
Zeno Rogue | 7aa11a83ec | |
Zeno Rogue | 19fbb43bab | |
Zeno Rogue | a07dac637b | |
Zeno Rogue | fa03b4f275 | |
Zeno Rogue | 65883a53cf | |
Zeno Rogue | 5a40534c85 | |
Zeno Rogue | f73660c801 | |
Zeno Rogue | acdac858a3 | |
Zeno Rogue | a3b815741d | |
Zeno Rogue | 5764e46bbe | |
Zeno Rogue | 573304faab | |
Zeno Rogue | 1eaa6d4dd9 | |
Zeno Rogue | e40bd436af | |
Zeno Rogue | d108f27dcf | |
Zeno Rogue | 53483005cf | |
Zeno Rogue | 9bda1ecbf3 | |
Zeno Rogue | 9853de5775 | |
Zeno Rogue | c53972c4b0 | |
Zeno Rogue | f252456578 | |
Zeno Rogue | 37aa0dadee | |
Zeno Rogue | 23f8be380d | |
Zeno Rogue | 7cf7c6b216 | |
Zeno Rogue | f820f356b1 | |
Zeno Rogue | ec4ceb5347 | |
Zeno Rogue | c5e05bd199 | |
Zeno Rogue | 1295ea7920 | |
Zeno Rogue | 03336ecae0 | |
Zeno Rogue | 5bdae71879 | |
Zeno Rogue | 29d1a0c191 | |
Zeno Rogue | fb2a3a7931 | |
Zeno Rogue | c2070a6fd6 | |
Zeno Rogue | c7de7df6fe | |
Zeno Rogue | d0f6a94418 | |
Zeno Rogue | 903c654c44 | |
Zeno Rogue | 597d95ccc2 | |
Zeno Rogue | 6115e5a96d | |
Zeno Rogue | b104cc0361 | |
Zeno Rogue | 7d600ecdfe | |
Zeno Rogue | 472443a6d2 | |
Zeno Rogue | 0fd676e6d3 | |
Zeno Rogue | fe6ae71990 | |
Zeno Rogue | 60c041e397 | |
Zeno Rogue | 9fd7d94af2 | |
Zeno Rogue | c900d6823e | |
Zeno Rogue | e1ed7284dd | |
Zeno Rogue | ce90bb6db2 | |
Zeno Rogue | 23e4f90685 | |
Zeno Rogue | b89ba69fd9 | |
Zeno Rogue | 6a1cb13c11 | |
Zeno Rogue | 73fc9192ce | |
Zeno Rogue | 52d38665ae | |
Zeno Rogue | 2d4cb637f2 | |
Zeno Rogue | e29b28ddb9 | |
Zeno Rogue | e3b87792aa | |
Zeno Rogue | e8c03acf07 | |
Zeno Rogue | 2aafe6829c | |
Zeno Rogue | f9fb1b9e84 | |
Zeno Rogue | cd673b2fd2 | |
Zeno Rogue | dea0c5cc58 | |
Zeno Rogue | 334c4715af | |
Zeno Rogue | 2fe39a6613 | |
Zeno Rogue | d67b157904 | |
Zeno Rogue | d4eb33cd71 | |
Zeno Rogue | a48f255c17 | |
Zeno Rogue | 53bc23e280 | |
Zeno Rogue | 3183e10168 | |
Zeno Rogue | caf5b5dc8e | |
Zeno Rogue | 01a3f620b0 | |
Zeno Rogue | 5b89cfdecf | |
Zeno Rogue | 793ae6fcd9 | |
Zeno Rogue | 3f44c71fea | |
Zeno Rogue | db6d9c0245 | |
Zeno Rogue | 373c0fe152 | |
Zeno Rogue | a14bceb681 | |
Zeno Rogue | 32491d6425 | |
Zeno Rogue | de9149a8cd | |
Zeno Rogue | 3811eebc8f | |
Zeno Rogue | 3e615d3c53 | |
Zeno Rogue | 4ee2c9faa3 | |
Zeno Rogue | 13a90006b8 | |
Zeno Rogue | 21e399648f | |
Zeno Rogue | d868548fa2 | |
Zeno Rogue | 8e004230a7 | |
Zeno Rogue | 93ebe337b5 | |
Zeno Rogue | 6056fce41a | |
Zeno Rogue | d8a0023c54 | |
Zeno Rogue | 7ffa2a3806 | |
Zeno Rogue | 941379ba2a | |
Zeno Rogue | f09b94bfcd | |
Zeno Rogue | a536a3bc61 | |
Zeno Rogue | 43f345234a | |
Zeno Rogue | 6950e0e1ba | |
Zeno Rogue | 5e0d05f10b | |
Zeno Rogue | 6be7951187 | |
Zeno Rogue | 9c04b39ed3 | |
Zeno Rogue | bc3b4841b7 | |
Zeno Rogue | 5f3c638653 | |
Zeno Rogue | e4c775b986 | |
Zeno Rogue | d305896c96 | |
Zeno Rogue | dc1aa2c4c0 | |
Zeno Rogue | bccb7b1d5d | |
Zeno Rogue | 637feb315a | |
Zeno Rogue | 8e17338585 | |
Zeno Rogue | a84596a355 | |
Zeno Rogue | 0b11c9388b | |
Zeno Rogue | 9ce2a90c33 | |
Zeno Rogue | ad93a6db0b | |
Zeno Rogue | 98690c225c | |
Zeno Rogue | 439850f74c | |
Zeno Rogue | c21d5373e5 | |
Zeno Rogue | c468c90463 | |
Zeno Rogue | 395cbf3668 | |
Zeno Rogue | 80c0b4bb0c | |
Zeno Rogue | b11e270eb5 | |
Zeno Rogue | 40ad4f04d2 | |
Zeno Rogue | ba03d33959 | |
Zeno Rogue | 5c2b206433 | |
Zeno Rogue | a6d53944cd | |
Zeno Rogue | c0c6f44c19 | |
Zeno Rogue | 31a5a9e5c7 | |
Zeno Rogue | 1e6e75c7d4 | |
Zeno Rogue | ce72e55353 | |
Zeno Rogue | 8e577bc2de | |
Zeno Rogue | 43b3a13dc4 | |
Zeno Rogue | 9ca8f20dc3 | |
Zeno Rogue | fd55d4de89 | |
Zeno Rogue | 3af71864c7 | |
Zeno Rogue | c155491ca2 | |
Zeno Rogue | 0873fe2088 | |
Zeno Rogue | a45ae2cd21 | |
Zeno Rogue | d7fe4af1e9 | |
Zeno Rogue | 9e2059e72b | |
Zeno Rogue | a73f85c88a | |
Zeno Rogue | 9e6e8e02b0 | |
Zeno Rogue | 56f5fee8dd | |
Zeno Rogue | e4239a11a4 | |
Zeno Rogue | 85dffdbeff | |
Zeno Rogue | 8744420504 | |
Zeno Rogue | bab78c8179 | |
Zeno Rogue | 146c075210 | |
Zeno Rogue | 02e8dec195 | |
Zeno Rogue | 3013e956b9 | |
Zeno Rogue | 2d21e9122a | |
Zeno Rogue | 8a5e768b51 | |
Zeno Rogue | 4ff8f4b68a | |
Zeno Rogue | b6c257a264 | |
Zeno Rogue | a7f95cfe3d | |
Zeno Rogue | faee70ec3e | |
Zeno Rogue | 763a932aca | |
Zeno Rogue | 742355433a | |
Zeno Rogue | ce93910f0f | |
Zeno Rogue | 5f3c58154c | |
Zeno Rogue | 8118ecd4f3 | |
Zeno Rogue | 6259815f7f | |
Zeno Rogue | 5dcddc9365 | |
Zeno Rogue | 5c1ab36b16 | |
Zeno Rogue | 351ef88df7 | |
Zeno Rogue | 4351f99432 | |
Zeno Rogue | 8e49baef0e | |
Zeno Rogue | 6d0c0daa40 | |
Zeno Rogue | 88ca5c920f | |
Zeno Rogue | 14d6e33768 | |
Zeno Rogue | 64b5c52b80 | |
Zeno Rogue | 8136d9b554 | |
Zeno Rogue | f02073a35f | |
Zeno Rogue | e4839a19b7 | |
Zeno Rogue | 8dede9f8a0 | |
Zeno Rogue | 0e2b9d07ee | |
Zeno Rogue | b7a4997509 | |
Zeno Rogue | 3f2a84be5f | |
Zeno Rogue | 57b762dfe8 | |
Zeno Rogue | 63032a42a2 | |
Zeno Rogue | f5f6bdcf3b | |
Zeno Rogue | dfb73bbdaa | |
Zeno Rogue | d32b0855a0 | |
Zeno Rogue | 1fc48be781 | |
Zeno Rogue | 4b3bfb9932 | |
Zeno Rogue | 28146b13f7 | |
Zeno Rogue | 3052a9f29b | |
Zeno Rogue | 2d5bfc7b5a | |
Zeno Rogue | dd01cd9af4 | |
Zeno Rogue | 2182f442d9 | |
Zeno Rogue | 731fcee7ce | |
Zeno Rogue | 82ce9914c5 | |
Zeno Rogue | 601457ebc2 | |
Zeno Rogue | 32546cee4a | |
Zeno Rogue | bc96b7fba9 | |
Zeno Rogue | 1dced09f71 | |
Zeno Rogue | 502e2c6102 | |
Zeno Rogue | a55ed32fa1 | |
Zeno Rogue | 016b0a95bc | |
Zeno Rogue | 7d0235b459 | |
Zeno Rogue | 7068b41d28 | |
Zeno Rogue | 78fb0cca20 | |
Zeno Rogue | 2999818eaf | |
Zeno Rogue | 86492d1181 | |
Zeno Rogue | 080e853364 | |
Zeno Rogue | 176d5b76c1 | |
Zeno Rogue | 868ffba2d4 | |
Zeno Rogue | 978d9d6eda | |
Zeno Rogue | 09ae23b310 | |
Zeno Rogue | 9dee000a6a | |
Zeno Rogue | 8ca0ef23fa | |
Zeno Rogue | 272523d185 | |
Zeno Rogue | 0bedb56296 | |
Zeno Rogue | 1f3db08ac4 | |
Zeno Rogue | 006a325d36 | |
Zeno Rogue | 547c0785ef | |
Zeno Rogue | c2dc16f8ca | |
Zeno Rogue | c252e8f51e | |
Zeno Rogue | 9793ebbff8 | |
Zeno Rogue | a5ff327ef3 | |
Zeno Rogue | 22d4a49b68 | |
Zeno Rogue | 1ac28797de | |
Zeno Rogue | 14ac186fe2 | |
Zeno Rogue | 8884fbc11f | |
Zeno Rogue | e68c807f68 | |
Zeno Rogue | 8e726d1231 | |
Zeno Rogue | 534448967f | |
Zeno Rogue | d623593392 | |
Zeno Rogue | 72c1cf300e | |
Zeno Rogue | be747b7a44 | |
Zeno Rogue | 805cb4dc0c | |
Zeno Rogue | 014b4a8b23 | |
Zeno Rogue | 0e83580199 | |
Zeno Rogue | a3b8cdb149 | |
Zeno Rogue | 8de0f4e2e4 | |
Zeno Rogue | d5e5e65745 | |
Zeno Rogue | 2e0b3c5811 | |
Zeno Rogue | 6b337bc262 | |
Zeno Rogue | 14fd283dd2 | |
Zeno Rogue | 436f782541 | |
Zeno Rogue | 5f645f2f25 | |
Zeno Rogue | b2f9038cd4 | |
Zeno Rogue | 814467082f | |
Zeno Rogue | 5da1b8f88e | |
Zeno Rogue | 4da63f57dc | |
Zeno Rogue | e1301e10bd | |
Zeno Rogue | 70718b2602 | |
Zeno Rogue | 1210de672e | |
Zeno Rogue | dfbf553608 | |
Zeno Rogue | 78356114c1 | |
Zeno Rogue | 4f0d16f9ed | |
Zeno Rogue | a525de9759 | |
Zeno Rogue | e1ce20cabe | |
Zeno Rogue | db43ea9de8 | |
Zeno Rogue | 68b7beb753 | |
Zeno Rogue | d61e498d4b | |
Zeno Rogue | 5edb1dba04 | |
Zeno Rogue | 16a2aa0f4b | |
Zeno Rogue | 7195d688d0 | |
Zeno Rogue | ad7cbac338 | |
Zeno Rogue | 90977aacaf | |
Zeno Rogue | 74b59d3331 | |
Zeno Rogue | 9b91d46f47 | |
Zeno Rogue | 735db2bcc4 | |
Zeno Rogue | 6473ff8b45 | |
Zeno Rogue | a20ee8e716 | |
Zeno Rogue | 585ab12e4f | |
Zeno Rogue | a67081adf8 | |
Zeno Rogue | e8b93600f7 | |
Zeno Rogue | 33380fba89 | |
Zeno Rogue | 839beabbc9 | |
Zeno Rogue | 6b262104fd | |
Zeno Rogue | 3233ecbfde | |
Zeno Rogue | 91ac8a600b | |
Zeno Rogue | 9498a1de03 | |
Zeno Rogue | 18cc8cbba3 | |
Zeno Rogue | 10e543a44e | |
Zeno Rogue | 7dac26a85a | |
Zeno Rogue | 3b1b263c95 | |
Zeno Rogue | 4e3c72551a | |
Zeno Rogue | 62ffefc0cc | |
Zeno Rogue | f9552eb74e | |
Zeno Rogue | d7f7f567f7 | |
Zeno Rogue | 45d2a2c4bb | |
Zeno Rogue | 1b8e2623ac | |
Zeno Rogue | 4356f41621 | |
Zeno Rogue | e9c04e1e77 | |
Zeno Rogue | 557d3206a8 | |
Zeno Rogue | 39ce564d40 | |
Zeno Rogue | f61adc2865 | |
Zeno Rogue | 63b17a605c | |
Zeno Rogue | 5477b0e863 | |
Zeno Rogue | 0dd29dd7cf | |
Zeno Rogue | aee6285505 | |
Zeno Rogue | 8c601bb575 | |
Zeno Rogue | 1bb8056e0d | |
Zeno Rogue | 9b3324b7eb | |
Zeno Rogue | 0febf06462 | |
Zeno Rogue | 70421ed506 | |
Zeno Rogue | 852dc94fad | |
Zeno Rogue | 0570d3afee | |
Zeno Rogue | 07931fcf54 | |
Zeno Rogue | 80ab199607 | |
Zeno Rogue | acaa04dace | |
Zeno Rogue | fbeac1354d | |
Zeno Rogue | 69af3ee4e3 | |
Zeno Rogue | 0c59d626bb | |
Zeno Rogue | d334062656 | |
Zeno Rogue | 689f64ed98 | |
Zeno Rogue | 107cae8f5c | |
Zeno Rogue | 2857bc95dc | |
Zeno Rogue | 0fd929a53b | |
Zeno Rogue | 08b72c52b3 | |
Zeno Rogue | bcbd5808f9 | |
Zeno Rogue | ababcdfee8 | |
Zeno Rogue | 2f2e770d64 | |
Zeno Rogue | 49c871cf19 | |
Zeno Rogue | 3e733ae6e9 | |
Zeno Rogue | 90dd9e9866 | |
Zeno Rogue | 41d28b267f | |
Zeno Rogue | 429ed81293 | |
Zeno Rogue | bf001926c2 | |
Zeno Rogue | adfab30c62 | |
Zeno Rogue | 8a7b35e3ee | |
Zeno Rogue | cfc62c5ee0 | |
Zeno Rogue | 9337240d49 | |
Zeno Rogue | 0f4cb95adc | |
Zeno Rogue | fcfadf9eaa | |
Zeno Rogue | 2524fb76d0 | |
Zeno Rogue | 31f7db81c7 | |
Zeno Rogue | 2e9ee75dc3 | |
Zeno Rogue | 42f96b768c | |
Zeno Rogue | 0770a11164 | |
Zeno Rogue | 5d13663695 | |
Zeno Rogue | 2cb27a165b | |
Jacob Mandelson | 2e3d0ecd7c | |
Zeno Rogue | 301dad5d7b | |
Zeno Rogue | 9297c94028 | |
Zeno Rogue | 828c185520 | |
Zeno Rogue | 84344e7d5d | |
Zeno Rogue | 6450f7c8a6 | |
Zeno Rogue | 97fb10b6f0 | |
Zeno Rogue | 0faf07741c | |
Zeno Rogue | 67b70ea7fd | |
Zeno Rogue | b7aae63b90 | |
Zeno Rogue | 06523e063e | |
Zeno Rogue | 563b9c1f74 | |
Zeno Rogue | 612356db7f | |
Zeno Rogue | cf75e6f2ab | |
Zeno Rogue | 13b8230238 | |
Zeno Rogue | 6fff924753 | |
Zeno Rogue | 16d142711a | |
Zeno Rogue | 1cbaf36698 | |
Zeno Rogue | ba009a80b2 | |
Zeno Rogue | af851a1d70 | |
Zeno Rogue | f2785d22a4 | |
Zeno Rogue | 2bab227d4e | |
Zeno Rogue | e65723002f | |
Zeno Rogue | c65d17063f | |
Zeno Rogue | 266d6fd50d | |
Zeno Rogue | b4302ac6b4 | |
Zeno Rogue | 035532ef26 | |
Zeno Rogue | 774c8a9744 | |
Zeno Rogue | 4daacb7337 | |
Zeno Rogue | 622bb9e5f7 | |
Zeno Rogue | 320aac6b9a | |
Zeno Rogue | 2bc0de05a6 | |
Zeno Rogue | 8e1c05d3cf | |
Zeno Rogue | 0ff46ff143 | |
Zeno Rogue | 3ab4915ff4 | |
Zeno Rogue | 5c4cf73937 | |
Jacob Mandelson | 383dd421bd | |
Jacob Mandelson | 94d90cf5e0 | |
Zeno Rogue | 1482a7aca2 | |
Zeno Rogue | 85483d62dd | |
Zeno Rogue | cfac1cf3ab | |
Zeno Rogue | 303d173bf6 | |
Zeno Rogue | 2d1cff6549 | |
Zeno Rogue | 7267b3c7ce | |
Zeno Rogue | fb6e8b72da | |
Zeno Rogue | 32f876dc4f | |
Zeno Rogue | 0639c9c027 | |
Zeno Rogue | 64a613572a | |
Zeno Rogue | 18f571b683 | |
Zeno Rogue | f606174445 | |
Zeno Rogue | 0c22ab2b4b | |
Zeno Rogue | 6ef282173f | |
Zeno Rogue | 87921fe0f9 | |
Zeno Rogue | 419837a375 | |
Zeno Rogue | 1ac22f4be1 | |
Zeno Rogue | 3ce5597cc1 | |
Zeno Rogue | f4282e1118 | |
Zeno Rogue | a83228cd15 | |
Zeno Rogue | efe7eea3de | |
Zeno Rogue | 1791190493 | |
Zeno Rogue | c2acb4f271 | |
Zeno Rogue | e653f4eaeb | |
Zeno Rogue | 60a3f21b9f | |
Zeno Rogue | 7ca6eb1658 | |
Zeno Rogue | a71207800b | |
Zeno Rogue | 3506ccac13 | |
Zeno Rogue | 5cdbca3b21 | |
Zeno Rogue | e011f86671 | |
Zeno Rogue | 5a19fffd8f | |
Zeno Rogue | bb5fa51965 | |
Zeno Rogue | d828ff0e7e | |
Zeno Rogue | fa7145586f | |
Zeno Rogue | a1695a82d0 | |
Zeno Rogue | c8a1c8b5d7 | |
Zeno Rogue | 4c30e6051f | |
Zeno Rogue | 15d97a8cd1 | |
Zeno Rogue | d39623fdd5 | |
Zeno Rogue | fd9d58073a | |
Zeno Rogue | 7ad4668623 | |
Zeno Rogue | e7bebaa79c | |
Zeno Rogue | b8b1df01e7 | |
Zeno Rogue | 472cbe205b | |
Zeno Rogue | b89204e616 | |
Zeno Rogue | fc2e10739d | |
Zeno Rogue | 8294246449 | |
Zeno Rogue | caa4ac5bb4 | |
Zeno Rogue | 5c507e58fd | |
Zeno Rogue | 9ab7bfeaae | |
Zeno Rogue | cb4955e397 | |
Zeno Rogue | 65095edea8 | |
Zeno Rogue | bcadbdbcab | |
Zeno Rogue | 29ba4138a4 | |
Zeno Rogue | 06f450af22 | |
Zeno Rogue | 3408c1119f | |
Zeno Rogue | 40ca8b8553 | |
Zeno Rogue | bf86077ebf | |
Zeno Rogue | 6b8c177c33 | |
Zeno Rogue | bbbf2f9cd0 | |
Zeno Rogue | 0fc2dc2d65 | |
Zeno Rogue | 10e9c0fabe | |
Zeno Rogue | 781d6f0257 | |
Zeno Rogue | 3b5a5c01c5 | |
Zeno Rogue | 42a1615d0d | |
Zeno Rogue | 5ca19a0d9b | |
Zeno Rogue | 72bdd123a2 | |
Zeno Rogue | 601250f2de | |
Zeno Rogue | 0d2f054d2b | |
Jacob Mandelson | 7e2b8baf2f | |
Zeno Rogue | 93892718c5 | |
Zeno Rogue | 49564b2e0e | |
Zeno Rogue | 3c867a7ff0 | |
Zeno Rogue | 0c38c4ad68 | |
Zeno Rogue | 122ea6dfb4 | |
Zeno Rogue | 875b0159e6 | |
Zeno Rogue | 9c603c13d4 | |
Zeno Rogue | e74f2e3c78 | |
Zeno Rogue | 10856a6694 | |
Zeno Rogue | 55d4f93873 | |
Zeno Rogue | 4e7b95e346 | |
Zeno Rogue | 971ce2aade | |
Zeno Rogue | e129ce08c6 | |
Zeno Rogue | 6e1c32787a | |
Zeno Rogue | 38fddfa43f | |
Zeno Rogue | 1ace6d4fff | |
Zeno Rogue | 1d41b80b2a | |
Zeno Rogue | c6dad6ee99 | |
Zeno Rogue | 17e2a56320 | |
Zeno Rogue | 5423eebc2d | |
Zeno Rogue | 0ddc6c722f | |
Zeno Rogue | 9121eb7d72 | |
Zeno Rogue | a5a7e8a5fa | |
Zeno Rogue | 1cde76c880 | |
Zeno Rogue | 970c2acc96 | |
Zeno Rogue | 45141a9df0 | |
Zeno Rogue | a7ca4c2902 | |
Zeno Rogue | 7a6df6f060 | |
Zeno Rogue | e6d0ff8789 | |
Zeno Rogue | d218896b63 | |
Zeno Rogue | 7f0bf3b269 | |
Zeno Rogue | 6ac17b31f1 | |
Zeno Rogue | f666f51bcd | |
Zeno Rogue | c10906d349 | |
Zeno Rogue | 4cdc7db18d | |
Zeno Rogue | 73c689211f | |
Zeno Rogue | 9184532036 | |
Zeno Rogue | 97a4f13ff8 | |
Zeno Rogue | 757660edd0 | |
Zeno Rogue | 4e0f99f60b | |
Zeno Rogue | 2bafda5f18 | |
Zeno Rogue | 5008609b95 | |
Zeno Rogue | 60d0d15dab | |
Zeno Rogue | d8da9639d0 | |
Zeno Rogue | 29f6bbbe90 | |
Zeno Rogue | 9284cb237a | |
Zeno Rogue | 35fa99460b | |
Zeno Rogue | 7e28ce278e | |
Zeno Rogue | 12316ed631 | |
Zeno Rogue | b76ab8ebdd | |
Zeno Rogue | 2168d5ad4c | |
Zeno Rogue | f3427c4968 | |
Zeno Rogue | 8b758bded9 | |
Zeno Rogue | 70b5da8178 | |
Zeno Rogue | a1cbf8c906 | |
Zeno Rogue | fe937cf20a | |
Zeno Rogue | 313666a240 | |
Zeno Rogue | 03b7804817 | |
Zeno Rogue | 6de6e71bd4 | |
Zeno Rogue | ddf8ea17e3 | |
Zeno Rogue | 8bf80dd96c | |
Zeno Rogue | 2a5cdf28c8 | |
Zeno Rogue | 6a626007bb | |
Zeno Rogue | 789770da43 | |
Zeno Rogue | 07ce60c3ef | |
Zeno Rogue | 8b6effba1b | |
Zeno Rogue | 8aaf06969c | |
Zeno Rogue | f4cf3440ff | |
Zeno Rogue | 6c88e9b2c3 | |
Zeno Rogue | 9004fdeee5 | |
Zeno Rogue | d44e8b6416 | |
Zeno Rogue | bef884c9dc | |
Zeno Rogue | 5a9e7e4069 | |
Zeno Rogue | 3369adfc98 | |
Zeno Rogue | 30839fdb15 | |
Zeno Rogue | f9fdc2ee0a | |
Zeno Rogue | 93727e433e | |
Zeno Rogue | 06c73ad9fb | |
Zeno Rogue | 21cbc2d621 | |
Jacob Mandelson | f2623ff6ab | |
Jacob Mandelson | 00c4d2c0a5 | |
Jacob Mandelson | 6b9728b385 | |
Zeno Rogue | 1aa4242ace | |
Zeno Rogue | a3e6d79607 | |
Zeno Rogue | 6514c8758e | |
Zeno Rogue | 5a6444b45a | |
Zeno Rogue | 0fb4033868 | |
Zeno Rogue | 31318862cb | |
Zeno Rogue | ac088d1d41 | |
Zeno Rogue | 1c24daea77 | |
Zeno Rogue | 628f19a0a0 | |
Zeno Rogue | c4a4b21296 | |
Zeno Rogue | 171b198cd8 | |
Zeno Rogue | 9c7f23e16e | |
Zeno Rogue | 3518c9abf3 | |
Zeno Rogue | 6fa7cdaf0a | |
Zeno Rogue | f161f9bf0a | |
Zeno Rogue | 80c02c7e38 | |
Zeno Rogue | 25997dc6c1 | |
Zeno Rogue | 1391a0e47f | |
Zeno Rogue | 553bd8f466 | |
Zeno Rogue | 01c7ff5bc6 | |
Zeno Rogue | cc1d2c1b48 | |
Zeno Rogue | 3808d93a11 | |
Zeno Rogue | 293c271c7f | |
Zeno Rogue | b26ce4a067 | |
Zeno Rogue | b8eeec248e | |
Zeno Rogue | 84022c1ab4 | |
Zeno Rogue | 6549637f8d | |
Zeno Rogue | b34fbba7b4 | |
Zeno Rogue | 85816ca0bb | |
Zeno Rogue | 864f6d7899 | |
Zeno Rogue | b0ae2774a1 | |
Zeno Rogue | ef7050aed2 | |
Zeno Rogue | 49ce0c1551 | |
Zeno Rogue | bcd6d772f6 | |
Zeno Rogue | 0c6d83b702 | |
Zeno Rogue | 7f8a2f7a49 | |
Zeno Rogue | a401a7ed67 | |
Zeno Rogue | a84a9c94dd | |
Zeno Rogue | a775a74bb2 | |
Zeno Rogue | a3b85103b6 | |
Zeno Rogue | 0367d9553d | |
Zeno Rogue | a9c416ac64 | |
Zeno Rogue | 773e73dcc2 | |
Zeno Rogue | 95b205cce0 | |
Zeno Rogue | ade4f9c030 | |
Zeno Rogue | 22a5729d35 | |
Zeno Rogue | 54e0d85ea7 | |
Zeno Rogue | 4af232e9c1 | |
Zeno Rogue | c49b320330 | |
Zeno Rogue | 40d3c39cf1 | |
Zeno Rogue | 69280c7efe | |
Zeno Rogue | df6dd67fc1 | |
Zeno Rogue | e459723836 | |
Zeno Rogue | 804308c03e | |
Zeno Rogue | 624cac0c80 | |
Zeno Rogue | 2e5d9dd626 | |
Zeno Rogue | f33d169fe1 | |
Zeno Rogue | 62fed6129f | |
Zeno Rogue | bdbf4e2935 | |
Zeno Rogue | fbf0b487b1 | |
Zeno Rogue | 720ccc649c | |
Zeno Rogue | 8f086f7bb5 | |
Zeno Rogue | f375d609c6 | |
Zeno Rogue | 987c0e6113 | |
Zeno Rogue | 2e99da82ba | |
Zeno Rogue | 4b74fdf7c1 | |
Zeno Rogue | 277b1e1fd0 | |
Zeno Rogue | bbc57d9b8f | |
Zeno Rogue | f46279843d | |
Zeno Rogue | fcd54e3d62 | |
Zeno Rogue | 567ef8e7e6 | |
Zeno Rogue | a1a65ac612 | |
Zeno Rogue | 43305ea1cd | |
Zeno Rogue | 03a3fd14a0 | |
Zeno Rogue | 7a7ee1a13f | |
Zeno Rogue | 11a059eb60 | |
Zeno Rogue | b7c15e0978 | |
Zeno Rogue | 04c43e99e6 | |
Zeno Rogue | 62996d0d4c | |
Zeno Rogue | 707247d297 | |
Zeno Rogue | 00b2dc522a | |
Zeno Rogue | eefb91501e | |
Zeno Rogue | d76b2156f2 | |
Zeno Rogue | 29ed17410b | |
Zeno Rogue | 6ea3cc4bcc | |
Zeno Rogue | 11b70006aa | |
Zeno Rogue | 8a35e6facb | |
Zeno Rogue | 11fe91fb5a | |
Jacob Mandelson | 63c68831b2 | |
Jacob Mandelson | d32772fd1e | |
Jacob Mandelson | d0564026d7 | |
Jacob Mandelson | fb3c0e38b7 | |
Jacob Mandelson | 2939191fa1 | |
Jacob Mandelson | c7f8cafc28 | |
Jacob Mandelson | 71cf4bc678 | |
Jacob Mandelson | f10751a7f0 | |
Jacob Mandelson | 4d766655ba | |
Jacob Mandelson | 41e8466dad | |
Jacob Mandelson | f7e8818e01 | |
Zeno Rogue | fc184640d3 | |
Zeno Rogue | 9799ff1ccf | |
Zeno Rogue | 37ab1b523d | |
Zeno Rogue | b75bb20246 | |
Zeno Rogue | 21ebbc6ca4 | |
Zeno Rogue | 75902e5fd3 | |
Zeno Rogue | 22ef01964a | |
Zeno Rogue | de859c35aa | |
Zeno Rogue | 84a6d2f8f9 | |
Zeno Rogue | 505e9dcbbe | |
Zeno Rogue | 8e23039fc0 | |
Zeno Rogue | 2f672bc4f3 | |
Zeno Rogue | fa1f237f37 | |
Zeno Rogue | b1baf393ba | |
Zeno Rogue | 38b817187e | |
Zeno Rogue | 3a95b5f8d5 | |
Zeno Rogue | cb839ed895 | |
Zeno Rogue | f0200ee32c | |
Zeno Rogue | 85f214c9a2 | |
Zeno Rogue | 69d0c05628 | |
Zeno Rogue | db353755d3 | |
Zeno Rogue | f0f6ae7514 | |
Jacob Mandelson | 21a7c4f365 | |
Jacob Mandelson | 371a324085 | |
Jacob Mandelson | 1ad6b7ebe9 | |
Zeno Rogue | 5af23eab7d | |
Jacob Mandelson | 22e1799ab3 | |
Jacob Mandelson | ae89d73598 | |
Jacob Mandelson | 9018d32173 | |
Jacob Mandelson | d2c4382e14 | |
Jacob Mandelson | fabf0e3eb0 | |
Jacob Mandelson | 048ad9a030 | |
Zeno Rogue | b0577deb9a | |
Zeno Rogue | ca3cb88399 | |
Zeno Rogue | 5e8f3b609b | |
Zeno Rogue | 30217ac23b | |
Zeno Rogue | 637ca35d62 | |
Zeno Rogue | 1ec7b0ece1 | |
Zeno Rogue | 308fcd90aa | |
Zeno Rogue | a20063c119 | |
Zeno Rogue | d7e4c25c92 | |
Zeno Rogue | 1b4e0bfa79 | |
Jacob Mandelson | d0273d3ed6 | |
Jacob Mandelson | df6f9eb86a | |
Jacob Mandelson | 2933b256e0 | |
Zeno Rogue | f29f908e05 | |
Zeno Rogue | dbf9b2b325 | |
Zeno Rogue | ce5c1bc369 | |
Zeno Rogue | 18113f157f | |
Zeno Rogue | 53537271eb | |
Zeno Rogue | 8715770649 | |
Zeno Rogue | b6073679b2 | |
Zeno Rogue | 0084a951e6 | |
Zeno Rogue | 3f005908c4 | |
Zeno Rogue | 38767cf801 | |
Zeno Rogue | 4c27c16931 | |
Zeno Rogue | b87a936a61 | |
Zeno Rogue | 905c4e3afb | |
Zeno Rogue | ae7574483e | |
Zeno Rogue | db3d710dd4 | |
Zeno Rogue | db32bae51e | |
Zeno Rogue | 6a39ed54c6 | |
Zeno Rogue | acc90b80b7 | |
Zeno Rogue | 90669b6bb8 | |
Zeno Rogue | 944f5e30af | |
Zeno Rogue | c637dd4322 | |
Zeno Rogue | f537abf71c | |
Zeno Rogue | 898a2463c0 | |
Zeno Rogue | c3a1f8cc12 | |
Zeno Rogue | 16bf285f15 | |
Zeno Rogue | 02e88579f6 | |
Zeno Rogue | 142de7cdc5 | |
Zeno Rogue | b7a2e87d28 | |
Zeno Rogue | f23c10d1e6 | |
Zeno Rogue | e393929237 | |
Zeno Rogue | d081bfb7ee | |
Zeno Rogue | d279d2098e | |
Marcin Puc | 8fb143a742 | |
Jacob Mandelson | 92fc237a3e | |
Jacob Mandelson | 45207e3ba7 | |
Jacob Mandelson | da822fc4e9 | |
Jacob Mandelson | 360aa921aa | |
Zeno Rogue | d3b4b880fc | |
Zeno Rogue | 818d943827 | |
Zeno Rogue | ae0ab132e1 | |
Zeno Rogue | 7c87df85ac | |
Zeno Rogue | d5251664cb | |
Zeno Rogue | d4d7842e5a | |
Zeno Rogue | 2f78601f0b | |
Zeno Rogue | 7958c095d0 | |
Zeno Rogue | cd84dfca4f | |
Zeno Rogue | 3578ae0631 | |
Zeno Rogue | dbcc88b42a | |
Zeno Rogue | b056b5c153 | |
Zeno Rogue | 9545796a1d | |
Zeno Rogue | 2522b16e55 | |
Zeno Rogue | a221244cab | |
Zeno Rogue | 06832c5371 | |
Zeno Rogue | 4eebc5858e | |
Zeno Rogue | ab7ebd3bbc | |
Zeno Rogue | ed7c5d8e69 | |
Zeno Rogue | b934819ac3 | |
Zeno Rogue | 92291c437a | |
Zeno Rogue | e74d79583b | |
Zeno Rogue | d03db1115c | |
Zeno Rogue | 466cc5cc0a | |
Zeno Rogue | 9110b6ac88 | |
Zeno Rogue | 852c637e4f | |
Zeno Rogue | 613672b662 | |
Jacob Mandelson | 2f51cfc49e | |
Jacob Mandelson | a2482b033d | |
Jacob Mandelson | 7441642b30 | |
Jacob Mandelson | 4c75779692 | |
Jacob Mandelson | 3081817872 | |
Jacob Mandelson | 94b2a27b35 | |
Jacob Mandelson | f8c9562a74 | |
Jacob Mandelson | ef28ce708e | |
Jacob Mandelson | 5239f6eadc | |
Jacob Mandelson | 067f959ab1 | |
Jacob Mandelson | c9f24344af | |
Jacob Mandelson | aefbd359e4 | |
Jacob Mandelson | ae284d68e8 | |
Jacob Mandelson | a6c8894166 | |
Jacob Mandelson | 0f6754b43e | |
Jacob Mandelson | e1f3df2e65 | |
Jacob Mandelson | cc29338305 | |
Jacob Mandelson | 5ec6783a2d | |
Jacob Mandelson | f1b75537f8 | |
Jacob Mandelson | afd57fe81d | |
Jacob Mandelson | c4a7776977 | |
Jacob Mandelson | 20a6876763 | |
Marcin Puc | 4468061568 | |
Jacob Mandelson | 0ebee6a1a3 | |
Jacob Mandelson | f5d4586d0f | |
Jacob Mandelson | af4a0c1da9 | |
Jacob Mandelson | 46872919ba | |
Jacob Mandelson | cc3065f204 | |
Jacob Mandelson | 5766299c0a | |
Jacob Mandelson | 591acfebe4 | |
Jacob Mandelson | 1561d84f1b | |
Jacob Mandelson | 3521ee917c | |
Jacob Mandelson | 064468b480 | |
Jacob Mandelson | 1f842704ec | |
Jacob Mandelson | b71b34e734 | |
Jacob Mandelson | d85ad065f6 | |
Jacob Mandelson | 18e1912884 | |
Jacob Mandelson | 446b23f83d | |
Zeno Rogue | ae003f7847 | |
Zeno Rogue | e70f3d1fe6 | |
Zeno Rogue | 9f1480d21e | |
Zeno Rogue | 3080e5d05b | |
Zeno Rogue | ec3bb7a5df | |
Zeno Rogue | aa539335b4 | |
Zeno Rogue | eef03514ca | |
Zeno Rogue | 841108726c | |
Zeno Rogue | 31b2bd9690 | |
Zeno Rogue | 7be773ea03 | |
Zeno Rogue | d66a877889 | |
Zeno Rogue | 9f48d4f194 | |
Zeno Rogue | 5146fc00f0 | |
Zeno Rogue | 4947b8c1b5 | |
Zeno Rogue | 53839be194 | |
Zeno Rogue | 14a9961f92 | |
Zeno Rogue | 3f32112937 | |
Zeno Rogue | a439b16602 | |
Zeno Rogue | ae0425038b | |
Zeno Rogue | ffe8e9cef3 | |
Zeno Rogue | 7411f21b59 | |
Zeno Rogue | b6d665ff0e | |
Zeno Rogue | d4ea078f7f | |
Zeno Rogue | 5c97fbb06e | |
Zeno Rogue | 9ab84d9afd | |
Zeno Rogue | ecadc352f1 | |
Zeno Rogue | 41d14e0607 | |
Zeno Rogue | b7c8e7b754 | |
Zeno Rogue | 50087e032a | |
Zeno Rogue | 0f0d0ff7a9 | |
Zeno Rogue | c07f84205b | |
Zeno Rogue | 764afbcd11 | |
Zeno Rogue | 121b3f2d58 | |
Zeno Rogue | 84d15a121b | |
Zeno Rogue | 97c10ff878 | |
Zeno Rogue | 1c4aa3e71c | |
Zeno Rogue | 01cb5eb9ef | |
Zeno Rogue | cccab05f66 | |
Zeno Rogue | 59b45c1be0 | |
Zeno Rogue | 285beb4ad2 | |
Zeno Rogue | 2d35e40dba | |
Zeno Rogue | 2fe521452a | |
Zeno Rogue | 9c0231c455 | |
Zeno Rogue | 7a5b2dcf25 | |
Zeno Rogue | f866f66582 | |
Zeno Rogue | d571d2f1cb | |
Zeno Rogue | d6376bcaec | |
Zeno Rogue | 437dce455a | |
Zeno Rogue | 14f1da6de4 | |
Zeno Rogue | cc258f1f31 | |
Zeno Rogue | a26234012f | |
Zeno Rogue | 304c9efe54 | |
Zeno Rogue | 80c3dfcd34 | |
Zeno Rogue | a441ab474f | |
Zeno Rogue | 2ddc35179a | |
Zeno Rogue | 75c9258537 | |
Zeno Rogue | 47d2b5b27b | |
Zeno Rogue | ecee5b7f21 | |
Zeno Rogue | ca315c2582 | |
Zeno Rogue | fe7b54d256 | |
Zeno Rogue | 7f0bbcfef3 | |
Zeno Rogue | eb4af6c584 | |
Zeno Rogue | d22d840f01 | |
Zeno Rogue | d55a2022c0 | |
Zeno Rogue | 9e56312dab | |
Zeno Rogue | 35bd625a87 | |
Zeno Rogue | 16cdaa5a00 | |
Zeno Rogue | df5c36c2a6 | |
Zeno Rogue | 40765e8808 | |
Zeno Rogue | 9108d06543 | |
Zeno Rogue | 576e21ece9 | |
Zeno Rogue | ffcf7853cb | |
Zeno Rogue | 82e2e853bf | |
Zeno Rogue | dbab2254c6 | |
Zeno Rogue | 3cffc218e6 | |
Zeno Rogue | dc37e1ed23 | |
Zeno Rogue | dfce80d152 | |
Zeno Rogue | 0b24804934 | |
Zeno Rogue | 44e8f31545 | |
Zeno Rogue | 68da2e967c | |
Zeno Rogue | cfb47631ac | |
Zeno Rogue | cafd721284 | |
Zeno Rogue | 5e59f299c6 | |
Zeno Rogue | 48c99f296a | |
Zeno Rogue | e86e6267ec | |
Zeno Rogue | 0eed6a03d4 | |
Zeno Rogue | 41ccb86c8c | |
Zeno Rogue | d5467eb379 | |
Zeno Rogue | dd4001601f | |
Zeno Rogue | 608c283f2d | |
Zeno Rogue | c7663c83be | |
Zeno Rogue | c261db8a08 | |
Zeno Rogue | e686f5bc39 | |
Zeno Rogue | ce8e3c8640 | |
Zeno Rogue | 7883d569d6 | |
Zeno Rogue | ad744820ae | |
Zeno Rogue | 2a33f86f6f | |
Zeno Rogue | 0265f76c69 | |
Zeno Rogue | f38da4cba9 | |
Zeno Rogue | cfad696d4a | |
Zeno Rogue | 2354be07e5 | |
Zeno Rogue | 22523ccfc3 | |
Zeno Rogue | 91f0f7ff03 | |
Zeno Rogue | 0dc84d8f34 | |
Zeno Rogue | 884a9bb2c5 | |
Zeno Rogue | 4ed44d78cc | |
Zeno Rogue | 6030dd2a47 | |
Zeno Rogue | eec0c968d9 | |
Zeno Rogue | c87bca5da0 | |
Zeno Rogue | 4497821b35 | |
Zeno Rogue | 389acc68e3 | |
Zeno Rogue | f138bbb5c2 | |
Zeno Rogue | 1f832faeba | |
Zeno Rogue | 1c01cc7f94 | |
Zeno Rogue | 0b3980a5a4 | |
Zeno Rogue | db8c4ee0b9 | |
Zeno Rogue | 7931ced3f8 | |
Zeno Rogue | dd0c1e6b3d | |
Zeno Rogue | dee519badd | |
Zeno Rogue | 7787f26bc2 | |
Zeno Rogue | ed4c715a5e | |
Zeno Rogue | 3184aea2be | |
Zeno Rogue | 1da912a0a2 | |
Zeno Rogue | 8b68ad2fdd | |
Zeno Rogue | 464f4277cc | |
Zeno Rogue | fba2cc95cf | |
Zeno Rogue | c8f3dc827e | |
Zeno Rogue | 4b4103f667 | |
Zeno Rogue | 70561f1f5a | |
Zeno Rogue | 498c9828c3 | |
Zeno Rogue | 647a70e27f | |
Zeno Rogue | e6879ee806 | |
Zeno Rogue | 1529986d6a | |
Zeno Rogue | e3925d6bad | |
Zeno Rogue | c647431486 | |
Zeno Rogue | 7b47a301a3 | |
Zeno Rogue | 8a58604371 | |
Zeno Rogue | 8e094e93a5 | |
Zeno Rogue | e9bb38d3b1 | |
Zeno Rogue | 67267cbe6b | |
Zeno Rogue | cd58923454 | |
Zeno Rogue | 57f9e3efb6 | |
Zeno Rogue | 10f1559da0 | |
Zeno Rogue | 96b335e465 | |
Zeno Rogue | dcffdbbca5 | |
Zeno Rogue | 6291da56c4 | |
Zeno Rogue | 41bfaeaf36 | |
Zeno Rogue | a8b27b2bdb | |
Zeno Rogue | 62132073de | |
Zeno Rogue | ded7bde82c | |
Zeno Rogue | 42abdd223e | |
Zeno Rogue | e8b3f0c5c9 | |
Zeno Rogue | b07b805b33 | |
Zeno Rogue | 238828e300 | |
Zeno Rogue | 436cc15dba | |
Zeno Rogue | e7818829e2 | |
Zeno Rogue | b76bddb47b | |
Zeno Rogue | 1a245b2523 | |
Zeno Rogue | f2efc6f295 | |
Zeno Rogue | 7c6fece132 | |
Zeno Rogue | 11426c30b3 | |
Zeno Rogue | 2f7a6194a6 | |
Zeno Rogue | 5c302a4c52 | |
Zeno Rogue | 894ee3ad8e | |
Zeno Rogue | c5650e4e46 | |
Zeno Rogue | 6225fd38e8 | |
Zeno Rogue | 7c1d083afa | |
Zeno Rogue | 32ed3d98ee | |
Zeno Rogue | b229f2c9b8 | |
Zeno Rogue | 3b4571aa16 | |
Zeno Rogue | 6c4a53c001 | |
Zeno Rogue | 43ff375435 | |
Zeno Rogue | f101ddb7fd | |
Zeno Rogue | 48702739fd | |
Zeno Rogue | f25379ca7d | |
Zeno Rogue | 58c78220df | |
Zeno Rogue | 0e14d06e40 | |
Zeno Rogue | 4c4120e4f0 | |
Zeno Rogue | 906ad4ab90 | |
Zeno Rogue | 0b4df47964 | |
Zeno Rogue | 6bc3dc9d6f | |
Zeno Rogue | 7252b04626 | |
Zeno Rogue | 94a243a825 | |
Zeno Rogue | 5ef8092af2 | |
Zeno Rogue | 91e405e421 | |
Zeno Rogue | ffdc74a0b5 | |
Dennis Payne | 3023b12e93 |
|
@ -1,68 +0,0 @@
|
|||
name: Github CI on Android
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
android_build:
|
||||
name: Test build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Validate gradle-wrapper.jar
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install gcc libsdl1.2-dev libsdl-ttf2.0-dev libsdl-gfx1.2-dev libsdl-mixer1.2-dev libglew-dev libpng-dev
|
||||
- name: Build
|
||||
run: |
|
||||
cd hyperroid
|
||||
./copy.sh
|
||||
./gradlew assembleDebug
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: hyperroid_debug
|
||||
path: hyperroid/app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
android_test:
|
||||
needs: android_build
|
||||
name: Test-run in emulator
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Download APK
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: hyperroid_debug
|
||||
- name: Create a helper wait script
|
||||
run: |
|
||||
cat > wait-for-load.sh << ENDOFSCRIPT
|
||||
#!/bin/sh
|
||||
while ! adb logcat -d "HyperRogue:V" "*:S" | grep "Game initialized"
|
||||
do
|
||||
sleep 2
|
||||
done
|
||||
ENDOFSCRIPT
|
||||
chmod u+x wait-for-load.sh
|
||||
- name: Run in emulator
|
||||
uses: ReactiveCircus/android-emulator-runner@v2.11.1
|
||||
with:
|
||||
api-level: 28
|
||||
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -no-snapstorage -noaudio -no-boot-anim -skin 1440x2560
|
||||
script: |
|
||||
adb wait-for-device
|
||||
adb install -t app-debug.apk
|
||||
adb shell am start -W -n com.roguetemple.hyperroid/com.roguetemple.hyperroid.HyperRogue
|
||||
./wait-for-load.sh
|
||||
adb shell input keyevent 41 # send "M" keypress to display main menu
|
||||
adb shell screencap /sdcard/hyperroid.png
|
||||
adb pull /sdcard/hyperroid.png
|
||||
- name: Upload screenshot
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: screenshot
|
||||
path: hyperroid.png
|
|
@ -13,7 +13,9 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
# os: [ubuntu-latest, macos-latest]
|
||||
# macos is broken for now
|
||||
os: [ubuntu-latest]
|
||||
compiler: [gcc, clang]
|
||||
build_system: [makefile, mymake]
|
||||
hyper_use_rviz: [rviz_1, rviz_0]
|
||||
|
@ -71,13 +73,15 @@ jobs:
|
|||
- name: Do a simple test
|
||||
run: .github/workflows/test_simple.sh
|
||||
|
||||
emscripten:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: |
|
||||
docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten
|
||||
- name: Do a simple test
|
||||
run: |
|
||||
ls -lAF hyper.html hyper.js hyper.wasm
|
||||
# broken for now
|
||||
|
||||
# emscripten:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - name: Build
|
||||
# run: |
|
||||
# docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten
|
||||
# - name: Do a simple test
|
||||
# run: |
|
||||
# ls -lAF hyper.html hyper.js hyper.wasm
|
||||
|
|
|
@ -9,7 +9,9 @@ cat << ENDOFCMDS > .github/workflows/gdb_cmds.txt
|
|||
exit 1
|
||||
ENDOFCMDS
|
||||
|
||||
gdb --batch -x .github/workflows/gdb_cmds.txt ./hyperrogue
|
||||
echo not running gdb -- not working currently
|
||||
echo gdb --batch -x .github/workflows/gdb_cmds.txt ./hyperrogue
|
||||
|
||||
else
|
||||
./hyperrogue --version
|
||||
fi
|
||||
|
|
193
.travis.yml
193
.travis.yml
|
@ -1,193 +0,0 @@
|
|||
language: cpp
|
||||
dist: bionic
|
||||
services:
|
||||
- docker
|
||||
matrix:
|
||||
include:
|
||||
- os: linux # Linux GCC, make
|
||||
compiler: gcc
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=gcc
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
- os: linux # Linux GCC, make, no libpng
|
||||
compiler: gcc
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=gcc
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=0
|
||||
- os: linux # Linux GCC, make, Rogueviz
|
||||
compiler: gcc
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=gcc
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
HYPERROGUE_USE_ROGUEVIZ=1
|
||||
- os: linux # Linux Clang, make
|
||||
compiler: clang
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=clang
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
- os: linux # Linux Clang, make, Rogueviz
|
||||
compiler: clang
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=clang
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
HYPERROGUE_USE_ROGUEVIZ=1
|
||||
- os: osx # OSX, make
|
||||
osx_image: xcode12u
|
||||
compiler: clang
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=osx
|
||||
TRAVIS_COMPILER_NAME=clang
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
- os: osx # OSX, make, no libpng
|
||||
osx_image: xcode11.6
|
||||
compiler: clang
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=osx
|
||||
TRAVIS_COMPILER_NAME=clang
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=0
|
||||
- os: osx # OSX, make, Rogueviz
|
||||
osx_image: xcode11.5
|
||||
compiler: clang
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=osx
|
||||
TRAVIS_COMPILER_NAME=clang
|
||||
TRAVIS_BUILD_SYSTEM=Makefile
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
HYPERROGUE_USE_ROGUEVIZ=1
|
||||
- os: linux # Linux GCC, mymake
|
||||
compiler: gcc
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=gcc
|
||||
TRAVIS_BUILD_SYSTEM=mymake
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
- os: linux # Linux GCC, mymake, Rogueviz
|
||||
compiler: gcc
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=gcc
|
||||
TRAVIS_BUILD_SYSTEM=mymake
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
HYPERROGUE_USE_ROGUEVIZ=1
|
||||
- os: osx # OSX, mymake
|
||||
osx_image: xcode11.4
|
||||
compiler: clang
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=osx
|
||||
TRAVIS_COMPILER_NAME=clang
|
||||
TRAVIS_BUILD_SYSTEM=mymake
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
- os: osx # OSX, mymake, Rogueviz
|
||||
osx_image: xcode11.3
|
||||
compiler: clang
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=osx
|
||||
TRAVIS_COMPILER_NAME=clang
|
||||
TRAVIS_BUILD_SYSTEM=mymake
|
||||
HYPERROGUE_USE_GLEW=1
|
||||
HYPERROGUE_USE_PNG=1
|
||||
HYPERROGUE_USE_ROGUEVIZ=1
|
||||
- os: linux # Emscripten
|
||||
env: >-
|
||||
TRAVIS_OS_NAME=linux
|
||||
TRAVIS_COMPILER_NAME=emscripten
|
||||
TRAVIS_BUILD_SYSTEM=emscripten
|
||||
|
||||
before_install:
|
||||
- |-
|
||||
# Install SDL
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qq libsdl1.2-dev libsdl-gfx1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev
|
||||
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
brew update
|
||||
brew install sdl sdl_gfx sdl_mixer sdl_ttf
|
||||
# work around https://stackoverflow.com/questions/51034399/ for now
|
||||
(cd /usr/local/include && ln -sf SDL/SDL.h)
|
||||
else
|
||||
exit 'Unsupported OS'
|
||||
fi
|
||||
- |-
|
||||
# Install GLEW if asked for
|
||||
if [[ "$HYPERROGUE_USE_GLEW" == "1" ]]; then
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
sudo apt-get install -qq libglew-dev
|
||||
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
brew install glew
|
||||
else
|
||||
exit 'Unsupported OS'
|
||||
fi
|
||||
fi
|
||||
- |-
|
||||
# Install libpng if asked for
|
||||
if [[ "$HYPERROGUE_USE_PNG" == "1" ]]; then
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
echo 'libpng is installed by default'
|
||||
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
brew install libpng
|
||||
else
|
||||
exit 'Unsupported OS'
|
||||
fi
|
||||
fi
|
||||
|
||||
script:
|
||||
- |-
|
||||
make clean
|
||||
if [[ "$(git status --porcelain)" ]]; then
|
||||
git status
|
||||
exit 'A build artifact was committed; git rm it and try again'
|
||||
fi
|
||||
- |-
|
||||
# Build hyperrogue.
|
||||
export CXXFLAGS_EARLY=-Werror
|
||||
if [[ "$TRAVIS_BUILD_SYSTEM" == "Makefile" ]]; then
|
||||
make
|
||||
elif [[ "$TRAVIS_BUILD_SYSTEM" == "mymake" ]]; then
|
||||
make mymake
|
||||
if [[ "$HYPERROGUE_USE_ROGUEVIZ" == "1" ]]; then
|
||||
./mymake -rv
|
||||
else
|
||||
./mymake
|
||||
fi
|
||||
mv hyper hyperrogue
|
||||
elif [[ "$TRAVIS_BUILD_SYSTEM" == "emscripten" ]]; then
|
||||
docker run --rm -v $(pwd):/src trzeci/emscripten make emscripten
|
||||
else
|
||||
exit 'Unsupported build system'
|
||||
fi
|
||||
- |-
|
||||
# Test hyperrogue.
|
||||
if [[ "$TRAVIS_BUILD_SYSTEM" == "emscripten" ]]; then
|
||||
ls -lAF hyper.html hyper.js hyper.wasm
|
||||
else
|
||||
./hyperrogue --help
|
||||
fi
|
||||
- |-
|
||||
make clean
|
||||
if [[ "$(git status --porcelain)" ]]; then
|
||||
git status
|
||||
exit 'make clean did not return the repository to its pre-build state'
|
||||
fi
|
333
3d-models.cpp
333
3d-models.cpp
|
@ -15,9 +15,9 @@ ld eyepos;
|
|||
#if MAXMDIM >= 4
|
||||
|
||||
#define S (cgi.scalefactor / 0.805578)
|
||||
#define SH (cgi.scalefactor / 0.805578 * vid.height_width / 1.5)
|
||||
#define SH (embedded_plane ? cgi.human_height : (cgi.scalefactor / 0.805578 * (vid.height_width / 1.5)))
|
||||
|
||||
#define revZ ((WDIM == 2 || prod) ? -1 : 1)
|
||||
#define revZ ((WDIM == 2 || gproduct) ? -1 : 1)
|
||||
|
||||
hyperpoint shcenter;
|
||||
|
||||
|
@ -34,7 +34,8 @@ vector<hyperpoint> geometry_information::get_shape(hpcshape sh) {
|
|||
hyperpoint get_center(const vector<hyperpoint>& vh) {
|
||||
hyperpoint h = Hypc;
|
||||
for(auto h1: vh) h = h + h1;
|
||||
return normalize_flat(h);
|
||||
h /= isize(vh);
|
||||
return cgi.emb->normalize_flat(h);
|
||||
}
|
||||
|
||||
EX ld zc(ld z) {
|
||||
|
@ -46,9 +47,9 @@ EX ld zc(ld z) {
|
|||
void geometry_information::add_cone(ld z0, const vector<hyperpoint>& vh, ld z1) {
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
for(int i=0; i<isize(vh); i++) {
|
||||
hpcpush(zpush(z0) * vh[i]);
|
||||
hpcpush(zpush(z0) * vh[(i+1) % isize(vh)]);
|
||||
hpcpush(zpush(z1) * shcenter);
|
||||
hpcpush(lzpush(z0) * vh[i]);
|
||||
hpcpush(lzpush(z0) * vh[(i+1) % isize(vh)]);
|
||||
hpcpush(lzpush(z1) * shcenter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,12 +57,12 @@ void geometry_information::add_prism_sync(ld z0, vector<hyperpoint> vh0, ld z1,
|
|||
last->flags |= POLY_TRIANGLES;
|
||||
for(int i=0; i<isize(vh0); i++) {
|
||||
int i1 = (i+1) % isize(vh0);
|
||||
hpcpush(zpush(z0) * vh0[i]);
|
||||
hpcpush(zpush(z1) * vh1[i]);
|
||||
hpcpush(zpush(z0) * vh0[i1]);
|
||||
hpcpush(zpush(z1) * vh1[i]);
|
||||
hpcpush(zpush(z0) * vh0[i1]);
|
||||
hpcpush(zpush(z1) * vh1[i1]);
|
||||
hpcpush(lzpush(z0) * vh0[i]);
|
||||
hpcpush(lzpush(z1) * vh1[i]);
|
||||
hpcpush(lzpush(z0) * vh0[i1]);
|
||||
hpcpush(lzpush(z1) * vh1[i]);
|
||||
hpcpush(lzpush(z0) * vh0[i1]);
|
||||
hpcpush(lzpush(z1) * vh1[i1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,19 +89,19 @@ void geometry_information::add_prism(ld z0, vector<hyperpoint> vh0, ld z1, vecto
|
|||
|
||||
for(auto pp: pairs) {
|
||||
int id = pp.owner;
|
||||
hpcpush(zpush(z0) * lasts[0]);
|
||||
hpcpush(zpush(z1) * lasts[1]);
|
||||
hpcpush(zpush(id == 0 ? z0 : z1) * pp.h);
|
||||
hpcpush(lzpush(z0) * lasts[0]);
|
||||
hpcpush(lzpush(z1) * lasts[1]);
|
||||
hpcpush(lzpush(id == 0 ? z0 : z1) * pp.h);
|
||||
lasts[id] = pp.h;
|
||||
}
|
||||
}
|
||||
|
||||
void geometry_information::shift_last(ld z) {
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = zshift(hpc[i], z);
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = lzpush(z) * hpc[i];
|
||||
}
|
||||
|
||||
void geometry_information::shift_shape(hpcshape& sh, ld z) {
|
||||
for(int i=sh.s; i<sh.e; i++) hpc[i] = zshift(hpc[i], z);
|
||||
for(int i=sh.s; i<sh.e; i++) hpc[i] = lzpush(z) * hpc[i];
|
||||
}
|
||||
|
||||
void geometry_information::shift_shape_orthogonally(hpcshape& sh, ld z) {
|
||||
|
@ -115,9 +116,19 @@ void geometry_information::add_texture(hpcshape& sh) {
|
|||
auto& utt = models_texture;
|
||||
sh.tinf = &utt;
|
||||
sh.texture_offset = isize(utt.tvertices);
|
||||
|
||||
auto f = [] (hyperpoint h) {
|
||||
if(!embedded_plane && gproduct) return product::inverse_exp(h);
|
||||
return cgi.emb->actual_to_logical(h);
|
||||
};
|
||||
|
||||
hyperpoint ct = Hypc;
|
||||
int n = 0;
|
||||
for(int i=sh.s; i<isize(hpc); i++) ct += f(hpc[i]), n++;
|
||||
ct /= n;
|
||||
|
||||
for(int i=sh.s; i<isize(hpc); i++) {
|
||||
hyperpoint h = hpc[i];
|
||||
if(prod) h = product::inverse_exp(h);
|
||||
hyperpoint h = f(hpc[i]) - ct;
|
||||
ld rad = hypot_d(3, h);
|
||||
ld factor = 0.50 + (0.17 * h[2] + 0.13 * h[1] + 0.15 * h[0]) / rad;
|
||||
utt.tvertices.push_back(glhr::makevertex(0, factor, 0));
|
||||
|
@ -127,18 +138,18 @@ void geometry_information::add_texture(hpcshape& sh) {
|
|||
|
||||
vector<hyperpoint> scaleshape(const vector<hyperpoint>& vh, ld s) {
|
||||
vector<hyperpoint> res;
|
||||
for(hyperpoint h: vh) res.push_back(normalize_flat(h * s + shcenter * (1-s)));
|
||||
for(hyperpoint h: vh) res.push_back(cgi.emb->normalize_flat(h * s + shcenter * (1-s)));
|
||||
return res;
|
||||
}
|
||||
|
||||
ld get_zlevel(hyperpoint h) {
|
||||
if(prod) return zlevel(h);
|
||||
if(gproduct) return zlevel(h);
|
||||
if(sl2) return atan2(h[2], h[3]);
|
||||
return asin_auto(h[2]);
|
||||
}
|
||||
|
||||
void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
|
||||
shcenter = C0;
|
||||
shcenter = tile_center();
|
||||
|
||||
auto groin = get_shape(shHumanGroin);
|
||||
auto body = get_shape(shPBodyOnly);
|
||||
|
@ -154,13 +165,15 @@ void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
|
|||
auto body26 = body[26];
|
||||
body.clear();
|
||||
|
||||
auto& T = cgi.emb->intermediate_to_logical;
|
||||
|
||||
bool foundplus = false, foundminus = false;
|
||||
for(hyperpoint h: fullbody) {
|
||||
if(h[1] > 0.14 * S) {
|
||||
if((T*h)[1] > 0.14 * S) {
|
||||
if(foundplus) ;
|
||||
else foundplus = true, body.push_back(body7);
|
||||
}
|
||||
else if(h[1] < -0.14 * S) {
|
||||
else if((T*h)[1] < -0.14 * S) {
|
||||
if(foundminus) ;
|
||||
else foundminus = true, body.push_back(body26);
|
||||
}
|
||||
|
@ -171,19 +184,20 @@ void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
|
|||
bool armused = false;
|
||||
arm.clear();
|
||||
for(hyperpoint h: fullbody) {
|
||||
if(h[1] < 0.08 * S) ;
|
||||
else if(h[0] > -0.03 * S) {
|
||||
if((T*h)[1] < 0.08 * S) ;
|
||||
else if((T*h)[0] > -0.03 * S) {
|
||||
if(armused) ;
|
||||
else armused = true, arm.push_back(arm8);
|
||||
}
|
||||
else arm.push_back(h);
|
||||
}
|
||||
|
||||
|
||||
auto hand0 = hand[0];
|
||||
hand.clear();
|
||||
hand.push_back(hand0);
|
||||
for(hyperpoint h: fullbody) {
|
||||
if(h[1] + h[0] > 0.13 * S) hand.push_back(h);
|
||||
auto h1 = T*h;
|
||||
if(h1[1] + h1[0] > 0.13 * S) hand.push_back(h);
|
||||
}
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
|
@ -207,12 +221,12 @@ void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
|
|||
for(int i=arm0; i<arm1; i++) {
|
||||
hyperpoint h = hpc[i];
|
||||
ld zl = get_zlevel(h);
|
||||
h = zpush(-zl) * h;
|
||||
h = lzpush(-zl) * h;
|
||||
ld rad = hdist0(h);
|
||||
rad = (rad - 0.1124*S) / (0.2804*S - 0.1124*S);
|
||||
rad = 1 - rad;
|
||||
rad *= zc(0.7) - BODY;
|
||||
hpc[i] = zpush(rad) * hpc[i];
|
||||
hpc[i] = lzpush(rad) * hpc[i];
|
||||
}
|
||||
}
|
||||
// 0.2804 - keep
|
||||
|
@ -259,7 +273,7 @@ void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
|
|||
bool ok = true;
|
||||
ld zzes[3];
|
||||
for(int s=0; s<3; s++) {
|
||||
hs[s] = normalize_flat(hs[s]);
|
||||
hs[s] = cgi.emb->normalize_flat(hs[s]);
|
||||
hyperpoint h = hs[s];
|
||||
ld zz = zc(0.78);
|
||||
hsh[s] = abs(h[1]);
|
||||
|
@ -267,8 +281,8 @@ void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
|
|||
zz -= h[0] * h[0] / 0.10 / 0.10 * 0.01 / S / S * SH;
|
||||
if(abs(h[1]) > 0.14*S) ok = false, zz -= revZ * (abs(h[1])/S - 0.14) * SH;
|
||||
if(abs(h[0]) > 0.08*S) ok = false, zz -= revZ * (abs(h[0])/S - 0.08) * (abs(h[0])/S - 0.08) * 25 * SH;
|
||||
h = normalize_flat(h);
|
||||
if(!prod || kind != 1) ht[s] = zpush(zz) * h;
|
||||
h = cgi.emb->normalize_flat(h);
|
||||
if(!gproduct || kind != 1) ht[s] = lzpush(zz) * h;
|
||||
else ht[s] = h;
|
||||
if(hsh[s] < 0.1*S) shi[s] = 0.5;
|
||||
else if(hsh[s] < 0.12*S) shi[s] = 0.1 + 0.4 * (hsh[s]/S - 0.1) / (0.12 - 0.1);
|
||||
|
@ -285,14 +299,14 @@ void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
|
|||
htx[2][i][1] *= 1.7;
|
||||
htx[4][i][0] = htx[4][i][0] * 0.4 + scalefactor * 0.1;
|
||||
htx[5][i][0] = htx[5][i][0] * 0.3 + scalefactor * 0.1;
|
||||
if(!prod)
|
||||
if(!gproduct)
|
||||
for(int a=0; a<6; a++) htx[a][i] = hpxy3(htx[a][i][0], htx[a][i][1], htx[a][i][2]);
|
||||
else
|
||||
for(int a=0; a<6; a++) htx[a][i] = zpush(zzes[i]) * hpxy(htx[a][i][0], htx[a][i][1]);
|
||||
for(int a=0; a<6; a++) htx[a][i] = lzpush(zzes[i]) * hpxy(htx[a][i][0], htx[a][i][1]);
|
||||
}
|
||||
ld levels[6] = {0, 0.125, 0.125, 0.250, 0.375, 0.5};
|
||||
for(int a=0; a<6; a++) for(int i=0; i<3; i++)
|
||||
htx[a][i] = zpush(-min(shi[i], levels[a]) * human_height * revZ) * htx[a][i];
|
||||
htx[a][i] = lzpush(-min(shi[i], levels[a]) * human_height * revZ) * htx[a][i];
|
||||
|
||||
hpcpush(htx[0][0]);
|
||||
hpcpush(htx[0][1]);
|
||||
|
@ -320,7 +334,7 @@ void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
|
|||
if(hdist0(h) <= 0.0501*S) {
|
||||
zz += revZ * sqrt(0.0026 - pow(hdist0(h)/S, 2)) * SH;
|
||||
}
|
||||
hpcpush(zpush(zz) * h);
|
||||
hpcpush(lzpush(zz) * h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -376,13 +390,13 @@ void geometry_information::make_foot_3d(hpcshape& sh) {
|
|||
add_cone(zc(0.4), leg5, zc(0.45));
|
||||
add_texture(sh);
|
||||
// shift_last(-LEG0);
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = cpush(0, -0.0125*S) * hpc[i];
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = lxpush(-0.0125*S) * hpc[i];
|
||||
}
|
||||
|
||||
void geometry_information::make_head_only() {
|
||||
|
||||
auto addpt = [this] (int d, int u) {
|
||||
hpcpush(zpush(zc(eyepos) + 0.06 * SH * sin(u * degree)) * xspinpush0(d * degree, 0.05 * S * cos(u * degree)));
|
||||
hpcpush(lzpush(zc(eyepos) + 0.06 * SH * sin(u * degree)) * xspinpush0(d * degree, 0.05 * S * cos(u * degree)));
|
||||
};
|
||||
|
||||
bshape(shPHeadOnly, shPHeadOnly.prio);
|
||||
|
@ -415,7 +429,7 @@ void geometry_information::make_head_3d(hpcshape& sh) {
|
|||
|
||||
array<ld, 2> zero = make_array<ld>(0,0);
|
||||
pts[1].emplace_back(zero);
|
||||
head.push_back(C0);
|
||||
head.push_back(tile_center());
|
||||
|
||||
bshape(sh, sh.prio);
|
||||
|
||||
|
@ -491,8 +505,15 @@ void geometry_information::make_skeletal(hpcshape& sh, ld push) {
|
|||
}
|
||||
|
||||
hyperpoint yzspin(ld alpha, hyperpoint h) {
|
||||
if(prod) return product::direct_exp(cspin(1, 2, alpha) * product::inverse_exp(h));
|
||||
else return cspin(1, 2, alpha) * h;
|
||||
if(embedded_plane) {
|
||||
h = cgi.emb->actual_to_logical(h);
|
||||
h = cspin(1, 2, alpha) * h;
|
||||
h[2] *= cgi.human_height;
|
||||
h = cgi.emb->logical_to_actual(h);
|
||||
return h;
|
||||
}
|
||||
if(gproduct) return product::direct_exp(cspin(1, 2, alpha) * product::inverse_exp(h));
|
||||
return cspin(1, 2, alpha) * h;
|
||||
}
|
||||
|
||||
void geometry_information::make_revolution(hpcshape& sh, int mx, ld push) {
|
||||
|
@ -519,8 +540,8 @@ void geometry_information::make_revolution(hpcshape& sh, int mx, ld push) {
|
|||
void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push, ld width) {
|
||||
auto body = get_shape(sh);
|
||||
body.resize(isize(body) / 2);
|
||||
ld fx = body[0][0];
|
||||
ld lx = body.back()[0];
|
||||
ld fx = cgi.emb->actual_to_logical(body[0])[0];
|
||||
ld lx = cgi.emb->actual_to_logical(body.back())[0];
|
||||
body.insert(body.begin(), hpxy(fx + (fx-lx) * 1e-3, 0));
|
||||
body.push_back(hpxy(lx + (lx-fx) * 1e-3, 0));
|
||||
int n = isize(body);
|
||||
|
@ -541,9 +562,12 @@ void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push,
|
|||
int cand = -1;
|
||||
ld cv = 0;
|
||||
for(int i=1; i<n-1; i++) if(stillin[i]) {
|
||||
if((gbody[i][0] < gbody[lastid[i]][0] && gbody[i][0] < gbody[nextid[i]][0]) || (gbody[i][0] > gbody[lastid[i]][0] && gbody[i][0] > gbody[nextid[i]][0]) || abs(gbody[i][1]) > width)
|
||||
if(abs(gbody[i][1]) > cv)
|
||||
cand = i, cv = abs(gbody[i][1]);
|
||||
auto gi = cgi.emb->actual_to_logical(gbody[i]);
|
||||
auto gl = cgi.emb->actual_to_logical(gbody[lastid[i]]);
|
||||
auto gn = cgi.emb->actual_to_logical(gbody[nextid[i]]);
|
||||
if((gi[0] < gl[0] && gi[0] < gn[0]) || (gi[0] > gl[0] && gi[0] > gn[0]) || abs(gi[1]) > width)
|
||||
if(abs(gi[1]) > cv)
|
||||
cand = i, cv = abs(gi[1]);
|
||||
}
|
||||
if(cand == -1) break;
|
||||
int i = cand;
|
||||
|
@ -556,7 +580,11 @@ void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push,
|
|||
for(int i=0; i<n; i++) if(!stillin[i] && !stillin[lastid[i]]) lastid[i] = lastid[lastid[i]];
|
||||
|
||||
for(int i=0; i<n; i++) {
|
||||
if(!stillin[i]) gbody[i] = normalize_flat(gbody[lastid[i]] * (i - lastid[i]) + gbody[nextid[i]] * (nextid[i] - i));
|
||||
if(!stillin[i]) {
|
||||
auto gl = cgi.emb->actual_to_logical(gbody[lastid[i]]);
|
||||
auto gn = cgi.emb->actual_to_logical(gbody[nextid[i]]);
|
||||
gbody[i] = cgi.emb->logical_to_actual((gl * (i - lastid[i]) + gn * (nextid[i] - i)) / (nextid[i] - lastid[i]));
|
||||
}
|
||||
}
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
|
@ -596,6 +624,7 @@ void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push,
|
|||
}
|
||||
|
||||
void geometry_information::clone_shape(hpcshape& sh, hpcshape& target) {
|
||||
finishshape();
|
||||
target = sh;
|
||||
target.s = isize(hpc);
|
||||
for(int i=sh.s; i<sh.e; i++) hpc.push_back(hpc[i]);
|
||||
|
@ -606,13 +635,18 @@ void geometry_information::animate_bird(hpcshape& orig, hpcshape_animated& anima
|
|||
for(int i=0; i<=WINGS; i++) {
|
||||
auto& tgt = animated[i];
|
||||
clone_shape(orig, tgt);
|
||||
ld alpha = cos(180. * degree * i / WINGS) * 30 * degree;
|
||||
ld alpha = cos(M_PI * i / WINGS) * 30 * degree;
|
||||
for(int i=tgt.s; i<tgt.e; i++) {
|
||||
if(abs(hpc[i][1]) > body) {
|
||||
ld off = hpc[i][1] > 0 ? body : -body;
|
||||
hpc[i][2] += abs(hpc[i][1] - off) * sin(alpha);
|
||||
hpc[i][1] = off + (hpc[i][1] - off) * cos(alpha);
|
||||
hpc[i] = normalize(hpc[i]);
|
||||
hyperpoint h = hpc[i];
|
||||
h = cgi.emb->actual_to_logical(hpc[i]);
|
||||
if(abs(h[1]) > body) {
|
||||
ld off = h[1] > 0 ? body : -body;
|
||||
h[2] += abs(h[1] - off) * sin(alpha);
|
||||
if(embedded_plane) h[2] *= cgi.human_height;
|
||||
h[1] = off + (h[1] - off) * cos(alpha);
|
||||
h = cgi.emb->logical_to_actual(h);
|
||||
h = normalize(h);
|
||||
hpc[i] = h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -622,9 +656,12 @@ void geometry_information::animate_bird(hpcshape& orig, hpcshape_animated& anima
|
|||
|
||||
void geometry_information::slimetriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev) {
|
||||
dynamicval<int> d(vid.texture_step, 8);
|
||||
ld sca = 1;
|
||||
if(mhybrid) sca = .5;
|
||||
if(cgi.emb->is_euc_in_noniso()) sca *= .3 * geom3::euclid_embed_scale;
|
||||
texture_order([&] (ld x, ld y) {
|
||||
ld z = 1-x-y;
|
||||
ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8) * (hybri ? .5 : 1);
|
||||
ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8) * sca;
|
||||
hyperpoint h = direct_exp(tangent_length(a*x+b*y+c*z, r));
|
||||
hpcpush(h);
|
||||
});
|
||||
|
@ -691,9 +728,10 @@ void geometry_information::make_star(hpcshape& sh, ld rad) {
|
|||
ld r1 = sqrt(1 - z1*z1) * rad;
|
||||
z0 *= rad;
|
||||
z1 *= rad;
|
||||
for(int b=0; b<360; b+=(BADMODEL?60:15)) {
|
||||
int step = BADMODEL ? 60 : 15;
|
||||
for(int b=0; b<360; b+=step) {
|
||||
ld b0 = b * degree;
|
||||
ld b1 = (b+15) * degree;
|
||||
ld b1 = (b+step) * degree;
|
||||
hpcsquare(
|
||||
hpxy3(r0 * cos(b0), r0 * sin(b0), z0), hpxy3(r0 * cos(b1), r0 * sin(b1), z0),
|
||||
hpxy3(r1 * cos(b0), r1 * sin(b0), z1), hpxy3(r1 * cos(b1), r1 * sin(b1), z1)
|
||||
|
@ -705,18 +743,23 @@ void geometry_information::make_star(hpcshape& sh, ld rad) {
|
|||
void geometry_information::make_euclidean_sky() {
|
||||
bshape(cgi.shEuclideanSky, PPR::EUCLIDEAN_SKY);
|
||||
for(int x=-20; x<20; x++)
|
||||
for(int y=-20; y<20; y++)
|
||||
for(int y=-20; y<20; y++) {
|
||||
auto x0 = x * cgi.LOWSKY;
|
||||
auto x1 = (x+1) * cgi.LOWSKY;
|
||||
auto y0 = y * cgi.LOWSKY;
|
||||
auto y1 = (y+1) * cgi.LOWSKY;
|
||||
hpcsquare(
|
||||
zpush(cgi.WALL) * hpxy(x, y),
|
||||
zpush(cgi.WALL) * hpxy(x, y+1),
|
||||
zpush(cgi.WALL) * hpxy(x+1, y),
|
||||
zpush(cgi.WALL) * hpxy(x+1, y+1)
|
||||
lzpush(cgi.LOWSKY) * hpxy(x0, y0),
|
||||
lzpush(cgi.LOWSKY) * hpxy(x0, y1),
|
||||
lzpush(cgi.LOWSKY) * hpxy(x1, y0),
|
||||
lzpush(cgi.LOWSKY) * hpxy(x1, y1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** res[0] and res[1] place H on the plane, while res[2] is the altitude */
|
||||
hyperpoint psmin(hyperpoint H) {
|
||||
if(prod) {
|
||||
if(gproduct) {
|
||||
auto d = product_decompose(H);
|
||||
d.second[2] = d.first;
|
||||
return d.second;
|
||||
|
@ -732,8 +775,10 @@ hyperpoint psmin(hyperpoint H) {
|
|||
|
||||
void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye, ld shift_head, int q, ld zoom) {
|
||||
hyperpoint center = Hypc;
|
||||
for(int i=eye.s; i<eye.e; i++) if(q == 1 || hpc[i][1] > 0) center += hpc[i];
|
||||
center = normalize_flat(center);
|
||||
int c = 0;
|
||||
for(int i=eye.s; i<eye.e; i++) if(q == 1 || hpc[i][1] > 0) center += hpc[i], c++;
|
||||
center /= c;
|
||||
center = cgi.emb->normalize_flat(center);
|
||||
// center /= (eye.e - eye.s);
|
||||
ld rad = 0;
|
||||
for(int i=eye.s; i<eye.e; i++) if(q == 1 || hpc[i][1] > 0) rad += hdist(center, hpc[i]);
|
||||
|
@ -746,14 +791,14 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye
|
|||
|
||||
vector<hyperpoint> pss;
|
||||
|
||||
for(int i=head.s; i<head.e; i++) pss.push_back(psmin(zpush(shift_head) * hpc[i]));
|
||||
for(int i=head.s; i<head.e; i++) pss.push_back(psmin(lzpush(shift_head - cgi.emb->center_z()) * hpc[i]));
|
||||
|
||||
ld zmid = 0;
|
||||
for(hyperpoint& h: pss) zmid += h[2];
|
||||
zmid /= isize(pss);
|
||||
|
||||
ld mindist = 1e9;
|
||||
for(int i=0; i<isize(pss); i+=3) if(pss[i][2] < zmid || (WDIM == 3 && !prod)) {
|
||||
for(int i=0; i<isize(pss); i+=3) if(pss[i][2] < zmid || (WDIM == 3 && !gproduct)) {
|
||||
ld d = sqhypot_d(2, pss[i]-pscenter) + sqhypot_d(2, pss[i+1]-pscenter) + sqhypot_d(2, pss[i+2]-pscenter);
|
||||
if(d < mindist) mindist = d, pos = min(min(pss[i][2], pss[i+1][2]), pss[i+2][2]), qty++;
|
||||
qtyall++;
|
||||
|
@ -764,11 +809,11 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye
|
|||
if(&eye == &shFamiliarEye) cgi.eyelevel_familiar = pos;
|
||||
|
||||
make_ball(eye, rad, 0);
|
||||
transmatrix T = zpush(-shift_eye) * rgpushxto0(center) * zpush(pos);
|
||||
transmatrix T = lzpush(-shift_eye) * rgpushxto0(center) * lzpush(pos);
|
||||
for(int i=eye.s; i<isize(hpc); i++) hpc[i] = T * hpc[i];
|
||||
int s = isize(hpc);
|
||||
if(&eye == &shSkullEyes)
|
||||
for(int i=eye.s; i<s; i++) hpc[i] = xpush(0.07 * scalefactor) * hpc[i];
|
||||
for(int i=eye.s; i<s; i++) hpc[i] = lxpush(0.07 * scalefactor) * hpc[i];
|
||||
if(q == 2)
|
||||
for(int i=eye.s; i<s; i++) {
|
||||
hpcpush(MirrorY * hpc[i]);
|
||||
|
@ -782,22 +827,22 @@ void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye
|
|||
}
|
||||
|
||||
void geometry_information::shift_last_straight(ld z) {
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = zpush(z) * hpc[i];
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = lzpush(z) * hpc[i];
|
||||
}
|
||||
|
||||
EX void queueball(const shiftmatrix& V, ld rad, color_t col, eItem what) {
|
||||
if(what == itOrbSpeed) {
|
||||
shiftmatrix V1 = V * cspin(1, 2, M_PI/2);
|
||||
shiftmatrix V1 = V * cspin90(1, 2);
|
||||
ld tt = ptick(100);
|
||||
for(int t=0; t<5; t++) {
|
||||
for(int a=-50; a<50; a++)
|
||||
curvepoint(cspin(0, 2, a * M_PI/100.) * cspin(0, 1, t * 72 * degree + tt + a*2*M_PI/50.) * xpush0(rad));
|
||||
curvepoint(cspin(0, 2, a * M_PI/100.) * cspin(0, 1, t * 72._deg + tt + a*TAU/50.) * xpush0(rad));
|
||||
queuecurve(V1, col, 0, PPR::LINE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ld z = 63.43 * degree;
|
||||
shiftmatrix V1 = V * cspin(0, 2, M_PI/2);
|
||||
shiftmatrix V1 = V * cspin90(0, 2);
|
||||
if(what == itOrbShield) V1 = V * cspin(0, 1, ptick(500));
|
||||
if(what == itOrbFlash) V1 = V * cspin(0, 1, ptick(1500));
|
||||
if(what == itOrbShield) V1 = V * cspin(1, 2, ptick(1000));
|
||||
|
@ -821,7 +866,7 @@ EX void queueball(const shiftmatrix& V, ld rad, color_t col, eItem what) {
|
|||
line(a, c);
|
||||
line(a, d);
|
||||
line(d, c);
|
||||
line(c, spin(M_PI));
|
||||
line(c, spin180());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -835,7 +880,7 @@ void geometry_information::make_3d_models() {
|
|||
if(GDIM == 2 || noGUI) return;
|
||||
eyepos = WDIM == 2 ? 0.875 : 0.925;
|
||||
DEBBI(DF_POLY, ("make_3d_models"));
|
||||
shcenter = C0;
|
||||
shcenter = tile_center();
|
||||
|
||||
#if CAP_GL
|
||||
if(floor_textures) {
|
||||
|
@ -851,12 +896,13 @@ void geometry_information::make_3d_models() {
|
|||
&shEagle, &shFemaleBody, &shFlailMissile, &shGadflyWing, &shGargoyleWings, &shHawk, &shJiangShi, &shKnife,
|
||||
&shPBody, &shPHead, &shRaiderBody, &shReptileBody, &shSkeletonBody, &shTongue, &shTrapArrow, &shTrylobite,
|
||||
&shWaterElemental, &shWolfBody, &shYeti, &shWormHead, &shWormHead, &shDragonHead, &shDragonSegment, &shDragonTail,
|
||||
&shTentacleX, &shTentHead, &shILeaf[0], &shILeaf[1], &shWormSegment, &shSmallWormSegment, &shFrogBody })
|
||||
&shTentacleX, &shTentHead, &shILeaf[0], &shILeaf[1], &shWormSegment, &shSmallWormSegment,
|
||||
&shWormTail, &shSmallWormTail, &shFrogBody })
|
||||
make_shadow(*sh);
|
||||
|
||||
for(int i=0; i<8; i++) make_shadow(shAsteroid[i]);
|
||||
}
|
||||
|
||||
|
||||
DEBB(DF_POLY, ("humanoids"));
|
||||
make_humanoid_3d(shPBody);
|
||||
make_humanoid_3d(shYeti);
|
||||
|
@ -926,9 +972,9 @@ void geometry_information::make_3d_models() {
|
|||
for(int i=shDogRearPaw.s; i<shDogRearPaw.e; i++) rear_leg += hpc[i];
|
||||
front_leg = normalize(front_leg);
|
||||
rear_leg = normalize(rear_leg);
|
||||
front_leg_move = zpush(zc(0.4)) * rgpushxto0(front_leg);
|
||||
front_leg_move = lzpush(zc(0.4)) * rgpushxto0(front_leg);
|
||||
front_leg_move_inverse = inverse(front_leg_move);
|
||||
rear_leg_move = zpush(zc(0.4)) * rgpushxto0(rear_leg);
|
||||
rear_leg_move = lzpush(zc(0.4)) * rgpushxto0(rear_leg);
|
||||
rear_leg_move_inverse = inverse(rear_leg_move);
|
||||
leg_length = zc(0.4) - zc(0);
|
||||
|
||||
|
@ -1075,13 +1121,10 @@ void geometry_information::make_3d_models() {
|
|||
make_ball(shDisk, orbsize*.2, 2);
|
||||
make_ball(shHeptaMarker, zhexf*.2, 1);
|
||||
make_ball(shSnowball, zhexf*.1, 1);
|
||||
if(euclid) {
|
||||
make_ball(shSun, 0.5, 2);
|
||||
make_euclidean_sky();
|
||||
}
|
||||
else
|
||||
make_star(shSun, 3);
|
||||
make_star(shNightStar, 0.75);
|
||||
make_ball(shSkyboxSun, 8 * zhexf, 2);
|
||||
if(euclid) make_euclidean_sky();
|
||||
make_star(shSun, vid.sun_size * zhexf);
|
||||
make_star(shNightStar, vid.star_size * zhexf);
|
||||
|
||||
if(WDIM == 2) {
|
||||
for(int i=0; i<3; i++) {
|
||||
|
@ -1130,10 +1173,10 @@ void geometry_information::make_3d_models() {
|
|||
hyperpoint atip = xtangent(-1);
|
||||
ld z = 63.43 * degree;
|
||||
for(int i=0; i<5; i++) {
|
||||
auto a = cspin(1, 2, (72 * i ) * degree) * spin(z) * xtangent(1);
|
||||
auto b = cspin(1, 2, (72 * i-72) * degree) * spin(z) * xtangent(1);
|
||||
auto c = cspin(1, 2, (72 * i+36) * degree) * spin(M_PI-z) * xtangent(1);
|
||||
auto d = cspin(1, 2, (72 * i-36) * degree) * spin(M_PI-z) * xtangent(1);
|
||||
auto a = cspin(1, 2, (72 * i ) * degree) * cspin(0, 1, z) * xtangent(1);
|
||||
auto b = cspin(1, 2, (72 * i-72) * degree) * cspin(0, 1, z) * xtangent(1);
|
||||
auto c = cspin(1, 2, (72 * i+36) * degree) * cspin(0, 1, M_PI-z) * xtangent(1);
|
||||
auto d = cspin(1, 2, (72 * i-36) * degree) * cspin(0, 1, M_PI-z) * xtangent(1);
|
||||
slimetriangle(tip, a, b, 1, 0);
|
||||
slimetriangle(a, b, c, 1, 0);
|
||||
slimetriangle(b, c, d, 1, 0);
|
||||
|
@ -1141,7 +1184,7 @@ void geometry_information::make_3d_models() {
|
|||
}
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
add_texture(*last);
|
||||
if(WDIM == 2) shift_last_straight(FLOOR);
|
||||
if(WDIM == 2) shift_last_straight(FLOOR + cgi.emb->center_z());
|
||||
finishshape();
|
||||
shJelly = shSlime;
|
||||
|
||||
|
@ -1219,9 +1262,9 @@ void geometry_information::make_3d_models() {
|
|||
texture_order([&] (ld x, ld y) {
|
||||
ld z = 1-x-y;
|
||||
ld rad = 2.1 - i * 0.2;
|
||||
hyperpoint hx = ddi(t*12, -zhexf*rad) * C0;
|
||||
hyperpoint hy = ddi(t*12+12, -zhexf*rad) * C0;
|
||||
hyperpoint hz = C0;
|
||||
hyperpoint hx = ddi(t*12, -zhexf*rad) * tile_center();
|
||||
hyperpoint hy = ddi(t*12+12, -zhexf*rad) * tile_center();
|
||||
hyperpoint hz = tile_center();
|
||||
hyperpoint h = hx * x + hy * y + hz * z;
|
||||
h = mid(h, h);
|
||||
h = orthogonal_move(h, FLOOR - human_height * (i+2.5) / 100 * (x+y+1)/2);
|
||||
|
@ -1235,45 +1278,101 @@ void geometry_information::make_3d_models() {
|
|||
finishshape();
|
||||
}
|
||||
|
||||
hpcshape& geometry_information::generate_pipe(ld length, ld width) {
|
||||
int id = int(length * 17 + .5) + int(157003 * log(width+.001));
|
||||
if(shPipe.count(id)) return shPipe[id];
|
||||
hpcshape& pipe = shPipe[id];
|
||||
println(hlog, "generating pipe of length ", length, " and width ", width);
|
||||
bshape(pipe, PPR::WALL);
|
||||
hpcshape& geometry_information::gen_pipe(hpcshape& pipe, ePipeEnd endtype, ld ratio, const hr::function<hyperpoint(ld,ld,ld)>& f) {
|
||||
cgi.bshape(pipe, PPR::WALL);
|
||||
|
||||
const int MAX_X = 8;
|
||||
#if CAP_GL
|
||||
auto& utt = cgi.models_texture;
|
||||
if(floor_textures) {
|
||||
pipe.tinf = &utt;
|
||||
pipe.texture_offset = isize(utt.tvertices);
|
||||
}
|
||||
#endif
|
||||
|
||||
const int MAX_X = 32;
|
||||
const int MAX_R = 20;
|
||||
auto at = [length, width] (int i, int a) {
|
||||
return xpush(i * length / MAX_X) * cspin(1, 2, 360 * degree * a / MAX_R) * ypush0(width);
|
||||
auto at = [&] (ld i, ld a, ld z = 1, ld s = 1) {
|
||||
a += 0.5;
|
||||
ld alpha = TAU * a / MAX_R;
|
||||
cgi.hpcpush(f(i / MAX_X, alpha, z));
|
||||
#if CAP_GL
|
||||
if(floor_textures) utt.tvertices.push_back(glhr::makevertex(0, true ? 0.549 - s * 0.45 * sin(alpha) : 0.999, 0));
|
||||
#endif
|
||||
};
|
||||
for(int i=0; i<MAX_X; i++) {
|
||||
for(int a=0; a<MAX_R; a++) {
|
||||
hpcpush(at(i, a));
|
||||
hpcpush(at(i, a+1));
|
||||
hpcpush(at(i+1, a));
|
||||
hpcpush(at(i+1, a+1));
|
||||
hpcpush(at(i+1, a));
|
||||
hpcpush(at(i, a+1));
|
||||
at(i, a, 1);
|
||||
at(i, a+1, 1);
|
||||
at(i+1, a, 1);
|
||||
at(i+1, a+1, 1);
|
||||
at(i+1, a, 1);
|
||||
at(i, a+1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for(int a=0; a<MAX_R; a++) {
|
||||
hpcpush(at(MAX_X, a));
|
||||
hpcpush(at(MAX_X, a+1));
|
||||
hpcpush(xpush0(length));
|
||||
hpcpush(at(MAX_X, a+1));
|
||||
hpcpush(at(MAX_X, a));
|
||||
hpcpush(C0);
|
||||
if(endtype == ePipeEnd::sharp) for(int a=0; a<MAX_R; a++) for(int x: {0, MAX_X}) {
|
||||
at(x, a, 1, 0);
|
||||
at(x, a+1, 1, 0);
|
||||
at(x, 0, 0, 0);
|
||||
}
|
||||
|
||||
if(endtype == ePipeEnd::ball) for(int a=0; a<MAX_R; a++) for(int x=-MAX_R; x<MAX_R; x++) {
|
||||
ld xb = x < 0 ? 0 : MAX_X;
|
||||
ld mul = MAX_X * ratio * .9; // .9 to prevent Z-fighting
|
||||
ld x0 = xb + mul * sin(x * 90._deg / MAX_R);
|
||||
ld x1 = xb + mul * sin((x+1) * 90._deg / MAX_R);
|
||||
ld z0 = cos(x * 90._deg / MAX_R);
|
||||
ld z1 = cos((x+1) * 90._deg / MAX_R);
|
||||
at(x0, a, z0, z0);
|
||||
at(x0, a+1, z0, z0);
|
||||
at(x1, a, z1, z1);
|
||||
at(x1, a+1, z1, z1);
|
||||
at(x1, a, z1, z1);
|
||||
at(x0, a+1, z0, z0);
|
||||
}
|
||||
|
||||
last->flags |= POLY_TRIANGLES | POLY_PRINTABLE;
|
||||
add_texture(*last);
|
||||
finishshape();
|
||||
extra_vertices();
|
||||
return pipe;
|
||||
}
|
||||
|
||||
hpcshape& geometry_information::get_pipe_noniso(hyperpoint target, ld width, ePipeEnd endtype) {
|
||||
int id = bucketer(target) + int(157003 * log(width+.001));
|
||||
if(cgi.shPipe.count(id)) return cgi.shPipe[id];
|
||||
hpcshape& pipe = cgi.shPipe[id];
|
||||
|
||||
hyperpoint lmax = sol ? inverse_exp_newton(target, 10) : inverse_exp(shiftless(target));
|
||||
transmatrix lT;
|
||||
ld length;
|
||||
if(1) {
|
||||
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
||||
length = hdist0(lmax);
|
||||
lT = rspintox(lmax);
|
||||
}
|
||||
|
||||
return gen_pipe(pipe, endtype, width/length, [&] (ld i, ld alpha, ld z) {
|
||||
hyperpoint p;
|
||||
if(1) {
|
||||
dynamicval<eGeometry> g(geometry, gCubeTiling);
|
||||
p = xpush(i * length) * cspin(1, 2, alpha) * ypush0(width*z);
|
||||
p = lT * p;
|
||||
}
|
||||
return direct_exp(p);
|
||||
});
|
||||
}
|
||||
|
||||
hpcshape& geometry_information::get_pipe_iso(ld length, ld width, ePipeEnd endtype) {
|
||||
int id = int(length * 172 + .5) + int(157003 * log(width+.001));
|
||||
bool pers = in_perspective();
|
||||
if(!pers) id ^= 0x4126891;
|
||||
if(shPipe.count(id)) return shPipe[id];
|
||||
hpcshape& pipe = shPipe[id];
|
||||
println(hlog, "generating pipe of length ", length, " and width ", width);
|
||||
|
||||
return gen_pipe(pipe, endtype, width/length, [&] (ld i, ld alpha, ld z) { return xpush(i * length) * cspin(1, 2, alpha) * ypush0(width*z); });
|
||||
}
|
||||
|
||||
#undef S
|
||||
#undef SH
|
||||
#undef revZ
|
||||
|
|
45
Makefile
45
Makefile
|
@ -1,16 +1,24 @@
|
|||
# This Makefile works for Mac OS X (El Capitan), MinGW, and Linux.
|
||||
#
|
||||
# Environmental vairables:
|
||||
# If you want to build with Glew, set
|
||||
# HYPERROGUE_USE_GLEW=1
|
||||
# If you want to use libpng, set
|
||||
# HYPERROGUE_USE_PNG=1
|
||||
#
|
||||
# For Mac OS X:
|
||||
# Run "brew install sdl" to install SDL in /usr/local.
|
||||
# Run "brew install sdl_gfx".
|
||||
# Run "brew install sdl_mixer".
|
||||
# Run "brew install sdl_ttf".
|
||||
# Run "make" to build HyperRogue as ./hyperrogue.
|
||||
# Run `brew install sdl12-compat sdl_gfx sdl_mixer sdl_ttf`
|
||||
# Run `brew install glew libpng` to install the optional dependencies
|
||||
# Run `make` to build HyperRogue as `./hyperrogue`.
|
||||
#
|
||||
# For MSYS2 and MinGW-w64:
|
||||
# You might need to run commands such as "pacman -S mingw-w64-x86_64-SDL"
|
||||
# to install SDL and other required libraries.
|
||||
# Run "make" to build HyperRogue as ./hyperrogue.exe.
|
||||
# To install SDL and other required libraries, run these commands
|
||||
# from the MSYS2 shell:
|
||||
# pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-glew
|
||||
# pacman -S mingw-w64-ucrt-x86_64-SDL mingw-w64-ucrt-x86_64-SDL_mixer
|
||||
# pacman -S mingw-w64-ucrt-x86_64-SDL_ttf mingw-w64-ucrt-x86_64-SDL_gfx
|
||||
# pacman -S make
|
||||
# Then run "make" to build HyperRogue as ./hyperrogue.exe.
|
||||
#
|
||||
# For Ubuntu Linux:
|
||||
# Run "sudo apt-get install libsdl-dev" to install SDL in /usr/local.
|
||||
|
@ -54,7 +62,7 @@ ifeq (${OS},linux)
|
|||
endif
|
||||
|
||||
ifeq (${OS},mingw)
|
||||
CXXFLAGS_EARLY += -DWINDOWS -mwindows -D_A_VOLID=8
|
||||
CXXFLAGS_EARLY += -DWINDOWS -mwindows -D_A_VOLID=8 -I/ucrt64/include/SDL
|
||||
EXE_EXTENSION := .exe
|
||||
LDFLAGS_GL := -lopengl32
|
||||
LDFLAGS_GLEW := -lglew32
|
||||
|
@ -68,9 +76,10 @@ ifeq (${OS},mingw)
|
|||
endif
|
||||
|
||||
ifeq (${OS},osx)
|
||||
CXXFLAGS_EARLY += -DMAC -I/usr/local/include
|
||||
HOMEBREW_PREFIX := $(shell brew --prefix)
|
||||
CXXFLAGS_EARLY += -DMAC -I$(HOMEBREW_PREFIX)/include -I$(HOMEBREW_PREFIX)/include/SDL
|
||||
EXE_EXTENSION :=
|
||||
LDFLAGS_EARLY += -L/usr/local/lib
|
||||
LDFLAGS_EARLY += -L$(HOMEBREW_PREFIX)/lib
|
||||
LDFLAGS_GL := -framework AppKit -framework OpenGL
|
||||
LDFLAGS_GLEW := -lGLEW
|
||||
LDFLAGS_PNG := -lpng
|
||||
|
@ -80,7 +89,7 @@ ifeq (${OS},osx)
|
|||
endif
|
||||
|
||||
ifeq (${TOOLCHAIN},clang)
|
||||
CXXFLAGS_STD = -std=c++11
|
||||
CXXFLAGS_STD = -std=c++14
|
||||
CXXFLAGS_EARLY += -fPIC
|
||||
CXXFLAGS_EARLY += -W -Wall -Wextra -Wsuggest-override -pedantic
|
||||
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized -Wno-char-subscripts -Wno-unknown-warning-option
|
||||
|
@ -88,7 +97,7 @@ ifeq (${TOOLCHAIN},clang)
|
|||
endif
|
||||
|
||||
ifeq (${TOOLCHAIN},gcc)
|
||||
CXXFLAGS_STD = -std=c++11
|
||||
CXXFLAGS_STD = -std=c++14
|
||||
CXXFLAGS_EARLY += -fPIC
|
||||
CXXFLAGS_EARLY += -W -Wall -Wextra -pedantic
|
||||
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized
|
||||
|
@ -96,12 +105,16 @@ ifeq (${TOOLCHAIN},gcc)
|
|||
endif
|
||||
|
||||
ifeq (${TOOLCHAIN},mingw)
|
||||
CXXFLAGS_STD = -std=c++11
|
||||
CXXFLAGS_STD = -std=c++14
|
||||
CXXFLAGS_EARLY += -W -Wall -Wextra
|
||||
CXXFLAGS_EARLY += -Wno-unused-parameter -Wno-implicit-fallthrough -Wno-maybe-uninitialized
|
||||
CXXFLAGS_EARLY += -Wno-invalid-offsetof
|
||||
endif
|
||||
|
||||
ifeq (${FONTCONFIG},1)
|
||||
CXXFLAGS_EARLY += -DFONTCONFIG `pkg-config --cflags fontconfig`
|
||||
LDFLAGS_EARLY += `pkg-config --libs fontconfig`
|
||||
endif
|
||||
|
||||
## We have now finished OS-specific and TOOLCHAIN-specific computations.
|
||||
## Begin customization points for user-specifiable HYPERROGUE_USE_XXX macros.
|
||||
|
@ -155,7 +168,7 @@ makeh$(EXE_EXTENSION): makeh.cpp
|
|||
$(CXX) -O2 makeh.cpp -o $@
|
||||
|
||||
autohdr.h: makeh$(EXE_EXTENSION) language-data.cpp *.cpp
|
||||
./makeh classes.cpp locations.cpp colors.cpp hyperpoint.cpp geometry.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp util.cpp complex.cpp multigame.cpp *.cpp > autohdr.h
|
||||
./makeh classes.cpp locations.cpp colors.cpp hyperpoint.cpp geometry.cpp embeddings.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp util.cpp complex.cpp multigame.cpp arbitrile.cpp rulegen.cpp *.cpp > autohdr.h
|
||||
|
||||
language-data.cpp: langen$(EXE_EXTENSION)
|
||||
./langen > language-data.cpp
|
||||
|
@ -169,7 +182,7 @@ mymake$(EXE_EXTENSION): mymake.cpp
|
|||
emscripten: hyper.html
|
||||
|
||||
%.html %.js %.wasm: %.emscripten-sources
|
||||
emcc -std=c++11 -O3 -s USE_ZLIB=1 -s LEGACY_GL_EMULATION=1 -s TOTAL_MEMORY=128MB hyperweb.cpp -o hyper.html
|
||||
emcc -std=c++14 -O3 -s USE_ZLIB=1 -s LEGACY_GL_EMULATION=1 -s TOTAL_MEMORY=128MB hyperweb.cpp -o hyper.html
|
||||
|
||||
hyper.emscripten-sources: *.cpp autohdr.h
|
||||
|
||||
|
|
19
README.md
19
README.md
|
@ -1,14 +1,4 @@
|
|||
# HyperRogue
|
||||
<p align="right">
|
||||
<a href="https://travis-ci.org/zenorogue/hyperrogue/builds">
|
||||
<img align="right" src="https://badges.herokuapp.com/travis/zenorogue/hyperrogue?branch=master&env=TRAVIS_BUILD_SYSTEM=Makefile&label=make" alt="TravisCI badge">
|
||||
<img align="right" src="https://badges.herokuapp.com/travis/zenorogue/hyperrogue?branch=master&env=TRAVIS_BUILD_SYSTEM=mymake&label=mymake" alt="TravisCI badge">
|
||||
<img align="right" src="https://badges.herokuapp.com/travis/zenorogue/hyperrogue?branch=master&env=TRAVIS_BUILD_SYSTEM=emscripten&label=web" alt="TravisCI badge">
|
||||
</a>
|
||||
</p>
|
||||
<p align="left">
|
||||
<b>Current version: 11.3f</b>
|
||||
</p>
|
||||
|
||||
A puzzle roguelike in the hyperbolic plane. See the [HyperRogue website](http://roguetemple.com/z/hyper.php) for detailed and most up-to-date information.
|
||||
Compiled executables can be downloaded from [itch.io](https://zenorogue.itch.io/hyperrogue) and from the [HyperRogue website](http://www.roguetemple.com/z/hyper/download.php).
|
||||
|
@ -65,15 +55,13 @@ On Linux with apt-get:
|
|||
|
||||
On macOS with Homebrew:
|
||||
|
||||
```brew install sdl sdl_ttf sdl_gfx sdl_mixer glew```
|
||||
|
||||
macOS users might also have to edit /usr/local/include/SDL/SDL_gfxPrimitives.h at line 38 to use quote include.
|
||||
```brew install sdl sdl_ttf sdl_gfx sdl_mixer glew libpng```
|
||||
|
||||
### Building HyperRogue from source ###
|
||||
```
|
||||
git clone https://github.com/zenorogue/hyperrogue.git hyperrogue
|
||||
cd hyperrogue
|
||||
make
|
||||
HYPERROGUE_USE_GLEW=1 HYPERROGUE_USE_PNG=1 make
|
||||
```
|
||||
|
||||
The `mymake` program builds HyperRogue in parts. It takes longer than the method shown above, but it uses significantly less memory during compilation, and when you change something, `mymake` will only recompile the changed file.
|
||||
|
@ -86,3 +74,6 @@ make mymake && ./mymake
|
|||
```
|
||||
|
||||
The source code is not documented very well. You can see the current state of the documentation, as generated by Doxygen, [here](https://zenorogue.github.io/hyperrogue-doc/).
|
||||
|
||||
## Discussion ##
|
||||
The best place to discuss HyperRogue is our [Discord server|https://discord.com/invite/8G44XkR].
|
||||
|
|
146
achievement.cpp
146
achievement.cpp
|
@ -10,7 +10,9 @@
|
|||
#include "hyper.h"
|
||||
namespace hr {
|
||||
|
||||
#define NUMLEADER 87
|
||||
#if HDR
|
||||
#define NUMLEADER 90
|
||||
#endif
|
||||
|
||||
EX bool test_achievements = false;
|
||||
|
||||
|
@ -80,12 +82,33 @@ EX const char* leadernames[NUMLEADER] = {
|
|||
"Lazurite Figurines", // 83
|
||||
"Water Lilies", // 84
|
||||
"Capon Stones", // 85
|
||||
"Crystal Dice" // 86
|
||||
"Crystal Dice", // 86
|
||||
"Crossbow (bull)", // 87
|
||||
"Crossbow (geodesic)", // 88
|
||||
"Crossbow (geometric)", // 89
|
||||
};
|
||||
|
||||
#if HDR
|
||||
#define LB_PRINCESS 36
|
||||
#define LB_STATISTICS 62
|
||||
#define LB_HALLOWEEN 63
|
||||
#define LB_HALLOWEEN 63
|
||||
#define LB_YENDOR_CHALLENGE 40
|
||||
#define LB_PURE_TACTICS 41
|
||||
#define LB_PURE_TACTICS_SHMUP 49
|
||||
#define LB_PURE_TACTICS_COOP 50
|
||||
#define LB_RACING 81
|
||||
#endif
|
||||
|
||||
EX void achievement_init();
|
||||
EX string myname();
|
||||
EX void achievement_close();
|
||||
EX void achievement_pump();
|
||||
|
||||
/** gain the given achievement.
|
||||
* @param s name of the achievement, e.g., DIAMOND1
|
||||
* @param flags one of the constants from namespace rg. The achievement is only awarded if special modes are matched exactly.
|
||||
*/
|
||||
EX void achievement_gain(const char* s, char flags IS(0));
|
||||
|
||||
EX bool haveLeaderboard(int id);
|
||||
EX int get_currentscore(int id);
|
||||
|
@ -93,11 +116,11 @@ EX void set_priority_board(int id);
|
|||
EX int get_sync_status();
|
||||
EX bool score_loaded(int id);
|
||||
EX int score_default(int id);
|
||||
|
||||
EX void improveItemScores();
|
||||
EX void upload_score(int id, int v);
|
||||
|
||||
string achievementMessage[3];
|
||||
int achievementTimer;
|
||||
EX string achievementMessage[3];
|
||||
EX int achievementTimer;
|
||||
/** achievements received this game */
|
||||
EX vector<string> achievementsReceived;
|
||||
|
||||
|
@ -108,12 +131,15 @@ EX bool wrongMode(char flags) {
|
|||
if(cheater) return true;
|
||||
if(casual) return true;
|
||||
if(flags == rg::global) return false;
|
||||
if(flags == rg::fail) return true;
|
||||
|
||||
if(flags != rg::special_geometry && flags != rg::special_geometry_nicewalls) {
|
||||
if(!BITRUNCATED) return true;
|
||||
if(geometry != gNormal) return true;
|
||||
if(disksize) return true;
|
||||
}
|
||||
if(ineligible_starting_land && !flags) return true;
|
||||
if(use_custom_land_list) return true;
|
||||
|
||||
if(shmup::on != (flags == rg::shmup || flags == rg::racing)) return true;
|
||||
if(racing::on != (flags == rg::racing)) return true;
|
||||
|
@ -129,12 +155,17 @@ EX bool wrongMode(char flags) {
|
|||
if(tour::on) return true;
|
||||
#endif
|
||||
eLandStructure dls = lsNiceWalls;
|
||||
if(flags == rg::special_geometry || flags == rg::racing || flags == rg::princess)
|
||||
if(flags == rg::princess && !princess::challenge) return true;
|
||||
if(flags == rg::special_geometry || flags == rg::princess)
|
||||
dls = lsSingle;
|
||||
if(flags == rg::chaos)
|
||||
dls = lsChaos;
|
||||
/* in the official racing achievements, the tracks are saved maps anyway */
|
||||
if(flags == rg::racing)
|
||||
dls = land_structure;
|
||||
|
||||
if(land_structure != dls) return true;
|
||||
if(shmup::on && vid.creature_scale != 1) return true;
|
||||
if(numplayers() > 1 && !multi::friendly_fire) return true;
|
||||
if(numplayers() > 1 && multi::pvp_mode) return true;
|
||||
if(numplayers() > 1 && multi::split_screen) return true;
|
||||
|
@ -155,6 +186,25 @@ EX void achievement_gain_once(const string& s, char flags IS(0)) {
|
|||
achievement_gain(s.c_str(), flags);
|
||||
}
|
||||
|
||||
namespace rg {
|
||||
char check(bool b, char val = special_geometry) { return b ? val : fail; }
|
||||
}
|
||||
|
||||
EX char specgeom_zebra() { return rg::check(geometry == gZebraQuotient && !disksize && BITRUNCATED && firstland == laDesert); }
|
||||
EX char specgeom_lovasz() { return rg::check(geometry == gKleinQuartic && variation == eVariation::untruncated && gp::param == gp::loc(1,1) && !disksize && in_lovasz()); }
|
||||
EX char specgeom_halloween() { return rg::check((geometry == gSphere || geometry == gElliptic) && BITRUNCATED && !disksize && firstland == laHalloween); }
|
||||
EX char specgeom_heptagonal() { return rg::check(PURE && geometry == gNormal && !disksize, rg::special_geometry_nicewalls); }
|
||||
EX char specgeom_euclid_gen() { return rg::check(geometry == gEuclid && !disksize && firstland == laMirrorOld); }
|
||||
EX char specgeom_crystal1() { return rg::check(PURE && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 4 && !crystal::used_compass_inside && !disksize && firstland == laCamelot); }
|
||||
EX char specgeom_crystal2() { return rg::check(BITRUNCATED && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 3 && !crystal::used_compass_inside && !disksize && firstland == laCamelot); }
|
||||
|
||||
EX vector<std::function<char()>> all_specgeom_checks = { specgeom_zebra, specgeom_lovasz, specgeom_halloween, specgeom_heptagonal, specgeom_crystal1, specgeom_crystal2, specgeom_euclid_gen };
|
||||
|
||||
EX char any_specgeom() {
|
||||
for(auto chk: all_specgeom_checks) if(chk() != rg::fail) return chk();
|
||||
return rg::fail;
|
||||
}
|
||||
|
||||
EX void achievement_log(const char* s, char flags) {
|
||||
|
||||
if(wrongMode(flags)) {
|
||||
|
@ -174,7 +224,7 @@ EX void achievement_log(const char* s, char flags) {
|
|||
#if CAP_SAVE
|
||||
remove_emergency_save();
|
||||
|
||||
FILE *f = fopen(scorefile, "at");
|
||||
FILE *f = fopen(scorefile.c_str(), "at");
|
||||
if(!f) return;
|
||||
|
||||
int t = (int) (time(NULL) - timerstart);
|
||||
|
@ -189,29 +239,24 @@ EX void achievement_log(const char* s, char flags) {
|
|||
#endif
|
||||
}
|
||||
|
||||
EX void achievement_init();
|
||||
EX string myname();
|
||||
EX void achievement_close();
|
||||
#ifndef LEADER
|
||||
#define LEADER "Unknown"
|
||||
#define LEADERFULL "Unknown"
|
||||
#endif
|
||||
|
||||
/** gain the given achievement.
|
||||
* @param s name of the achievement, e.g., DIAMOND1
|
||||
* @param flags one of the constants from namespace rg. The achievement is only awarded if special modes are matched exactly.
|
||||
*/
|
||||
EX void achievement_gain(const char* s, char flags IS(0));
|
||||
|
||||
#if ISSTEAM
|
||||
void improveItemScores();
|
||||
#include "private/hypersteam.cpp"
|
||||
#elif !ISANDROID && !ISIOS
|
||||
#if !CAP_ACHIEVE
|
||||
void achievement_init() {}
|
||||
string myname() { return "Rogue"; }
|
||||
void achievement_close() {}
|
||||
// gain the achievement with the given name.
|
||||
// flags: 'e' - for Euclidean, 's' - for Shmup, '7' - for heptagonal
|
||||
// Only awarded if special modes are matched exactly.
|
||||
void achievement_gain(const char* s, char flags IS(0)) {
|
||||
void achievement_gain(const char* s, char flags) {
|
||||
achievement_log(s, flags);
|
||||
}
|
||||
void achievement_pump() {}
|
||||
EX int get_sync_status() { return 0; }
|
||||
EX void set_priority_board(int) { }
|
||||
#endif
|
||||
|
||||
// gain the achievement for collecting a number of 'it'.
|
||||
|
@ -225,11 +270,11 @@ EX void achievement_collection2(eItem it, int q) {
|
|||
if(randomPatternsMode) return;
|
||||
LATE( achievement_collection2(it, q); )
|
||||
|
||||
if(it == itTreat && q == 50 && (geometry == gSphere || geometry == gElliptic) && BITRUNCATED && !disksize)
|
||||
achievement_gain("HALLOWEEN1", rg::special_geometry);
|
||||
if(it == itTreat && q == 50)
|
||||
achievement_gain("HALLOWEEN1", specgeom_halloween());
|
||||
|
||||
if(it == itTreat && q == 100 && (geometry == gSphere || geometry == gElliptic) && BITRUNCATED && !disksize)
|
||||
achievement_gain("HALLOWEEN2", rg::special_geometry);
|
||||
if(it == itTreat && q == 100)
|
||||
achievement_gain("HALLOWEEN2", specgeom_halloween());
|
||||
|
||||
if(q == 1) {
|
||||
if(it == itDiamond) achievement_gain("DIAMOND1");
|
||||
|
@ -309,13 +354,10 @@ EX void achievement_collection2(eItem it, int q) {
|
|||
// 32
|
||||
if(it == itHolyGrail) {
|
||||
if(q == 1) achievement_gain("GRAIL2");
|
||||
if(PURE && geometry == gNormal && !disksize)
|
||||
achievement_gain("GRAILH", rg::special_geometry_nicewalls);
|
||||
achievement_gain("GRAILH", specgeom_heptagonal());
|
||||
#if CAP_CRYSTAL
|
||||
if(PURE && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 4 && !crystal::used_compass_inside && !disksize)
|
||||
achievement_gain("GRAIL4D", rg::special_geometry);
|
||||
if(BITRUNCATED && cryst && ginf[gCrystal].sides == 8 && ginf[gCrystal].vertex == 3 && !crystal::used_compass_inside && !disksize)
|
||||
achievement_gain("GRAIL4D2", rg::special_geometry);
|
||||
achievement_gain("GRAIL4D", specgeom_crystal1());
|
||||
achievement_gain("GRAIL4D2", specgeom_crystal2());
|
||||
#endif
|
||||
if(q == 3) achievement_gain("GRAIL3");
|
||||
if(q == 8) achievement_gain("GRAIL4");
|
||||
|
@ -599,14 +641,18 @@ EX void achievement_count(const string& s, int current, int prev) {
|
|||
achievement_gain("LIGHTNING2");
|
||||
if(s == "LIGHTNING" && current-prev >= 10)
|
||||
achievement_gain("LIGHTNING3");
|
||||
if(s == "MIRAGE" && current >= 35 && geometry == gEuclid && !disksize)
|
||||
achievement_gain("MIRAGE", rg::special_geometry);
|
||||
if(s == "MIRAGE" && current >= 35)
|
||||
achievement_gain("MIRAGE", specgeom_euclid_gen());
|
||||
if(s == "ORB" && current >= 10)
|
||||
achievement_gain("ORB3");
|
||||
if(s == "BUG" && current >= 1000)
|
||||
achievement_gain("BUG3");
|
||||
if(s == "ELEC" && current >= 10)
|
||||
achievement_gain("ELEC3");
|
||||
if(s == "BOWVARIETY" && current >= 2)
|
||||
achievement_gain("BOWVARIETY1");
|
||||
if(s == "BOWVARIETY" && current >= 6)
|
||||
achievement_gain("BOWVARIETY2");
|
||||
}
|
||||
|
||||
int specific_improved = 0;
|
||||
|
@ -615,7 +661,7 @@ int specific_what = 0;
|
|||
EX void improve_score(int i, eItem what) {
|
||||
if(offlineMode) return;
|
||||
LATE( improve_score(i, what); )
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
#if CAP_ACHIEVE
|
||||
if(haveLeaderboard(i)) updateHi(what, get_currentscore(i));
|
||||
if(items[what] && haveLeaderboard(i)) {
|
||||
if(items[what] > get_currentscore(i) && score_loaded(i)) {
|
||||
|
@ -629,7 +675,7 @@ EX void improve_score(int i, eItem what) {
|
|||
// scores for special challenges
|
||||
EX void achievement_score(int cat, int number) {
|
||||
if(offlineMode) return;
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
#if CAP_ACHIEVE
|
||||
if(cheater) return;
|
||||
if(casual) return;
|
||||
LATE( achievement_score(cat, number); )
|
||||
|
@ -650,6 +696,8 @@ EX void achievement_score(int cat, int number) {
|
|||
if(tactic::on && cat != LB_PURE_TACTICS && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP)
|
||||
return;
|
||||
if(racing::on && cat != LB_RACING) return;
|
||||
if(bow::weapon) return;
|
||||
if(use_custom_land_list) return;
|
||||
upload_score(cat, number);
|
||||
#endif
|
||||
}
|
||||
|
@ -733,7 +781,7 @@ EX void achievement_final(bool really_final) {
|
|||
|
||||
LATE( achievement_final(really_final); )
|
||||
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
#if CAP_ACHIEVE
|
||||
if(ticks > next_stat_tick) {
|
||||
upload_score(LB_STATISTICS, time(NULL));
|
||||
next_stat_tick = ticks + 600000;
|
||||
|
@ -771,6 +819,10 @@ EX void achievement_final(bool really_final) {
|
|||
if(PURE) specialcode+=4;
|
||||
if(numplayers() > 1) specialcode+=8;
|
||||
if(inv::on) specialcode+=16;
|
||||
if(bow::crossbow_mode() && bow::style == bow::cbBull) specialcode += 32;
|
||||
if(bow::crossbow_mode() && bow::style == bow::cbGeodesic) specialcode += 64;
|
||||
if(bow::crossbow_mode() && bow::style == bow::cbGeometric) specialcode += 96;
|
||||
if(shmup::on && vid.creature_scale != 1) return;
|
||||
|
||||
if(sphere && specialland == laHalloween) {
|
||||
if(specialcode) return;
|
||||
|
@ -781,6 +833,7 @@ EX void achievement_final(bool really_final) {
|
|||
if(ineligible_starting_land) return;
|
||||
if(geometry) return;
|
||||
if(NONSTDVAR) return;
|
||||
if(use_custom_land_list) return;
|
||||
|
||||
if(numplayers() > 1 && !multi::friendly_fire) return;
|
||||
if(numplayers() > 1 && multi::pvp_mode) return;
|
||||
|
@ -797,6 +850,9 @@ EX void achievement_final(bool really_final) {
|
|||
case 8: sid = 61; break;
|
||||
case 9: sid = 44; break;
|
||||
case 16: sid = 69; break;
|
||||
case 32: sid = 87; break;
|
||||
case 64: sid = 88; break;
|
||||
case 96: sid = 89; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
|
@ -860,9 +916,10 @@ EX void check_total_victory() {
|
|||
EX void achievement_victory(bool hyper) {
|
||||
DEBBI(DF_STEAM, ("achievement_victory"))
|
||||
if(offlineMode) return;
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
#if CAP_ACHIEVE
|
||||
if(cheater) return;
|
||||
if(casual) return;
|
||||
if(bow::weapon) return;
|
||||
if(geometry) return;
|
||||
if(CHANGED_VARIATION) return;
|
||||
if(randomPatternsMode) return;
|
||||
|
@ -872,6 +929,7 @@ EX void achievement_victory(bool hyper) {
|
|||
if(tactic::on) return;
|
||||
if(!ls::nice_walls()) return;
|
||||
if(ineligible_starting_land) return;
|
||||
if(use_custom_land_list) return;
|
||||
LATE( achievement_victory(hyper); )
|
||||
DEBB(DF_STEAM, ("after checks"))
|
||||
|
||||
|
@ -954,6 +1012,7 @@ EX string get_rich_presence_text() {
|
|||
if(inv::on) res += "OSM ";
|
||||
if(multi::players > 1) res += "multi ";
|
||||
if(casual) res += "casual ";
|
||||
if(bow::weapon) res += bow::style == bow::cbBull ? "bow/bull " : "bow/geo ";
|
||||
|
||||
if(cheater || among(cwt.at->land, laCanvas, laCA))
|
||||
return res + "(?)";
|
||||
|
@ -991,13 +1050,9 @@ EX string get_rich_presence_text() {
|
|||
return res;
|
||||
}
|
||||
|
||||
#ifndef HAVE_ACHIEVEMENTS
|
||||
void achievement_pump() {}
|
||||
#endif
|
||||
|
||||
/** display the last achievement gained. */
|
||||
EX void achievement_display() {
|
||||
#ifdef HAVE_ACHIEVEMENTS
|
||||
#if CAP_ACHIEVE
|
||||
if(achievementTimer) {
|
||||
int col = (ticks - achievementTimer);
|
||||
if(col > 5000) { achievementTimer = 0; return; }
|
||||
|
@ -1027,9 +1082,4 @@ EX int score_default(int i) {
|
|||
else return 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_ACHIEVEMENTS
|
||||
EX int get_sync_status() { return 0; }
|
||||
EX void set_priority_board(int) { }
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
589
arbitrile.cpp
589
arbitrile.cpp
File diff suppressed because it is too large
Load Diff
242
archimedean.cpp
242
archimedean.cpp
|
@ -96,11 +96,11 @@ struct archimedean_tiling {
|
|||
#endif
|
||||
|
||||
#if HDR
|
||||
static const int sfPH = 1;
|
||||
static const int sfLINE = 2;
|
||||
static const int sfCHESS = 4;
|
||||
static const int sfTHREE = 8;
|
||||
static const int sfSEMILINE = 16;
|
||||
static constexpr int sfPH = 1;
|
||||
static constexpr int sfLINE = 2;
|
||||
static constexpr int sfCHESS = 4;
|
||||
static constexpr int sfTHREE = 8;
|
||||
static constexpr int sfSEMILINE = 16;
|
||||
#endif
|
||||
|
||||
#if CAP_ARCM
|
||||
|
@ -168,7 +168,7 @@ EX ld compute_edgelength(vector<pair<ld, ld>> facemul, ld halftotal IS(M_PI)) {
|
|||
else {
|
||||
ld gamma = M_PI / fm.first;
|
||||
auto c = asin_auto(sin_auto(edgelength/2) / sin(gamma));
|
||||
hyperpoint h = xpush(c) * spin(M_PI - 2*gamma) * xpush0(c);
|
||||
hyperpoint h = lxpush(c) * spin(M_PI - 2*gamma) * lxpush0(c);
|
||||
ld a = atan2(h);
|
||||
cyclefix(a, 0);
|
||||
if(a < 0) a = -a;
|
||||
|
@ -291,7 +291,7 @@ void archimedean_tiling::prepare() {
|
|||
int inv = oi;
|
||||
DEBB0(DF_GEOM, ("vertex "));
|
||||
for(int z=0; z<faces[i]; z++) {
|
||||
DEBB0(DF_GEOM, (format("[%d %d] " , at, inv)));
|
||||
DEBB0(DF_GEOM, (hr::format("[%d %d] " , at, inv)));
|
||||
adjacent[2*i+oi].emplace_back(2*N+int(inv), inv ? (2*at+2*N-2) % (2*N) : 2*at);
|
||||
if(invert[at]) inv ^= 1;
|
||||
at = adj[at];
|
||||
|
@ -299,7 +299,7 @@ void archimedean_tiling::prepare() {
|
|||
else at = (at+N-1) % N;
|
||||
}
|
||||
if(!inv) make_match(2*i, 0, inv ? (2*at+2*N-1) % 2*N : 2*at, 0);
|
||||
DEBB(DF_GEOM, (format("-> [%d %d]\n", at, inv)));
|
||||
DEBB(DF_GEOM, (hr::format("-> [%d %d]\n", at, inv)));
|
||||
}
|
||||
}
|
||||
for(int i=0; i<N; i++) {
|
||||
|
@ -348,11 +348,11 @@ void archimedean_tiling::prepare() {
|
|||
int ai = i, aj = j;
|
||||
DEBB0(DF_GEOM, ("triangle "));
|
||||
for(int s=0; s<3; s++) {
|
||||
DEBB0(DF_GEOM, (format("[%d %d] ", ai, aj)));
|
||||
DEBB0(DF_GEOM, (hr::format("[%d %d] ", ai, aj)));
|
||||
tie(ai, aj) = adjacent[ai][aj];
|
||||
aj++; if(aj >= isize(adjacent[ai])) aj = 0;
|
||||
}
|
||||
DEBB(DF_GEOM, (format("-> [%d %d]\n", ai, aj)));
|
||||
DEBB(DF_GEOM, (hr::format("-> [%d %d]\n", ai, aj)));
|
||||
make_match(i, j, ai, aj);
|
||||
}
|
||||
}
|
||||
|
@ -406,23 +406,35 @@ void archimedean_tiling::regroup() {
|
|||
|
||||
if(debugflags & DF_GEOM) {
|
||||
for(int i=0; i<M; i+=(have_symmetry?1:2)) {
|
||||
DEBB(DF_GEOM, (format("tiling group of %2d: [%2d]%2d+Z%2d\n", i, tilegroup[i], groupoffset[i], periods[i])));
|
||||
DEBB(DF_GEOM, (hr::format("tiling group of %2d: [%2d]%2d+Z%2d\n", i, tilegroup[i], groupoffset[i], periods[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
geometryinfo1& archimedean_tiling::get_geometry(ld mul) {
|
||||
if(euclidean_angle_sum * mul < 1.999999) return ginf[gSphere].g;
|
||||
else if(euclidean_angle_sum * mul > 2.000001) return ginf[gNormal].g;
|
||||
else return ginf[gEuclid].g;
|
||||
if(euclidean_angle_sum * mul < 1.999999) return giSphere2;
|
||||
else if(euclidean_angle_sum * mul > 2.000001) return giHyperb2;
|
||||
else return giEuclid2;
|
||||
}
|
||||
|
||||
void archimedean_tiling::compute_geometry() {
|
||||
ginf[gArchimedean].g = get_geometry();
|
||||
set_flag(ginf[gArchimedean].flags, qCLOSED, get_class() == gcSphere);
|
||||
|
||||
DEBB(DF_GEOM, (format("euclidean_angle_sum = %f\n", float(euclidean_angle_sum))));
|
||||
|
||||
|
||||
if(embedded_plane && geometry != gArchimedean) return;
|
||||
if(embedded_plane) return IPF(compute_geometry());
|
||||
|
||||
auto gg = get_geometry();
|
||||
|
||||
for(int a=0; a<2; a++) {
|
||||
auto& arr = a ? geom3::ginf_backup : ginf;
|
||||
if(arr.empty()) continue;
|
||||
if(gg.kind == gcSphere) arr[gArchimedean].g = arr[gSphere].g;
|
||||
if(gg.kind == gcEuclid) arr[gArchimedean].g = arr[gEuclid].g;
|
||||
if(gg.kind == gcHyperbolic) arr[gArchimedean].g = arr[gNormal].g;
|
||||
set_flag(arr[gArchimedean].flags, qCLOSED, gg.kind == gcSphere);
|
||||
}
|
||||
|
||||
DEBB(DF_GEOM, (hr::format("euclidean_angle_sum = %f\n", float(euclidean_angle_sum))));
|
||||
|
||||
bool infake = fake::in();
|
||||
|
||||
dynamicval<eGeometry> dv(geometry, gArchimedean);
|
||||
|
@ -444,25 +456,28 @@ void archimedean_tiling::compute_geometry() {
|
|||
ld elmin = 0, elmax = hyperbolic ? 10 : sphere ? M_PI : 2 * euclidean_edge_length;
|
||||
|
||||
/* inradius[N] is used in farcorner and nearcorner. Probably a bug */
|
||||
|
||||
bool need_flip = embedded_plane;
|
||||
if(need_flip) geom3::light_flip(true);
|
||||
|
||||
if(real_faces == 2) {
|
||||
/* standard methods fail for dihedra, but the answer is easy */
|
||||
edgelength = 2 * M_PI / faces[0];
|
||||
edgelength = TAU / faces[0];
|
||||
for(int i=0; i<N; i++)
|
||||
if(faces[i] == 2)
|
||||
alphas[i] = 0,
|
||||
circumradius[i] = M_PI / real_face_type,
|
||||
inradius[i] = 0;
|
||||
else
|
||||
alphas[i] = M_PI/2,
|
||||
circumradius[i] = inradius[i] = M_PI/2;
|
||||
alphas[i] = 90._deg,
|
||||
circumradius[i] = inradius[i] = 90._deg;
|
||||
}
|
||||
else if(real_faces == 0) {
|
||||
// these are called hosohedra
|
||||
edgelength = M_PI;
|
||||
for(int i=0; i<N; i++)
|
||||
alphas[i] = M_PI / N,
|
||||
circumradius[i] = M_PI/2,
|
||||
circumradius[i] = 90._deg,
|
||||
inradius[i] = 0;
|
||||
}
|
||||
else for(int p=0; p<100; p++) {
|
||||
|
@ -478,9 +493,9 @@ void archimedean_tiling::compute_geometry() {
|
|||
auto& c = circumradius[i];
|
||||
|
||||
c = asin_auto(sin_auto(edgelength/2) / sin(gamma));
|
||||
inradius[i] = hdist0(mid(xpush0(circumradius[i]), xspinpush0(2*gamma, circumradius[i])));
|
||||
inradius[i] = hdist0(mid(xpush0(circumradius[i]), cspin(0, 1, 2*gamma) * xpush0(circumradius[i])));
|
||||
|
||||
hyperpoint h = xpush(c) * spin(M_PI - 2*gamma) * xpush0(c);
|
||||
hyperpoint h = xpush(c) * cspin(0, 1, M_PI - 2*gamma) * xpush0(c);
|
||||
ld a = atan2(h);
|
||||
cyclefix(a, 0);
|
||||
if(a < 0) a = -a;
|
||||
|
@ -497,14 +512,16 @@ void archimedean_tiling::compute_geometry() {
|
|||
else elmax = edgelength;
|
||||
if(euclid) break;
|
||||
}
|
||||
|
||||
if(need_flip) geom3::light_flip(false);
|
||||
|
||||
DEBB(DF_GEOM, (format("computed edgelength = %f\n", float(edgelength))));
|
||||
DEBB(DF_GEOM, (hr::format("computed edgelength = %f\n", float(edgelength))));
|
||||
|
||||
triangles.clear();
|
||||
triangles.resize(2*N+2);
|
||||
for(int i=0; i<N; i++) for(int j=0; j<2; j++)
|
||||
for(int k=0; k<faces[i]; k++)
|
||||
triangles[2*i+j].emplace_back(2*M_PI/faces[i], circumradius[i]);
|
||||
triangles[2*i+j].emplace_back(TAU/faces[i], circumradius[i]);
|
||||
|
||||
for(int k=0; k<N; k++) {
|
||||
triangles[2*N].emplace_back(alphas[k], circumradius[k]);
|
||||
|
@ -520,7 +537,7 @@ void archimedean_tiling::compute_geometry() {
|
|||
|
||||
if(debugflags & DF_GEOM) for(auto& ts: triangles) {
|
||||
DEBB0(DF_GEOM, ("T"));
|
||||
for(auto& t: ts) DEBB0(DF_GEOM, (format(" %f@%f", float(t.first), float(t.second))));
|
||||
for(auto& t: ts) DEBB0(DF_GEOM, (hr::format(" %f@%f", float(t.first), float(t.second))));
|
||||
DEBB(DF_GEOM, ());
|
||||
}
|
||||
|
||||
|
@ -529,9 +546,9 @@ void archimedean_tiling::compute_geometry() {
|
|||
}
|
||||
|
||||
ld archimedean_tiling::scale() {
|
||||
if(real_faces == 0 && N == 2) return M_PI / 2;
|
||||
if(real_faces == 2) return M_PI / 2;
|
||||
if(real_faces == 0) return 2 * M_PI / N;
|
||||
if(real_faces == 0 && N == 2) return 90._deg;
|
||||
if(real_faces == 2) return 90._deg;
|
||||
if(real_faces == 0) return TAU / N;
|
||||
return edgelength;
|
||||
}
|
||||
|
||||
|
@ -555,13 +572,14 @@ EX bool use_gmatrix = true;
|
|||
* not used by arcm itself, but used in fake arcm
|
||||
*/
|
||||
|
||||
EX geometry_information *alt_cgip;
|
||||
EX geometry_information *alt_cgip[2];
|
||||
|
||||
EX geometry_information *find_alt_cgip() {
|
||||
if(alt_cgip) return alt_cgip;
|
||||
auto& galt_cgip = alt_cgip[embedded_plane];
|
||||
if(galt_cgip) return galt_cgip;
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
return alt_cgip = cgip;
|
||||
return galt_cgip = cgip;
|
||||
}
|
||||
|
||||
struct hrmap_archimedean : hrmap {
|
||||
|
@ -583,16 +601,24 @@ struct hrmap_archimedean : hrmap {
|
|||
heptagon *alt = NULL;
|
||||
|
||||
if(hyperbolic) {
|
||||
dynamicval<eGeometry> g(geometry, gNormal);
|
||||
dynamicval<eVariation> gv(variation, eVariation::pure);
|
||||
dynamicval<geometry_information*> gi(cgip, find_alt_cgip());
|
||||
alt = init_heptagon(S7);
|
||||
alt->s = hsOrigin;
|
||||
alt->alt = alt;
|
||||
current_altmap = newAltMap(alt);
|
||||
bool f = geom3::flipped;
|
||||
if(f) geom3::light_flip(false);
|
||||
if(1) {
|
||||
dynamicval<eGeometry> g(geometry, gNormal);
|
||||
dynamicval<eVariation> gv(variation, eVariation::pure);
|
||||
dynamicval<geometry_information*> gi(cgip, find_alt_cgip());
|
||||
alt = init_heptagon(S7);
|
||||
alt->s = hsOrigin;
|
||||
alt->alt = alt;
|
||||
current_altmap = newAltMap(alt);
|
||||
}
|
||||
if(f) geom3::light_flip(true);
|
||||
}
|
||||
|
||||
transmatrix T = xpush(.01241) * spin(1.4117) * xpush(0.1241) * Id;
|
||||
bool f = geom3::flipped;
|
||||
if(f) geom3::light_flip(false);
|
||||
transmatrix T = lxpush(.01241) * spin(1.4117) * lxpush(0.1241) * Id;
|
||||
if(f) geom3::light_flip(true);
|
||||
archimedean_gmatrix[origin] = make_pair(alt, T);
|
||||
altmap[alt].emplace_back(origin, T);
|
||||
|
||||
|
@ -643,6 +669,19 @@ struct hrmap_archimedean : hrmap {
|
|||
|
||||
heptagon *create_step(heptagon *h, int d) override {
|
||||
|
||||
bool f = geom3::flipped;
|
||||
if(f) {
|
||||
dynamicval<int> uc(cgip->use_count, cgip->use_count+1);
|
||||
auto bcgip = cgip;
|
||||
geom3::light_flip(false);
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
auto h1 = create_step(h, d);
|
||||
geom3::light_flip(true);
|
||||
cgip = bcgip;
|
||||
return h1;
|
||||
}
|
||||
|
||||
DEBB(DF_GEOM, (heptspin(h,d), " ~ ?"));
|
||||
|
||||
dynamicval<geometryinfo1> gi(ginf[geometry].g, ginf[gArchimedean].g);
|
||||
|
@ -653,16 +692,17 @@ struct hrmap_archimedean : hrmap {
|
|||
|
||||
auto& t1 = current.get_triangle(hi);
|
||||
|
||||
// * spin(-tri[id][pi+i].first) * xpush(t.second) * pispin * spin(tri[id'][p'+d'].first)
|
||||
|
||||
// * spin(-tri[id][pi+i].first) * lxpush(t.second) * pispin * spin(tri[id'][p'+d'].first)
|
||||
|
||||
auto& p1 = archimedean_gmatrix[h];
|
||||
|
||||
heptagon *alt = p1.first;
|
||||
|
||||
transmatrix T = p1.second * spin(-t1.first) * xpush(t1.second);
|
||||
transmatrix T = p1.second * spin(-t1.first) * lxpush(t1.second);
|
||||
transmatrix U = Id;
|
||||
|
||||
|
||||
if(hyperbolic) {
|
||||
dynamicval<int> uc(cgip->use_count, cgip->use_count+1);
|
||||
dynamicval<eGeometry> g(geometry, gNormal);
|
||||
dynamicval<eVariation> gv(variation, eVariation::pure);
|
||||
dynamicval<geometry_information*> gi(cgip, find_alt_cgip());
|
||||
|
@ -678,24 +718,24 @@ struct hrmap_archimedean : hrmap {
|
|||
alt = (heptagon*) s;
|
||||
}
|
||||
|
||||
DEBB(DF_GEOM, ("look for: ", alt, " / ", T * C0));
|
||||
DEBB(DF_GEOM, ("look for: ", alt, " / ", kz(T * C0)));
|
||||
|
||||
for(auto& p2: altmap[alt]) if(same_point_may_warn(p2.second * C0, T * C0)) {
|
||||
for(auto& p2: altmap[alt]) if(same_point_may_warn(p2.second * tile_center(), T * tile_center())) {
|
||||
DEBB(DF_GEOM, ("cell found: ", p2.first));
|
||||
for(int d2=0; d2<p2.first->degree(); d2++) {
|
||||
heptspin hs(p2.first, d2);
|
||||
auto& t2 = current.get_triangle(p2.first, d2);
|
||||
transmatrix T1 = T * spin(M_PI + t2.first);
|
||||
DEBB(DF_GEOM, ("compare: ", T1 * xpush0(1), ":: ", p2.second * xpush0(1)));
|
||||
if(same_point_may_warn(T1 * xpush0(1), p2.second * xpush0(1))) {
|
||||
DEBB(DF_GEOM, ("compare: ", kz(T1 * lxpush0(1)), ":: ", kz(p2.second * lxpush0(1))));
|
||||
if(same_point_may_warn(T1 * lxpush0(1), p2.second * lxpush0(1))) {
|
||||
|
||||
// T1 = p2.second
|
||||
// T * spin(pi+t2.first) == p2.second
|
||||
// p1.second * spinm(-t1.first) * xpush(t1.second) * spin(pi+t2.first) == p2.second
|
||||
// p1.second * spinm(-t1.first) * lxpush(t1.second) * spin(pi+t2.first) == p2.second
|
||||
|
||||
// bring p1 and p2 closer, to prevent floating point errors
|
||||
if(hyperbolic) {
|
||||
fixup_matrix(p1.second, U * p2.second * spin(-M_PI - t2.first) * xpush(-t1.second) * spin(t1.first), 0.25);
|
||||
fixup_matrix(p1.second, U * p2.second * spin(-M_PI - t2.first) * lxpush(-t1.second) * spin(t1.first), 0.25);
|
||||
fixup_matrix(p2.second, T1, 0.25);
|
||||
}
|
||||
|
||||
|
@ -837,7 +877,7 @@ struct hrmap_archimedean : hrmap {
|
|||
auto& t1 = ac.get_triangle(c->master, cid);
|
||||
hyperpoint h0 = xspinpush0(-t0.first, t0.second * 3 / cf * (ac.real_faces == 0 ? 0.999 : 1));
|
||||
hyperpoint h1 = xspinpush0(-t1.first, t1.second * 3 / cf * (ac.real_faces == 0 ? 0.999 : 1));
|
||||
return mid3(C0, h0, h1);
|
||||
return mid3(tile_center(), h0, h1);
|
||||
}
|
||||
if(DUAL) {
|
||||
auto& t0 = ac.get_triangle(c->master, 2*cid-1);
|
||||
|
@ -897,7 +937,7 @@ void connect_digons_too(heptspin h1, heptspin h2) {
|
|||
// no need to specify archimedean_gmatrix and altmap
|
||||
hnew->c.connect(1, h2);
|
||||
h1--, h2++;
|
||||
DEBB(DF_GEOM, (format("OL2 %p.%d ~ %p.%d\n", hr::voidp(h1.at), h1.spin, hr::voidp(h2.at), h2.spin)));
|
||||
DEBB(DF_GEOM, (hr::format("OL2 %p.%d ~ %p.%d\n", hr::voidp(h1.at), h1.spin, hr::voidp(h2.at), h2.spin)));
|
||||
h1.at->c.connect(h1.spin, h2);
|
||||
}
|
||||
}
|
||||
|
@ -905,15 +945,15 @@ void connect_digons_too(heptspin h1, heptspin h2) {
|
|||
void connectHeptagons(heptspin hi, heptspin hs) {
|
||||
DEBB(DF_GEOM, ("OLD ", hi, " ~ ", hs));
|
||||
if(hi.at->move(hi.spin) == hs.at && hi.at->c.spin(hi.spin) == hs.spin) {
|
||||
DEBB(DF_GEOM, (format("WARNING: already connected\n")));
|
||||
DEBB(DF_GEOM, (hr::format("WARNING: already connected\n")));
|
||||
return;
|
||||
}
|
||||
if(hi.peek()) {
|
||||
DEBB(DF_GEOM, (format("ERROR: already connected left\n")));
|
||||
DEBB(DF_GEOM, (hr::format("ERROR: already connected left\n")));
|
||||
throw hr_archimedean_error("Archimedean error: already connected left");
|
||||
}
|
||||
if(hs.peek()) {
|
||||
DEBB(DF_GEOM, (format("ERROR: already connected right\n")));
|
||||
DEBB(DF_GEOM, (hr::format("ERROR: already connected right\n")));
|
||||
throw hr_archimedean_error("Archimedean error: already connected right");
|
||||
}
|
||||
hi.at->c.connect(hi.spin, hs);
|
||||
|
@ -965,7 +1005,7 @@ transmatrix archimedean_tiling::adjcell_matrix(heptagon *h, int d) {
|
|||
int d2 = h->c.spin(d);
|
||||
auto& t2 = get_triangle(h2, d2);
|
||||
|
||||
return spin(-t1.first) * xpush(t1.second) * spin(M_PI + t2.first);
|
||||
return spin(-t1.first) * lxpush(t1.second) * spin(M_PI + t2.first);
|
||||
}
|
||||
|
||||
EX int fix(heptagon *h, int spin) {
|
||||
|
@ -1038,6 +1078,20 @@ void archimedean_tiling::parse() {
|
|||
prepare();
|
||||
}
|
||||
|
||||
EX bool load_symbol(const string& s, bool switch_geom) {
|
||||
archimedean_tiling at; at.parse(s);
|
||||
if(at.errors) {
|
||||
DEBB(DF_ERROR | DF_GEOM, ("error: ", at.errormsg));
|
||||
return false;
|
||||
}
|
||||
if(!switch_geom && geometry != gArchimedean) return true;
|
||||
stop_game();
|
||||
set_geometry(gArchimedean);
|
||||
current = at;
|
||||
if(!delayed_start) start_game();
|
||||
return true;
|
||||
}
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
int readArgs() {
|
||||
using namespace arg;
|
||||
|
@ -1045,16 +1099,8 @@ int readArgs() {
|
|||
if(0) ;
|
||||
else if(argis("-symbol")) {
|
||||
PHASEFROM(2);
|
||||
archimedean_tiling at;
|
||||
shift(); at.parse(args());
|
||||
if(at.errors) {
|
||||
DEBB(DF_ERROR | DF_GEOM, ("error: ", at.errormsg));
|
||||
}
|
||||
else {
|
||||
set_geometry(gArchimedean);
|
||||
current = at;
|
||||
showstartmenu = false;
|
||||
}
|
||||
shift(); load_symbol(args(), true);
|
||||
showstartmenu = false;
|
||||
}
|
||||
else if(argis("-dual")) { PHASEFROM(2); set_variation(eVariation::dual); }
|
||||
else if(argis("-d:arcm"))
|
||||
|
@ -1074,14 +1120,21 @@ auto hook =
|
|||
#if MAXMDIM >= 4
|
||||
auto hooksw = addHook(hooks_swapdim, 100, [] {
|
||||
|
||||
if(!arcm::in()) return;
|
||||
|
||||
dynamicval<eGeometry> g(geometry, gNormal);
|
||||
dynamicval<eVariation> gv(variation, eVariation::pure);
|
||||
|
||||
alt_cgip[0] = nullptr;
|
||||
alt_cgip[1] = nullptr;
|
||||
|
||||
dynamicval<geometry_information*> gi(cgip, find_alt_cgip());
|
||||
|
||||
for(auto& p: altmap) for(auto& pp: p.second) swapmatrix(pp.second);
|
||||
for(auto& p: archimedean_gmatrix) swapmatrix(p.second.second);
|
||||
|
||||
alt_cgip = nullptr;
|
||||
alt_cgip[0] = nullptr;
|
||||
alt_cgip[1] = nullptr;
|
||||
});
|
||||
#endif
|
||||
|
||||
|
@ -1293,15 +1346,25 @@ EX void enable(archimedean_tiling& arct) {
|
|||
start_game();
|
||||
}
|
||||
|
||||
function<void()> setcanvas(char c) {
|
||||
return [c] () {
|
||||
function<void()> setcanvas(ccolor::data& c) {
|
||||
auto pc = &c;
|
||||
return [pc] () {
|
||||
stop_game();
|
||||
enable_canvas();
|
||||
patterns::whichCanvas = c;
|
||||
ccolor::which = pc;
|
||||
start_game();
|
||||
};
|
||||
}
|
||||
|
||||
dialog::string_dialog se;
|
||||
|
||||
EX void init_symbol_edit() {
|
||||
symbol_editing = true;
|
||||
edited = current;
|
||||
se.start_editing(edited.symbol);
|
||||
edited.parse();
|
||||
}
|
||||
|
||||
EX void show() {
|
||||
if(lastsample < isize(samples)) {
|
||||
string s = samples[lastsample].first;
|
||||
|
@ -1327,7 +1390,7 @@ EX void show() {
|
|||
dialog::init(XLAT("Archimedean tilings"));
|
||||
|
||||
if(symbol_editing) {
|
||||
dialog::addSelItem("edit", dialog::view_edited_string(), '/');
|
||||
dialog::addSelItem("edit", se.view_edited_string(), '/');
|
||||
dialog::add_action([] () {
|
||||
symbol_editing = false;
|
||||
if(!edited.errors) enable(edited);
|
||||
|
@ -1355,12 +1418,7 @@ EX void show() {
|
|||
else {
|
||||
string cs = in() ? current.symbol : XLAT("OFF");
|
||||
dialog::addSelItem("edit", cs, '/');
|
||||
dialog::add_action([] () {
|
||||
symbol_editing = true;
|
||||
edited = current;
|
||||
dialog::start_editing(edited.symbol);
|
||||
edited.parse();
|
||||
});
|
||||
dialog::add_action(init_symbol_edit);
|
||||
dialog::addBreak(100);
|
||||
int nextpos = spos;
|
||||
int shown = 0;
|
||||
|
@ -1414,11 +1472,15 @@ EX void show() {
|
|||
});
|
||||
|
||||
if(in()) {
|
||||
dialog::addSelItem(XLAT("size of the world"), current.world_size(), 0);
|
||||
dialog::addSelItem(XLAT("size of the world"), current.world_size(), 'S');
|
||||
add_size_action();
|
||||
|
||||
dialog::addSelItem(XLAT("edge length"), current.get_class() == gcEuclid ? (fts(current.edgelength) + XLAT(" (arbitrary)")) : fts(current.edgelength), 0);
|
||||
|
||||
dialog::addItem(XLAT("color by symmetries"), 't');
|
||||
dialog::add_action(setcanvas('A'));
|
||||
dialog::add_action(setcanvas(ccolor::shape));
|
||||
dialog::addItem(XLAT("color by symmetries (reversed tiles marked)"), 'r');
|
||||
dialog::add_action(setcanvas(ccolor::shape_mirror));
|
||||
}
|
||||
else {
|
||||
dialog::addBreak(100);
|
||||
|
@ -1428,20 +1490,20 @@ EX void show() {
|
|||
|
||||
if(true) {
|
||||
dialog::addItem(XLAT("color by sides"), 'u');
|
||||
dialog::add_action(setcanvas('B'));
|
||||
dialog::add_action(setcanvas(ccolor::sides));
|
||||
}
|
||||
|
||||
if(geosupport_threecolor() == 2) {
|
||||
dialog::addItem(XLAT("three colors"), 'w');
|
||||
dialog::add_action(setcanvas('T'));
|
||||
dialog::add_action(setcanvas(ccolor::threecolor));
|
||||
}
|
||||
else if(geosupport_football() == 2) {
|
||||
dialog::addItem(XLAT("football"), 'w');
|
||||
dialog::add_action(setcanvas('F'));
|
||||
dialog::add_action(setcanvas(ccolor::football));
|
||||
}
|
||||
else if(geosupport_chessboard()) {
|
||||
dialog::addItem(XLAT("chessboard"), 'w');
|
||||
dialog::add_action(setcanvas('c'));
|
||||
dialog::add_action(setcanvas(ccolor::chessboard));
|
||||
}
|
||||
else dialog::addBreak(100);
|
||||
|
||||
|
@ -1459,7 +1521,7 @@ EX void show() {
|
|||
keyhandler = [] (int sym, int uni) {
|
||||
if(symbol_editing && sym == SDLK_RETURN) sym = uni = '/';
|
||||
dialog::handleNavigation(sym, uni);
|
||||
if(symbol_editing && dialog::handle_edit_string(sym, uni)) {
|
||||
if(symbol_editing && se.handle_edit_string(sym, uni)) {
|
||||
edited.parse(edited.symbol);
|
||||
return;
|
||||
}
|
||||
|
@ -1518,6 +1580,14 @@ EX bool is_vertex(heptagon *h) {
|
|||
return id_of(h) >= 2 * current.N;
|
||||
}
|
||||
|
||||
EX int get_graphical_id(cell *c) {
|
||||
int id = arcm::id_of(c->master);
|
||||
int tid = arcm::current.tilegroup[id];
|
||||
int tid2 = arcm::current.tilegroup[id^1];
|
||||
if(tid2 >= 0) tid = min(tid, tid2);
|
||||
return tid;
|
||||
}
|
||||
|
||||
bool archimedean_tiling::get_step_values(int& steps, int& single_step) {
|
||||
|
||||
int nom = -2;
|
||||
|
|
59
attack.cpp
59
attack.cpp
|
@ -126,8 +126,10 @@ EX bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags)
|
|||
|
||||
if(!(flags & AF_NOSHIELD) && ((flags & AF_NEXTTURN) ? checkOrb2 : checkOrb)(m2, itOrbShield)) return false;
|
||||
|
||||
if((flags & AF_STAB) && m2 != moHedge)
|
||||
if((flags & AF_STAB) && m2 != moHedge) {
|
||||
if(!checkOrb(m1, itOrbThorns)) return false;
|
||||
else flags |= AF_IGNORE_UNARMED;
|
||||
}
|
||||
|
||||
if(flags & AF_BACK) {
|
||||
if(m2 == moFlailer && !c2->stuntime) flags |= AF_IGNORE_UNARMED;
|
||||
|
@ -135,9 +137,9 @@ EX bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags)
|
|||
else return false;
|
||||
}
|
||||
|
||||
if(flags & AF_APPROACH) {
|
||||
if(m2 == moLancer) ;
|
||||
else if((flags & AF_HORNS) && checkOrb(m1, itOrbHorns)) ;
|
||||
if(flags & (AF_APPROACH | AF_HORNS)) {
|
||||
if(m2 == moLancer && (flags & AF_APPROACH)) ;
|
||||
else if((flags & AF_HORNS) && checkOrb(m1, itOrbHorns)) { flags |= AF_IGNORE_UNARMED; }
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
@ -149,7 +151,7 @@ EX bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags)
|
|||
if(!(flags & (AF_GUN | AF_SWORD | AF_SWORD_INTO | AF_MAGIC | AF_PLAGUE)))
|
||||
if(c1 != c2 && !logical_adjacent(c1, m1, c2)) return false;
|
||||
|
||||
if(!(flags & (AF_LANCE | AF_STAB | AF_BACK | AF_APPROACH | AF_GUN | AF_MAGIC | AF_PLAGUE | AF_SIDE)))
|
||||
if(!(flags & (AF_LANCE | AF_STAB | AF_BACK | AF_APPROACH | AF_GUN | AF_MAGIC | AF_PLAGUE | AF_SIDE | AF_BOW)))
|
||||
if(c1 && c2 && againstRose(c1, c2) && !ignoresSmell(m1))
|
||||
return false;
|
||||
|
||||
|
@ -157,7 +159,8 @@ EX bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags)
|
|||
if(isWorm(m2) && m2 != moTentacleGhost && !isDragon(m2)) return false;
|
||||
|
||||
// dragon can't attack itself, or player who mounted it
|
||||
if(c1 && c2 && isWorm(c1->monst) && isWorm(c2->monst) && wormhead(c1) == wormhead(c2)
|
||||
cell *cp = (flags & AF_BOW) ? cwt.at : c1;
|
||||
if(cp && c2 && isWorm(cp->monst) && isWorm(c2->monst) && wormhead(cp) == wormhead(c2)
|
||||
&& m1 != moTentacleGhost && m2 != moTentacleGhost)
|
||||
return false;
|
||||
|
||||
|
@ -337,6 +340,10 @@ EX eWall conditional_flip_slime(bool flip, eWall t) {
|
|||
return t;
|
||||
}
|
||||
|
||||
EX void chainspill(cell *c) {
|
||||
if(c->wall == waMagma && c->monst == moSlimeNextTurn) killMonster(c, moNone, 0);
|
||||
}
|
||||
|
||||
EX void spillfix(cell* c, eWall t, int rad) {
|
||||
if(c->wall == waTemporary) {
|
||||
changes.ccell(c);
|
||||
|
@ -345,6 +352,7 @@ EX void spillfix(cell* c, eWall t, int rad) {
|
|||
if(rad) for(auto p: adj_minefield_cells_full(c)) {
|
||||
spillfix(p.c, conditional_flip_slime(p.mirrored, t), rad-1);
|
||||
}
|
||||
chainspill(c);
|
||||
}
|
||||
|
||||
EX void spill(cell* c, eWall t, int rad) {
|
||||
|
@ -359,6 +367,7 @@ EX void spill(cell* c, eWall t, int rad) {
|
|||
si.second.spill_b > si.second.spill_a ? waFloorB :
|
||||
isAlchAny(si.second.orig) ? si.second.orig :
|
||||
waNone;
|
||||
chainspill(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,7 +463,7 @@ EX void killMutantIvy(cell *c, eMonster who) {
|
|||
changes.ccell(c);
|
||||
removeIvy(c);
|
||||
for(int i=0; i<c->type; i++)
|
||||
if(c->move(i)->mondir == c->c.spin(i) && (isMutantIvy(c->move(i)) || c->move(i)->monst == moFriendlyIvy))
|
||||
if(c->move(i) && c->move(i)->mondir == c->c.spin(i) && (isMutantIvy(c->move(i)) || c->move(i)->monst == moFriendlyIvy))
|
||||
kills[c->move(i)->monst]++, killMutantIvy(c->move(i), who);
|
||||
if(c->land == laClearing) clearing::imput(c);
|
||||
}
|
||||
|
@ -506,6 +515,8 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if(m == moHunterGuard) ambush::guard_attack();
|
||||
|
||||
if(m == moGolemMoved) m = moGolem;
|
||||
if(m == moKnightMoved) m = moKnight;
|
||||
if(m == moSlimeNextTurn) m = moSlime;
|
||||
|
@ -752,13 +763,18 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
|
|||
// a reward for killing him before he shoots!
|
||||
c->item = itOrbDragon;
|
||||
}
|
||||
if(m == moAsteroid && !shmup::on && c->item == itNone && c->wall != waChasm && c->land == laAsteroids) {
|
||||
c->item = itAsteroid;
|
||||
changes.value_add(splitrocks, 2);
|
||||
}
|
||||
|
||||
if(m == moOutlaw && (c->item == itNone || c->item == itRevolver) && c->wall != waChasm)
|
||||
c->item = itBounty;
|
||||
// note: an Orb appears underwater!
|
||||
if(m == moWaterElemental && c->item == itNone)
|
||||
c->item = itOrbWater;
|
||||
|
||||
if(m == moPirate && isOnCIsland(c) && c->item == itNone && (
|
||||
if(m == moPirate && (isOnCIsland(c) || ls::hv_structure()) && c->item == itNone && (
|
||||
eubinary ||
|
||||
(c->master->alt && celldistAlt(c) <= 2-getDistLimit()) ||
|
||||
isHaunted(c->land)) && !cryst) {
|
||||
|
@ -934,6 +950,14 @@ EX void fightmessage(eMonster victim, eMonster attacker, bool stun, flagtype fla
|
|||
else
|
||||
addMessage(XLAT("You pierce %the1.", victim)); // normal
|
||||
}
|
||||
else if(items[itOrbSlaying]) {
|
||||
playSound(NULL, "hit-crush"+pick123());
|
||||
addMessage(XLAT("You crush %the1!", victim)); // normal
|
||||
}
|
||||
else if(stun && items[itCurseWeakness]) {
|
||||
playSound(NULL, "click");
|
||||
addMessage(XLAT("You punch %the1.", victim)); // normal
|
||||
}
|
||||
else if(!peace::on) {
|
||||
playSound(NULL, "hit-sword"+pick123());
|
||||
addMessage(XLAT("You kill %the1.", victim)); // normal
|
||||
|
@ -1106,11 +1130,11 @@ EX bool should_switchplace(cell *c1, cell *c2) {
|
|||
EX bool switchplace_prevent(cell *c1, cell *c2, struct pcmove& m) {
|
||||
if(!should_switchplace(c1, c2)) return false;
|
||||
if(peace::on && (isMultitile(c2->monst) || saved_tortoise_on(c2) || isDie(c2->monst))) {
|
||||
if(m.vmsg(miRESTRICTED)) addMessage(XLAT("Cannot switch places with %the1!", c2->monst));
|
||||
if(m.vmsg(miRESTRICTED, siMONSTER, c2, c2->monst)) addMessage(XLAT("Cannot switch places with %the1!", c2->monst));
|
||||
return true;
|
||||
}
|
||||
if(c1->monst && c1->monst != moFriendlyIvy) {
|
||||
if(m.vmsg(miRESTRICTED)) addMessage(XLAT("There is no room for %the1!", c2->monst));
|
||||
if(m.vmsg(miRESTRICTED, siMONSTER, c1, c1->monst)) addMessage(XLAT("There is no room for %the1!", c2->monst));
|
||||
return true;
|
||||
}
|
||||
if(passable(c1, c2, P_ISFRIEND | (c2->monst == moTameBomberbird ? P_FLYING : 0))) return false;
|
||||
|
@ -1222,11 +1246,13 @@ EX void killThePlayer(eMonster m, int id, flagtype flags) {
|
|||
}
|
||||
else if(hardcore) {
|
||||
addMessage(XLAT("You are killed by %the1!", m));
|
||||
yasc_message = XLAT("killed by %the1", m);
|
||||
killHardcorePlayer(id, flags);
|
||||
}
|
||||
else if(m == moLightningBolt && lastmovetype == lmAttack && isAlchAny(playerpos(id))) {
|
||||
addMessage(XLAT("You are killed by %the1!", m));
|
||||
addMessage(XLAT("Don't play with slime and electricity next time, okay?"));
|
||||
yasc_message = XLAT("killed by %the1", m);
|
||||
kills[moPlayer]++;
|
||||
items[itOrbSafety] = 0;
|
||||
}
|
||||
|
@ -1279,6 +1305,7 @@ EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
|
|||
for(int bb=0; bb<2; bb++) achievement_count("SLASH", numbb[bb], 0);
|
||||
|
||||
if(peace::on) return;
|
||||
bool out = who == moPlayer && bow::crossbow_mode();
|
||||
|
||||
for(int t=0; t<mf->type; t++) {
|
||||
cell *c = mf->move(t);
|
||||
|
@ -1291,9 +1318,9 @@ EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
|
|||
if(stabthere && c->wall == waExplosiveBarrel && markOrb(itOrbThorns))
|
||||
explodeBarrel(c);
|
||||
|
||||
if(stabthere && canAttack(mt,who,c,c->monst,AF_STAB)) {
|
||||
if(stabthere && (items[itOrbThorns] || !out) && canAttack(mt,who,c,c->monst,AF_STAB)) {
|
||||
changes.ccell(c);
|
||||
if(c->monst != moHedge) {
|
||||
if(c->monst != moHedge || out) {
|
||||
markOrb(itOrbThorns); if(who != moPlayer) markOrb(itOrbEmpathy);
|
||||
}
|
||||
eMonster m = c->monst;
|
||||
|
@ -1337,11 +1364,13 @@ EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
|
|||
}
|
||||
}
|
||||
|
||||
if(!isUnarmed(who)) forCellIdEx(c, t, mt) {
|
||||
forCellIdEx(c, t, mt) {
|
||||
if(!logical_adjacent(mt, who, c)) continue;
|
||||
eMonster mm = c->monst;
|
||||
int flag = AF_APPROACH;
|
||||
int flag = 0;
|
||||
if(!isUnarmed(who) && !out) flag |= AF_APPROACH;
|
||||
if(proper(mt, backdir) && anglestraight(mt, backdir, t)) flag |= AF_HORNS;
|
||||
if(!flag) continue;
|
||||
if(canAttack(mt,who,c,c->monst, flag)) {
|
||||
changes.ccell(c);
|
||||
if(attackMonster(c, flag | AF_MSG, who)) numlance++;
|
||||
|
@ -1350,7 +1379,7 @@ EX void stabbingAttack(movei mi, eMonster who, int bonuskill IS(0)) {
|
|||
}
|
||||
}
|
||||
|
||||
if(who == moPlayer) {
|
||||
if(who == moPlayer && !bow::crossbow_mode()) {
|
||||
if(numsh) achievement_count("STAB", numsh, 0);
|
||||
|
||||
if(numlance && numflail && numsh) achievement_gain_once("MELEE3");
|
||||
|
|
149
barriers.cpp
149
barriers.cpp
|
@ -34,11 +34,11 @@ EX bool checkBarriersFront(cellwalker bb, int q IS(5), bool cross IS(false)) {
|
|||
|
||||
/** return true if the cell c is not allowed to generate barriers because of other large things already existing nearby. */
|
||||
EX bool hasbardir(cell *c) {
|
||||
return c->bardir != NODIR && c->bardir != NOBARRIERS;
|
||||
return c->bardir != NODIR && c->bardir != NOBARRIERS && c->bardir != NOBARRIERS2;
|
||||
}
|
||||
|
||||
EX void preventbarriers(cell *c) {
|
||||
if(hybri) c = hybrid::get_where(c).first;
|
||||
if(mhybrid) c = hybrid::get_where(c).first;
|
||||
if(c && c->bardir == NODIR) c->bardir = NOBARRIERS;
|
||||
}
|
||||
|
||||
|
@ -324,12 +324,15 @@ EX void setbarrier(cell *c) {
|
|||
setbarrier(c, c->barleft, c->barright, ctof(c));
|
||||
}
|
||||
|
||||
EX int setland_max = 5;
|
||||
|
||||
EX void setland(cell *c, eLand l) {
|
||||
if(c->land != l) {
|
||||
c->landparam = 0;
|
||||
}
|
||||
if(l == laNone) {
|
||||
printf("setland\n"); // NONEDEBUG
|
||||
if(l == laNone && setland_max > 0) {
|
||||
setland_max--;
|
||||
printf("error: set land to laNone\n"); // NONEDEBUG
|
||||
}
|
||||
c->land = l;
|
||||
}
|
||||
|
@ -556,7 +559,9 @@ EX bool isbar4(cell *c) {
|
|||
}
|
||||
|
||||
EX bool barrier_cross(eLand l, eLand r) {
|
||||
if(land_structure == lsVineWalls) return false;
|
||||
if(l == laCrossroads3 || r == laCrossroads3) return hrand(100) < 66;
|
||||
if(land_structure == lsCrossWalls && !among(laCrossroads2, l, r)) return hrand(100) < 90;
|
||||
if(isElemental(l) && isElemental(r)) return hrand(100) < 75;
|
||||
return false;
|
||||
}
|
||||
|
@ -612,6 +617,12 @@ EX void extendBarrier(cell *c) {
|
|||
if(buildBarrier6(cw, 2)) return;
|
||||
}
|
||||
|
||||
if(land_structure == lsCursedWalls && c->barleft != laMirror && c->barright != laMirror && hrand(100) < 80 && !among(laCrossroads2, c->barleft, c->barright)) {
|
||||
cellwalker cw(c, c->bardir);
|
||||
cw = cw + wstep + 3 + wstep - 1;
|
||||
if(buildBarrier6(cw, c->barright, c->barleft)) return;
|
||||
}
|
||||
|
||||
if(barrier_cross(c->barleft, c->barright) || (firstmirror && hrand(100) < 60)) {
|
||||
|
||||
cellwalker cw(c, c->bardir);
|
||||
|
@ -677,6 +688,7 @@ EX void buildBarrier(cell *c, int d, eLand l IS(laNone)) {
|
|||
buildBarrierForce(c, d, l);
|
||||
}
|
||||
|
||||
/** mirror variant of 6-fold walls */
|
||||
EX bool buildBarrier6(cellwalker cw, int type) {
|
||||
limitgen("build6 %p/%d (%d)\n", hr::voidp(cw.at), cw.spin, type);
|
||||
|
||||
|
@ -721,21 +733,28 @@ EX bool buildBarrier6(cellwalker cw, int type) {
|
|||
if(!(PURE?checkBarriersFront:checkBarriersBack)(b[0], 6, true)) return false;
|
||||
if(!(PURE?checkBarriersFront:checkBarriersBack)(b[3], 6, true)) return false;
|
||||
}
|
||||
|
||||
|
||||
eLand m0 = laMirror;
|
||||
eLand m1 = laMirrored;
|
||||
eLand m2 = laMirrored2;
|
||||
eLand mw1 = laMirrorWall;
|
||||
eLand mw2 = laMirrorWall2;
|
||||
eWall w = waMirrorWall;
|
||||
|
||||
for(int d=0; d<4; d++) {
|
||||
b[d].at->bardir = b[d].spin;
|
||||
|
||||
if(PURE) {
|
||||
b[0].at->barleft = laMirrored, b[0].at->barright = laMirrored2;
|
||||
b[1].at->barleft = laMirror, b[1].at->barright = laMirrored;
|
||||
b[2].at->barleft = laMirrored2, b[2].at->barright = laMirrored;
|
||||
b[3].at->barleft = laMirrored, b[3].at->barright = laMirror;
|
||||
b[0].at->barleft = m1, b[0].at->barright = m2;
|
||||
b[1].at->barleft = m0, b[1].at->barright = m1;
|
||||
b[2].at->barleft = m2, b[2].at->barright = m1;
|
||||
b[3].at->barleft = m1, b[3].at->barright = m0;
|
||||
}
|
||||
else {
|
||||
b[0].at->barleft = laMirror, b[0].at->barright = laMirrored;
|
||||
b[1].at->barleft = laMirrored, b[1].at->barright = laMirror;
|
||||
b[2].at->barleft = laMirrored, b[2].at->barright = laMirrored2;
|
||||
b[3].at->barleft = laMirrored2, b[3].at->barright = laMirrored;
|
||||
b[0].at->barleft = m0, b[0].at->barright = m1;
|
||||
b[1].at->barleft = m1, b[1].at->barright = m0;
|
||||
b[2].at->barleft = m1, b[2].at->barright = m2;
|
||||
b[3].at->barleft = m2, b[3].at->barright = m1;
|
||||
}
|
||||
|
||||
(PURE?extendBarrierFront:extendBarrierBack)(b[d].at);
|
||||
|
@ -749,45 +768,87 @@ EX bool buildBarrier6(cellwalker cw, int type) {
|
|||
}
|
||||
|
||||
if(BITRUNCATED) {
|
||||
setland((cw+1).cpeek(), laMirrorWall);
|
||||
setland((cw+2).cpeek(), laMirrored);
|
||||
setland((cw+3).cpeek(), laMirrorWall2);
|
||||
setland((cw+4).cpeek(), laMirrorWall2);
|
||||
setland((cw+5).cpeek(), laMirrored);
|
||||
setland((cw+0).cpeek(), laMirrorWall);
|
||||
setland((b[0]+2).cpeek(), laMirrored);
|
||||
setland((b[3]+6).cpeek(), laMirrored2);
|
||||
setland((b[3]+5).cpeek(), laMirrored2);
|
||||
setland((b[1]-1).cpeek(), laMirrored);
|
||||
setland((b[2]-2).cpeek(), laMirrored);
|
||||
setland((b[1]-2).cpeek(), laMirrored);
|
||||
setland((b[0]-2).cpeek(), laMirror);
|
||||
cw.at->land = laMirrorWall;
|
||||
cw.at->wall = waMirrorWall;
|
||||
setland((cw+1).cpeek(), mw1);
|
||||
setland((cw+2).cpeek(), m1);
|
||||
setland((cw+3).cpeek(), mw2);
|
||||
setland((cw+4).cpeek(), mw2);
|
||||
setland((cw+5).cpeek(), m1);
|
||||
setland((cw+0).cpeek(), mw1);
|
||||
setland((b[0]+2).cpeek(), m1);
|
||||
setland((b[3]+6).cpeek(), m2);
|
||||
setland((b[3]+5).cpeek(), m2);
|
||||
setland((b[1]-1).cpeek(), m1);
|
||||
setland((b[2]-2).cpeek(), m1);
|
||||
setland((b[1]-2).cpeek(), m1);
|
||||
setland((b[0]-2).cpeek(), m0);
|
||||
cw.at->land = mw1;
|
||||
cw.at->wall = w;
|
||||
cw.at->landparam = 1;
|
||||
}
|
||||
else {
|
||||
setland(cw.at, laMirrorWall2);
|
||||
setland((cw+0).cpeek(), laMirrorWall2);
|
||||
setland((cw+1).cpeek(), laMirrored);
|
||||
setland((cw+2).cpeek(), laMirrored);
|
||||
setland((cw+3).cpeek(), laMirrorWall);
|
||||
setland((cw+4).cpeek(), laMirrored);
|
||||
setland((cw+5).cpeek(), laMirrorWall2);
|
||||
setland((cw+6).cpeek(), laMirrored2);
|
||||
setland(cw.at, mw2);
|
||||
setland((cw+0).cpeek(), mw2);
|
||||
setland((cw+1).cpeek(), m1);
|
||||
setland((cw+2).cpeek(), m1);
|
||||
setland((cw+3).cpeek(), mw1);
|
||||
setland((cw+4).cpeek(), m1);
|
||||
setland((cw+5).cpeek(), mw2);
|
||||
setland((cw+6).cpeek(), m2);
|
||||
|
||||
setland((b[1]).cpeek(), laMirrorWall);
|
||||
setland((b[1]+1).cpeek(), laMirror);
|
||||
setland((b[1]+2).cpeek(), laMirrorWall);
|
||||
setland((b[1]+6).cpeek(), laMirrored);
|
||||
setland((b[1]).cpeek(), mw1);
|
||||
setland((b[1]+1).cpeek(), m0);
|
||||
setland((b[1]+2).cpeek(), mw1);
|
||||
setland((b[1]+6).cpeek(), m1);
|
||||
|
||||
setland((b[0] + wstep - 2).cpeek(), laMirrored);
|
||||
setland((b[3] + wstep - 2).cpeek(), laMirrored);
|
||||
setland((b[0] + wstep - 2).cpeek(), m1);
|
||||
setland((b[3] + wstep - 2).cpeek(), m1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
EX int curse_percentage = 10;
|
||||
|
||||
/** cursed variant of 6-fold walls */
|
||||
EX bool buildBarrier6(cellwalker cw, eLand m0, eLand m1) {
|
||||
cellwalker b[6];
|
||||
if(buggyGeneration) return true;
|
||||
|
||||
for(int i=0; i<6; i+=2)
|
||||
b[i] = cw + i + wstep;
|
||||
for(int i=1; i<6; i+=2)
|
||||
b[i] = cw + i + wstep + 3 + wstep;
|
||||
|
||||
for(int i=0; i<6; i++) if(i != 1) {
|
||||
if(!(PURE?checkBarriersFront:checkBarriersBack)(b[i], 6, true)) return false;
|
||||
}
|
||||
|
||||
for(int d=0; d<6; d++) {
|
||||
b[d].at->bardir = b[d].spin;
|
||||
b[d].at->barleft = (d&1) ? m1 : m0;
|
||||
b[d].at->barright = (d&1) ? m0 : m1;
|
||||
(PURE?extendBarrierFront:extendBarrierBack)(b[d].at);
|
||||
}
|
||||
|
||||
cw.at->land = laBarrier;
|
||||
cw.at->wall = waBarrier;
|
||||
forCellCM(c, cw.at) { c->land = laBarrier; c->wall = waBarrier; }
|
||||
for(int d=0; d<6; d+=2) {
|
||||
setland((b[d]-2).cpeek(), m0);
|
||||
setland((b[d]+2).cpeek(), m1);
|
||||
setland((b[d+1]-2).cpeek(), m1);
|
||||
setland((b[d+1]+2).cpeek(), m0);
|
||||
}
|
||||
if(hrand(100) < curse_percentage) {
|
||||
setland(cw.at, laCursed);
|
||||
cw.at->wall = waRubble;
|
||||
cw.at->monst = moHexer;
|
||||
cw.at->item = random_curse();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EX bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) {
|
||||
limitgen("build4 %p\n", hr::voidp(c));
|
||||
if(buggyGeneration) return true;
|
||||
|
@ -871,6 +932,7 @@ EX void buildCrossroads2(cell *c) {
|
|||
if(buggyGeneration) return;
|
||||
|
||||
if(!c) return;
|
||||
if(ls::hv_structure()) return;
|
||||
|
||||
for(int i=0; i<c->type; i++)
|
||||
if(c->move(i) && !c->move(i)->landparam && c->move(i)->mpdist < c->mpdist)
|
||||
|
@ -1095,6 +1157,7 @@ EX bool buildBarrier3D(cell *c, eLand l2, int forced_dir) {
|
|||
#endif
|
||||
|
||||
EX bool buildBarrierNowall(cell *c, eLand l2, int forced_dir IS(NODIR)) {
|
||||
if(among(l2, laCrossroads2, laCrossroads5)) return false;
|
||||
return general_barrier_build(NOWALLSEP, c, l2, forced_dir);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
|
||||
#include "hyper.h"
|
||||
#ifdef FONTCONFIG
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#endif
|
||||
|
||||
namespace hr {
|
||||
|
||||
#if HDR
|
||||
|
@ -51,9 +55,10 @@ struct display_data {
|
|||
vector<radarpoint> radarpoints;
|
||||
vector<radarline> radarlines;
|
||||
transmatrix radar_transform;
|
||||
transmatrix radar_transform_post;
|
||||
|
||||
ld eyewidth();
|
||||
bool stereo_active();
|
||||
bool separate_eyes();
|
||||
bool in_anaglyph();
|
||||
|
||||
void set_viewport(int ed);
|
||||
|
@ -103,7 +108,7 @@ EX int get_sightrange_ambush() {
|
|||
}
|
||||
|
||||
bool display_data::in_anaglyph() { return vid.stereo_mode == sAnaglyph; }
|
||||
bool display_data::stereo_active() { return vid.stereo_mode != sOFF; }
|
||||
bool display_data::separate_eyes() { return among(vid.stereo_mode, sAnaglyph, sLR); }
|
||||
|
||||
ld display_data::eyewidth() {
|
||||
switch(vid.stereo_mode) {
|
||||
|
@ -215,12 +220,49 @@ EX void present_screen() {
|
|||
|
||||
#if CAP_SDLTTF
|
||||
|
||||
EX string fontpath = ISWEB ? "sans-serif" : HYPERFONTPATH "DejaVuSans-Bold.ttf";
|
||||
#define DEFAULT_FONT "DejaVuSans-Bold.ttf"
|
||||
|
||||
#ifdef FONTCONFIG
|
||||
/** if this is non-empty, find the font using fontconfig */
|
||||
EX string font_to_find = DEFAULT_FONT;
|
||||
#endif
|
||||
|
||||
/** actual font path */
|
||||
EX string fontpath = ISWEB ? "sans-serif" : string(HYPERFONTPATH) + DEFAULT_FONT;
|
||||
|
||||
const string& findfont() {
|
||||
#ifdef FONTCONFIG
|
||||
if(font_to_find == "") return fontpath;
|
||||
FcPattern *pat;
|
||||
FcResult result;
|
||||
if (!FcInit()) {
|
||||
return fontpath;
|
||||
}
|
||||
pat = FcNameParse((FcChar8 *)font_to_find.c_str());
|
||||
FcConfigSubstitute(0, pat, FcMatchPattern);
|
||||
FcDefaultSubstitute(pat);
|
||||
|
||||
FcPattern *match;
|
||||
match = FcFontMatch(0, pat, &result);
|
||||
if (match) {
|
||||
FcChar8 *file;
|
||||
if (FcPatternGetString(match, FC_FILE, 0, &file) == FcResultMatch) {
|
||||
fontpath = (const char *)file;
|
||||
}
|
||||
FcPatternDestroy(match);
|
||||
}
|
||||
FcPatternDestroy(pat);
|
||||
FcFini();
|
||||
font_to_find = "";
|
||||
if(debugflags & DF_INIT) println(hlog, "fontpath is: ", fontpath);
|
||||
#endif
|
||||
return fontpath;
|
||||
}
|
||||
|
||||
void loadfont(int siz) {
|
||||
fix_font_size(siz);
|
||||
if(!font[siz]) {
|
||||
font[siz] = TTF_OpenFont(fontpath.c_str(), siz);
|
||||
font[siz] = TTF_OpenFont(findfont().c_str(), siz);
|
||||
// Destination set by ./configure (in the GitHub repository)
|
||||
#ifdef FONTDESTDIR
|
||||
if (font[siz] == NULL) {
|
||||
|
@ -915,12 +957,19 @@ EX color_t colormix(color_t a, color_t b, color_t c) {
|
|||
return a;
|
||||
}
|
||||
|
||||
/* color difference for 24-bit colors, from 0 to 255*3 */
|
||||
EX int color_diff(color_t a, color_t b) {
|
||||
int res = 0;
|
||||
for(int i=0; i<3; i++) res += abs(part(a, i) - part(b, i));
|
||||
return res;
|
||||
}
|
||||
|
||||
EX int rhypot(int a, int b) { return (int) sqrt(a*a - b*b); }
|
||||
|
||||
EX ld realradius() {
|
||||
ld vradius = current_display->radius;
|
||||
if(sphere) {
|
||||
if(sphereflipped())
|
||||
if(flip_sphere())
|
||||
vradius /= sqrt(pconf.alpha*pconf.alpha - 1);
|
||||
else
|
||||
vradius = 1e12; // use the following
|
||||
|
@ -1017,7 +1066,7 @@ EX void drawCircle(int x, int y, int size, color_t color, color_t fillcolor IS(0
|
|||
if(pts > 1500) pts = 1500;
|
||||
if(ISMOBILE && pts > 72) pts = 72;
|
||||
for(int r=0; r<pts; r++) {
|
||||
float rr = (M_PI * 2 * r) / pts;
|
||||
float rr = (TAU * r) / pts;
|
||||
glcoords.push_back(glhr::makevertex(x + size * sin(rr), y + size * pconf.stretch * cos(rr), 0));
|
||||
}
|
||||
current_display->set_all(0, lband_shift);
|
||||
|
@ -1467,12 +1516,14 @@ EX void initialize_all() {
|
|||
|
||||
DEBBI(DF_INIT | DF_GRAPH, ("initgraph"));
|
||||
|
||||
DEBB(DF_INIT, ("initconfig"));
|
||||
initConfig();
|
||||
|
||||
#if CAP_SDLJOY
|
||||
joyx = joyy = 0; joydir.d = -1;
|
||||
#endif
|
||||
|
||||
DEBB(DF_INIT, ("restartGraph"));
|
||||
restartGraph();
|
||||
|
||||
if(noGUI) {
|
||||
|
@ -1482,32 +1533,42 @@ EX void initialize_all() {
|
|||
return;
|
||||
}
|
||||
|
||||
DEBB(DF_INIT, ("preparesort"));
|
||||
preparesort();
|
||||
#if CAP_CONFIG
|
||||
DEBB(DF_INIT, ("loadConfig"));
|
||||
loadConfig();
|
||||
#endif
|
||||
#if CAP_ARCM
|
||||
DEBB(DF_INIT, ("parse symbol"));
|
||||
arcm::current.parse();
|
||||
#endif
|
||||
if(hybri) geometry = hybrid::underlying;
|
||||
if(mhybrid) geometry = hybrid::underlying;
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
arg::read(2);
|
||||
#endif
|
||||
|
||||
DEBB(DF_INIT | DF_GRAPH, ("init graph"));
|
||||
init_graph();
|
||||
DEBB(DF_INIT | DF_POLY, ("check CGI"));
|
||||
check_cgi();
|
||||
DEBB(DF_INIT | DF_POLY, ("require basic"));
|
||||
cgi.require_basics();
|
||||
|
||||
DEBB(DF_INIT | DF_GRAPH, ("init font"));
|
||||
init_font();
|
||||
|
||||
#if CAP_SDLJOY
|
||||
initJoysticks();
|
||||
initJoysticks_async();
|
||||
#endif
|
||||
|
||||
#if CAP_SDLAUDIO
|
||||
DEBB(DF_INIT, ("init audio"));
|
||||
initAudio();
|
||||
#endif
|
||||
|
||||
DEBB(DF_INIT, ("initialize_all done"));
|
||||
}
|
||||
|
||||
EX void quit_all() {
|
||||
|
|
394
bigstuff.cpp
394
bigstuff.cpp
|
@ -153,7 +153,7 @@ EX int default_levs() {
|
|||
if(S3 >= OINF)
|
||||
return 1;
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::in_rule()) return 0;
|
||||
if(reg3::in_hrmap_rule_or_subrule()) return 0;
|
||||
#endif
|
||||
return S3-3;
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ map<heptagon*, short> altmap::quotient_relspins;
|
|||
auto qclear = addHook(hooks_clearmemory, 200, [] { altmap::quotient_relspins.clear(); });
|
||||
|
||||
void hrmap::extend_altmap(heptagon *h, int levs, bool link_cdata) {
|
||||
if(hybri) { PIU ( extend_altmap(h, levs, link_cdata) ); }
|
||||
if(mhybrid) { PIU ( extend_altmap(h, levs, link_cdata) ); }
|
||||
if(!h->alt) return;
|
||||
preventbarriers(h->c7);
|
||||
if(h->c7) forCellEx(c2, h->c7) preventbarriers(c2);
|
||||
|
@ -219,6 +219,182 @@ void hrmap::extend_altmap(heptagon *h, int levs, bool link_cdata) {
|
|||
}
|
||||
}
|
||||
|
||||
void new_voronoi_root(heptagon *h, int dist, int dir, eLand next) {
|
||||
heptagon *alt = init_heptagon(h->type);
|
||||
allmaps.push_back(newAltMap(alt));
|
||||
alt->s = hsA;
|
||||
alt->alt = alt;
|
||||
alt->cdata = (cdata*) h;
|
||||
alt->distance = dist;
|
||||
vector<pair<heptagon*, heptagon*>> altpairs;
|
||||
altpairs.emplace_back(h, alt);
|
||||
altmap::relspin(alt) = dir;
|
||||
|
||||
hv_land[alt] = next;
|
||||
|
||||
while(alt->distance > -100) {
|
||||
auto alt1 = createStep(alt, 0);
|
||||
alt1->alt = alt->alt;
|
||||
auto h1 = createStep(h, dir);
|
||||
if(h1->alt) return;
|
||||
altpairs.emplace_back(h1, alt1);
|
||||
h1->alt = alt1;
|
||||
|
||||
auto dir_alt = alt->c.spin(0);
|
||||
auto dir_h = h->c.spin(dir);
|
||||
|
||||
dir = altmap::relspin(alt1) = gmod(dir_h - dir_alt, alt->type);
|
||||
|
||||
h = h1; alt = alt1;
|
||||
}
|
||||
|
||||
for(auto p: altpairs) p.first->alt = p.second;
|
||||
}
|
||||
|
||||
|
||||
struct cand_info {
|
||||
int best, bqty;
|
||||
heptagon *candidate;
|
||||
vector<int> free_dirs;
|
||||
};
|
||||
|
||||
cand_info voronoi_candidate(heptagon *h) {
|
||||
cand_info ci;
|
||||
ci.best = 999999; ci.bqty = 0;
|
||||
|
||||
for(int i=0; i<h->type; i++) {
|
||||
heptagon *ho = createStep(h, i);
|
||||
int ri = h->c.spin(i);
|
||||
auto hoa = ho->alt;
|
||||
if(hoa && hoa->alt) {
|
||||
auto relspin = altmap::relspin(hoa);
|
||||
/* we want ho->move(ri) which is hoa->move(ri - relspin) */
|
||||
int dir = gmod(ri - relspin, hoa->type);
|
||||
heptagon *hoa1 = createStep(hoa, dir);
|
||||
if(!hoa1->alt) hoa1->alt = hoa->alt;
|
||||
auto dist = hoa1->distance;
|
||||
if(dist < ci.best) {
|
||||
ci.best = dist;
|
||||
ci.bqty = 0;
|
||||
}
|
||||
if(dist == ci.best && ci.candidate != hoa1) {
|
||||
ci.bqty++;
|
||||
ci.candidate = hoa1;
|
||||
int rb = hoa->c.spin(dir);
|
||||
/* hoa1->alt->move(rb) is h->move(rb+relspin to compute) */
|
||||
altmap::relspin(ci.candidate) = gmod(i - rb, ci.candidate->type);
|
||||
}
|
||||
}
|
||||
else ci.free_dirs.push_back(i);
|
||||
}
|
||||
return ci;
|
||||
}
|
||||
|
||||
vector<eLand> list_adjacent_lands(heptagon *h) {
|
||||
vector<eLand> res;
|
||||
for(int i=0; i<h->type; i++) {
|
||||
heptspin hs = heptspin(h, i);
|
||||
hs += wstep;
|
||||
auto alt = hs.at->alt;
|
||||
if(!alt) continue;
|
||||
alt = alt->alt;
|
||||
res.push_back(hv_land.at(alt));
|
||||
// go arround the region of alt using the 'butterfly' method, to find the other two lands which seem adjacent
|
||||
for(int d: {-1, 1}) {
|
||||
auto hs1 = hs;
|
||||
for(int i=0; i<100; i++) {
|
||||
hs1 += d;
|
||||
hs1 += wstep;
|
||||
if(!hs1.at->alt) { hs1 += wstep; continue; }
|
||||
auto alt1 = hs1.at->alt->alt;
|
||||
if(alt1 != alt) {
|
||||
res.push_back(hv_land.at(alt1)); break;
|
||||
}
|
||||
hs1 += d;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(res.empty()) return { laBarrier };
|
||||
return res;
|
||||
}
|
||||
|
||||
void extend_altmap_voronoi(heptagon *h) {
|
||||
if(h->alt) return;
|
||||
|
||||
auto ci = voronoi_candidate(h);
|
||||
|
||||
if(ci.bqty == 0) {
|
||||
new_voronoi_root(h, -30, hrand(h->type), firstland);
|
||||
return;
|
||||
}
|
||||
else if(ci.bqty > 0 && isize(ci.free_dirs)) {
|
||||
auto& expansion = get_expansion();
|
||||
ld growth = expansion.get_growth();
|
||||
ld odds = pow(growth, ci.candidate->distance) * isize(ci.free_dirs);
|
||||
if(hrandf() < odds / (1 + odds)) {
|
||||
vector<eLand> lands_list = list_adjacent_lands(h);
|
||||
|
||||
auto dist = ci.candidate->distance;
|
||||
// in PURE, could be a tie, or the new root could win
|
||||
if(PURE) dist -= hrand(2);
|
||||
// in BITRUNCATED, it could change too.. need a better formula probably
|
||||
if(BITRUNCATED) dist += hrand(3) - 1;
|
||||
// do not care about others...
|
||||
new_voronoi_root(h, dist, hrand_elt(ci.free_dirs), getNewLand2(lands_list));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
h->alt = ci.candidate;
|
||||
}
|
||||
|
||||
EX pair<heptagon*, int> get_voronoi_winner(cell *c) {
|
||||
if(c == c->master->c7) {
|
||||
extend_altmap_voronoi(c->master);
|
||||
auto ci = voronoi_candidate(c->master);
|
||||
if(ci.bqty == 1) return { ci.candidate->alt, ci.best };
|
||||
else return { nullptr, ci.best };
|
||||
}
|
||||
else if(!BITRUNCATED) return get_voronoi_winner(c->master->c7);
|
||||
else {
|
||||
vector<heptagon*> nearh;
|
||||
for(int i=0; i<c->type; i++) {
|
||||
c->cmove(i);
|
||||
if(c->move(i)->master->c7 == c->move(i)) nearh.push_back(c->move(i)->master);
|
||||
}
|
||||
for(auto h: nearh) extend_altmap_voronoi(h);
|
||||
for(auto h: nearh) if(!h->alt) return { nullptr, 0 };
|
||||
pair<heptagon*, int> best = {nullptr, 999999};
|
||||
int bqty = 0;
|
||||
for(auto h: nearh) {
|
||||
vector<int> dists;
|
||||
for(auto h1: nearh) {
|
||||
if(h == h1) dists.push_back(h->alt->distance);
|
||||
else {
|
||||
for(int i=0; i<h->type; i++) if(h->cmove(i) == h1) {
|
||||
auto ha1 = createStep(h->alt, gmod(i - altmap::relspin(h->alt), h->type));
|
||||
dists.push_back(ha1->distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
sort(dists.begin(), dists.end());
|
||||
int gdist;
|
||||
if(dists.back() == dists[0]) gdist = dists[0] - 1;
|
||||
else if(dists.back() == dists[0] + 2) gdist = dists[0] + 1;
|
||||
else gdist = dists[0];
|
||||
if(gdist < best.second) {
|
||||
best.second = gdist; bqty = 0;
|
||||
}
|
||||
if(gdist == best.second) {
|
||||
bqty++;
|
||||
if(bqty == 1 || best.first == h->alt->alt) best.first = h->alt->alt;
|
||||
else best.first = nullptr;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
EX int hrandom_adjacent(cellwalker cw) {
|
||||
auto& da = currentmap->dirdist(cw);
|
||||
|
@ -230,7 +406,7 @@ EX int hrandom_adjacent(cellwalker cw) {
|
|||
|
||||
EX heptagon *create_altmap(cell *c, int rad, hstate firststate, int special IS(0)) {
|
||||
|
||||
if(hybri) {
|
||||
if(mhybrid) {
|
||||
if(hybrid::under_class() == gcSphere) return NULL;
|
||||
c = hybrid::get_where(c).first;
|
||||
return PIU ( create_altmap(c, rad, firststate, special) );
|
||||
|
@ -240,7 +416,7 @@ EX heptagon *create_altmap(cell *c, int rad, hstate firststate, int special IS(0
|
|||
int gdir = -1;
|
||||
for(int i=0; i<c->type; i++) {
|
||||
#if MAXMDIM >= 4
|
||||
if(!reg3::in_rule()) {
|
||||
if(!reg3::in_hrmap_rule_or_subrule()) {
|
||||
#else
|
||||
if(true) {
|
||||
#endif
|
||||
|
@ -252,7 +428,7 @@ EX heptagon *create_altmap(cell *c, int rad, hstate firststate, int special IS(0
|
|||
}
|
||||
}
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::in_rule() && c->master->distance == 0) gdir = 0;
|
||||
if(reg3::in_hrmap_rule_or_subrule() && c->master->distance == 0) gdir = 0;
|
||||
#endif
|
||||
if(gdir < 0) return NULL;
|
||||
|
||||
|
@ -296,7 +472,7 @@ EX heptagon *create_altmap(cell *c, int rad, hstate firststate, int special IS(0
|
|||
if(!currentmap->link_alt(h, alt, firststate, p.last.spin)) {
|
||||
return nullptr;
|
||||
}
|
||||
if(hybri) hybrid::altmap_heights[alt] = hybrid::get_where(centerover).second;
|
||||
if(mhybrid) hybrid::altmap_heights[alt] = hybrid::get_where(centerover).second;
|
||||
alt->alt = alt;
|
||||
h->alt = alt;
|
||||
alt->cdata = (cdata*) h;
|
||||
|
@ -335,7 +511,12 @@ EX void beCIsland(cell *c) {
|
|||
}
|
||||
|
||||
EX void generateTreasureIsland(cell *c) {
|
||||
gen_alt(c);
|
||||
if(ls::voronoi_structure()) {
|
||||
if(c->land != laCaribbean) return;
|
||||
}
|
||||
else {
|
||||
gen_alt(c);
|
||||
}
|
||||
if(isOnCIsland(c)) return;
|
||||
|
||||
bool src = hrand(100) < 10;
|
||||
|
@ -348,13 +529,18 @@ EX void generateTreasureIsland(cell *c) {
|
|||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = createMov(c, i);
|
||||
if(!eubinary) currentmap->extend_altmap(c2->master);
|
||||
if(greater_alt(c, c2)) {
|
||||
auto ok = [&] (cell *c2) {
|
||||
if(ls::hv_structure() && get_voronoi_winner(c2).first != get_voronoi_winner(c).first) return false;
|
||||
return true;
|
||||
};
|
||||
if(ok(c2) && greater_alt(c, c2)) {
|
||||
ctab.push_back(c2);
|
||||
qlo = i; qhi = i;
|
||||
while(true && isize(ctab) < c->type) {
|
||||
qlo--;
|
||||
c2 = c->cmodmove(qlo);
|
||||
if(!have_alt(c2)) break;
|
||||
if(!ok(c2)) break;
|
||||
if(celldistAlt(c2) >= celldistAlt(c)) break;
|
||||
ctab.push_back(c2);
|
||||
}
|
||||
|
@ -362,6 +548,7 @@ EX void generateTreasureIsland(cell *c) {
|
|||
qhi++;
|
||||
c2 = c->cmodmove(qhi);
|
||||
if(!have_alt(c2)) break;
|
||||
if(!ok(c2)) break;
|
||||
if(celldistAlt(c2) >= celldistAlt(c)) break;
|
||||
ctab.push_back(c2);
|
||||
}
|
||||
|
@ -375,6 +562,7 @@ EX void generateTreasureIsland(cell *c) {
|
|||
return;
|
||||
}
|
||||
cell* c2 = c->cmodmove((qlo+qhi)/2);
|
||||
if(ls::voronoi_structure() && c2->land != laCaribbean) c2->land = laCaribbean;
|
||||
generateTreasureIsland(c2);
|
||||
if(!src) {
|
||||
c->wall = c2->wall;
|
||||
|
@ -515,6 +703,9 @@ EX int coastval(cell *c, eLand base) {
|
|||
if(!c->landparam) return UNKNOWN;
|
||||
return c->landparam & 255;
|
||||
}
|
||||
else if(base == laWestWall) {
|
||||
if(c->land != base) return 0;
|
||||
}
|
||||
else {
|
||||
if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool ||
|
||||
c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken || c->land == laDocks || c->land == laBrownian)
|
||||
|
@ -814,10 +1005,10 @@ EX void buildEquidistant(cell *c) {
|
|||
ls::nice_walls() ? true :
|
||||
false;
|
||||
|
||||
if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !hybri && hrand(10) < 5 && chance)
|
||||
if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !mhybrid && hrand(10) < 5 && chance)
|
||||
buildAnotherEquidistant(c);
|
||||
|
||||
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !hybri && hrand(100) < (PURE?25:5) && items[itBone] >= U10 && chance)
|
||||
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !mhybrid && hrand(100) < (PURE?25:5) && landUnlockedIngame(laHaunted) && chance)
|
||||
buildAnotherEquidistant(c);
|
||||
}
|
||||
|
||||
|
@ -921,7 +1112,7 @@ EX void setLandSphere(cell *c) {
|
|||
int y = getHemisphere(c, 2);
|
||||
elementalXY(c, x, y, (c->type != 6 || GOLDBERG));
|
||||
}
|
||||
if(!(euclid && quotient))
|
||||
if(!(euclid && (quotient || disksize)))
|
||||
if(specialland == laCrossroads || specialland == laCrossroads2 || specialland == laCrossroads3 || specialland == laTerracotta) {
|
||||
int x = getHemisphere(c, 1);
|
||||
if(x == 0 && specialland == laTerracotta)
|
||||
|
@ -944,6 +1135,7 @@ EX void setLandSphere(cell *c) {
|
|||
vector<eLand> euland;
|
||||
map<int, eLand> euland3;
|
||||
map<int, eLand> euland3_hash;
|
||||
EX map<array<int, 3>, eLand> landscape_lands;
|
||||
|
||||
EX eLand& get_euland(int c) {
|
||||
euland.resize(max_vec);
|
||||
|
@ -956,10 +1148,12 @@ EX void clear_euland(eLand first) {
|
|||
if(!nonisotropic) euland[0] = euland[1] = euland[max_vec-1] = first;
|
||||
euland3.clear();
|
||||
euland3[0] = first;
|
||||
landscape_lands.clear();
|
||||
landscape_lands[make_array(0,0,0)] = first;
|
||||
}
|
||||
|
||||
bool valid_wall_at(int c) {
|
||||
if(nonisotropic || hybri) return true;
|
||||
if(nonisotropic || mhybrid) return true;
|
||||
return short(c) % 3 == 0;
|
||||
}
|
||||
|
||||
|
@ -972,7 +1166,7 @@ EX eLand switchable(eLand nearland, eLand farland, int c) {
|
|||
else if(ls::no_walls()) {
|
||||
if((dual::state && nearland == laCrossroads4) || hrand(15) == 0)
|
||||
return getNewLand(nearland);
|
||||
if(nearland == laCrossroads4 && (nonisotropic || hybri))
|
||||
if(nearland == laCrossroads4 && (nonisotropic || mhybrid))
|
||||
return getNewLand(nearland);
|
||||
return nearland;
|
||||
}
|
||||
|
@ -1135,7 +1329,7 @@ EX void setLandEuclid(cell *c) {
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
setland(c, specialland);
|
||||
if(!c->land) setland(c, specialland);
|
||||
if(ls::any_nowall()) {
|
||||
auto co = euc2_coordinates(c);
|
||||
int y = co.second;
|
||||
|
@ -1369,9 +1563,13 @@ EX int wallchance(cell *c, bool deepOcean) {
|
|||
|
||||
/** \brief should we generate the horocycles in the current geometry? */
|
||||
EX bool horo_ok() {
|
||||
if(INVERSE) return false;
|
||||
if(INVERSE) return false;
|
||||
if(hat::in()) return false;
|
||||
if(currentmap->strict_tree_rules()) return true;
|
||||
return hyperbolic && !bt::in() && !arcm::in() && !kite::in() && !experimental && !hybri && !arb::in() && !quotient;
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::in_hrmap_h3() && !PURE) return false;
|
||||
#endif
|
||||
return mhyperbolic && !bt::in() && !arcm::in() && !kite::in() && !experimental && !mhybrid && !arb::in() && !quotient;
|
||||
}
|
||||
|
||||
/** \brief should we either generate the horocycles in the current geometry, or have them exist via eubinary? */
|
||||
|
@ -1430,7 +1628,9 @@ EX bool extend_alt(cell *c, eLand horoland, eLand overland, bool extend_in_singl
|
|||
return false;
|
||||
}
|
||||
|
||||
EX bool can_start_horo(cell *c) {
|
||||
EX bool can_start_horo(cell *c, bool allowed_in_horo IS(false)) {
|
||||
if(ls::voronoi_structure()) return false;
|
||||
if(!allowed_in_horo && ls::horodisk_structure()) return false;
|
||||
if(yendor::on && !among(c->land, laCaribbean, laStorms))
|
||||
return false;
|
||||
return ctof(c) && !have_alt(c) && horo_ok() && !randomPatternsMode && !racing::on;
|
||||
|
@ -1486,7 +1686,7 @@ EX bool good_for_wall(cell *c) {
|
|||
|
||||
EX bool walls_not_implemented() {
|
||||
// if(WDIM == 3 && !PURE) return true;
|
||||
if(sphere || quotient || nonisotropic || (kite::in() && !bt::in()) || experimental) return true;
|
||||
if(sphere || quotient || nonisotropic || aperiodic || experimental) return true;
|
||||
return WDIM == 3 && (cgflags & qIDEAL);
|
||||
}
|
||||
|
||||
|
@ -1495,7 +1695,7 @@ EX bool old_nice_walls() {
|
|||
}
|
||||
|
||||
EX bool nice_walls_available() {
|
||||
if(hybri) return PIU(nice_walls_available());
|
||||
if(mhybrid) return PIU(nice_walls_available());
|
||||
if(fake::in()) return FPIU(nice_walls_available());
|
||||
return WDIM == 2;
|
||||
}
|
||||
|
@ -1519,7 +1719,7 @@ EX void build_walls(cell *c, cell *from) {
|
|||
|
||||
// buildgreatwalls
|
||||
|
||||
if(hybri) return; /* Great Walls generated via the underlying geometry */
|
||||
if(mhybrid) return; /* Great Walls generated via the underlying geometry */
|
||||
|
||||
if(walls_not_implemented()) return; // walls not implemented here
|
||||
|
||||
|
@ -1574,6 +1774,21 @@ EX void build_walls(cell *c, cell *from) {
|
|||
|
||||
else if(good_for_wall(c) && isWarpedType(c->land) && hrand(10000) < 3000 && c->land &&
|
||||
buildBarrierNowall(c, eLand(c->land ^ laWarpSea ^ laWarpCoast))) { }
|
||||
|
||||
else if(land_structure == lsVineWalls) {
|
||||
int ev = emeraldval(c);
|
||||
if((ev | 11) == 43 && c->bardir == NODIR) {
|
||||
for(int i=0; i<c->type; i++) if(emeraldval(c->cmove(i)) == ev-4) {
|
||||
bool oldleft = true;
|
||||
for(int j=1; j<=3; j++)
|
||||
if(c->modmove(i+j) && c->modmove(i+j)->mpdist < c->mpdist)
|
||||
oldleft = false;
|
||||
buildBarrierStrong(c, i, oldleft, getNewLand(c->land));
|
||||
extendBarrier(c);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
else if(ls::single()) return;
|
||||
|
||||
|
@ -1595,11 +1810,11 @@ EX void build_walls(cell *c, cell *from) {
|
|||
return;
|
||||
}
|
||||
|
||||
else if(good_for_wall(c) && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && !c->master->alt && !tactic::on && !racing::on &&
|
||||
else if(good_for_wall(c) && ls::any_wall() && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && !c->master->alt && !tactic::on && !racing::on &&
|
||||
buildBarrierNowall(c, getNewLand(laCrossroads4))) ;
|
||||
|
||||
else if(good_for_wall(c) && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !racing::on && !isCrossroads(c->land) &&
|
||||
gold() >= R200 && !weirdhyperbolic && !c->master->alt && c->bardir != NOBARRIERS &&
|
||||
|
||||
else if(good_for_wall(c) && ls::any_wall() && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !racing::on && !isCrossroads(c->land) &&
|
||||
landUnlockedIngame(laCrossroads4) && !weirdhyperbolic && !c->master->alt && c->bardir != NOBARRIERS &&
|
||||
!inmirror(c) && !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) &&
|
||||
(c->land != laRlyeh || rlyehComplete()) &&
|
||||
c->land != laTortoise && c->land != laPrairie && c->land &&
|
||||
|
@ -1652,10 +1867,14 @@ EX void start_camelot(cell *c) {
|
|||
heptagon *alt = create_altmap(c, ls::single() ? 2 : rtr+(hyperbolic && WDIM == 3 ? 11 : 14), ls::single() ? hsA : hsOrigin);
|
||||
if(alt) {
|
||||
altmap::radius(alt) = rtr;
|
||||
altmap::orig_land(alt) = c->land;
|
||||
altmap::orig_land(alt) = ls::horodisk_structure() ? laCrossroads : c->land;
|
||||
hv_land[alt] = laCamelot;
|
||||
}
|
||||
}
|
||||
|
||||
EX bool debug_voronoi;
|
||||
EX map<heptagon*, eLand> hv_land;
|
||||
|
||||
EX void build_horocycles(cell *c, cell *from) {
|
||||
|
||||
bool deepOcean = deep_ocean_at(c, from);
|
||||
|
@ -1667,21 +1886,21 @@ EX void build_horocycles(cell *c, cell *from) {
|
|||
|
||||
// buildbigstuff
|
||||
|
||||
if(ls::any_order() && bearsCamelot(c->land) && can_start_horo(c) && !bt::in() &&
|
||||
if(ls::any_order() && (ls::horodisk_structure() || bearsCamelot(c->land)) && can_start_horo(c, true) && !bt::in() && !ls::voronoi_structure() &&
|
||||
#if MAXMDIM >= 4
|
||||
!(hyperbolic && WDIM == 3 && !reg3::in_rule()) &&
|
||||
!(hyperbolic && WDIM == 3 && !reg3::in_hrmap_rule_or_subrule()) &&
|
||||
#endif
|
||||
(quickfind(laCamelot) || peace::on || (hrand(I2000) < (c->land == laCrossroads4 || ls::no_walls() ? 800 : 200) && horo_ok() &&
|
||||
items[itEmerald] >= U5)))
|
||||
start_camelot(c);
|
||||
|
||||
if(c->land == laRlyeh && can_start_horo(c) && (quickfind(laTemple) || peace::on || (hrand(I2000) < 100 && items[itStatue] >= U5)))
|
||||
if(c->land == laRlyeh && can_start_horo(c) && (quickfind(laTemple) || (hrand(I2000) < 100 && landUnlockedIngame(laTemple))))
|
||||
create_altmap(c, horo_gen_distance(), hsA);
|
||||
|
||||
if(c->land == laJungle && can_start_horo(c) && (quickfind(laMountain) || (hrand(I2000) < 100 && landUnlocked(laMountain))))
|
||||
if(c->land == laJungle && can_start_horo(c) && (quickfind(laMountain) || (hrand(I2000) < 100 && landUnlockedIngame(laMountain))))
|
||||
create_altmap(c, horo_gen_distance(), hsA);
|
||||
|
||||
if(c->land == laOvergrown && can_start_horo(c) && (quickfind(laClearing) || (hrand(I2000) < 25 && items[itMutant] >= U5 && isLandIngame(laClearing)))) {
|
||||
if(c->land == laOvergrown && can_start_horo(c) && (quickfind(laClearing) || (hrand(I2000) < 25 && landUnlockedIngame(laClearing)))) {
|
||||
heptagon *h = create_altmap(c, horo_gen_distance(), hsA);
|
||||
if(h) clearing::bpdata[h].root = NULL;
|
||||
}
|
||||
|
@ -1693,24 +1912,33 @@ EX void build_horocycles(cell *c, cell *from) {
|
|||
|
||||
if(c->land == laOcean && deepOcean && !generatingEquidistant && !peace::on && can_start_horo(c) &&
|
||||
(quickfind(laWhirlpool) || (
|
||||
hrand(2000) < (PURE ? 500 : 1000))))
|
||||
hrand(2000) < (PURE ? 500 : 1000) && landUnlockedIngame(laWhirlpool))))
|
||||
create_altmap(c, horo_gen_distance(), hsA);
|
||||
|
||||
#if CAP_COMPLEX2
|
||||
if(c->land == laOcean && deepOcean && !generatingEquidistant && hrand(10000) < 20 && no_barriers_in_radius(c, 2) && hyperbolic && !quotient && !tactic::on && !safety)
|
||||
if(c->land == laOcean && deepOcean && !generatingEquidistant && hrand(10000) < 20 && no_barriers_in_radius(c, 2) && hyperbolic && !quotient && !tactic::on && !safety && !ls::hv_structure()
|
||||
&& landUnlockedIngame(laBrownian))
|
||||
brownian::init_further(c);
|
||||
#endif
|
||||
|
||||
if(c->land == laCaribbean && can_start_horo(c))
|
||||
create_altmap(c, horo_gen_distance(), hsA);
|
||||
|
||||
if(ls::horodisk_structure() && can_start_horo(c, true)) {
|
||||
auto m = create_altmap(c, horo_gen_distance(), hsA);
|
||||
if(m) {
|
||||
hv_land[m] = getNewLand(laCrossroads);
|
||||
clearing::bpdata[m].root = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(c->land == laCanvas && can_start_horo(c) && ls::any_order())
|
||||
create_altmap(c, horo_gen_distance(), hsA);
|
||||
|
||||
if(c->land == laPalace && can_start_horo(c) && !princess::generating && !shmup::on && multi::players == 1 && !weirdhyperbolic &&
|
||||
(princess::forceMouse ? canReachPlayer(from, moMouse) :
|
||||
(hrand(2000) < (peace::on ? 100 : 20))) &&
|
||||
(princess::challenge || kills[moVizier] || peace::on)) {
|
||||
landUnlockedIngame(laPrincessQuest)) {
|
||||
create_altmap(c, PRADIUS0, hsOrigin, waPalace);
|
||||
celllister cl(c, 5, 1000000, NULL);
|
||||
for(cell *c: cl.lst) if(c->master->alt) currentmap->extend_altmap(c->master);
|
||||
|
@ -1853,13 +2081,16 @@ EX void buildCamelot(cell *c) {
|
|||
if(c->land == laNone) printf("Camelot\n"); // NONEDEBUG
|
||||
}
|
||||
}
|
||||
else if(ls::hv_structure()) {
|
||||
setland(c, eLand(altmap::orig_land(c->master->alt->alt)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EX int masterAlt(cell *c) {
|
||||
if(eubinary) return celldistAlt(c);
|
||||
#if MAXMDIM >= 4
|
||||
if(WDIM == 3 && hyperbolic && !reg3::in_rule()) return reg3::altdist(c->master);
|
||||
if(WDIM == 3 && hyperbolic && !reg3::in_hrmap_rule_or_subrule()) return reg3::altdist(c->master);
|
||||
#endif
|
||||
return c->master->alt->distance;
|
||||
}
|
||||
|
@ -1919,7 +2150,7 @@ EX void gen_temple(cell *c) {
|
|||
auto d = hybrid::get_where(c);
|
||||
if(!PIU(pseudohept(d.first))) c->wall = waColumn;
|
||||
}
|
||||
else if(hybri) {
|
||||
else if(mhybrid) {
|
||||
auto d = hybrid::get_where(c);
|
||||
if(d.first->wall == waColumn || (d.second&1)) c->wall = waColumn;
|
||||
}
|
||||
|
@ -1946,9 +2177,38 @@ EX void gen_temple(cell *c) {
|
|||
else c->landparam = 2;
|
||||
}
|
||||
|
||||
/* -2 should be perfect */
|
||||
EX int horodisk_from = -2;
|
||||
|
||||
EX void pick_hv_subland(cell *c, eLand l, int depth) {
|
||||
if(l == laElementalWall) {
|
||||
auto land_at = [] (int dp) {
|
||||
int i = dp - 12;
|
||||
if((i & 7) == 7) return laElementalWall;
|
||||
i >>= 3;
|
||||
eLand tab[4] = { laEAir, laEWater, laEEarth, laEFire };
|
||||
return tab[i&3];
|
||||
};
|
||||
|
||||
setland(c, land_at(depth));
|
||||
if(c->land == laElementalWall) {
|
||||
c->barleft = land_at(depth-1);
|
||||
c->barright = land_at(depth+1);
|
||||
if(hrand(100) < 75)
|
||||
c->wall = getElementalWall(hrand(2) ? c->barleft : c->barright);
|
||||
}
|
||||
}
|
||||
else if(l == laWarpCoast) {
|
||||
int i = (depth & 8);
|
||||
setland(c, i ? laWarpCoast : laWarpSea);
|
||||
}
|
||||
else setland(c, l);
|
||||
}
|
||||
|
||||
EX void moreBigStuff(cell *c) {
|
||||
if(disable_bigstuff) return;
|
||||
|
||||
if(!ls::hv_structure())
|
||||
if((bearsCamelot(c->land) && !euclid && !quotient && !nil) || c->land == laCamelot)
|
||||
if(have_alt(c)) if(!(bt::in() && specialland != laCamelot))
|
||||
buildCamelot(c);
|
||||
|
@ -1962,12 +2222,50 @@ EX void moreBigStuff(cell *c) {
|
|||
else
|
||||
c->wall = waSea;
|
||||
}
|
||||
|
||||
if(ls::voronoi_structure()) {
|
||||
auto p = get_voronoi_winner(c);
|
||||
auto ph = p.first;
|
||||
if(ph) {
|
||||
eLand l = hv_land[ph];
|
||||
pick_hv_subland(c, l, p.second);
|
||||
if(isEquidLand(l)) c->landparam = 1-p.second;
|
||||
}
|
||||
else {
|
||||
setland(c, laBarrier);
|
||||
}
|
||||
}
|
||||
|
||||
if(ls::horodisk_structure()) {
|
||||
if(have_alt(c) && masterAlt(c) <= 0) {
|
||||
gen_alt(c);
|
||||
preventbarriers(c);
|
||||
}
|
||||
if(have_alt(c) && hv_land[c->master->alt->alt] == laCamelot) {
|
||||
buildCamelot(c);
|
||||
}
|
||||
else if(have_alt(c) && celldistAlt(c) <= horodisk_from) {
|
||||
eLand l = hv_land[c->master->alt->alt];
|
||||
pick_hv_subland(c, l, celldistAlt(c));
|
||||
if(l == laCaribbean) generateTreasureIsland(c);
|
||||
if(l == laWhirlpool && celldistAlt(c) >= -1) {
|
||||
setland(c, laOcean);
|
||||
c->landparam = 30;
|
||||
}
|
||||
if(l == laWestWall && celldistAlt(c) >= -1) {
|
||||
setland(c, laCrossroads);
|
||||
}
|
||||
if(isEquidLand(l)) c->landparam = 1-celldistAlt(c);
|
||||
}
|
||||
else
|
||||
setland(c, laCrossroads);
|
||||
}
|
||||
|
||||
extend_alt(c, laPalace, laPalace, false, PRADIUS1);
|
||||
if(!ls::hv_structure()) extend_alt(c, laPalace, laPalace, false, PRADIUS1);
|
||||
|
||||
extend_alt(c, laCanvas, laCanvas);
|
||||
|
||||
if(extend_alt(c, laStorms, laStorms, false)) {
|
||||
if(!ls::hv_structure() && extend_alt(c, laStorms, laStorms, false)) {
|
||||
int d = celldistAlt(c);
|
||||
if(d <= -2) {
|
||||
c->wall = eubinary ? waCharged : (altmap::which(c->master->alt->alt) & 1) ? waCharged : waGrounded;
|
||||
|
@ -1986,10 +2284,12 @@ EX void moreBigStuff(cell *c) {
|
|||
c->wall = waColumn;
|
||||
}
|
||||
|
||||
else if(extend_alt(c, laTemple, laRlyeh))
|
||||
else if(!ls::hv_structure() && extend_alt(c, laTemple, laRlyeh))
|
||||
gen_temple(c);
|
||||
|
||||
if(extend_alt(c, laClearing, laOvergrown)) {
|
||||
if(ls::hv_structure() && c->land == laTemple) gen_temple(c);
|
||||
|
||||
if(!ls::hv_structure() && extend_alt(c, laClearing, laOvergrown)) {
|
||||
if(in_single_horo(c, laClearing)) {
|
||||
c->land = laClearing, c->wall = waNone;
|
||||
}
|
||||
|
@ -1997,11 +2297,21 @@ EX void moreBigStuff(cell *c) {
|
|||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
|
||||
}
|
||||
|
||||
if(extend_alt(c, laMountain, laJungle) && in_single_horo(c, laMountain)) {
|
||||
if(ls::horodisk_structure() && c->land == laClearing) {
|
||||
if(celldistAlt(c) >= -1)
|
||||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
|
||||
}
|
||||
|
||||
if(ls::voronoi_structure() && c->land == laClearing) {
|
||||
if(celldistAlt(c) == -20)
|
||||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
|
||||
}
|
||||
|
||||
if(!ls::hv_structure() && extend_alt(c, laMountain, laJungle) && in_single_horo(c, laMountain)) {
|
||||
c->land = laMountain, c->wall = waNone;
|
||||
}
|
||||
|
||||
if(extend_alt(c, laWhirlpool, laOcean) && in_single_horo(c, laWhirlpool))
|
||||
if(!ls::hv_structure() && extend_alt(c, laWhirlpool, laOcean) && in_single_horo(c, laWhirlpool))
|
||||
c->land = laWhirlpool, c->wall = waSea, c->monst = moNone, c->item = itNone;
|
||||
}
|
||||
|
||||
|
@ -2027,7 +2337,7 @@ EX void pregen() {
|
|||
currentlands.clear();
|
||||
if(ls::any_chaos() && !ls::std_chaos())
|
||||
for(eLand l: land_over)
|
||||
if(landUnlocked(l) && isLandIngame(l))
|
||||
if(landUnlockedIngame(l))
|
||||
currentlands.push_back(l);
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ EX namespace bt {
|
|||
h->emeraldval = gmod((parent->emeraldval - d1) * 7508, 15015);
|
||||
break;
|
||||
case gTernary:
|
||||
if(d < 2)
|
||||
if(d <= 2)
|
||||
h->emeraldval = gmod(parent->emeraldval * 3 + d, 10010);
|
||||
else
|
||||
h->emeraldval = gmod((parent->emeraldval - d1) * 3337, 10010);
|
||||
|
@ -478,24 +478,24 @@ EX namespace bt {
|
|||
}
|
||||
if(d == NODIR) return 0;
|
||||
if(d == c->type-1) d++;
|
||||
return -(d+2)*M_PI/4;
|
||||
return -(d+2) * 45._deg;
|
||||
}
|
||||
|
||||
transmatrix adj(heptagon *h, int dir) override {
|
||||
if(geometry == gBinaryTiling) switch(dir) {
|
||||
case bd_up: return xpush(-log(2));
|
||||
case bd_up: return lxpush(-log(2));
|
||||
case bd_left: return parabolic(-2);
|
||||
case bd_right: return parabolic(+2);
|
||||
case bd_down:
|
||||
if(h->type == 6) return xpush(log(2));
|
||||
if(h->type == 6) return lxpush(log(2));
|
||||
/* case bd_down_left: */
|
||||
return parabolic(-2) * xpush(log(2));
|
||||
return parabolic(-2) * lxpush(log(2));
|
||||
case bd_down_right:
|
||||
return parabolic(+2) * xpush(log(2));
|
||||
return parabolic(+2) * lxpush(log(2));
|
||||
case bd_up_left:
|
||||
return xpush(-log(2)) * parabolic(-2);
|
||||
return lxpush(-log(2)) * parabolic(-2);
|
||||
case bd_up_right:
|
||||
return xpush(-log(2)) * parabolic(2);
|
||||
return lxpush(-log(2)) * parabolic(2);
|
||||
default:
|
||||
throw hr_exception("unknown direction");
|
||||
}
|
||||
|
@ -604,7 +604,7 @@ EX namespace bt {
|
|||
/** \brief by what factor do the lengths expand after moving one level in hr::bt::expansion_coordinate() */
|
||||
EX ld expansion() {
|
||||
if(WDIM == 2) return area_expansion_rate();
|
||||
else if(prod) return PIU( area_expansion_rate() );
|
||||
else if(mproduct) return PIU( area_expansion_rate() );
|
||||
else return sqrt(area_expansion_rate());
|
||||
}
|
||||
|
||||
|
@ -634,9 +634,9 @@ EX namespace bt {
|
|||
auto &x = h[0], &y = h[1], &z = h[2];
|
||||
switch(geometry) {
|
||||
case gBinaryTiling: case gBinary4:
|
||||
return bt::parabolic(y) * xpush(x*z2*2);
|
||||
return bt::parabolic(y) * lxpush(x*z2*2);
|
||||
case gTernary:
|
||||
return bt::parabolic(y) * xpush(x*z3*2);
|
||||
return bt::parabolic(y) * lxpush(x*z3*2);
|
||||
#if CAP_SOLV
|
||||
case gSol:
|
||||
return xpush(bwh*x) * ypush(bwh*y) * zpush(z2*z);
|
||||
|
@ -700,16 +700,16 @@ EX namespace bt {
|
|||
use_direct = (1 << (S7-1)) - 1;
|
||||
if(geometry == gBinary4) {
|
||||
use_direct = 3;
|
||||
direct_tmatrix[0] = xpush(-log(2)) * parabolic(-1);
|
||||
direct_tmatrix[1] = xpush(-log(2)) * parabolic(+1);
|
||||
direct_tmatrix[0] = lxpush(-log(2)) * parabolic(-1);
|
||||
direct_tmatrix[1] = lxpush(-log(2)) * parabolic(+1);
|
||||
direct_tmatrix[2] = parabolic(2);
|
||||
direct_tmatrix[4] = parabolic(-2);
|
||||
use_direct = 1+2+4+16;
|
||||
}
|
||||
if(geometry == gTernary) {
|
||||
direct_tmatrix[0] = xpush(-log(3)) * parabolic(-2);
|
||||
direct_tmatrix[1] = xpush(-log(3));
|
||||
direct_tmatrix[2] = xpush(-log(3)) * parabolic(+2);
|
||||
direct_tmatrix[0] = lxpush(-log(3)) * parabolic(-2);
|
||||
direct_tmatrix[1] = lxpush(-log(3));
|
||||
direct_tmatrix[2] = lxpush(-log(3)) * parabolic(+2);
|
||||
direct_tmatrix[3] = parabolic(2);
|
||||
direct_tmatrix[5] = parabolic(-2);
|
||||
use_direct = 1+2+4+8+32;
|
||||
|
@ -726,20 +726,20 @@ EX namespace bt {
|
|||
}
|
||||
if(geometry == gHoroTris) {
|
||||
ld r3 = sqrt(3);
|
||||
direct_tmatrix[0] = xpush(-log(2)) * cspin(1,2, M_PI);
|
||||
direct_tmatrix[0] = xpush(-log(2)) * cspin180(1,2);
|
||||
direct_tmatrix[1] = parabolic3(0, +r3/3) * xpush(-log(2));
|
||||
direct_tmatrix[2] = parabolic3(-0.5, -r3/6) * xpush(-log(2));
|
||||
direct_tmatrix[3] = parabolic3(+0.5, -r3/6) * xpush(-log(2));
|
||||
direct_tmatrix[4] = parabolic3(0, -r3*2/3) * cspin(1,2, M_PI);
|
||||
direct_tmatrix[5] = parabolic3(1, r3/3) * cspin(1,2,M_PI);
|
||||
direct_tmatrix[6] = parabolic3(-1, r3/3) * cspin(1,2,M_PI);
|
||||
direct_tmatrix[4] = parabolic3(0, -r3*2/3) * cspin180(1,2);
|
||||
direct_tmatrix[5] = parabolic3(1, r3/3) * cspin180(1,2);
|
||||
direct_tmatrix[6] = parabolic3(-1, r3/3) * cspin180(1,2);
|
||||
}
|
||||
if(geometry == gHoroRec) {
|
||||
ld r2 = sqrt(2);
|
||||
ld l = -log(2)/2;
|
||||
ld z = hororec_scale;
|
||||
direct_tmatrix[0] = parabolic3(0, -z) * xpush(l) * cspin(2,1,M_PI/2);
|
||||
direct_tmatrix[1] = parabolic3(0, +z) * xpush(l) * cspin(2,1,M_PI/2);
|
||||
direct_tmatrix[0] = parabolic3(0, -z) * xpush(l) * cspin90(2,1);
|
||||
direct_tmatrix[1] = parabolic3(0, +z) * xpush(l) * cspin90(2,1);
|
||||
direct_tmatrix[2] = parabolic3(+2*r2*z, 0);
|
||||
direct_tmatrix[3] = parabolic3(0, +4*z);
|
||||
direct_tmatrix[4] = parabolic3(-2*r2*z, 0);
|
||||
|
@ -749,9 +749,9 @@ EX namespace bt {
|
|||
// also generated with the help of hexb.cpp
|
||||
ld l = log(3)/2;
|
||||
auto& t = direct_tmatrix;
|
||||
t[0] = parabolic3(horohex_scale, 0) * xpush(-l) * cspin(1, 2, M_PI/2);
|
||||
t[1] = cspin(1, 2, 2*M_PI/3) * t[0];
|
||||
t[2] = cspin(1, 2, 4*M_PI/3) * t[0];
|
||||
t[0] = parabolic3(horohex_scale, 0) * xpush(-l) * cspin(1, 2, 90._deg);
|
||||
t[1] = cspin(1, 2, 120*degree) * t[0];
|
||||
t[2] = cspin(1, 2, 240*degree) * t[0];
|
||||
auto it = iso_inverse(t[0]);
|
||||
|
||||
t[5] = it * t[1] * t[1];
|
||||
|
@ -854,14 +854,35 @@ auto bt_config = arg::add2("-btwidth", [] {arg::shift_arg_formula(vid.binary_wid
|
|||
#endif
|
||||
|
||||
EX bool pseudohept(cell *c) {
|
||||
if(WDIM == 2)
|
||||
return c->type & c->master->distance & 1;
|
||||
else if(geometry == gHoroRec)
|
||||
return c->c.spin(S7-1) == 0 && (c->master->distance & 1) && c->cmove(S7-1)->c.spin(S7-1) == 0;
|
||||
else if(geometry == gHoroTris)
|
||||
return c->c.spin(S7-1) == 0 && (c->master->distance & 1);
|
||||
else
|
||||
return (c->master->zebraval == 1) && (c->master->distance & 1);
|
||||
switch(geometry) {
|
||||
case gBinary4:
|
||||
c->cmove(3);
|
||||
return (c->master->distance & 1) && (c->c.spin(3) == 0);
|
||||
|
||||
case gBinaryTiling:
|
||||
return c->master->distance & c->type & 1;
|
||||
|
||||
case gTernary: {
|
||||
return c->master->emeraldval & 1;
|
||||
/* auto m = dynamic_cast<hrmap_binary*> (current_map());
|
||||
auto o = m->origin;
|
||||
int flips = 0;
|
||||
while(m != o) {
|
||||
if(m->master->distance >= o->master->distance) { if(m->c.spin(4) == 1) flips++; m = m->cmove(4); }
|
||||
}
|
||||
heptagon *origin;
|
||||
c->cmove(4); return (c->c.spin(4) == 1); */
|
||||
}
|
||||
|
||||
case gHoroRec:
|
||||
return c->c.spin(S7-1) == 0 && (c->master->distance & 1) && c->cmove(S7-1)->c.spin(S7-1) == 0;
|
||||
|
||||
case gHoroTris:
|
||||
return c->c.spin(S7-1) == 0 && (c->master->distance & 1);
|
||||
|
||||
default:
|
||||
return (c->master->zebraval == 1) && (c->master->distance & 1);
|
||||
}
|
||||
}
|
||||
|
||||
EX pair<gp::loc, gp::loc> gpvalue(heptagon *h) {
|
||||
|
@ -978,7 +999,7 @@ EX int celldistance3_hex(heptagon *c1, heptagon *c2) {
|
|||
while(isize(d1)) {
|
||||
xsteps -= 2;
|
||||
|
||||
T = euscalezoom(hpxy(0,sqrt(3))) * eupush(1,0) * spin(-d2.back() * 2 * M_PI/3) * T * spin(d1.back() * 2 * M_PI/3) * eupush(-1,0) * euscalezoom(hpxy(0,-1/sqrt(3)));
|
||||
T = euscalezoom(hpxy(0,sqrt(3))) * eupush(1,0) * spin(-d2.back() * 120._deg) * T * spin(d1.back() * 2 * M_PI/3) * eupush(-1,0) * euscalezoom(hpxy(0,-1/sqrt(3)));
|
||||
|
||||
d1.pop_back(); d2.pop_back();
|
||||
|
||||
|
@ -1027,25 +1048,30 @@ EX int celldistance3(heptagon *c1, heptagon *c2) {
|
|||
EX int celldistance3(cell *c1, cell *c2) { return celldistance3(c1->master, c2->master); }
|
||||
|
||||
EX hyperpoint get_horopoint(ld y, ld x) {
|
||||
return xpush(-y) * bt::parabolic(x*2) * C0;
|
||||
return bt::parabolic(x*2) * lxpush(-y) * C0;
|
||||
}
|
||||
|
||||
EX hyperpoint get_horopoint(hyperpoint h) {
|
||||
return get_horopoint(h[0], h[1]);
|
||||
}
|
||||
|
||||
EX hyperpoint inverse_horopoint(hyperpoint h) {
|
||||
hyperpoint h1 = deparabolic13(h);
|
||||
h1[1] /= 2 * bt::xy_mul(); h1[0] *= -1;
|
||||
return h1;
|
||||
}
|
||||
|
||||
EX hyperpoint get_corner_horo_coordinates(cell *c, int i) {
|
||||
ld yx = log(2) / 2;
|
||||
ld yy = yx;
|
||||
ld xx = 1 / sqrt(2)/2;
|
||||
ld yy = log(2) / 2;
|
||||
ld xx = 1 / 2.;
|
||||
switch(geometry) {
|
||||
case gBinaryTiling:
|
||||
switch(gmod(i, c->type)) {
|
||||
case 0: return point2(-yy, xx);
|
||||
case 1: return point2(yy, 2*xx);
|
||||
case 2: return point2(yy, xx);
|
||||
case 3: return point2(yy, -xx);
|
||||
case 4: return point2(yy, -2*xx);
|
||||
case 1: return point2(yy, xx);
|
||||
case 2: return point2(yy, xx/2);
|
||||
case 3: return point2(yy, -xx/2);
|
||||
case 4: return point2(yy, -xx);
|
||||
case 5: return point2(-yy, -xx);
|
||||
case 6: return point2(-yy, 0);
|
||||
default: return point2(0, 0);
|
||||
|
@ -1053,9 +1079,9 @@ EX hyperpoint get_corner_horo_coordinates(cell *c, int i) {
|
|||
|
||||
case gBinary4:
|
||||
switch(gmod(i, c->type)) {
|
||||
case 0: return point2(yy, -2*xx);
|
||||
case 0: return point2(yy, -xx);
|
||||
case 1: return point2(yy, +0*xx);
|
||||
case 2: return point2(yy, +2*xx);
|
||||
case 2: return point2(yy, +xx);
|
||||
case 3: return point2(-yy, xx);
|
||||
case 4: return point2(-yy, -xx);
|
||||
default: return point2(0, 0);
|
||||
|
@ -1063,12 +1089,11 @@ EX hyperpoint get_corner_horo_coordinates(cell *c, int i) {
|
|||
|
||||
case gTernary:
|
||||
yy = log(3) / 2;
|
||||
xx = 1 / sqrt(3) / 2;
|
||||
switch(gmod(i, c->type)) {
|
||||
case 0: return point2(yy, -3*xx);
|
||||
case 1: return point2(yy, -1*xx);
|
||||
case 2: return point2(yy, +1*xx);
|
||||
case 3: return point2(yy, +3*xx);
|
||||
case 0: return point2(yy, -xx);
|
||||
case 1: return point2(yy, -xx/3);
|
||||
case 2: return point2(yy, +xx/3);
|
||||
case 3: return point2(yy, +xx);
|
||||
case 4: return point2(-yy, xx);
|
||||
case 5: return point2(-yy, -xx);
|
||||
default: return point2(0, 0);
|
||||
|
@ -1166,7 +1191,7 @@ EX void create_faces() {
|
|||
hyperpoint down = point3(0,0,2*z);
|
||||
|
||||
for(int j=0; j<4; j++) for(int i=0; i<3; i++) {
|
||||
transmatrix T = cspin(0, 1, 2*M_PI*i/3);
|
||||
transmatrix T = cspin(0, 1, 120._deg * i);
|
||||
|
||||
hyperpoint hcenter = point3(0,0,-z);
|
||||
hyperpoint hu0 = T*point3(+h, +r3,-z);
|
||||
|
|
|
@ -241,7 +241,7 @@ EX void drawArrowTraps() {
|
|||
hyperpoint trel = inverse_shift(tu, tC0(tv));
|
||||
shiftmatrix tpartial = tu * rspintox(trel) * xpush(hdist0(trel) * tt / 401.0);
|
||||
tpartial = tpartial * ypush(.05);
|
||||
if(GDIM == 3) tpartial = tpartial * cspin(1, 2, M_PI/2);
|
||||
if(GDIM == 3) tpartial = tpartial * cspin90(1, 2);
|
||||
queuepoly(tpartial, cgi.shTrapArrow, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
|
269
cell.cpp
269
cell.cpp
|
@ -51,7 +51,7 @@ public:
|
|||
virtual transmatrix spin_to(cell *c, int d, ld bonus=0);
|
||||
virtual transmatrix spin_from(cell *c, int d, ld bonus=0);
|
||||
|
||||
virtual double spacedist(cell *c, int i) { return hdist0(tC0(adj(c, i))); }
|
||||
virtual double spacedist(cell *c, int i);
|
||||
|
||||
virtual bool strict_tree_rules() { return false; }
|
||||
|
||||
|
@ -77,6 +77,11 @@ public:
|
|||
|
||||
/** generate a new map that is disconnected from what we already have, disconnected from the map we have so far */
|
||||
virtual cell* gen_extra_origin(int fv) { throw hr_exception("gen_extra_origin not supported on this map"); }
|
||||
|
||||
transmatrix adjmod(cell *c, int i) { return adj(c, gmod(i, c->type)); }
|
||||
transmatrix adjmod(heptagon *h, int i) { return adj(h, gmod(i, h->type)); }
|
||||
transmatrix iadjmod(cell *c, int i) { return iadj(c, gmod(i, c->type)); }
|
||||
transmatrix iadjmod(heptagon *h, int i) { return iadj(h, gmod(i, h->type)); }
|
||||
};
|
||||
|
||||
/** hrmaps which are based on regular non-Euclidean 2D tilings, possibly quotient
|
||||
|
@ -94,10 +99,11 @@ struct hrmap_standard : hrmap {
|
|||
ld spin_angle(cell *c, int d) override;
|
||||
double spacedist(cell *c, int i) override;
|
||||
void find_cell_connection(cell *c, int d) override;
|
||||
virtual int shvid(cell *c) override;
|
||||
virtual hyperpoint get_corner(cell *c, int cid, ld cf) override;
|
||||
virtual transmatrix master_relative(cell *c, bool get_inverse) override;
|
||||
virtual bool link_alt(heptagon *h, heptagon *alt, hstate firststate, int dir) override;
|
||||
int shvid(cell *c) override;
|
||||
hyperpoint get_corner(cell *c, int cid, ld cf) override;
|
||||
transmatrix master_relative(cell *c, bool get_inverse) override;
|
||||
bool link_alt(heptagon *h, heptagon *alt, hstate firststate, int dir) override;
|
||||
void on_dim_change() override;
|
||||
};
|
||||
|
||||
void clearfrom(heptagon*);
|
||||
|
@ -118,6 +124,13 @@ struct hrmap_hyperbolic : hrmap_standard {
|
|||
};
|
||||
#endif
|
||||
|
||||
void hrmap_standard::on_dim_change() {
|
||||
for(auto& p: gp::gp_swapped) swapmatrix(gp::gp_adj[p]);
|
||||
gp::gp_swapped.clear();
|
||||
}
|
||||
|
||||
double hrmap::spacedist(cell *c, int i) { return hdist(tile_center(), adj(c, i) * tile_center()); }
|
||||
|
||||
heptagon *hrmap::create_step(heptagon *h, int direction) {
|
||||
throw hr_exception("create_step called unexpectedly");
|
||||
return NULL;
|
||||
|
@ -169,7 +182,7 @@ const vector<int>& hrmap::get_move_seq(cell *c, int i) {
|
|||
transmatrix hrmap::spin_to(cell *c, int d, ld bonus) {
|
||||
ld sa = spin_angle(c, d);
|
||||
if(sa != SPIN_NOT_AVAILABLE) { return spin(bonus + sa); }
|
||||
transmatrix T = rspintox(tC0(adj(c, d)));
|
||||
transmatrix T = lrspintox(tC0(adj(c, d)));
|
||||
if(WDIM == 3) return T * cspin(2, 0, bonus);
|
||||
return T * spin(bonus);
|
||||
}
|
||||
|
@ -177,7 +190,7 @@ transmatrix hrmap::spin_to(cell *c, int d, ld bonus) {
|
|||
transmatrix hrmap::spin_from(cell *c, int d, ld bonus) {
|
||||
ld sa = spin_angle(c, d);
|
||||
if(sa != SPIN_NOT_AVAILABLE) { return spin(bonus - sa); }
|
||||
transmatrix T = spintox(tC0(adj(c, d)));
|
||||
transmatrix T = lspintox(tC0(adj(c, d)));
|
||||
if(WDIM == 3) return T * cspin(2, 0, bonus);
|
||||
return T * spin(bonus);
|
||||
}
|
||||
|
@ -187,7 +200,7 @@ transmatrix hrmap::adj(heptagon *h, int i) { return relative_matrix(h->cmove(i),
|
|||
vector<cell*>& hrmap::allcells() {
|
||||
static vector<cell*> default_allcells;
|
||||
if(disksize) return all_disk_cells;
|
||||
if(closed_manifold && !(cgflags & qHUGE_BOUNDED) && !(hybri && hybrid::csteps == 0)) {
|
||||
if(closed_manifold && !(cgflags & qHUGE_BOUNDED) && !(mhybrid && hybrid::csteps == 0)) {
|
||||
celllister cl(gamestart(), 1000000, 1000000, NULL);
|
||||
default_allcells = cl.lst;
|
||||
return default_allcells;
|
||||
|
@ -232,7 +245,7 @@ EX vector<hrmap*> allmaps;
|
|||
|
||||
EX hrmap *newAltMap(heptagon *o) {
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::in_rule())
|
||||
if(reg3::in_hrmap_rule_or_subrule())
|
||||
return reg3::new_alt_map(o);
|
||||
#endif
|
||||
if(currentmap->strict_tree_rules())
|
||||
|
@ -400,16 +413,163 @@ EX bool is_in_disk(cell *c) {
|
|||
return *it == c;
|
||||
}
|
||||
|
||||
bool sierpinski3(gp::loc g) {
|
||||
int x = g.first;
|
||||
int y = g.second;
|
||||
set<pair<int, int>> visited;
|
||||
while(true) {
|
||||
if(visited.count({x,y})) return false;
|
||||
visited.insert({x,y});
|
||||
// if(x == -1 && y == -2) return false;
|
||||
// if(x == -2 && y == -3) return false;
|
||||
if(x == 0 && y == 0) return true;
|
||||
if((x&1) == 1 && (y&1) == 1) return false;
|
||||
x >>= 1;
|
||||
y >>= 1;
|
||||
// x--; y++;
|
||||
tie(x, y) = make_pair(-x-y, x);
|
||||
}
|
||||
}
|
||||
|
||||
bool sierpinski46(gp::loc g) {
|
||||
int x = g.first;
|
||||
int y = g.second;
|
||||
set<pair<int, int>> visited;
|
||||
if(S7 == 6)
|
||||
x += 2785684, y += 289080;
|
||||
else
|
||||
x += 75239892, y += 7913772;
|
||||
while(true) {
|
||||
if(visited.count({x,y})) return false;
|
||||
visited.insert({x,y});
|
||||
if(x == 0 && y == 0) return true;
|
||||
int dx = gmod(x, 3);
|
||||
int dy = gmod(y, 3);
|
||||
if(dx == 1 && dy == 1) return false;
|
||||
if(S7 == 6 && dx == dy) return false;
|
||||
x = (x-dx) / 3;
|
||||
y = (y-dy) / 3;
|
||||
}
|
||||
}
|
||||
|
||||
bool menger_sponge(euc::coord c) {
|
||||
c[0] += 528120*9; c[1] += 438924*9; c[2] += 306712*9;
|
||||
set<euc::coord> visited;
|
||||
while(true) {
|
||||
if(visited.count(c)) return false;
|
||||
visited.insert(c);
|
||||
if(c[0] == 0 && c[1] == 0 && c[2] == 0) return true;
|
||||
int ones = 0;
|
||||
for(int i=0; i<3; i++) {
|
||||
int d = gmod(c[i], 3);
|
||||
c[i] = (c[i] - d) / 3;
|
||||
if(d == 1) ones++;
|
||||
}
|
||||
if(ones >= 2) return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool sierpinski_tet(euc::coord c) {
|
||||
set<euc::coord> visited;
|
||||
c[0] += 16 * (1+8+64+512);
|
||||
c[1] += 16 * (1+8+64+512);
|
||||
c[1] += 32 * (1+8+64+512);
|
||||
c[2] += 32 * (1+8+64+512);
|
||||
c[0] += 64 * (1+8+64+512);
|
||||
c[1] += 64 * (1+8+64+512);
|
||||
while(true) {
|
||||
if(visited.count(c)) return false;
|
||||
visited.insert(c);
|
||||
if(c[0] == 0 && c[1] == 0 && c[2] == 0) return true;
|
||||
int ones = 0;
|
||||
for(int i=0; i<3; i++) {
|
||||
int d = gmod(c[i], 2);
|
||||
c[i] = (c[i] - d) / 2;
|
||||
if(d == 1) ones++;
|
||||
}
|
||||
if(ones & 1) return false;
|
||||
}
|
||||
}
|
||||
|
||||
EX bool is_in_fractal(cell *c) {
|
||||
if(fake::in()) return FPIU(is_in_fractal(c));
|
||||
if(mhybrid) { c = hybrid::get_where(c).first; return PIU(is_in_fractal(c)); }
|
||||
switch(geometry) {
|
||||
case gSierpinski3:
|
||||
return sierpinski3(euc::full_coords2(c));
|
||||
case gSierpinski4:
|
||||
case gSixFlake:
|
||||
return sierpinski46(euc::full_coords2(c));
|
||||
case gMengerSponge:
|
||||
return menger_sponge(euc::get_ispacemap()[c->master]);
|
||||
case gSierpinskiTet: {
|
||||
return sierpinski_tet(euc::get_ispacemap()[c->master]);
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
EX cell *fractal_rep(cell *c) {
|
||||
switch(geometry) {
|
||||
case gSierpinski3: {
|
||||
auto co = euc::full_coords2(c);
|
||||
co.first += 4;
|
||||
co.first &= ~15;
|
||||
co.first -= 4;
|
||||
co.second += 2;
|
||||
co.second &= ~15;
|
||||
co.second -= 2;
|
||||
if(co.first == -4 && co.second == -2) co.first = 0, co.second = 0;
|
||||
return euc::get_at(euc::to_coord(co))->c7;
|
||||
}
|
||||
case gSierpinski4:
|
||||
case gSixFlake: {
|
||||
auto co = euc::full_coords2(c);
|
||||
if(S7 == 6) co.first += 4;
|
||||
co.first -= gmod(co.first, 9);
|
||||
co.second -= gmod(co.second, 9);
|
||||
return euc::get_at(euc::to_coord(co))->c7;
|
||||
}
|
||||
case gSierpinskiTet: {
|
||||
auto co = euc::get_ispacemap()[c->master];
|
||||
co[0] &=~7;
|
||||
co[1] &=~7;
|
||||
co[2] &=~7;
|
||||
return euc::get_at(co)->c7;
|
||||
}
|
||||
case gMengerSponge: {
|
||||
auto co = euc::get_ispacemap()[c->master];
|
||||
for(int i=0; i<3; i++) co[i] = co[i] - gmod(co[i], 9);
|
||||
return euc::get_at(co)->c7;
|
||||
}
|
||||
default:
|
||||
throw hr_exception("unknown fractal");
|
||||
}
|
||||
}
|
||||
|
||||
/** create a map in the current geometry */
|
||||
EX void initcells() {
|
||||
DEBB(DF_INIT, ("initcells"));
|
||||
|
||||
|
||||
if(embedded_plane) {
|
||||
geom3::swap_direction = -1;
|
||||
check_cgi();
|
||||
for(auto& m: cgi.heptmove) swapmatrix(m);
|
||||
IPF(initcells());
|
||||
check_cgi();
|
||||
geom3::swap_direction = +1;
|
||||
for(auto& m: cgi.heptmove) swapmatrix(m);
|
||||
currentmap->on_dim_change();
|
||||
return;
|
||||
}
|
||||
|
||||
hrmap* res = callhandlers((hrmap*)nullptr, hooks_newmap);
|
||||
if(res) currentmap = res;
|
||||
#if CAP_SOLV
|
||||
else if(asonov::in()) currentmap = asonov::new_map();
|
||||
#endif
|
||||
else if(nonisotropic || hybri) currentmap = nisot::new_map();
|
||||
else if(nonisotropic || mhybrid) currentmap = nisot::new_map();
|
||||
else if(INVERSE) currentmap = gp::new_inverse();
|
||||
else if(fake::in()) currentmap = fake::new_map();
|
||||
#if CAP_CRYSTAL
|
||||
|
@ -421,6 +581,7 @@ EX void initcells() {
|
|||
else if(arcm::in()) currentmap = arcm::new_map();
|
||||
#endif
|
||||
else if(euc::in()) currentmap = euc::new_map();
|
||||
else if(hat::in()) currentmap = hat::new_map();
|
||||
#if CAP_BT
|
||||
else if(kite::in()) currentmap = kite::new_map();
|
||||
#endif
|
||||
|
@ -446,17 +607,17 @@ EX void initcells() {
|
|||
|
||||
EX void clearcell(cell *c) {
|
||||
if(!c) return;
|
||||
DEBB(DF_MEMORY, (format("c%d %p\n", c->type, hr::voidp(c))));
|
||||
DEBB(DF_MEMORY, (hr::format("c%d %p\n", c->type, hr::voidp(c))));
|
||||
for(int t=0; t<c->type; t++) if(c->move(t)) {
|
||||
DEBB(DF_MEMORY, (format("mov %p [%p] S%d\n", hr::voidp(c->move(t)), hr::voidp(c->move(t)->move(c->c.spin(t))), c->c.spin(t))));
|
||||
DEBB(DF_MEMORY, (hr::format("mov %p [%p] S%d\n", hr::voidp(c->move(t)), hr::voidp(c->move(t)->move(c->c.spin(t))), c->c.spin(t))));
|
||||
if(c->move(t)->move(c->c.spin(t)) != NULL &&
|
||||
c->move(t)->move(c->c.spin(t)) != c) {
|
||||
DEBB(DF_MEMORY | DF_ERROR, (format("cell error: type = %d %d -> %d\n", c->type, t, c->c.spin(t))));
|
||||
DEBB(DF_MEMORY | DF_ERROR, (hr::format("cell error: type = %d %d -> %d\n", c->type, t, c->c.spin(t))));
|
||||
if(worst_precision_error < 1e-3) exit(1);
|
||||
}
|
||||
c->move(t)->move(c->c.spin(t)) = NULL;
|
||||
}
|
||||
DEBB(DF_MEMORY, (format("DEL %p\n", hr::voidp(c))));
|
||||
DEBB(DF_MEMORY, (hr::format("DEL %p\n", hr::voidp(c))));
|
||||
gp::delete_mapped(c);
|
||||
destroy_cell(c);
|
||||
}
|
||||
|
@ -510,7 +671,7 @@ EX void clearfrom(heptagon *at) {
|
|||
// if(q.size() > maxq) maxq = q.size();
|
||||
q.pop();
|
||||
DEBB(DF_MEMORY, ("from %p", at));
|
||||
if(!at->c7) {
|
||||
if(!at->c7 && !ls::voronoi_structure()) {
|
||||
heptagon *h = dynamic_cast<heptagon*> ((cdata_or_heptagon*) at->cdata);
|
||||
if(h) {
|
||||
if(h->alt != at) { DEBB(DF_MEMORY | DF_ERROR, ("alt error :: h->alt = ", h->alt, " expected ", at)); }
|
||||
|
@ -586,11 +747,12 @@ EX int compdist(int dx[]) {
|
|||
|
||||
EX int celldist(cell *c) {
|
||||
if(experimental) return 0;
|
||||
if(hybri)
|
||||
if(mhybrid)
|
||||
return hybrid::celldistance(c, currentmap->gamestart());
|
||||
if(nil && !quotient) return DISTANCE_UNKNOWN;
|
||||
if(hat::in()) return clueless_celldistance(currentmap->gamestart(), c);
|
||||
if(euc::in()) return celldistance(currentmap->gamestart(), c);
|
||||
if(sphere || bt::in() || WDIM == 3 || cryst || sn::in() || kite::in() || closed_manifold) return celldistance(currentmap->gamestart(), c);
|
||||
if(sphere || bt::in() || WDIM == 3 || cryst || sn::in() || aperiodic || closed_manifold) return celldistance(currentmap->gamestart(), c);
|
||||
#if CAP_IRR
|
||||
if(IRREGULAR) return irr::celldist(c, false);
|
||||
#endif
|
||||
|
@ -610,14 +772,14 @@ EX int celldist(cell *c) {
|
|||
}
|
||||
|
||||
#if HDR
|
||||
static const int ALTDIST_BOUNDARY = 99999;
|
||||
static const int ALTDIST_UNKNOWN = 99998;
|
||||
static const int ALTDIST_ERROR = 90000;
|
||||
static constexpr int ALTDIST_BOUNDARY = 99999;
|
||||
static constexpr int ALTDIST_UNKNOWN = 99998;
|
||||
static constexpr int ALTDIST_ERROR = 90000;
|
||||
#endif
|
||||
|
||||
EX int celldistAlt(cell *c) {
|
||||
if(experimental) return 0;
|
||||
if(hybri) {
|
||||
if(mhybrid) {
|
||||
if(in_s2xe()) return hybrid::get_where(c).second;
|
||||
auto w = hybrid::get_where(c);
|
||||
int d = c->master->alt && c->master->alt->alt ? hybrid::altmap_heights[c->master->alt->alt] : 0;
|
||||
|
@ -638,7 +800,7 @@ EX int celldistAlt(cell *c) {
|
|||
}
|
||||
#if MAXMDIM >= 4
|
||||
if(euc::in()) return euc::dist_alt(c);
|
||||
if(hyperbolic && WDIM == 3 && !reg3::in_rule())
|
||||
if(hyperbolic && WDIM == 3 && !reg3::in_hrmap_rule_or_subrule())
|
||||
return reg3::altdist(c->master);
|
||||
#endif
|
||||
if(!c->master->alt) return 0;
|
||||
|
@ -676,8 +838,8 @@ EX int updir(heptagon *h) {
|
|||
if(bt::in()) return bt::updir();
|
||||
#endif
|
||||
#if MAXMDIM >= 4
|
||||
if(WDIM == 3 && reg3::in_rule()) {
|
||||
for(int i=0; i<S7; i++) if(h->move(i) && h->move(i)->distance < h->distance)
|
||||
if(WDIM == 3 && reg3::in_hrmap_rule_or_subrule()) {
|
||||
for(int i=0; i<h->type; i++) if(h->move(i) && h->move(i)->distance < h->distance)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
@ -690,7 +852,7 @@ EX int updir(heptagon *h) {
|
|||
EX int updir_alt(heptagon *h) {
|
||||
if(euclid || !h->alt) return -1;
|
||||
#if MAXMDIM >= 4
|
||||
if(WDIM == 3 && reg3::in_rule()) {
|
||||
if(WDIM == 3 && reg3::in_hrmap_rule_or_subrule()) {
|
||||
for(int i=0; i<S7; i++) if(h->move(i) && h->move(i)->alt && h->move(i)->alt->distance < h->alt->distance)
|
||||
return i;
|
||||
return -1;
|
||||
|
@ -701,12 +863,12 @@ EX int updir_alt(heptagon *h) {
|
|||
|
||||
|
||||
#if HDR
|
||||
static const int RPV_MODULO = 5;
|
||||
static const int RPV_RAND = 0;
|
||||
static const int RPV_ZEBRA = 1;
|
||||
static const int RPV_EMERALD = 2;
|
||||
static const int RPV_PALACE = 3;
|
||||
static const int RPV_CYCLE = 4;
|
||||
static constexpr int RPV_MODULO = 5;
|
||||
static constexpr int RPV_RAND = 0;
|
||||
static constexpr int RPV_ZEBRA = 1;
|
||||
static constexpr int RPV_EMERALD = 2;
|
||||
static constexpr int RPV_PALACE = 3;
|
||||
static constexpr int RPV_CYCLE = 4;
|
||||
#endif
|
||||
|
||||
// x mod 5 = pattern type
|
||||
|
@ -831,7 +993,8 @@ EX bool randpatternMajority(cell *c, int ival, int iterations) {
|
|||
cdata orig_cdata;
|
||||
|
||||
EX bool geometry_supports_cdata() {
|
||||
if(hybri) return PIU(geometry_supports_cdata());
|
||||
if(mhybrid) return PIU(geometry_supports_cdata());
|
||||
if(embedded_plane) return IPF( geometry_supports_cdata() );
|
||||
return among(geometry, gEuclid, gEuclidSquare, gNormal, gOctagon, g45, g46, g47, gBinaryTiling) || (arcm::in() && !sphere) || (currentmap && currentmap->strict_tree_rules());
|
||||
}
|
||||
|
||||
|
@ -925,7 +1088,8 @@ cdata *getHeptagonCdata_legacy(heptagon *h) {
|
|||
|
||||
|
||||
cdata *getHeptagonCdata(heptagon *h) {
|
||||
if(hybri) return PIU ( getHeptagonCdata(h) );
|
||||
if(mhybrid) return PIU ( getHeptagonCdata(h) );
|
||||
if(embedded_plane) return IPF( getHeptagonCdata(h) );
|
||||
if(geometry == gNormal && BITRUNCATED) return getHeptagonCdata_legacy(h);
|
||||
if(h->cdata) return h->cdata;
|
||||
|
||||
|
@ -1071,7 +1235,7 @@ int ld_to_int(ld x) {
|
|||
#if CAP_ARCM
|
||||
EX gp::loc pseudocoords(cell *c) {
|
||||
transmatrix T = arcm::archimedean_gmatrix[c->master].second;
|
||||
return {ld_to_int(T[0][LDIM]), ld_to_int((spin(60*degree) * T)[0][LDIM])};
|
||||
return {ld_to_int(T[0][LDIM]), ld_to_int((spin(60._deg) * T)[0][LDIM])};
|
||||
}
|
||||
|
||||
EX cdata *arcmCdata(cell *c) {
|
||||
|
@ -1090,8 +1254,9 @@ EX cdata *arcmCdata(cell *c) {
|
|||
|
||||
EX int getCdata(cell *c, int j) {
|
||||
if(fake::in()) return FPIU(getCdata(c, j));
|
||||
if(embedded_plane) return IPF(getCdata(c, j));
|
||||
if(experimental) return 0;
|
||||
if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
|
||||
if(mhybrid) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
|
||||
else if(INVERSE) {
|
||||
cell *c1 = gp::get_mapped(c);
|
||||
return UIU(getCdata(c1, j));
|
||||
|
@ -1116,8 +1281,9 @@ EX int getCdata(cell *c, int j) {
|
|||
|
||||
EX int getBits(cell *c) {
|
||||
if(fake::in()) return FPIU(getBits(c));
|
||||
if(embedded_plane) return IPF(getBits(c));
|
||||
if(experimental) return 0;
|
||||
if(hybri) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
|
||||
if(mhybrid) { c = hybrid::get_where(c).first; return PIU(getBits(c)); }
|
||||
else if(INVERSE) {
|
||||
cell *c1 = gp::get_mapped(c);
|
||||
return UIU(getBits(c1));
|
||||
|
@ -1263,9 +1429,11 @@ EX int clueless_celldistance(cell *c1, cell *c2) {
|
|||
|
||||
EX int celldistance(cell *c1, cell *c2) {
|
||||
|
||||
if(embedded_plane) return IPF(celldistance(c1, c2));
|
||||
|
||||
if(fake::in()) return FPIU(celldistance(c1, c2));
|
||||
|
||||
if(hybri) return hybrid::celldistance(c1, c2);
|
||||
if(mhybrid) return hybrid::celldistance(c1, c2);
|
||||
|
||||
#if CAP_FIELD
|
||||
if(geometry == gFieldQuotient && (PURE || BITRUNCATED)) {
|
||||
|
@ -1284,7 +1452,7 @@ EX int celldistance(cell *c1, cell *c2) {
|
|||
return euc::cyldist(euc2_coordinates(c1), euc2_coordinates(c2));
|
||||
}
|
||||
|
||||
if(arcm::in() || quotient || sn::in() || (kite::in() && euclid) || experimental || sl2 || nil || arb::in())
|
||||
if(arcm::in() || quotient || sn::in() || (aperiodic && euclid) || experimental || sl2 || nil || arb::in())
|
||||
return clueless_celldistance(c1, c2);
|
||||
|
||||
if(S3 >= OINF) return inforder::celldistance(c1, c2);
|
||||
|
@ -1301,12 +1469,15 @@ EX int celldistance(cell *c1, cell *c2) {
|
|||
if(hyperbolic && WDIM == 3) return reg3::celldistance(c1, c2);
|
||||
#endif
|
||||
|
||||
if(INVERSE) {
|
||||
/* if(INVERSE) {
|
||||
c1 = gp::get_mapped(c1);
|
||||
c2 = gp::get_mapped(c2);
|
||||
return UIU(celldistance(c1, c2)) / 2;
|
||||
/* TODO */
|
||||
}
|
||||
// that does not seem to work
|
||||
} */
|
||||
|
||||
if(euclid) return clueless_celldistance(c1, c2);
|
||||
if(INVERSE) return clueless_celldistance(c1, c2);
|
||||
|
||||
return hyperbolic_celldistance(c1, c2);
|
||||
}
|
||||
|
@ -1365,7 +1536,7 @@ EX vector<cell*> build_shortest_path(cell *c1, cell *c2) {
|
|||
}
|
||||
|
||||
EX void clearCellMemory() {
|
||||
#if MAXMDIM >= 4 && CAP_RAY
|
||||
#if CAP_PORTALS
|
||||
if(intra::in) {
|
||||
intra::erase_all_maps();
|
||||
return;
|
||||
|
@ -1415,6 +1586,7 @@ EX array<map<cell*, vector<adj_data>>, 2> adj_memo;
|
|||
|
||||
EX bool geometry_has_alt_mine_rule() {
|
||||
if(S3 >= OINF) return false;
|
||||
if(aperiodic) return true;
|
||||
if(WDIM == 2) return valence() > 3;
|
||||
if(WDIM == 3) return !among(geometry, gHoroHex, gCell5, gBitrunc3, gCell8, gECell8, gCell120, gECell120);
|
||||
return true;
|
||||
|
@ -1461,7 +1633,7 @@ EX vector<adj_data> adj_minefield_cells_full(cell *c) {
|
|||
if(hdist(h, T * h2) < 1e-6) shares = true;
|
||||
if(shares) res.emplace_back(adj_data{c1, det(T) < 0, T});
|
||||
}
|
||||
if(shares || c == c1) forCellIdEx(c2, i, c1) {
|
||||
if(shares || c == c1) forCellIdCM(c2, i, c1) {
|
||||
if(cl.listed(c2)) continue;
|
||||
cl.add(c2);
|
||||
M.push_back(T * currentmap->adj(c1, i));
|
||||
|
@ -1475,11 +1647,16 @@ EX vector<cell*> adj_minefield_cells(cell *c) {
|
|||
vector<cell*> res;
|
||||
auto ori = adj_minefield_cells_full(c);
|
||||
for(auto p: ori) res.push_back(p.c);
|
||||
if(hat::in()) {
|
||||
// reduce repetitions
|
||||
sort(res.begin(), res.end());
|
||||
res.erase(std::unique(res.begin(), res.end()), res.end());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
EX vector<int> reverse_directions(cell *c, int dir) {
|
||||
if(PURE && !(kite::in() && WDIM == 2)) return reverse_directions(c->master, dir);
|
||||
if(PURE && !(aperiodic && WDIM == 2)) return reverse_directions(c->master, dir);
|
||||
int d = c->degree();
|
||||
if(d & 1)
|
||||
return { gmod(dir + c->type/2, c->type), gmod(dir + (c->type+1)/2, c->type) };
|
||||
|
@ -1531,7 +1708,7 @@ EX vector<int> reverse_directions(heptagon *c, int dir) {
|
|||
}
|
||||
|
||||
EX bool standard_tiling() {
|
||||
return !arcm::in() && !kite::in() && !bt::in() && !arb::in() && !nonisotropic && !hybri;
|
||||
return !arcm::in() && !aperiodic && !bt::in() && !arb::in() && (WDIM == 2 || !nonisotropic) && !mhybrid;
|
||||
}
|
||||
|
||||
EX int valence() {
|
||||
|
|
635
celldrawer.cpp
635
celldrawer.cpp
File diff suppressed because it is too large
Load Diff
570
changelog.txt
570
changelog.txt
|
@ -4730,3 +4730,573 @@ Menu improvements:
|
|||
- options to show less items/kills in the portrait/landscape mode
|
||||
- an option to have menus centered even in widescreen
|
||||
- mobile fixes: fixed an incorrect button shown in the mobile game menu, and items/kills going over buttons
|
||||
|
||||
2022-07-17 14:47 Update 12.0v:
|
||||
- fixes for new Android
|
||||
- preliminary work on tree structures for 3D honeycombs
|
||||
- auto-rotation (Ivory Tower etc.) now works on devices who know their orientation
|
||||
- nicer "pipes" (fat grid lines) in 3D
|
||||
- fixed some crash bugs related to the memory saving mode
|
||||
|
||||
2022-08-07 03:03 Update 12.0w:
|
||||
- fixed a bug with 'world overview' breaking ESC menu
|
||||
- racing fixed (hopefully)
|
||||
- minor changes to HyperRogue help: now directly offered when displaying context help; do not suggest to try the Guided Tour if already in the Guided Tour
|
||||
- made the RogueViz presentations which contain no HyperRogue PC easier to control (control the camera by using the keys which usually move the PC)
|
||||
- added some more demos to RogueViz
|
||||
|
||||
2022-08-07 15:01 Update 12.0x:
|
||||
- yet another fix to racing
|
||||
- fixed a crash when deleting 3-sphere maps
|
||||
|
||||
2022-08-26 13:46 Update 12.0y:
|
||||
- new implemenatation of hyperbolic honeycombs in action
|
||||
- field quotients in 3D now finds more honeycombs
|
||||
- variations now work for Euclidean cube tiling
|
||||
- tessellation, texture, etc. files can now be found via HYPERPATH
|
||||
- fixed the Slaying+side attack combo
|
||||
- Pearls now use the Disk graphics
|
||||
- Added some land incompatibilities
|
||||
- updates to French translation
|
||||
- fixes to stereographic projection (as a way to get high FOV)
|
||||
|
||||
2022-09-06 14:20 Update 12.0z:
|
||||
- various fixes related to 'orb used' rollback
|
||||
- fixed Sol geometry (a bug caused the map to change incorrectly when moving)
|
||||
- fixed variations of hyperbolic honeycombs (when a ruleset was available only for the pure honeycomb, loading it would reset variation to pure)
|
||||
|
||||
2022-09-15 12:40 Update 12.1:
|
||||
- documentation for TES files added
|
||||
- an option to select the savefile on startup (settings -> other settings)
|
||||
- fixed missing 'too far' messages on Frog-like orbs
|
||||
- fixed Teleport and Illusion draining Aether etc on mousing (disregarding Time)
|
||||
- fixed a crash problem with tes files in 2.5D
|
||||
- fixed a possible crash in raytracer
|
||||
- when tes files are loaded, football-colorability is now detected (and used to improve the graphics and gameplay)
|
||||
- GPU glitches when rendering long bands should be no more
|
||||
- fixed the loading of tessellations/affine/affine-square.tes
|
||||
- fixed the crash on converting regular/Archimedean tilings to tes format and generating tree rules
|
||||
- improvements to line patterns
|
||||
- fixed a possible crash when saving images
|
||||
|
||||
2022-09-17 12:12 Update 12.1a:
|
||||
- fixed Orb of Teleport/Illusion thinking that they are unusable
|
||||
- Orb of Earth no longer marked useless in Wetland
|
||||
- some fixes for the treasure/kill list: fixed the Onyx graphics; made some icons larger; dark stuff have their text brightened (or use the auxiliary orb color)
|
||||
- the monster movement order is more random now (no preference for clockwise)
|
||||
|
||||
2022-10-06 13:13 Update 12.1b:
|
||||
- Orb icons thanks to Jacob Mandelson. (Can be disabled in general settings)
|
||||
- hostile dice are highlighted
|
||||
- racing mode fixes: the menu shows whether an official track is on; the settings are set correctly, and land structure is ignored for the achievement
|
||||
- Orb of Choice now works with Orb of Safety
|
||||
- an option to arbitrarily change the width of tile boundaries (in 'patterns' menu)
|
||||
- the option to debug tile/edge/vertexs IDs in the 'experiments with geometry' menu (if a tes file is on, but it works in general)
|
||||
- tes format now supports declaring a tile as having a mirror symmetry
|
||||
- tile-type display now displays mirror images as the same color (or slightly different colors, depending on settings)
|
||||
- tile-type display no longer assigns different colors depending on football type
|
||||
- when editing color tables, it is now possible to add more colors
|
||||
- Crystal World and Snake Nest were legal in some tilings but they did not actually appear -- should be fixed
|
||||
- vertical strafe in walkingmode no longer brings eye level below 0
|
||||
|
||||
2022-10-08 02:14 Update 12.1c:
|
||||
- some improvements to tes file support. Mirrored tiles should now work for apeirogons. Valence check and thus football colorability should now work with affine/star tessellations.
|
||||
- also included more tes samples
|
||||
|
||||
2022-10-27 15:53 Update 12.1d:
|
||||
- Various menus displaying lists now use a nicer list widget (including the file dialog and map editor selection).
|
||||
- Map editor improvements:
|
||||
- - "building mode", which allows Minecraft-style building in 3D geometries
|
||||
- - shift-clicking in the map editor now deletes stuff
|
||||
- - improvements to portal spaces, including easier creation (convert to portal space from the map editor -> settings, then you can add new worlds from save files)
|
||||
- improvements to SL(2,R) and similar:
|
||||
- - nonisotropic range parameters now work in all perspective modes
|
||||
- - Panini in all perspective modes
|
||||
- - more projections possible for SL(2,R)
|
||||
- - fixed the 'penrose staircases' on wall blocks in rotation spaces
|
||||
- 'load from file' appears directly in the geometry menu in 'experiments with geometry'
|
||||
- achievements disabled in ineligible starting lands
|
||||
- limit on pauses in the racing mode
|
||||
- fixed the ogg files
|
||||
|
||||
2022-11-04 23:58 Update 12.1e:
|
||||
- fixed some bugs with editing portal spaces
|
||||
- some fixes in help text
|
||||
- page buttons in PTM are back
|
||||
- layout in Yendor should be improved
|
||||
- fixed buggy generation when setting Elemental Wall as cheat destination
|
||||
- file dialog improvements (more options, automatically set position, search mode)
|
||||
- fixes to the shmup mode:
|
||||
- - Gadflies no longer appear forever with high Spinel counts
|
||||
- - pause count is no longer displayed in non-racing; also reset to 0
|
||||
- - fixed pink tortoises appearing in Galápagos
|
||||
- - Bulls now correctly destroy walls they crash into
|
||||
- - fixed wrong time used in some places (running time instead of game time)
|
||||
- - fixed the Flail Guards
|
||||
|
||||
2022-12-09 02:38 Update 12.1f:
|
||||
|
||||
- WIP: In '3d settings' menu for 2D maps, you can now select the way how the 2D map will be embedded into a 3D space (space of the same curvature as flat/concave/convex eequidistant, space of lower curvature, product space).
|
||||
The basic functionality should work, but there are probably some bugs and lots of missing features (to do: shmup, raycasting, fog, radar, more intuitive menu, better default settings, embedding into nonisotropic geometries).
|
||||
On the way also some bugs with 2.5D should be fixed ("draw sky" disabled now also disables Euclidean sky; correct movement if the surface the camera moves on is not flat; fixed sky colors; fixed the radar transform computation in 2.5D which also affected fog rendering).
|
||||
- fixed: inventory glyphs were missing outlines due to a bug
|
||||
- improved the display in OSM when using orb icons
|
||||
- Give the Plane of Fire a redder floor than CR4 (thanks to jlm)
|
||||
- Draw mimics with sword in left hand if PC's sword in left hand (thanks to jlm)
|
||||
|
||||
2022-12-18 00:59 Update 12.1g:
|
||||
|
||||
Further improvements to the "3D style" (embed 2D in a 3D geometry) feature:
|
||||
- more intuitive settings
|
||||
- kite-and-dart and tes should now work correctly
|
||||
- Lower and Much Lower curvature settings are now respected even if it was already hyperbolic
|
||||
- pure regular Euclidean hex/square tilings can now be embedded in Nil and Sol/NIH
|
||||
- binary tiling and similar can now be embedded in Nil and Sol/NIH
|
||||
- shmup should work now
|
||||
- fixed sky over irregular map
|
||||
- fixed slime size
|
||||
|
||||
There are still some bugs to fix, but it should mostly work now. And there are more embeddings coming :)
|
||||
|
||||
Other bugfixes:
|
||||
- fixed coloring of info items
|
||||
- fixed centering on reset
|
||||
- disabling geodesic movement in Sol/Nil now also assumes that light moves along Lie lines, and shmup monsters move correctly too
|
||||
- fixed grid drawing for binary variants
|
||||
|
||||
|
||||
2023-01-08 00:59 Update 12.1h:
|
||||
|
||||
Bug fixes:
|
||||
- fixed context help getting stuck in corner stats mode
|
||||
- fixed Princess AI using boat
|
||||
- shallow water is no longer glitched when the 3D settings are illegal
|
||||
|
||||
Further improvements to the "3D style" (embed 2D in a 3D geometry) feature:
|
||||
- four new embeddings of Euclidean space: Clifford torus (S3), product space (H2xR, S2xR), and SL2
|
||||
- Hypersian Rug options are now linked in 3D settings
|
||||
- fixed movement animations
|
||||
- better diagnostics when an embedding does not work
|
||||
- fixed a bug rendering band model without shader
|
||||
|
||||
2023-02-05 11:27 Update 12.1i:
|
||||
|
||||
Further improvements to the "3D style" (embed 2D in a 3D geometry) feature:
|
||||
- Overall better design fixes various small errors, including nicer floor shapes, radar, shmup, and 3D models.
|
||||
- Six new embeddings of the Euclidean cylinder.
|
||||
- Hints how to change settings if the current embedding does not work.
|
||||
- some crashes have been fixed (in Zebra/ Reptiles, thanks to Masala for the report; also crashes related to possible missing shadow models)
|
||||
|
||||
Also fixed a bug generating Dice in some tessellations.
|
||||
|
||||
2023-02-22 00:31 Update 12.1j:
|
||||
|
||||
Further fixes and improvements to the "3d style" (embed 2D in a 3D geometry) feature:
|
||||
- more settings (regarding altitudes) are now configurable
|
||||
- fixed VR (correct gravity alignment and eye position computation), also added new headset setting "holonomy Z" for embedded planes (also fixed a bug causing spinning in VR)
|
||||
- fixed some minor bugs with "same curvature" and "product" embeddings
|
||||
- fixed "SL(2,R) cylinder" (it was not actually implemented)
|
||||
- full floors now used by default (also floor shape setting has other options now)
|
||||
- when you change the settings, the engine now tries to keep as much as possible (e.g., remap the camera position)
|
||||
- no shadow option now disables monster shadows
|
||||
- fixed a bug with Goldberg embeddings
|
||||
|
||||
Other fixes:
|
||||
- fixed key conflict for the cell boundaries option
|
||||
- fixed an error computing distances in bitruncated {5,4} causing crashes
|
||||
- when you die in the racing mode, you just die without obtaining etherality (possible when you change the land e.g. to Rose Garden or Land of Storms)
|
||||
- fixed single tile pattern for texture mode in spherical geometry; also changing the pattern in texture mode no longer affects map editor pattern
|
||||
|
||||
2023-03-23 09:34 Update 12.1k:
|
||||
Aperiodic tilings:
|
||||
- "Aperiodic Hat" tiling [ https://arxiv.org/pdf/2303.10798.pdf ]
|
||||
- adjacency rule (for Minefield) now changeable in aperiodic tilings
|
||||
- patched chaos now works in aperiodic tilings
|
||||
- nicer tile borders in aperiodic tilings
|
||||
|
||||
New projections:
|
||||
- nicer Conformal Square projection (with transition and shader, and all 2D geometries)
|
||||
- horocyclic equal-area projection
|
||||
- change axe angle in axial-like projections
|
||||
|
||||
Line patterns:
|
||||
- more configuration for meridian/parallel patterns
|
||||
- new linepattern "tessellation walls"
|
||||
|
||||
Other:
|
||||
- better fog color in 3D ball model
|
||||
|
||||
2023-03-25 09:28 Update 12.1l:
|
||||
Improvements to the "aperiodic hat":
|
||||
- better centering
|
||||
- fixed a bug creating bad tiles
|
||||
- "hat parameter" transforms continuously (as in Section 6 of https://arxiv.org/pdf/2303.10798.pdf)
|
||||
- better pseudo-heptagon assignment (for Graveyard/RRV/etc)
|
||||
- improved Jungle, Land of Storms, Palace
|
||||
- "fake curvature" works with hat now
|
||||
|
||||
Other fixes:
|
||||
- do not display relativistic modes in model list
|
||||
- an option to not display default help (in "basic interface")
|
||||
|
||||
2023-03-26 09:41 Update 12.1m:
|
||||
- Fixed some crashes when changing the hat parameter, embedding hat, while embedding tessellation from file, using hat with fake geometry. Also fake geometry now appears in the menu for hat.
|
||||
|
||||
2023-03-28 22:58 Update 12.1n:
|
||||
- Aperiodic Hat fixes:
|
||||
- - fixed Frog Park (jump rules and graphics)
|
||||
- - fixed the Terracotta display (lines displayed, but they are not accurate, so cells are marked too)
|
||||
- - interesting values of the hat parameter are displayed in hat parameter config
|
||||
- - special welcome message
|
||||
|
||||
- fixed crashes and floor graphics in Zebra in some geometries (hat, kite-and-dart)
|
||||
- Swap the Red Troll's hair & fur colors (thanks to @jlmjlm)
|
||||
- Experimental fractal geometries (experiment with geometry -> Euclidean)
|
||||
- fixed Terracotta in Euclidean disk
|
||||
|
||||
2023-03-29 09:10 Update 12.1o:
|
||||
- fixed the orientation in the hat tiling
|
||||
- fixed bugs when regenerating a map in the hat tiling + embedding
|
||||
- fixed variation not showing in some geometries
|
||||
|
||||
2023-05-19 01:15 Update 12.1p:
|
||||
Mostly embedding-related improvements:
|
||||
- embedding scale parameter now works in "lower curvature" (horospher) embedding (redundant, but useful)
|
||||
- better wall shading in EuclidSquare embeddings
|
||||
- many embedding-related fixes
|
||||
- "Non-Euclidean Third Dimension" demo (of embeddings) in RogueViz
|
||||
(also, the "imaginary" hat parameter)
|
||||
|
||||
2023-05-31 02:18 Update 12.1q:
|
||||
- Aperiodic Spectre tiling [https://arxiv.org/abs/2305.17743]
|
||||
- fixed embeddings of Archimedean tilings
|
||||
- Berger sphere should now work correctly with subdivided cells
|
||||
- new options mostly for 3D visualizations: circumscribed pseudohedra (a new option in 'make the tiles flat' in 3D config), use plain non-textured floors with alpha transparency (not in menus, find setting 'draw_plain_floors' and 'floor_alpha'); 'big triangular grid' line pattern should now work in Euclidean "Goldberg"
|
||||
|
||||
2023-07-21 09:32 Update 12.1r -- mostly minor bugfixes:
|
||||
- fixed a bug with apeirogonal tiles
|
||||
- fixed some bugs with the "ball projection" of anisotropic geometries
|
||||
- fixed stereo_alpha in some geometries
|
||||
- fixed the combinations of Archimedean, fake, and embedding
|
||||
- "pipes" (fat grid lines) for anisotropic geometries
|
||||
|
||||
2023-08-16 09:32 Update 12.1s
|
||||
- Most angles are now specified using a special dialog (rather than degrees, or a bunch of degree values in the 3D case). This is more powerful (more intuitive in 3D cases; 3D rotations like 'camera angle' and '3D model rotation' became 3D).
|
||||
- Fixes to how hyperboloid/hemisphere/ball models are rendered
|
||||
- Minor improvements to the number dialogs (immediately visible effects, etc.) and parameter (animation formulas allowed in more places)
|
||||
- Fixed centering in multiplayer
|
||||
- Fixed a bug which caused the screen to disappear on switch-to-fpp
|
||||
- Fixed the movement in Nil geometry
|
||||
- Fixed a crash when changing sight range while in rug
|
||||
|
||||
2023-09-15 07:48 Update 12.1t
|
||||
- fixed a crash on projection changing
|
||||
- two new land structure options: horodisk and ideal Voronoi
|
||||
|
||||
2023-09-19 08:01 Update 12.1u
|
||||
Fixes to the Horodisk/ideal Voronoi land structures:
|
||||
- horodisk mode now has a parameter controlling perfection vs density, and is set by default to generate less dense but perfect horocycles
|
||||
- Ivory Tower, Hive, and Galápagos join the H/V modes (also getting some interesting modifications from standard)
|
||||
- fixed some lands (Ocean/Lost Memory/Space Rocks/Eclectic) spilling when restarted in Safety in h/v mode
|
||||
- fixed a part of generation not being executed, or being executed for the starting land rather than the actual land, in some lands (e.g. Krakens not appearing)
|
||||
- more careful land incompatibility handling in voronoi
|
||||
|
||||
2023-09-22 13:00 Update 12.1v
|
||||
- fixed land generation becoming glitched in standard modes when Lost Mountain or Clearing becomes unlocked
|
||||
- fixed some lands not appearing in horodisk (Caribbean, Kraken, Whirlpool, Rlyeh, Temple, Haunted)
|
||||
- fixed roses and dragons not appearing in h/v
|
||||
- horocyclic variants of Warped Coast and Elemental Plains
|
||||
- the "random walk" land structure now has a parameter controlling the land size
|
||||
|
||||
2023-10-05 14:12 Update 12.1w:
|
||||
- reverted the unintentional change which caused holes to appear in the platforms on Ivory Tower
|
||||
- fixed model color not taken into account in sphere stereographic projection
|
||||
- Prairie joins the horodisk land structure
|
||||
- fixed Hives missing in ideal Voronoi land structure
|
||||
- fixed some tiles pre-marked as mines in Minefield next to Ivory Tower in Voronoi land structure
|
||||
- fixed burial mounds not appearing in chaos/h/v land structures
|
||||
|
||||
2023-10-29 09:13 Update 12.1x:
|
||||
- a new alternative mode where the Rogue fights with a crossbow. Currently testing, so no achievements yet.
|
||||
- friendly ghosts are now flagged as non-living (thanks to @jlm)
|
||||
|
||||
2023-10-30 10:16 Update 12.1y:
|
||||
Updates to the crossbow mode:
|
||||
- no time passes when shooting while unstable
|
||||
- graves, shrubs, and Round Table no longer block the line of fire (but shooting through half-vines do)
|
||||
- fixed the 3D graphics
|
||||
- fixed some bugs with fire mode not disabling correctly
|
||||
- crossbows mimics no longer attack in melee, and it is also no longer possible to swing at mirrors with crossbow
|
||||
- crossbow moves are no longer considered valid moves for the checkmate rule when the crossbow is not loaded
|
||||
- improved messages
|
||||
- in fire mode, no longer display ranged orb icons on mousing
|
||||
- crossbow now shoots the targets in the logical order
|
||||
- fire mode now can be enabled even while reloading, for more consistency and examination
|
||||
- clarify that the Water Elemental special case only affects melee
|
||||
- fixed the bug which made the crossbow not pierce dragons
|
||||
- fixed the bug which made saving tortoises not possible
|
||||
- attacking guarding dogs now wakes up all other existing guarding dogs, and causes a small ambush (this fix also affects other ranged attacks)
|
||||
- fixed crossbow mode not changing the PTM/etc. scoreboards
|
||||
- mode change confirmation is now only required when actually changing a relevant option
|
||||
- new aim style 'geometric'
|
||||
|
||||
2023-12-02 12:54 Update 12.1z:
|
||||
Gameplay (mostly crossbow modes)
|
||||
- an option to automatically shoot when clicking a tile with mouse
|
||||
- press 'f' + direction for auto fire at distant enemies in the given direction
|
||||
- bulls are now enraged by crossbow shots
|
||||
- ratlings no longer move when shooting pointlessly
|
||||
- the warped space distracts you from reloading while staying in place
|
||||
- Warped Coast/Sea now prevents crossbow bolts from moving between triangles
|
||||
- clarified that only direct melee attacks trigger Storms/Flash
|
||||
- fixed Horns in the crossbow mode; the unarmed Princess is now also able to use Empathy+Thorns and Empathy+Horns
|
||||
- reduced CR3 land requirement to 20 in casual
|
||||
|
||||
Other
|
||||
- fixed the drawing mode on quotient spaces (including torus display)
|
||||
- fixed point recognition in rug mode
|
||||
- cleaned up high-FOV and stereo modes into one setting
|
||||
|
||||
2023-12-27 12:54 Update 13.0:
|
||||
|
||||
Summary post: https://zenorogue.blogspot.com/2023/12/hyperrogue-130.html
|
||||
|
||||
Voronoi mode fixes:
|
||||
- fixed Caribbean
|
||||
- made Rlyeh and Temple appear, and Haunted and Free Fall are now unavailable
|
||||
- better land compatibility
|
||||
- fixed CR2
|
||||
- fixed Land of Storms (in Horodisk and Voronoi)
|
||||
|
||||
Crossbow fixes:
|
||||
- in shmup, crossbow bolts now pierce multi-tile monsters, and fire-on-mouse is disabled
|
||||
- remove crossbow paths on orb use
|
||||
- pressing ESC key while in fire mode now disables the fire mode
|
||||
- geometric crossbow can now hit monsters on the edge of vision and inside walls
|
||||
- crossbow achievements and leaderboards
|
||||
- fixed false game over messages after shooting a bow
|
||||
|
||||
other updates:
|
||||
- updated the Czech and Polish translations
|
||||
- display achievement eligiblity
|
||||
- make the Key fireproof; make tortoise if first 21/21 tile created in > 100 turns (thanks to jlm)
|
||||
|
||||
Other fixes:
|
||||
- fixed restoring golems in casual mode
|
||||
- fixed a crash while loading races
|
||||
- fixed a bug with embedded maps (i.e., 2D maps in 3D) being destroyed when the game is restarted
|
||||
- fixed the drawing of half-vines and mirror walls in spatial
|
||||
- fixed the bug where tides may move on orb use
|
||||
- fixed Sol, NIH and SolN embeddings being always displayed as legal
|
||||
- fixed the name displayed on mouseover for slime
|
||||
|
||||
2024-01-12 08:59 Update 13.0a:
|
||||
|
||||
- fixed some bugs with high-FOV modes (reset shaders, show upper FOV ranges correctly, buggy two-eye rendering)
|
||||
- as a new positive, the Curse of Fatigue makes you not care about roses when very fatigued
|
||||
- changed one Prince(ss) message
|
||||
- crossbow leaderboards should be fixed
|
||||
- fixed button placement on Android once more
|
||||
- fixed mirrors in crossbow fire mode
|
||||
- the bump-to-shoot flag now actually works
|
||||
- fixed a bug in "memory saving" mode to not remove the current altmap
|
||||
- variant fisheye projection
|
||||
- fixed tides in shmup and when scrolling
|
||||
- the dipping rule no longer affects Tiger's Eyes
|
||||
- screenshots were sometimes not correctly centered
|
||||
|
||||
2024-02-23 01:34 Update 13.0b:
|
||||
|
||||
When you are checkmated or die, a message explaining the cause is now displayed in the quit screen and saved in the local score file.
|
||||
|
||||
Crossbow fixes:
|
||||
- opening inventory mode when you can just shoot should be fixed
|
||||
- rusałka curses now work
|
||||
- fixed tricking Pikemen with a bow
|
||||
- while rosed, you can now only shoot when this kills a monster at point blank in the rose direction
|
||||
|
||||
Crash fixes:
|
||||
- fixed crash when e.g. entering 'ma' as a value, or when editing some settings such as sight range bonus
|
||||
- fixed a crash when viewing help on tide tiles (thanks to jlm)
|
||||
- fixed a crash with too large band
|
||||
- fixed some cases where untruncated/unrectified/warped maps would freeze when computing distances or crash due to trees are not known
|
||||
|
||||
Gameplay fixes:
|
||||
- restarting a race now resets pause counter
|
||||
- World Turtle kills are recorded (thanks to jlm)
|
||||
- boat can go thru non-adjacent using Orb of Warp in shmup
|
||||
- fixed the items (key, OoY, baby tortoise) moved by the Orb of Chaos and Curse of Repulsion
|
||||
- fixed the Yard bug (graveless graveyard when you somehow used Orb of Safety in the Haunted Woods strip)
|
||||
- Trollheim no longer generates adjacent non-unlocked troll lands
|
||||
- alternative land unlock rules when monster/item requested is not available due to geometry etc
|
||||
|
||||
Other:
|
||||
- in Goldberg variation, x/y limit is now based on what the engine allows, and 'dual of current' no longer can circumvent the limits
|
||||
- New projection: polar coordinates
|
||||
|
||||
2024-02-24 09:54 Update 13.0c:
|
||||
|
||||
- fixed the off-by-one error in thehelp line displayed for tides and lava
|
||||
- fixed a bug with rusalka-cursing the first tile when you shoot
|
||||
- when you press ESC in the gameover screen, the YASC message is displayed
|
||||
- special YASC message for pinches, and being on the Round Table
|
||||
- in YASC messages, mention the knights blocking the way, and also mention their names
|
||||
|
||||
2024-03-24 11:32 Update 13.0d:
|
||||
|
||||
System:
|
||||
* itch.io Windows binaries and Steam Windows/Linux binaries now use SDL2 instead of SDL1.2
|
||||
|
||||
Custom mode:
|
||||
* A new mode where you can select the lands to be used.
|
||||
* Another menu can be used to save a mode to a file.
|
||||
* Enabling Halloween or Space Rocks in infinite geometries now produces something that makes sense.
|
||||
* Previously changing the creature scale was disabled in non-cheat shmup. Now it can be changed (but it counts as a cheat).
|
||||
* New land structure 'landscape'.
|
||||
|
||||
Graphics:
|
||||
* Font scale used in ASCII maps now can be changed.
|
||||
* Items moved by Orb of Water, Magnetism, Winter, Space, and Repulsion are now animated.
|
||||
* VR: fixed items, Ivy, compasses, etc. being placed incorrectly in 2.5D.
|
||||
* VR: compass/Yendor targets now should be displayed.
|
||||
|
||||
Gameplay:
|
||||
* Void Beasts are now pulled by Orb of Air.
|
||||
* Changed the electrical properties of some walls to make Eclectic City more friendly.
|
||||
* Trees etc are now mentioned as blockers in YASC messages.
|
||||
* YASC codes work better if killed on a 10+ tile.
|
||||
|
||||
Alternate geometries:
|
||||
* Clear more walls when generating Wild West in high GP.
|
||||
* Better Emerald in Octagon chamfered.
|
||||
* Fixed Emerald Mine and Vineyard generating very bad in {n,oo} and binary tiling.
|
||||
* Fixed the lack of non-trapdoors in Zebra 435.
|
||||
* Better 'pseudohept' tiles in INVERSE tilings.
|
||||
* In grid mode, don't try to draw greatwall lines outside of normal geometry pure/bitruncated.
|
||||
* Nicer cell boundaries used in Archimedean and irregular tilings.
|
||||
* When you save an irregular map using Orb of Safety or map editor (or custom mode), it should now save the irregular map used.
|
||||
|
||||
Bug fixes:
|
||||
* Fixed dice hints over different heights.
|
||||
* Fixed troll nests in Horodisk/Voronoi.
|
||||
* Fixed a crash when running away from Clearing in single-land mode.
|
||||
* Some values are tracked in savefiles while previously they did not (fatigue, snake oil, crossbow reload time, gun ammo, etc.) (Thanks to jlm)
|
||||
|
||||
2024-03-24 20:10 Update 13.0e:
|
||||
|
||||
* in Steam, option `-achievement-always` to always display achievements, even if you already got them.
|
||||
* rosebushes now show up on the radar in 3D geometries, and they now blink if they are close to going off
|
||||
* if you are in water (and have no Fish), you can now see Orbs of Fish and Aether in adjacent water tiles, and also you can move there and pick them up
|
||||
* crossbow bolt now ignore rose restrictions on attack
|
||||
* migrating to SDL2 caused crashes in shmup, with the game_keys_scroll option, and with the shift-target option -- this should be fixed
|
||||
* 'custom' land list mode is now mentioned in the watermark (bottom left of the screen)
|
||||
|
||||
2024-03-27 23:47 Update 13.0f:
|
||||
|
||||
* new messages on Orb of Phasing, Slaying, and Weakness
|
||||
* more accurate messages on dice pushing
|
||||
* when loading save, load full mode data including custom lands
|
||||
* irregular maps no longer change on every load due to floating point precision
|
||||
* [custom lands list] Space Rock monsters now drop treasure only if in Space Rock land
|
||||
* ineligible starting land also if land is not in game
|
||||
* [custom lands list] do not freeze if no new sealand is available
|
||||
* in countHyperstones, two variants of Mirror are counted once
|
||||
* specially generated lands (horocycles, Brown Islands) now respect Unlocked and LandIngame rules
|
||||
* fixed some more crashes related to SDL2 (e.g., right-click in shmup)
|
||||
|
||||
2024-04-09 02:46 Update 13.0g:
|
||||
|
||||
- New land structures: CR2-like, CR3-like, and "cursed"
|
||||
- Space Rocks and Halloween stuff are now saved correctly (thanks to jlm)
|
||||
- since the Aether users now see adjacent items in water, they can also pick them up
|
||||
- fixed the bug where moving a boat with Compass would cause items to be picked up
|
||||
- pushing an exploding barrel on a mine now causes an explosion
|
||||
- fixed pressing numpad keys with numpad on acting both as moves and quick-keys
|
||||
- a new pseudoheptagon pattern in standard binary and ternary tiling
|
||||
- fixed the Free Fall being not inaccessible from some lands
|
||||
- auto-pause shmup game when it loses focus
|
||||
- fixed some possible crashes: with keys being generated on ivy, when using Orb of Space on Orb of Safety, Ocean in the chaos modes, after killing 400 mutants, when generating YASC message
|
||||
|
||||
2024-05-09 10:45 Update 13.0h
|
||||
|
||||
- Orb of Summoning now works on deep water, shallow water, and Camelot moat tiles
|
||||
- more settings for minefield graphics
|
||||
- removed Haunted and Elemental from the landscape mode
|
||||
- stone gargoyles and statues are now non-blocking for missiles
|
||||
- Orb of Earth now cancels Invisibility only if it is doing something
|
||||
- new line pattern 'wall highlight', and also line patterns are now easier to reach (via creative mode)
|
||||
- fixed the Yendor beacon to appear in the correct place (usually on the boundary, not the closest visible tile)
|
||||
|
||||
Minor bug fixes:
|
||||
- some leaderboards still activated when custom_land_list was used
|
||||
- fixed CR3 generated in CR2 layout
|
||||
- fixed CR2 generated in CR3/CR4 layouts
|
||||
- fixed single wrong tile of the first land when safetying in landscape etc
|
||||
- fixed 534 distance computation
|
||||
- fixed CLI -picload
|
||||
- clear boats from removed Orbs of Water
|
||||
- fixed a crash setting landscape_div to 0
|
||||
- fixed a crash with irregular spherical maps
|
||||
- show weapon watermark with geometric xbow (thanks to @jlm)
|
||||
|
||||
2024-05-10 19:36 Update 13.0i
|
||||
|
||||
- reverted numlock fix on MAC since it apparently does not work as expected
|
||||
- right shift no longer assumes mouse-strafe if no mouse moved
|
||||
- fixed the "display zeros in minefield" option
|
||||
- fixed crashes when adding/deleting colors
|
||||
- rosewaves no longer go through the fake cells in Crystal World
|
||||
- changed the guarding in Power landscape
|
||||
- display Compass and Orb of Yendor beacon on radar
|
||||
- fixed some problems with tides (thanks to jlm)
|
||||
|
||||
2024-05-28 19:35 Update 13.0j
|
||||
|
||||
- display charge count for all orbs, and activation costs for frog-like orbs
|
||||
- "(v) menu" can now be replaced to show turn count or another parameter/formula
|
||||
- Orb of Luck now removes the blue bug bias
|
||||
- fixed the shape pattern for converted tilings
|
||||
- fixed a bug in the tessellation converter
|
||||
- the game spent 5s on startup initializing SDL joysticks -- this now can be avoided
|
||||
- chainspilling lava slimes
|
||||
- more explanation is now available for ON/OFF parameters
|
||||
- fixed product rendering
|
||||
- fixed model orientation for spiral
|
||||
- fixed a crash when changing the 'race angle' setting
|
||||
- fixed a possible crash when trying to build CR2 or CR5 next to CR4
|
||||
|
||||
Changes to the parameter/formula system:
|
||||
- more values and functions are now available in formulas (including the new color formulas, including the 'formula' canvas pattern)
|
||||
|
||||
2024-05-28 20:21 Update 13.0k
|
||||
|
||||
- fixed orb change display
|
||||
- fixed backward incompatible color reading from config
|
||||
- fixed symbol changed enable archimedean unexpectedly
|
||||
|
||||
2024-05-29 13:54 Update 13.0l
|
||||
|
||||
- fixed some more errors with the config file
|
||||
- show charges for Orb of Air, also fixed the line for Orb Energy
|
||||
- fixed some characters not being enterable in SDL2
|
||||
|
||||
2024-06-06 19:06 Update 13.0n
|
||||
|
||||
Bugfixes:
|
||||
- (v13.0m) fixed a bug with smart range
|
||||
- (v13.0m) partially fixed a bug with non-enterable characters in string edit in SDL2 (Windows)
|
||||
- fixed some bugs with not recognizing modes from earlier versions (for saved score purposes)
|
||||
- fixed land search in Overview
|
||||
- fixed a problem when loading saved maps from tes files
|
||||
- YASC code explanation now appears when it should (not when it should not)
|
||||
|
||||
Gameplay:
|
||||
- boats now erase rose waves when moved
|
||||
- illegal moves into dice now become kills if you have an Orb of Slaying
|
||||
- in Chaos mode, crossroads now appear if Hyperstones are unlocked (thanks to jlm)
|
||||
|
||||
Modes:
|
||||
- improved custom mode manager: it now displays all the modes you have tried (with PTM/YC/saved scores), and also you can name modes
|
||||
|
||||
2024-06-06 19:06 Update 13.0o
|
||||
Fixed a crash on load.
|
||||
|
|
182
checkmove.cpp
182
checkmove.cpp
|
@ -27,29 +27,49 @@ EX bool canmove = true;
|
|||
|
||||
// how many monsters are near
|
||||
EX eMonster who_kills_me;
|
||||
EX cell *who_kills_me_cell;
|
||||
|
||||
EX int lastkills;
|
||||
|
||||
EX vector<bool> legalmoves;
|
||||
|
||||
/* why is a move illegal */
|
||||
EX vector<int> move_issues;
|
||||
|
||||
#if HDR
|
||||
static const int miVALID = 10000;
|
||||
static const int miENTITY = 11000;
|
||||
static const int miRESTRICTED = 10100;
|
||||
static const int miTHREAT = 10010;
|
||||
static const int miWALL = 10001;
|
||||
struct moveissue {
|
||||
int type;
|
||||
int subtype;
|
||||
eMonster monster;
|
||||
cell *where;
|
||||
};
|
||||
|
||||
static constexpr int miVALID = 10000;
|
||||
static constexpr int miENTITY = 11000;
|
||||
static constexpr int miRESTRICTED = 10100;
|
||||
static constexpr int miTHREAT = 10010;
|
||||
static constexpr int miWALL = 10001;
|
||||
|
||||
static constexpr int siWALL = 1;
|
||||
static constexpr int siMONSTER = 2;
|
||||
static constexpr int siGRAVITY = 3;
|
||||
static constexpr int siROSE = 4;
|
||||
static constexpr int siITEM = 5;
|
||||
static constexpr int siWIND = 6;
|
||||
static constexpr int siCURRENT = 7;
|
||||
static constexpr int siFATIGUE = 8;
|
||||
static constexpr int siWARP = 9;
|
||||
static constexpr int siUNKNOWN = 10;
|
||||
#endif
|
||||
|
||||
EX int checked_move_issue;
|
||||
/* why is a move illegal */
|
||||
EX vector<moveissue> move_issues;
|
||||
|
||||
EX moveissue checked_move_issue;
|
||||
EX moveissue stay_issue;
|
||||
EX int yasc_code;
|
||||
|
||||
EX void check_if_monster() {
|
||||
eMonster m = cwt.peek()->monst;
|
||||
if(m && m != passive_switch && !isFriendly(m))
|
||||
checked_move_issue = miENTITY;
|
||||
checked_move_issue = moveissue { miENTITY, siMONSTER, m, cwt.peek() };
|
||||
}
|
||||
|
||||
EX bool hasSafeOrb(cell *c) {
|
||||
|
@ -108,14 +128,14 @@ EX bool monstersnear(cell *c, eMonster who) {
|
|||
bool kraken_will_destroy_boat = false;
|
||||
|
||||
elec::builder b;
|
||||
if(elec::affected(c)) { who_kills_me = moLightningBolt; res++; }
|
||||
if(elec::affected(c)) { who_kills_me = moLightningBolt; who_kills_me_cell = nullptr; res++; }
|
||||
|
||||
if(c->wall == waArrowTrap && c->wparam == 2) {
|
||||
who_kills_me = moArrowTrap; res++;
|
||||
who_kills_me = moArrowTrap; who_kills_me_cell = nullptr; res++;
|
||||
}
|
||||
|
||||
for(auto c1: crush_now) if(c == c1) {
|
||||
who_kills_me = moCrusher; res++;
|
||||
who_kills_me = moCrusher; who_kills_me_cell = nullptr; res++;
|
||||
}
|
||||
|
||||
if(who == moPlayer || items[itOrbEmpathy]) {
|
||||
|
@ -126,7 +146,7 @@ EX bool monstersnear(cell *c, eMonster who) {
|
|||
if(havewhat&HF_OUTLAW) {
|
||||
for(cell *c1: gun_targets(c))
|
||||
if(c1->monst == moOutlaw && !c1->stuntime) {
|
||||
res++; who_kills_me = moOutlaw;
|
||||
res++; who_kills_me = moOutlaw; who_kills_me_cell = c1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,13 +177,11 @@ EX bool monstersnear(cell *c, eMonster who) {
|
|||
}
|
||||
// flashwitches cannot attack if it would kill another enemy
|
||||
if(c3->monst == moWitchFlash && flashWouldKill(c3, 0)) continue;
|
||||
res++, who_kills_me = c3->monst;
|
||||
res++, who_kills_me = c3->monst; who_kills_me_cell = c3;
|
||||
}
|
||||
|
||||
// consider normal monsters
|
||||
if(c2 &&
|
||||
isArmedEnemy(c2, who) &&
|
||||
(c2->monst != moLancer || isUnarmed(who) || !logical_adjacent(c, who, c2))) {
|
||||
if(c2 && isArmedEnemy(c2, who)) {
|
||||
eMonster m = c2->monst;
|
||||
if(elec::affected(c2)) continue;
|
||||
if(fast && c2->monst != moWitchSpeed) continue;
|
||||
|
@ -179,12 +197,12 @@ EX bool monstersnear(cell *c, eMonster who) {
|
|||
eaten = true;
|
||||
else if(c2->monst != moHexSnake) continue;
|
||||
}
|
||||
res++, who_kills_me = m;
|
||||
res++, who_kills_me = m; who_kills_me_cell = c2;
|
||||
}
|
||||
}
|
||||
|
||||
if(kraken_will_destroy_boat && !krakensafe(c) && warningprotection(XLAT("This move appears dangerous -- are you sure?"))) {
|
||||
if (res == 0) who_kills_me = moWarning;
|
||||
if (res == 0) who_kills_me = moWarning; who_kills_me_cell = nullptr;
|
||||
res++;
|
||||
} else {
|
||||
if(who == moPlayer && res && (markOrb2(itOrbShield) || markOrb2(itOrbShell)) && !eaten)
|
||||
|
@ -200,8 +218,6 @@ EX bool monstersnear_aux() {
|
|||
changes.value_set(passive_switch, (gold() & 1) ? moSwitch1 : moSwitch2);
|
||||
multi::cpid++;
|
||||
bool b = false;
|
||||
bool recorduse[ittypes];
|
||||
for(int i=0; i<ittypes; i++) recorduse[i] = orbused[i];
|
||||
if(multi::cpid == multi::players || multi::players == 1 || multi::checkonly) {
|
||||
|
||||
if(shmup::delayed_safety) return false;
|
||||
|
@ -235,14 +251,13 @@ EX bool monstersnear_aux() {
|
|||
}
|
||||
else b = !multimove();
|
||||
multi::cpid--;
|
||||
for(int i=0; i<ittypes; i++) orbused[i] = recorduse[i];
|
||||
return b;
|
||||
}
|
||||
|
||||
/** like monstersnear but add the potential moves of other players into account */
|
||||
EX bool monstersnear_add_pmi(player_move_info pmi0) {
|
||||
if(suicidal) {
|
||||
who_kills_me = moPlayer;
|
||||
who_kills_me = moPlayer; who_kills_me_cell = nullptr;
|
||||
return true;
|
||||
}
|
||||
pmi.push_back(pmi0);
|
||||
|
@ -283,6 +298,110 @@ EX bool swordConflict(const player_move_info& sm1, const player_move_info& sm2)
|
|||
return false;
|
||||
}
|
||||
|
||||
EX string yasc_message;
|
||||
|
||||
EX string blocking_monster_name(const moveissue& mi) {
|
||||
if(mi.monster == moKnight && mi.where)
|
||||
return XLAT("%1 the Knight", camelot::knight_name(mi.where));
|
||||
else
|
||||
return dnameof(mi.monster);
|
||||
}
|
||||
|
||||
EX void create_yasc_message() {
|
||||
set<pair<cell*, string>> captures;
|
||||
auto all = move_issues;
|
||||
all.push_back(stay_issue);
|
||||
for(auto c: all) if(c.type == miTHREAT) captures.emplace(c.where, blocking_monster_name(c));
|
||||
|
||||
vector<string> context;
|
||||
if(!captures.empty()) {
|
||||
string msg = "captured by ";
|
||||
map<string, int> qties;
|
||||
for(auto ca: captures) qties[ca.second]++;
|
||||
int iqties = 0;
|
||||
for(auto q: qties) {
|
||||
if(iqties && iqties == isize(qties) - 1) msg += " and ";
|
||||
else if(iqties) msg += ", ";
|
||||
msg += q.first;
|
||||
if(q.second > 1) msg += " (x" + its(q.second) + ")";
|
||||
iqties++;
|
||||
}
|
||||
context.push_back(msg);
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for(auto c: all) if(idx == 0 && c.subtype == siROSE) context.push_back("rosed"), idx = 1;
|
||||
for(auto c: all) if(idx < 2 && c.subtype == siWIND) context.push_back("blown away"), idx = 2;
|
||||
for(auto c: all) if(idx < 3 && c.subtype == siGRAVITY) context.push_back("falling"), idx = 3;
|
||||
for(auto c: all) if(idx < 4 && c.subtype == siFATIGUE) context.push_back("fatigued"), idx = 4;
|
||||
for(auto c: all) if(idx < 5 && c.subtype == siCURRENT) context.push_back("whirled"), idx = 5;
|
||||
|
||||
bool in_ctx = true;
|
||||
|
||||
set<string> blocks;
|
||||
int index = 0;
|
||||
for(auto c: all) {
|
||||
if(c.type == miENTITY && !captures.count({c.where, blocking_monster_name(c)})) blocks.insert(blocking_monster_name(c));
|
||||
else if(c.type == miWALL && c.subtype == siMONSTER && !captures.count({c.where, blocking_monster_name(c)})) blocks.insert(blocking_monster_name(c));
|
||||
else if(c.subtype == siITEM) blocks.insert("item");
|
||||
else if(c.subtype == siWALL) {
|
||||
if(c.where == cwt.at) {
|
||||
if(in_ctx) {
|
||||
if(c.where->wall == waNone && c.where->land == laBrownian)
|
||||
context.push_back("on level 3");
|
||||
else if(c.where->wall == waRoundTable)
|
||||
context.push_back("being polite");
|
||||
else
|
||||
context.push_back(winf[c.where->wall].flags & WF_ON ? XLAT("on %the1", c.where->wall) : XLAT("in %the1", c.where->wall));
|
||||
}
|
||||
in_ctx = false;
|
||||
}
|
||||
else if(c.where && c.where->wall != cwt.at->wall) blocks.insert(dnameof(c.where->wall));
|
||||
}
|
||||
else if(c.type == siWARP) blocks.insert("warp");
|
||||
index++;
|
||||
}
|
||||
|
||||
if(!blocks.empty()) {
|
||||
string block = "blocked by ";
|
||||
int iqties = 0;
|
||||
for(auto& q: blocks) {
|
||||
if(iqties && iqties == isize(blocks) - 1) block += " and ";
|
||||
else if(iqties) block += ", ";
|
||||
block += q;
|
||||
iqties++;
|
||||
}
|
||||
context.push_back(block);
|
||||
}
|
||||
|
||||
yasc_message = "";
|
||||
int iqties = 0;
|
||||
for(auto& ctx: context) {
|
||||
if(iqties == 0) ;
|
||||
else if(iqties == 1) yasc_message += " while ";
|
||||
else if(iqties == isize(context) - 1) yasc_message += " and ";
|
||||
else yasc_message += ", ";
|
||||
yasc_message += ctx;
|
||||
iqties++;
|
||||
}
|
||||
|
||||
if(captures.size() == 2 && context.size() == 1 && cwt.at->type == 6) {
|
||||
vector<int> dirs;
|
||||
forCellIdEx(c1, i, cwt.at) for(auto cap: captures) if(cap.first == c1) dirs.push_back(i);
|
||||
if(isize(dirs) == 2 && abs(dirs[0]-dirs[1]) == 3) {
|
||||
auto c1 = captures.begin(); c1++;
|
||||
yasc_message = XLAT("pinched by %the1 and %the2", captures.begin()->second, c1->second);
|
||||
}
|
||||
}
|
||||
|
||||
println(hlog, "YASC_MESSAGE: ", yasc_message);
|
||||
}
|
||||
|
||||
int yasc_recode(int x) {
|
||||
if(cwt.at->type < 10 || x == 0) return x;
|
||||
return yasc_recode(x / 10) * 100 + (x % 10);
|
||||
};
|
||||
|
||||
EX void checkmove() {
|
||||
|
||||
if(dual::state == 2) return;
|
||||
|
@ -296,21 +415,19 @@ EX void checkmove() {
|
|||
|
||||
if(multi::players > 1 && !multi::checkonly) return;
|
||||
if(hardcore) return;
|
||||
bool orbusedbak[ittypes];
|
||||
|
||||
// do not activate orbs!
|
||||
for(int i=0; i<ittypes; i++) orbusedbak[i] = orbused[i];
|
||||
|
||||
legalmoves.clear(); legalmoves.resize(cwt.at->type+1, false);
|
||||
move_issues.clear(); move_issues.resize(cwt.at->type, 0);
|
||||
move_issues.clear(); move_issues.resize(cwt.at->type);
|
||||
|
||||
canmove = haveRangedTarget();
|
||||
items[itWarning]+=2;
|
||||
if(movepcto(-1, 0, true))
|
||||
canmove = legalmoves[cwt.at->type] = true;
|
||||
stay_issue = checked_move_issue;
|
||||
|
||||
if(true) {
|
||||
for(int i=0; i<cwt.at->type; i++) {
|
||||
dynamicval<bool> fm(bow::fire_mode, false);
|
||||
if(movepcto(1, -1, true)) {
|
||||
canmove = legalmoves[cwt.spin] = true;
|
||||
}
|
||||
|
@ -329,7 +446,9 @@ EX void checkmove() {
|
|||
|
||||
yasc_code = 0;
|
||||
for(int i=0; i<cwt.at->type; i++)
|
||||
yasc_code += move_issues[i];
|
||||
yasc_code += yasc_recode(move_issues[i].type);
|
||||
|
||||
if(!canmove && bow::crossbow_mode() && !items[itCrossbow]) canmove = bow::have_bow_target();
|
||||
|
||||
#if CAP_INV
|
||||
if(inv::on && !canmove && !inv::incheck) {
|
||||
|
@ -346,9 +465,11 @@ EX void checkmove() {
|
|||
#endif
|
||||
|
||||
if(!canmove) {
|
||||
create_yasc_message();
|
||||
achievement_final(true);
|
||||
if(cmode & sm::NORMAL) showMissionScreen();
|
||||
}
|
||||
else yasc_message = "";
|
||||
|
||||
if(canmove && timerstopped) {
|
||||
timerstart = time(NULL);
|
||||
|
@ -356,7 +477,6 @@ EX void checkmove() {
|
|||
}
|
||||
items[itWarning]-=2;
|
||||
|
||||
for(int i=0; i<ittypes; i++) orbused[i] = orbusedbak[i];
|
||||
if(recallCell.at && !markOrb(itOrbRecall)) activateRecall();
|
||||
}
|
||||
|
||||
|
|
497
classes.cpp
497
classes.cpp
|
@ -426,59 +426,59 @@ enum eSlimegroup { sgNone, sgCave, sgWater, sgFloorA, sgFloorB, sgVine, sgTree }
|
|||
|
||||
#if HDR
|
||||
// we use CF not MF to avoid confusion with MF_ movement flags
|
||||
static const flagtype CF_NOGHOST = Flag(0);
|
||||
static const flagtype CF_RAIDER = Flag(1);
|
||||
static const flagtype CF_PRINCESS = Flag(2);
|
||||
static const flagtype CF_MIMIC = Flag(3);
|
||||
static const flagtype CF_GOK = Flag(4);
|
||||
static const flagtype CF_NONLIVING = Flag(5);
|
||||
static const flagtype CF_METAL = Flag(6);
|
||||
static const flagtype CF_STUNNABLE = Flag(7);
|
||||
static const flagtype CF_HP = Flag(8);
|
||||
static const flagtype CF_MOUNTABLE = Flag(9);
|
||||
static const flagtype CF_FRIENDLY = Flag(10);
|
||||
static const flagtype CF_PLAYER = Flag(11);
|
||||
static const flagtype CF_BUG = Flag(12);
|
||||
static const flagtype CF_IVY = Flag(13);
|
||||
static const flagtype CF_PART = Flag(14);
|
||||
static const flagtype CF_MUTANTIVY = Flag(15);
|
||||
static const flagtype CF_ANYIVY = Flag(16);
|
||||
static const flagtype CF_BULLET = Flag(17);
|
||||
static const flagtype CF_DEMON = Flag(18);
|
||||
static const flagtype CF_WORM = Flag(19);
|
||||
static const flagtype CF_WITCH = Flag(20);
|
||||
static const flagtype CF_BIRD = Flag(21);
|
||||
static const flagtype CF_SLOWMOVER = Flag(22);
|
||||
static const flagtype CF_MAGNETIC = Flag(23);
|
||||
static const flagtype CF_SWITCH = Flag(24);
|
||||
static const flagtype CF_GHOST = Flag(25);
|
||||
static const flagtype CF_SHARK = Flag(26);
|
||||
static const flagtype CF_SLIME = Flag(27);
|
||||
static const flagtype CF_DRAGON = Flag(28);
|
||||
static const flagtype CF_KRAKEN = Flag(29);
|
||||
static const flagtype CF_NOBLOW = Flag(30);
|
||||
static const flagtype CF_MULTITILE = Flag(31);
|
||||
static const flagtype CF_LEADER = Flag(32);
|
||||
static const flagtype CF_FLYING = Flag(33);
|
||||
static const flagtype CF_ATTACK_THRU_VINE = Flag(34);
|
||||
static const flagtype CF_ATTACK_NONADJACENT = Flag(35);
|
||||
static const flagtype CF_NOHIGHLIGHT = Flag(36);
|
||||
static const flagtype CF_INACTIVE = Flag(37);
|
||||
static const flagtype CF_UNARMED = Flag(38);
|
||||
static const flagtype CF_IGNORE_PLATE = Flag(39);
|
||||
static const flagtype CF_BULL = Flag(40);
|
||||
static const flagtype CF_TROLL = Flag(41);
|
||||
static const flagtype CF_IGNORE_SMELL = Flag(42);
|
||||
static const flagtype CF_RATLING = Flag(43);
|
||||
static const flagtype CF_POWER = Flag(44);
|
||||
static const flagtype CF_GHOSTMOVER = Flag(45);
|
||||
static const flagtype CF_TECHNICAL = Flag(46);
|
||||
static const flagtype CF_MOVED = Flag(47);
|
||||
static const flagtype CF_FACING = Flag(48);
|
||||
static const flagtype CF_FACE_UP = Flag(49);
|
||||
static const flagtype CF_FACE_SIDE = Flag(50);
|
||||
static const flagtype CF_HIGH_THREAT = Flag(51);
|
||||
static const flagtype CF_SPAM = Flag(52);
|
||||
static constexpr flagtype CF_NOGHOST = Flag(0);
|
||||
static constexpr flagtype CF_RAIDER = Flag(1);
|
||||
static constexpr flagtype CF_PRINCESS = Flag(2);
|
||||
static constexpr flagtype CF_MIMIC = Flag(3);
|
||||
static constexpr flagtype CF_GOK = Flag(4);
|
||||
static constexpr flagtype CF_NONLIVING = Flag(5);
|
||||
static constexpr flagtype CF_METAL = Flag(6);
|
||||
static constexpr flagtype CF_STUNNABLE = Flag(7);
|
||||
static constexpr flagtype CF_HP = Flag(8);
|
||||
static constexpr flagtype CF_MOUNTABLE = Flag(9);
|
||||
static constexpr flagtype CF_FRIENDLY = Flag(10);
|
||||
static constexpr flagtype CF_PLAYER = Flag(11);
|
||||
static constexpr flagtype CF_BUG = Flag(12);
|
||||
static constexpr flagtype CF_IVY = Flag(13);
|
||||
static constexpr flagtype CF_PART = Flag(14);
|
||||
static constexpr flagtype CF_MUTANTIVY = Flag(15);
|
||||
static constexpr flagtype CF_ANYIVY = Flag(16);
|
||||
static constexpr flagtype CF_BULLET = Flag(17);
|
||||
static constexpr flagtype CF_DEMON = Flag(18);
|
||||
static constexpr flagtype CF_WORM = Flag(19);
|
||||
static constexpr flagtype CF_WITCH = Flag(20);
|
||||
static constexpr flagtype CF_BIRD = Flag(21);
|
||||
static constexpr flagtype CF_SLOWMOVER = Flag(22);
|
||||
static constexpr flagtype CF_MAGNETIC = Flag(23);
|
||||
static constexpr flagtype CF_SWITCH = Flag(24);
|
||||
static constexpr flagtype CF_GHOST = Flag(25);
|
||||
static constexpr flagtype CF_SHARK = Flag(26);
|
||||
static constexpr flagtype CF_SLIME = Flag(27);
|
||||
static constexpr flagtype CF_DRAGON = Flag(28);
|
||||
static constexpr flagtype CF_KRAKEN = Flag(29);
|
||||
static constexpr flagtype CF_NOBLOW = Flag(30);
|
||||
static constexpr flagtype CF_MULTITILE = Flag(31);
|
||||
static constexpr flagtype CF_LEADER = Flag(32);
|
||||
static constexpr flagtype CF_FLYING = Flag(33);
|
||||
static constexpr flagtype CF_ATTACK_THRU_VINE = Flag(34);
|
||||
static constexpr flagtype CF_ATTACK_NONADJACENT = Flag(35);
|
||||
static constexpr flagtype CF_NOHIGHLIGHT = Flag(36);
|
||||
static constexpr flagtype CF_INACTIVE = Flag(37);
|
||||
static constexpr flagtype CF_UNARMED = Flag(38);
|
||||
static constexpr flagtype CF_IGNORE_PLATE = Flag(39);
|
||||
static constexpr flagtype CF_BULL = Flag(40);
|
||||
static constexpr flagtype CF_TROLL = Flag(41);
|
||||
static constexpr flagtype CF_IGNORE_SMELL = Flag(42);
|
||||
static constexpr flagtype CF_RATLING = Flag(43);
|
||||
static constexpr flagtype CF_POWER = Flag(44);
|
||||
static constexpr flagtype CF_GHOSTMOVER = Flag(45);
|
||||
static constexpr flagtype CF_TECHNICAL = Flag(46);
|
||||
static constexpr flagtype CF_MOVED = Flag(47);
|
||||
static constexpr flagtype CF_FACING = Flag(48);
|
||||
static constexpr flagtype CF_FACE_UP = Flag(49);
|
||||
static constexpr flagtype CF_FACE_SIDE = Flag(50);
|
||||
static constexpr flagtype CF_HIGH_THREAT = Flag(51);
|
||||
static constexpr flagtype CF_SPAM = Flag(52);
|
||||
|
||||
enum eMonster {
|
||||
#define MONSTER(a,b,c,d,e,f,g,h) d,
|
||||
|
@ -536,16 +536,16 @@ EX genderswitch_t genderswitch[NUM_GS] = {
|
|||
#if HDR
|
||||
enum eOrbshape { osNone, osLove, osRanged, osOffensive, osFriend, osUtility, osDirectional, osWarping, osFrog, osPowerUtility, osProtective, osMovement, osTerraform };
|
||||
|
||||
static const flagtype ZERO = 0;
|
||||
static constexpr flagtype ZERO = 0;
|
||||
|
||||
static const flagtype IF_SHARD = Flag(0);
|
||||
static const flagtype IF_FIREPROOF = Flag(1);
|
||||
static const flagtype IF_PROTECTION = Flag(2);
|
||||
static const flagtype IF_EMPATHY = Flag(3);
|
||||
static const flagtype IF_RANGED = Flag(4);
|
||||
static const flagtype IF_SHMUPLIFE = Flag(5);
|
||||
static const flagtype IF_REVIVAL = Flag(6);
|
||||
static const flagtype IF_CURSE = Flag(7);
|
||||
static constexpr flagtype IF_SHARD = Flag(0);
|
||||
static constexpr flagtype IF_FIREPROOF = Flag(1);
|
||||
static constexpr flagtype IF_PROTECTION = Flag(2);
|
||||
static constexpr flagtype IF_EMPATHY = Flag(3);
|
||||
static constexpr flagtype IF_RANGED = Flag(4);
|
||||
static constexpr flagtype IF_SHMUPLIFE = Flag(5);
|
||||
static constexpr flagtype IF_REVIVAL = Flag(6);
|
||||
static constexpr flagtype IF_CURSE = Flag(7);
|
||||
|
||||
// 0 = basic treasure, 1 = other item, 2 = power orb, 3 = not an item
|
||||
#define IC_TREASURE 0
|
||||
|
@ -578,28 +578,30 @@ EX itemtype iinf[ittypes] = {
|
|||
// --- wall types ---
|
||||
|
||||
#if HDR
|
||||
static const flagtype WF_WATER = Flag(0);
|
||||
static const flagtype WF_BOAT = Flag(1);
|
||||
static const flagtype WF_CHASM = Flag(2);
|
||||
static const flagtype WF_NOFLIGHT = Flag(3);
|
||||
static const flagtype WF_FIRE = Flag(4);
|
||||
static const flagtype WF_THUMPER = Flag(5);
|
||||
static const flagtype WF_ACTIVABLE = Flag(6);
|
||||
static const flagtype WF_ALCHEMY = Flag(7);
|
||||
static const flagtype WF_RED = Flag(8);
|
||||
static const flagtype WF_WALL = Flag(9);
|
||||
static const flagtype WF_PUSHABLE = Flag(10);
|
||||
static const flagtype WF_CONE = Flag(11);
|
||||
static const flagtype WF_STDTREE = Flag(12);
|
||||
static const flagtype WF_GRAVE = Flag(13);
|
||||
static const flagtype WF_REPTILE = Flag(14);
|
||||
static const flagtype WF_HEATCOLOR = Flag(15);
|
||||
static const flagtype WF_HIGHWALL = Flag(16);
|
||||
static const flagtype WF_THORNY = Flag(17);
|
||||
static const flagtype WF_TIMEOUT = Flag(18);
|
||||
static const flagtype WF_CISLAND = Flag(19);
|
||||
static const flagtype WF_SULPHURIC = Flag(20);
|
||||
static const flagtype WF_HALFVINE = Flag(21);
|
||||
static constexpr flagtype WF_WATER = Flag(0);
|
||||
static constexpr flagtype WF_BOAT = Flag(1);
|
||||
static constexpr flagtype WF_CHASM = Flag(2);
|
||||
static constexpr flagtype WF_NOFLIGHT = Flag(3);
|
||||
static constexpr flagtype WF_FIRE = Flag(4);
|
||||
static constexpr flagtype WF_THUMPER = Flag(5);
|
||||
static constexpr flagtype WF_ACTIVABLE = Flag(6);
|
||||
static constexpr flagtype WF_ALCHEMY = Flag(7);
|
||||
static constexpr flagtype WF_RED = Flag(8);
|
||||
static constexpr flagtype WF_WALL = Flag(9);
|
||||
static constexpr flagtype WF_PUSHABLE = Flag(10);
|
||||
static constexpr flagtype WF_CONE = Flag(11);
|
||||
static constexpr flagtype WF_STDTREE = Flag(12);
|
||||
static constexpr flagtype WF_GRAVE = Flag(13);
|
||||
static constexpr flagtype WF_REPTILE = Flag(14);
|
||||
static constexpr flagtype WF_HEATCOLOR = Flag(15);
|
||||
static constexpr flagtype WF_HIGHWALL = Flag(16);
|
||||
static constexpr flagtype WF_THORNY = Flag(17);
|
||||
static constexpr flagtype WF_TIMEOUT = Flag(18);
|
||||
static constexpr flagtype WF_CISLAND = Flag(19);
|
||||
static constexpr flagtype WF_SULPHURIC = Flag(20);
|
||||
static constexpr flagtype WF_HALFVINE = Flag(21);
|
||||
static constexpr flagtype WF_NONBLOCK = Flag(22);
|
||||
static constexpr flagtype WF_ON = Flag(23); // just for grammar: 'on' not 'in'
|
||||
|
||||
struct walltype {
|
||||
char glyph;
|
||||
|
@ -631,23 +633,23 @@ enum eCanvasFloor { caflNone, caflM, caflFull, caflWarp, caflStar, caflCloud, ca
|
|||
caflPalace, caflDemon, caflCave, caflDesert, caflPower, caflRose, caflTurtle, caflDragon, caflReptile,
|
||||
caflHive, caflSwitch, caflTower, caflEND };
|
||||
|
||||
static const flagtype LF_GENERATE_ALL = Flag(0);
|
||||
static const flagtype LF_ICY = Flag(1);
|
||||
static const flagtype LF_GRAVITY = Flag(2);
|
||||
static const flagtype LF_EQUI = Flag(3);
|
||||
static const flagtype LF_WARPED = Flag(4);
|
||||
static const flagtype LF_CYCLIC = Flag(5);
|
||||
static const flagtype LF_TECHNICAL = Flag(6);
|
||||
static const flagtype LF_MIRROR = Flag(7);
|
||||
static const flagtype LF_SEA = Flag(8);
|
||||
static const flagtype LF_COASTAL = Flag(9);
|
||||
static const flagtype LF_PURESEA = Flag(10);
|
||||
static const flagtype LF_ELEMENTAL = Flag(11);
|
||||
static const flagtype LF_HAUNTED = Flag(12);
|
||||
static const flagtype LF_TROLL = Flag(13);
|
||||
static const flagtype LF_INMIRROR = Flag(14);
|
||||
static const flagtype LF_INMIRRORORWALL = Flag(15);
|
||||
static const flagtype LF_ELECTRIC = Flag(17);
|
||||
static constexpr flagtype LF_GENERATE_ALL = Flag(0);
|
||||
static constexpr flagtype LF_ICY = Flag(1);
|
||||
static constexpr flagtype LF_GRAVITY = Flag(2);
|
||||
static constexpr flagtype LF_EQUI = Flag(3);
|
||||
static constexpr flagtype LF_WARPED = Flag(4);
|
||||
static constexpr flagtype LF_CYCLIC = Flag(5);
|
||||
static constexpr flagtype LF_TECHNICAL = Flag(6);
|
||||
static constexpr flagtype LF_MIRROR = Flag(7);
|
||||
static constexpr flagtype LF_SEA = Flag(8);
|
||||
static constexpr flagtype LF_COASTAL = Flag(9);
|
||||
static constexpr flagtype LF_PURESEA = Flag(10);
|
||||
static constexpr flagtype LF_ELEMENTAL = Flag(11);
|
||||
static constexpr flagtype LF_HAUNTED = Flag(12);
|
||||
static constexpr flagtype LF_TROLL = Flag(13);
|
||||
static constexpr flagtype LF_INMIRROR = Flag(14);
|
||||
static constexpr flagtype LF_INMIRRORORWALL = Flag(15);
|
||||
static constexpr flagtype LF_ELECTRIC = Flag(17);
|
||||
|
||||
struct landtype {
|
||||
color_t color;
|
||||
|
@ -750,9 +752,12 @@ enum eGeometry {
|
|||
gInfOrderMixed, gSpace436, gFake,
|
||||
gSpace345, gSpace353, gSpace354, gSpace355,
|
||||
gHalfBring,
|
||||
gAperiodicHat,
|
||||
gSierpinski3, gSierpinski4, gSixFlake, gMengerSponge, gSierpinskiTet,
|
||||
gAperiodicSpectre,
|
||||
gGUARD};
|
||||
|
||||
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSolNIH, gcNil, gcProduct, gcSL2 };
|
||||
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSol, gcNIH, gcSolN, gcNil, gcProduct, gcSL2 };
|
||||
|
||||
enum class eVariation { bitruncated, pure, goldberg, irregular, dual, untruncated, warped, unrectified, subcubes, coxeter, dual_subcubes, bch, bch_oct };
|
||||
|
||||
|
@ -785,70 +790,76 @@ struct geometryinfo {
|
|||
eVariation default_variation;
|
||||
};
|
||||
|
||||
static const flagtype qCLOSED = 1;
|
||||
static const flagtype qANYQ = 2;
|
||||
static const flagtype qNONORIENTABLE = 4;
|
||||
static const flagtype qSMALL = 8;
|
||||
static constexpr flagtype qCLOSED = 1;
|
||||
static constexpr flagtype qANYQ = 2;
|
||||
static constexpr flagtype qNONORIENTABLE = 4;
|
||||
static constexpr flagtype qSMALL = 8;
|
||||
|
||||
static const flagtype qFIELD = 16;
|
||||
static const flagtype qDOCKS = 32;
|
||||
static const flagtype qZEBRA = 64;
|
||||
static constexpr flagtype qFIELD = 16;
|
||||
static constexpr flagtype qDOCKS = 32;
|
||||
static constexpr flagtype qZEBRA = 64;
|
||||
|
||||
static const flagtype qELLIPTIC = 128;
|
||||
static constexpr flagtype qELLIPTIC = 128;
|
||||
|
||||
static const flagtype qBINARY = 256;
|
||||
static const flagtype qKITE = 512;
|
||||
static constexpr flagtype qBINARY = 256;
|
||||
static constexpr flagtype qKITE = 512;
|
||||
|
||||
static const flagtype qREGULAR = 1024; /* not set! */
|
||||
static const flagtype qARCHI = 2048;
|
||||
static const flagtype qHYBRID = 4096;
|
||||
static const flagtype qCRYSTAL = 8192;
|
||||
static const flagtype qSOL = 16384;
|
||||
static const flagtype qEXPERIMENTAL = 32768;
|
||||
static const flagtype qNIH = 65536;
|
||||
static constexpr flagtype qREGULAR = 1024; /* not set! */
|
||||
static constexpr flagtype qARCHI = 2048;
|
||||
static constexpr flagtype qHYBRID = 4096;
|
||||
static constexpr flagtype qCRYSTAL = 8192;
|
||||
static constexpr flagtype qSOL = 16384;
|
||||
static constexpr flagtype qEXPERIMENTAL = 32768;
|
||||
static constexpr flagtype qNIH = 65536;
|
||||
|
||||
static const flagtype qIDEAL = 131072;
|
||||
static const flagtype qHUGE_BOUNDED = 262144;
|
||||
static const flagtype qOPTQ = Flag(19);
|
||||
static const flagtype qSINGLE = Flag(20);
|
||||
static constexpr flagtype qIDEAL = 131072;
|
||||
static constexpr flagtype qHUGE_BOUNDED = 262144;
|
||||
static constexpr flagtype qOPTQ = Flag(19);
|
||||
static constexpr flagtype qSINGLE = Flag(20);
|
||||
|
||||
static const flagtype qDEPRECATED = Flag(21);
|
||||
static const flagtype qINFMIXED = Flag(22);
|
||||
static constexpr flagtype qDEPRECATED = Flag(21);
|
||||
static constexpr flagtype qINFMIXED = Flag(22);
|
||||
|
||||
static const flagtype qRAYONLY = Flag(23);
|
||||
static const flagtype qAFFINE = Flag(24);
|
||||
static constexpr flagtype qRAYONLY = Flag(23);
|
||||
static constexpr flagtype qAFFINE = Flag(24);
|
||||
|
||||
static const flagtype qULTRA = Flag(25);
|
||||
static constexpr flagtype qULTRA = Flag(25);
|
||||
|
||||
static const flagtype qPORTALSPACE = Flag(26);
|
||||
static constexpr flagtype qPORTALSPACE = Flag(26);
|
||||
|
||||
static const flagtype qSTRETCHABLE = Flag(27);
|
||||
static constexpr flagtype qSTRETCHABLE = Flag(27);
|
||||
|
||||
static const flagtype qCAT = Flag(28);
|
||||
static constexpr flagtype qCAT = Flag(28);
|
||||
|
||||
static constexpr flagtype qAPERIODIC = Flag(29);
|
||||
static constexpr flagtype qHAT = Flag(30);
|
||||
|
||||
static constexpr flagtype qFRACTAL = Flag(31);
|
||||
|
||||
// note: dnext assumes that x&7 equals 7
|
||||
static const int SEE_ALL = 50;
|
||||
static const int OINF = 123;
|
||||
static constexpr int SEE_ALL = 50;
|
||||
// note: check_football_colorability in arbitrile.cpp assumes OINF is divisible by 3
|
||||
static constexpr int OINF = 123;
|
||||
|
||||
extern eGeometry geometry;
|
||||
extern eVariation variation;
|
||||
#endif
|
||||
|
||||
#if HDR
|
||||
static const flagtype qsNONOR = qANYQ | qSMALL | qCLOSED | qNONORIENTABLE;
|
||||
static const flagtype qsNONORE = qsNONOR | qELLIPTIC;
|
||||
static const flagtype qsBQ = qANYQ | qSMALL | qCLOSED;
|
||||
static const flagtype qsSMALL = qANYQ | qSMALL | qCLOSED;
|
||||
static const flagtype qsSMALLN = qANYQ | qSMALL | qCLOSED | qNONORIENTABLE;
|
||||
static const flagtype qsZEBRA = qANYQ | qSMALL | qCLOSED | qZEBRA;
|
||||
static const flagtype qsFIELD = qANYQ | qFIELD | qCLOSED;
|
||||
static const flagtype qsDOCKS = qANYQ | qSMALL | qCLOSED | qDOCKS;
|
||||
static const flagtype qsSMALLB = qSMALL | qCLOSED;
|
||||
static const flagtype qsSMALLBF = qsSMALLB | qsFIELD | qANYQ;
|
||||
static const flagtype qsSMALLBE = qsSMALLB | qELLIPTIC | qANYQ;
|
||||
static const flagtype qsBP = qBINARY | qKITE;
|
||||
static constexpr flagtype qsNONOR = qANYQ | qSMALL | qCLOSED | qNONORIENTABLE;
|
||||
static constexpr flagtype qsNONORE = qsNONOR | qELLIPTIC;
|
||||
static constexpr flagtype qsBQ = qANYQ | qSMALL | qCLOSED;
|
||||
static constexpr flagtype qsSMALL = qANYQ | qSMALL | qCLOSED;
|
||||
static constexpr flagtype qsSMALLN = qANYQ | qSMALL | qCLOSED | qNONORIENTABLE;
|
||||
static constexpr flagtype qsZEBRA = qANYQ | qSMALL | qCLOSED | qZEBRA;
|
||||
static constexpr flagtype qsFIELD = qANYQ | qFIELD | qCLOSED;
|
||||
static constexpr flagtype qsDOCKS = qANYQ | qSMALL | qCLOSED | qDOCKS;
|
||||
static constexpr flagtype qsSMALLB = qSMALL | qCLOSED;
|
||||
static constexpr flagtype qsSMALLBF = qsSMALLB | qsFIELD | qANYQ;
|
||||
static constexpr flagtype qsSMALLBE = qsSMALLB | qELLIPTIC | qANYQ;
|
||||
static constexpr flagtype qsBP = qBINARY | qKITE;
|
||||
|
||||
static const flagtype qsSINGLE = qANYQ | qSMALL | qCLOSED | qSINGLE;
|
||||
static constexpr flagtype qsSINGLE = qANYQ | qSMALL | qCLOSED | qSINGLE;
|
||||
#endif
|
||||
|
||||
EX geometryinfo1 giEuclid2 = { gcEuclid, 2, 2, 3, {1,1, 0,0 } };
|
||||
|
@ -859,9 +870,14 @@ EX geometryinfo1 giEuclid3 = { gcEuclid, 3, 3, 4, {1,1, 1,0 } };
|
|||
EX geometryinfo1 giHyperb3 = { gcHyperbolic, 3, 3, 4, {1,1, 1,-1} };
|
||||
EX geometryinfo1 giSphere3 = { gcSphere, 3, 3, 4, {1,1, 1,+1} };
|
||||
|
||||
EX geometryinfo1 giSolNIH = { gcSolNIH, 3, 3, 4, {1,1, 1,0 } };
|
||||
EX geometryinfo1 giSol = { gcSol, 3, 3, 4, {1,1, 1,0 } };
|
||||
EX geometryinfo1 giNIH = { gcNIH, 3, 3, 4, {1,1, 1,0 } };
|
||||
EX geometryinfo1 giSolN = { gcSolN, 3, 3, 4, {1,1, 1,0 } };
|
||||
|
||||
EX geometryinfo1 giNil = { gcNil, 3, 3, 4, {1,1, 1,0 } };
|
||||
EX geometryinfo1 giProduct = { gcSL2, 3, 3, 4, {1,1, 1,0 } /* will be filled in product::configure() */ };
|
||||
EX geometryinfo1 giProductH= { gcProduct, 3, 3, 3, {1,1,-1,0 } };
|
||||
EX geometryinfo1 giProductS= { gcProduct, 3, 3, 3, {1,1, 1,0 } };
|
||||
EX geometryinfo1 giProduct = { gcProduct, 3, 3, 3, {1,1, 1,0 } /* will be filled in product::configure() */ };
|
||||
EX geometryinfo1 giSL2 = { gcSL2, 3, 3, 4, {1,1,-1,-1} };
|
||||
|
||||
EX modecode_t no_code = 0x1;
|
||||
|
@ -918,20 +934,20 @@ EX vector<geometryinfo> ginf = {
|
|||
{"{4,3,5}","field", "{4,3,5} field quotient space", "f435", 6, 5, qsSMALLBF | qDEPRECATED, giHyperb3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"{5,3,4}","field", "{5,3,4} field quotient space", "f435", 12, 4, qsSMALLBF | qDEPRECATED, giHyperb3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
|
||||
{"binary4","none", "standard binary tiling", "binary4", 5, 3, qBINARY, giHyperb2, {{7, 5}}, eVariation::pure},
|
||||
{"sol", "none", "Solv geometry", "sol", 8, 3, qBINARY|qSOL, giSolNIH, {{7, 5}}, eVariation::pure},
|
||||
{"kd2", "none", "kite-and-dart", "kd2", 4, 3, qKITE, giEuclid2, {{7, 7}}, eVariation::pure},
|
||||
{"sol", "none", "Solv geometry", "sol", 8, 3, qBINARY|qSOL, giSol, {{7, 5}}, eVariation::pure},
|
||||
{"kd2", "none", "kite-and-dart", "kd2", 4, 3, qKITE | qAPERIODIC, giEuclid2, {{7, 7}}, eVariation::pure},
|
||||
{"kd3", "none", "kite-and-dart on horospheres", "kd3", 12, 3, qsBP, giHyperb3, {{7, 3}}, eVariation::pure},
|
||||
{"nil", "none", "Nil geometry", "nil", 6, 3, qOPTQ, giNil, {{7, 5}}, eVariation::pure},
|
||||
{"product","none", "product space", "product", 7, 3, qHYBRID, giProduct, {{7, 3}}, eVariation::pure},
|
||||
{"twisted","none", "rotation space", "twisted", 7, 3, qHYBRID, giSL2, {{6, 4}}, eVariation::pure},
|
||||
{"ternary","none", "standard ternary tiling", "ternary", 6, 3, qBINARY, giHyperb2, {{6, 4}}, eVariation::pure},
|
||||
{"3x2", "none", "stretched hyperbolic", "3:2", 11, 3, qBINARY|qNIH, giSolNIH, {{6, 3}}, eVariation::pure},
|
||||
{"3x1/2", "none", "stretched Solv", "3:1/2", 9, 3, (qBINARY|qSOL|qNIH), giSolNIH, {{7, 3}}, eVariation::pure},
|
||||
{"3x2", "none", "stretched hyperbolic", "3:2", 11, 3, qBINARY|qNIH, giNIH, {{6, 3}}, eVariation::pure},
|
||||
{"3x1/2", "none", "stretched Solv", "3:1/2", 9, 3, (qBINARY|qSOL|qNIH), giSolN, {{7, 3}}, eVariation::pure},
|
||||
{"{3,oo}", "none", "{3,∞} (infinite triangles)", "oox3", 3, OINF, qIDEAL, giHyperb2, {{7, 7}}, eVariation::pure},
|
||||
{"{3,3,6}","none", "{3,3,6} hyperbolic honeycomb", "336", 4, 6, qIDEAL, giHyperb3, {{7, 2}}, eVariation::pure},
|
||||
{"{3,4,4}","none", "{3,4,4} hyperbolic honeycomb", "344", 8, 4, qIDEAL, giHyperb3, {{7, 2}}, eVariation::pure},
|
||||
{"{3,4,4}","Crystal", "4D crystal in H3", "Cryst3" , 8, 4, qIDEAL | qANYQ | qCRYSTAL, giHyperb3, {{7, 3}}, eVariation::pure},
|
||||
{"cat", "cat", "Arnold's cat mapping torus", "cat", 12, 3, qBINARY | qSOL | qsBQ | qOPTQ | qCAT, giSolNIH, {{6, 4}}, eVariation::pure},
|
||||
{"cat", "cat", "Arnold's cat mapping torus", "cat", 12, 3, qBINARY | qSOL | qsBQ | qOPTQ | qCAT, giSol, {{6, 4}}, eVariation::pure},
|
||||
{"file", "none", "load from file", "file", 7, 3, 0, giEuclid2, {{7, 5}}, eVariation::pure},
|
||||
{"{4,oo}", "none", "{4,∞} (infinite squares)", "oox4", 4, OINF, qIDEAL, giHyperb2, {{5, 5}}, eVariation::pure},
|
||||
{"{5,3,4}","Crystal", "6D crystal in H3", "Cryst6" , 12, 4, qANYQ | qCRYSTAL, giHyperb3, {{7, 3}}, eVariation::pure},
|
||||
|
@ -948,29 +964,43 @@ EX vector<geometryinfo> ginf = {
|
|||
{"{3,5,4}","none", "{3,5,4} hyperbolic honeycomb", "354", 20, 5, qIDEAL | qULTRA, giHyperb3, {{7, 2}}, eVariation::pure},
|
||||
{"{3,5,5}","none", "{3,5,5} hyperbolic honeycomb", "355", 20, 5, qIDEAL | qULTRA, giHyperb3, {{7, 2}}, eVariation::pure},
|
||||
{"{5,4}", "pBring", "projective Bring's Surface", "pBring", 5, 4, qsSMALLN, giHyperb2, {{6, 4}}, eVariation::bitruncated},
|
||||
{"hat", "none", "aperiodic hat", "hat", 14, 3, qAPERIODIC | qHAT, giEuclid2, {{7, 7}}, eVariation::pure},
|
||||
{"triangle","none", "Sierpiński triangle", "S3", 6, 3, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
|
||||
{"carpet", "none", "Sierpiński carpet", "S4", 4, 4, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
|
||||
{"6-flake","none", "6-flake fractal", "S6", 6, 3, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
|
||||
{"{4,3,4}","none", "Menger sponge", "S8", 6, 4, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure},
|
||||
{"rh{4,3,4}","none", "Sierpiński tetrahedron", "S4b", 12, 3, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure},
|
||||
{"spectre","none", "aperiodic spectre", "spectre", 14, 3, qAPERIODIC | qHAT, giEuclid2, {{7, 7}}, eVariation::pure},
|
||||
};
|
||||
// bits: 9, 10, 15, 16, (reserved for later) 17, 18
|
||||
|
||||
#if HDR
|
||||
namespace mf {
|
||||
static const flagtype azimuthal = 1;
|
||||
static const flagtype cylindrical = 2;
|
||||
static const flagtype equiarea = 4;
|
||||
static const flagtype equidistant = 8;
|
||||
static const flagtype conformal = 16;
|
||||
static const flagtype euc_boring = 32;
|
||||
static const flagtype space = 64;
|
||||
static const flagtype hyper_only = 128;
|
||||
static const flagtype hyper_or_torus = 256;
|
||||
static const flagtype pseudocylindrical = 512; /* includes cylindrical */
|
||||
static const flagtype equivolume = 1024;
|
||||
static const flagtype twopoint = 2048;
|
||||
static const flagtype uses_bandshift = 4096;
|
||||
static const flagtype broken = 8192; /* in spherical case, these are broken along the meridian 180 deg */
|
||||
static const flagtype technical = 16384; /* don't display in the list */
|
||||
static constexpr flagtype azimuthal = 1;
|
||||
static constexpr flagtype cylindrical = 2; /* usually you want 'band' */
|
||||
static constexpr flagtype equiarea = 4;
|
||||
static constexpr flagtype equidistant = 8;
|
||||
static constexpr flagtype conformal = 16;
|
||||
static constexpr flagtype euc_boring = 32;
|
||||
static constexpr flagtype space = 64;
|
||||
static constexpr flagtype hyper_only = 128;
|
||||
static constexpr flagtype hyper_or_torus = 256;
|
||||
static constexpr flagtype pseudocylindrical = 512; /* includes cylindrical; usually you want 'band' or 'pseudoband' */
|
||||
static constexpr flagtype equivolume = 1024;
|
||||
static constexpr flagtype twopoint = 2048;
|
||||
static constexpr flagtype uses_bandshift = 4096;
|
||||
static constexpr flagtype broken = 8192; /* in spherical case, these are broken along the meridian 180 deg */
|
||||
static constexpr flagtype technical = 16384; /* don't display in the list */
|
||||
static constexpr flagtype product_special = (1<<15);
|
||||
static constexpr flagtype axial = (1<<16);
|
||||
static constexpr flagtype perspective = (1<<17);
|
||||
static constexpr flagtype orientation = (1<<18);
|
||||
static constexpr flagtype transition = (1<<19);
|
||||
static constexpr flagtype werner = (1<<20);
|
||||
static constexpr flagtype horocyclic = (1<<21);
|
||||
|
||||
static const flagtype band = (cylindrical | pseudocylindrical | uses_bandshift);
|
||||
static const flagtype pseudoband = (pseudocylindrical | uses_bandshift);
|
||||
static constexpr flagtype band = (cylindrical | pseudocylindrical | uses_bandshift | orientation);
|
||||
static constexpr flagtype pseudoband = (pseudocylindrical | uses_bandshift | orientation);
|
||||
}
|
||||
|
||||
struct modelinfo {
|
||||
|
@ -979,13 +1009,6 @@ struct modelinfo {
|
|||
const char *name_spherical;
|
||||
|
||||
flagtype flags;
|
||||
|
||||
int is_azimuthal;
|
||||
int is_band;
|
||||
int is_equiarea;
|
||||
int is_equidistant;
|
||||
int is_conformal;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
enum eModel : int {
|
||||
|
@ -1006,9 +1029,11 @@ enum eModel : int {
|
|||
mdHorocyclic, mdQuadrant, mdAxial, mdAntiAxial,
|
||||
// 32..38
|
||||
mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel,
|
||||
// 39..
|
||||
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal,
|
||||
// 47..
|
||||
// 39..48
|
||||
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal, mdRelPerspective, mdRelOrthogonal,
|
||||
// 49..50
|
||||
mdHorocyclicEqa, mdConformalSquare, mdFisheye2, mdPolar,
|
||||
// 51..
|
||||
mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual
|
||||
};
|
||||
#endif
|
||||
|
@ -1017,66 +1042,70 @@ enum eModel : int {
|
|||
// (other bits are used for other information)
|
||||
|
||||
#define X3(x) x, x, x
|
||||
#define DEFAULTS 0, 0, 0, 0, 0, nullptr
|
||||
|
||||
/** list of available models (i.e., projections) */
|
||||
EX vector<modelinfo> mdinf = {
|
||||
{"disk/Gans", "general perspective", "general perspective", mf::azimuthal | mf::conformal, DEFAULTS},
|
||||
{"half-plane", "inversion", "stereographic projection [VR]", mf::conformal, DEFAULTS},
|
||||
{"band", "band", "Mercator", mf::band | mf::conformal, DEFAULTS},
|
||||
{X3("polygonal"), mf::conformal, DEFAULTS},
|
||||
{X3("formula"), 0, DEFAULTS},
|
||||
{X3("azimuthal equidistant"), mf::azimuthal | mf::equidistant | mf::euc_boring, DEFAULTS},
|
||||
{X3("azimuthal equi-area"), mf::azimuthal | mf::equiarea | mf::euc_boring, DEFAULTS},
|
||||
{X3("ball model"), mf::conformal | mf::azimuthal | mf::space, DEFAULTS},
|
||||
{"Minkowski hyperboloid", "plane", "sphere", mf::conformal | mf::space | mf::euc_boring, DEFAULTS},
|
||||
{"hemisphere", "sphere", "Minkowski hyperboloid", mf::conformal | mf::space, DEFAULTS},
|
||||
{X3("band equidistant"), mf::band | mf::equidistant | mf::euc_boring, DEFAULTS},
|
||||
{X3("band equi-area"), mf::band | mf::equiarea | mf::euc_boring, DEFAULTS},
|
||||
{X3("sinusoidal"), mf::pseudoband | mf::equiarea | mf::euc_boring, DEFAULTS},
|
||||
{X3("two-point equidistant"), mf::equidistant | mf::euc_boring | mf::twopoint, DEFAULTS},
|
||||
{X3("fisheye"), 0, DEFAULTS},
|
||||
{X3("Joukowsky transform"), mf::hyper_only | mf::conformal, DEFAULTS},
|
||||
{X3("Joukowsky+inversion"), mf::hyper_only | mf::conformal, DEFAULTS},
|
||||
{X3("rotated hyperboles"), mf::hyper_only, DEFAULTS},
|
||||
{X3("spiral/ring"), mf::hyper_or_torus | mf::uses_bandshift, DEFAULTS},
|
||||
{X3("native perspective"), 0, DEFAULTS},
|
||||
{X3("azimuthal equi-volume"), mf::azimuthal | mf::equivolume | mf::euc_boring, DEFAULTS},
|
||||
{X3("central inversion"), mf::azimuthal | mf::conformal, DEFAULTS},
|
||||
{X3("two-point azimuthal"), mf::euc_boring | mf::twopoint, DEFAULTS},
|
||||
{X3("two-point hybrid"), mf::euc_boring | mf::twopoint, DEFAULTS},
|
||||
{X3("geodesic"), 0, DEFAULTS},
|
||||
{X3("Mollweide"), mf::euc_boring | mf::pseudoband | mf::equiarea, DEFAULTS},
|
||||
{X3("central cylindrical"), mf::euc_boring | mf::band, DEFAULTS},
|
||||
{X3("Collignon"), mf::pseudoband | mf::equiarea, DEFAULTS},
|
||||
{X3("horocyclic coordinates"), mf::euc_boring, DEFAULTS},
|
||||
{X3("quadrant coordinates"), mf::euc_boring, DEFAULTS},
|
||||
{X3("axial coordinates"), mf::euc_boring, DEFAULTS},
|
||||
{X3("anti-axial coordinates"), mf::euc_boring, DEFAULTS},
|
||||
{X3("Werner projection"), mf::euc_boring | mf::broken, DEFAULTS}, // keep distances from pole, and distances along parallels
|
||||
{X3("Aitoff projection"), mf::euc_boring | mf::broken, DEFAULTS}, // halve longitudes, do azequid, double x
|
||||
{X3("Hammer projection"), mf::euc_boring | mf::broken, DEFAULTS}, // halve longitudes, do azequia, double x
|
||||
{X3("loximuthal projection"), mf::euc_boring | mf::broken, DEFAULTS}, // map loxodromes azimuthally and equidistantly
|
||||
{X3("Miller projection"), mf::euc_boring | mf::band, DEFAULTS}, // scale latitude 4/5 -> Mercator -> 5/4
|
||||
{X3("Gall stereographic"), mf::euc_boring | mf::band, DEFAULTS}, // like central cylindrical but stereographic
|
||||
{X3("Winkel tripel"), mf::euc_boring | mf::broken, DEFAULTS}, // mean of equirec and Aitoff
|
||||
{X3("Poor man's square"), mf::euc_boring, DEFAULTS}, //
|
||||
{X3("Panini projection"), mf::euc_boring, DEFAULTS}, //
|
||||
{X3("Craig retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal cylindrical
|
||||
{X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal conformal
|
||||
{X3("Hammer retroazimuthal"), mf::euc_boring, DEFAULTS}, // retroazimuthal equidistant
|
||||
{X3("three-point equidistant"), mf::euc_boring, DEFAULTS},
|
||||
{X3("Lie perspective"), mf::euc_boring, DEFAULTS},
|
||||
{X3("Lie orthogonal"), mf::euc_boring, DEFAULTS},
|
||||
{X3("guard"), mf::technical, DEFAULTS},
|
||||
{X3("pixel"), mf::technical, DEFAULTS},
|
||||
{X3("hypflat"), mf::technical, DEFAULTS},
|
||||
{X3("polynomial"), mf::technical | mf::conformal, DEFAULTS},
|
||||
{X3("manual"), mf::technical, DEFAULTS},
|
||||
{"disk/Gans", "general perspective", "general perspective", mf::azimuthal | mf::conformal},
|
||||
{"half-plane", "inversion", "stereographic projection [VR]", mf::conformal | mf::orientation | mf::horocyclic},
|
||||
{"band", "band", "Mercator", mf::band | mf::conformal | mf::transition},
|
||||
{X3("polygonal"), mf::conformal | mf::orientation},
|
||||
{X3("formula"), 0},
|
||||
{X3("azimuthal equidistant"), mf::azimuthal | mf::equidistant | mf::euc_boring | mf::product_special},
|
||||
{X3("azimuthal equi-area"), mf::azimuthal | mf::equiarea | mf::euc_boring},
|
||||
{X3("ball model"), mf::conformal | mf::azimuthal | mf::space},
|
||||
{"Minkowski hyperboloid", "plane", "sphere", mf::conformal | mf::space | mf::euc_boring},
|
||||
{"hemisphere", "sphere", "Minkowski hyperboloid", mf::conformal | mf::space},
|
||||
{X3("band equidistant"), mf::band | mf::equidistant | mf::euc_boring},
|
||||
{X3("band equi-area"), mf::band | mf::equiarea | mf::euc_boring},
|
||||
{X3("sinusoidal"), mf::pseudoband | mf::equiarea | mf::euc_boring},
|
||||
{X3("two-point equidistant"), mf::equidistant | mf::euc_boring | mf::twopoint | mf::orientation},
|
||||
{X3("fisheye"), 0},
|
||||
{X3("Joukowsky transform"), mf::hyper_only | mf::conformal | mf::transition | mf::orientation},
|
||||
{X3("Joukowsky+inversion"), mf::hyper_only | mf::conformal | mf::transition | mf::orientation},
|
||||
{X3("rotated hyperboles"), mf::hyper_only | mf::orientation},
|
||||
{X3("spiral/ring"), mf::hyper_or_torus | mf::uses_bandshift | mf::orientation},
|
||||
{X3("native perspective"), mf::perspective | mf::product_special},
|
||||
{X3("azimuthal equi-volume"), mf::azimuthal | mf::equivolume | mf::euc_boring},
|
||||
{X3("central inversion"), mf::azimuthal | mf::conformal},
|
||||
{X3("two-point azimuthal"), mf::euc_boring | mf::azimuthal | mf::twopoint | mf::orientation},
|
||||
{X3("two-point hybrid"), mf::euc_boring | mf::azimuthal | mf::equidistant | mf::twopoint | mf::orientation},
|
||||
{X3("geodesic"), mf::perspective | mf::product_special},
|
||||
{X3("Mollweide"), mf::euc_boring | mf::pseudoband | mf::equiarea},
|
||||
{X3("central cylindrical"), mf::euc_boring | mf::band},
|
||||
{X3("Collignon"), mf::pseudoband | mf::equiarea},
|
||||
{X3("horocyclic coordinates"), mf::euc_boring | mf::orientation | mf::horocyclic},
|
||||
{X3("quadrant coordinates"), mf::euc_boring | mf::orientation},
|
||||
{X3("axial coordinates"), mf::euc_boring | mf::transition | mf::orientation},
|
||||
{X3("anti-axial coordinates"), mf::euc_boring | mf::orientation},
|
||||
{X3("Werner projection"), mf::euc_boring | mf::broken | mf::werner | mf::orientation}, // keep distances from pole, and distances along parallels
|
||||
{X3("Aitoff projection"), mf::euc_boring | mf::broken | mf::orientation}, // halve longitudes, do azequid, double x
|
||||
{X3("Hammer projection"), mf::euc_boring | mf::broken | mf::orientation}, // halve longitudes, do azequia, double x
|
||||
{X3("loximuthal projection"), mf::euc_boring | mf::broken | mf::orientation}, // map loxodromes azimuthally and equidistantly
|
||||
{X3("Miller projection"), mf::euc_boring | mf::band}, // scale latitude 4/5 -> Mercator -> 5/4
|
||||
{X3("Gall stereographic"), mf::euc_boring | mf::band}, // like central cylindrical but stereographic
|
||||
{X3("Winkel tripel"), mf::euc_boring | mf::broken | mf::orientation}, // mean of equirec and Aitoff
|
||||
{X3("Poor man's square"), mf::euc_boring | mf::orientation}, // https://archive.bridgesmathart.org/2018/bridges2018-59.html
|
||||
{X3("Panini projection"), mf::euc_boring | mf::orientation},
|
||||
{X3("Craig retroazimuthal"), mf::euc_boring | mf::broken | mf::pseudoband}, // retroazimuthal cylindrical
|
||||
{X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken | mf::pseudoband}, // retroazimuthal conformal
|
||||
{X3("Hammer retroazimuthal"), mf::euc_boring | mf::pseudoband}, // retroazimuthal equidistant
|
||||
{X3("three-point equidistant"), mf::euc_boring | mf::equidistant | mf::orientation | mf::product_special | mf::twopoint},
|
||||
{X3("Lie perspective"), mf::euc_boring | mf::perspective},
|
||||
{X3("Lie orthogonal"), mf::euc_boring},
|
||||
{X3("relativistic perspective"), mf::euc_boring | mf::perspective},
|
||||
{X3("relativistic orthogonal"), mf::euc_boring},
|
||||
{X3("horocyclic equal-area"), mf::euc_boring | mf::equiarea | mf::orientation | mf::horocyclic},
|
||||
{X3("conformal square"), mf::orientation | mf::broken | mf::transition},
|
||||
{X3("variant fisheye"), 0},
|
||||
{X3("polar coordinates"), mf::orientation},
|
||||
{X3("guard"), mf::technical},
|
||||
{X3("pixel"), mf::technical},
|
||||
{X3("hypflat"), mf::technical},
|
||||
{X3("polynomial"), mf::technical | mf::conformal | mf::orientation},
|
||||
{X3("manual"), mf::technical},
|
||||
};
|
||||
|
||||
#undef X3
|
||||
#undef DEFAULTS
|
||||
|
||||
#if HDR
|
||||
static inline bool orbProtection(eItem it) { return false; } // not implemented
|
||||
|
|
14
colors.cpp
14
colors.cpp
|
@ -25,7 +25,7 @@ EX unsigned char& part(color_t& col, int i) {
|
|||
}
|
||||
|
||||
#if HDR
|
||||
static const color_t NOCOLOR = 0;
|
||||
static constexpr color_t NOCOLOR = 0;
|
||||
|
||||
struct colortable: vector<color_t> {
|
||||
color_t& operator [] (int i) { i %= size(); if(i<0) i += size(); return ((vector<color_t>&)(*this)) [i]; }
|
||||
|
@ -111,7 +111,7 @@ EX color_t rainbow_color(ld sat, ld hue) {
|
|||
else if(hue<3) res = gradient(0x00FF00, 0x00FFFF, 2, hue, 3);
|
||||
else if(hue<4) res = gradient(0x0000FF, 0x00FFFF, 4, hue, 3);
|
||||
else if(hue<5) res = gradient(0x0000FF, 0xFF00FF, 4, hue, 5);
|
||||
else if(hue<6) res = gradient(0xFF0000, 0xFF00FF, 6, hue, 5);
|
||||
else if(hue<=6) res = gradient(0xFF0000, 0xFF00FF, 6, hue, 5);
|
||||
|
||||
return gradient(0xFFFFFF, res, 0, sat, 1);
|
||||
}
|
||||
|
@ -247,13 +247,15 @@ EX int cloakcolor(int rtr) {
|
|||
EX int firegradient(double p) {
|
||||
return gradient(0xFFFF00, 0xFF0000, 0, p, 1);
|
||||
}
|
||||
|
||||
|
||||
constexpr ld PI1000 = 0.001 / A_PI;
|
||||
|
||||
EX int firecolor(int phase IS(0), int mul IS(1)) {
|
||||
return gradient(0xFFFF00, 0xFF0000, -1, sintick(100*mul, phase/200./M_PI), 1);
|
||||
return gradient(0xFFFF00, 0xFF0000, -1, sintick(100*mul, phase * 5 * PI1000), 1);
|
||||
}
|
||||
|
||||
EX int watercolor(int phase) {
|
||||
return 0x0080C0FF + 256 * int(63 * sintick(50, phase/100./M_PI));
|
||||
return 0x0080C0FF + 256 * int(63 * sintick(50, phase * 10 * PI1000));
|
||||
}
|
||||
|
||||
EX int aircolor(int phase) {
|
||||
|
@ -270,7 +272,7 @@ EX int fghostcolor(cell *c) {
|
|||
}
|
||||
|
||||
EX int weakfirecolor(int phase) {
|
||||
return gradient(0xFF8000, 0xFF0000, -1, sintick(500, phase/1000./M_PI), 1);
|
||||
return gradient(0xFF8000, 0xFF0000, -1, sintick(500, phase * PI1000), 1);
|
||||
}
|
||||
|
||||
/* HTML color names */
|
||||
|
|
139
commandline.cpp
139
commandline.cpp
|
@ -17,7 +17,7 @@ EX string rsrcdir = "";
|
|||
#endif
|
||||
|
||||
#if CAP_COMMANDLINE
|
||||
EX const char *scorefile = "hyperrogue.log";
|
||||
EX string scorefile = "hyperrogue.log";
|
||||
|
||||
EX namespace arg {
|
||||
EX eLand readland(const string& ss) {
|
||||
|
@ -63,7 +63,7 @@ EX void initializeCLI() {
|
|||
if(getenv("HOME")) {
|
||||
sbuf = getenv("HOME"); sbuf += "/."; sbuf += scorefile;
|
||||
cbuf = getenv("HOME"); cbuf += "/."; cbuf += conffile;
|
||||
scorefile = sbuf.c_str();
|
||||
scorefile = sbuf;
|
||||
conffile = cbuf.c_str();
|
||||
}
|
||||
#endif
|
||||
|
@ -87,6 +87,7 @@ EX namespace arg {
|
|||
EX const string& args() { return argument[pos]; }
|
||||
EX const char* argcs() { return args().c_str(); }
|
||||
EX int argi() { return atoi(argcs()); }
|
||||
EX long long argll() { return atoll(argcs()); }
|
||||
|
||||
EX int shift_argi() { shift(); return argi(); }
|
||||
EX const string& shift_args() { shift(); return args(); }
|
||||
|
@ -104,21 +105,18 @@ EX namespace arg {
|
|||
EX bool argis(const string& s) { if(args()[0] == '-' && args()[1] == '-') return args().substr(1) == s; return args() == s; }
|
||||
|
||||
EX color_t argcolor(int bits) {
|
||||
string s = args();
|
||||
auto p = find_color_by_name(s);
|
||||
if(p && bits == 24) return p->second;
|
||||
if(p && bits == 32) return (p->second << 8) | 0xFF;
|
||||
return strtoll(argcs(), NULL, 16);
|
||||
return parsecolor(args(), bits == 32);
|
||||
}
|
||||
|
||||
int parameter_id;
|
||||
|
||||
EX void shift_arg_formula(ld& x, const reaction_t& r IS(reaction_t())) {
|
||||
shift(); ld old = x; x = argf();
|
||||
#if CAP_ANIMATIONS
|
||||
anims::animate_parameter(x, args(), r);
|
||||
#endif
|
||||
if(old != x && r) r();
|
||||
shift();
|
||||
auto par = anims::find_param(&x);
|
||||
if(!par) par = param_f(x, "tmp_parameter_" + its(parameter_id++))->set_reaction(r);
|
||||
par->load_as_animation(args());
|
||||
}
|
||||
|
||||
|
||||
#if HDR
|
||||
|
||||
// an useful macro
|
||||
|
@ -168,12 +166,20 @@ int arg::readCommon() {
|
|||
|
||||
// first phase options
|
||||
|
||||
if(argis("-s")) { PHASE(1); shift(); scorefile = argcs(); }
|
||||
if(argis("-s")) { PHASE(2); shift(); scorefile = args(); savefile_selection = false; }
|
||||
else if(argis("-no-s")) { PHASE(2); scorefile = ""; savefile_selection = false; }
|
||||
else if(argis("-rsrc")) { PHASE(1); shift(); rsrcdir = args(); }
|
||||
else if(argis("-nogui")) { PHASE(1); noGUI = true; }
|
||||
#ifndef EMSCRIPTEN
|
||||
#if CAP_SDL
|
||||
else if(argis("-font")) { PHASE(1); shift(); fontpath = args(); }
|
||||
else if(argis("-font")) { PHASE(1); shift(); fontpath = args();
|
||||
#ifdef FONTCONFIG
|
||||
font_to_find = "";
|
||||
#endif
|
||||
}
|
||||
#ifdef FONTCONFIG
|
||||
else if(argis("-find-font")) { PHASE(1); shift(); font_to_find = args(); }
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -250,44 +256,54 @@ int arg::readCommon() {
|
|||
else if(argis("-draw")) {
|
||||
PHASE(3); start_game(); drawscreen();
|
||||
}
|
||||
else if(argis("-rotate")) {
|
||||
else if(argis("-sview")) {
|
||||
PHASE(3); start_game();
|
||||
shift(); ld a = argf();
|
||||
shift(); ld b = argf();
|
||||
View = View * spin(M_PI * 2 * a / b);
|
||||
playermoved = false;
|
||||
transmatrix T = View;
|
||||
shift(); View = parsematrix(args());
|
||||
println(hlog, "View is set to ", View);
|
||||
current_display->which_copy = View * inverse(T) * current_display->which_copy;
|
||||
}
|
||||
else if(argis("-rotate-up")) {
|
||||
start_game();
|
||||
shiftmatrix S = ggmatrix(cwt.at->master->move(0)->c7);
|
||||
View = spin(90*degree) * spintox(S.T*C0) * View;
|
||||
}
|
||||
else if(argis("-rotate3")) {
|
||||
PHASE(3); start_game();
|
||||
shift(); ld a = argf();
|
||||
shift(); ld b = argf();
|
||||
View = View * cspin(1, 2, M_PI * 2 * a / b);
|
||||
View = spin90() * spintox(S.T*C0) * View;
|
||||
playermoved = false;
|
||||
}
|
||||
else if(argis("-face-vertex")) {
|
||||
PHASE(3); start_game();
|
||||
auto &ss = currentmap->get_cellshape(cwt.at);
|
||||
View = cspin(0, 2, M_PI/2) * spintox(ss.vertices_only_local[0]);
|
||||
View = cspin90(0, 2) * spintox(ss.vertices_only_local[0]);
|
||||
playermoved = false;
|
||||
}
|
||||
else if(argis("-face-face")) {
|
||||
PHASE(3); start_game();
|
||||
View = cspin(0, 2, M_PI/2);
|
||||
View = cspin90(0, 2);
|
||||
}
|
||||
else if(argis("-grotate")) {
|
||||
PHASE(3); start_game();
|
||||
shift(); int i = argi();
|
||||
else if(argis("-center-vertex")) {
|
||||
PHASE(3); shift(); int i = argi();
|
||||
shift(); int j = argi();
|
||||
shift(); View = View * cspin(i, j, argf());
|
||||
}
|
||||
else if(argis("-cview")) {
|
||||
PHASE(3); start_game();
|
||||
View = Id;
|
||||
shift(); int k = argi();
|
||||
start_game();
|
||||
auto fh = currentmap->get_cellshape(cwt.at).faces[j][k];
|
||||
hyperpoint h = View * fh;
|
||||
if(i == 0) {
|
||||
shift_view_to(shiftless(h));
|
||||
playermoved = false;
|
||||
}
|
||||
if(i == 1) {
|
||||
rotate_view(spintox(h));
|
||||
rotate_view(cspin90(0, 2));
|
||||
}
|
||||
}
|
||||
else if(argis("-exit")) {
|
||||
PHASE(3); printf("Success.\n");
|
||||
PHASE(3);
|
||||
int t = SDL_GetTicks();
|
||||
if(t > 1800 * 1000)
|
||||
println(hlog, "Great Success!\n");
|
||||
else
|
||||
println(hlog, "Success.\n");
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -315,38 +331,58 @@ int arg::readCommon() {
|
|||
clearMessages();
|
||||
}
|
||||
|
||||
else if(argis("-save-mode")) {
|
||||
save_mode_to_file(shift_args());
|
||||
}
|
||||
|
||||
else if(argis("-load-mode")) {
|
||||
try {
|
||||
load_mode_from_file(shift_args());
|
||||
}
|
||||
catch(hstream_exception& e) {
|
||||
println(hlog, "exception!");
|
||||
}
|
||||
}
|
||||
|
||||
// informational
|
||||
else if(argis("-version") || argis("-v")) {
|
||||
printf("HyperRogue version " VER "\n");
|
||||
exit(0);
|
||||
}
|
||||
else if(argis("-L")) {
|
||||
printf("Treasures:\n");
|
||||
printf("+ Treasures:\n");
|
||||
int qty = 0;
|
||||
for(int i=1; i<ittypes; i++)
|
||||
if(itemclass(eItem(i)) == IC_TREASURE)
|
||||
printf(" %s\n", iinf[i].name);
|
||||
printf(" %s\n", iinf[i].name), qty++;
|
||||
printf(" total = %d\n", qty); qty = 0;
|
||||
printf("\n");
|
||||
printf("Orbs:\n");
|
||||
printf("+ Orbs:\n");
|
||||
for(int i=1; i<ittypes; i++)
|
||||
if(itemclass(eItem(i)) == IC_ORB)
|
||||
printf(" %s\n", iinf[i].name);
|
||||
printf(" %s\n", iinf[i].name), qty++;
|
||||
printf(" total = %d\n", qty); qty = 0;
|
||||
printf("\n");
|
||||
printf("Other items:\n");
|
||||
printf("+ Other items:\n");
|
||||
for(int i=1; i<ittypes; i++)
|
||||
if(itemclass(eItem(i)) == IC_OTHER)
|
||||
printf(" %s\n", iinf[i].name);
|
||||
printf(" %s\n", iinf[i].name), qty++;
|
||||
printf(" total = %d\n", qty); qty = 0;
|
||||
printf("\n");
|
||||
printf("Monsters:\n");
|
||||
printf("+ Monsters:\n");
|
||||
for(int i=1; i<motypes; i++)
|
||||
printf(" %s\n", minf[i].name);
|
||||
printf(" %s\n", minf[i].name), qty++;
|
||||
printf(" total = %d\n", qty); qty = 0;
|
||||
printf("\n");
|
||||
printf("Lands:\n");
|
||||
for(int i=1; i<landtypes; i++)
|
||||
printf(" %s\n", linf[i].name);
|
||||
printf("+ Lands:\n");
|
||||
for(int i=1; i<landtypes; i++)
|
||||
printf(" %s\n", linf[i].name), qty++;
|
||||
printf(" total = %d\n", qty); qty = 0;
|
||||
printf("\n");
|
||||
printf("Walls:\n");
|
||||
printf("+ Walls:\n");
|
||||
for(int i=0; i<walltypes; i++)
|
||||
printf(" %s\n", winf[i].name);
|
||||
printf(" %s\n", winf[i].name), qty++;
|
||||
printf(" total = %d\n", qty); qty = 0;
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -405,6 +441,8 @@ EX hookset<int()> hooks_args;
|
|||
|
||||
EX map<string, pair<int, reaction_t>> *added_commands;
|
||||
|
||||
EX bool delayed_start;
|
||||
|
||||
EX namespace arg {
|
||||
|
||||
int read_added_commands() {
|
||||
|
@ -437,6 +475,7 @@ EX namespace arg {
|
|||
void read(int phase) {
|
||||
curphase = phase;
|
||||
callhooks(hooks_config);
|
||||
dynamicval<bool> ds(delayed_start, true);
|
||||
while(pos < isize(argument)) {
|
||||
int r = callhandlers(1, hooks_args);
|
||||
switch (r) {
|
||||
|
|
254
complex.cpp
254
complex.cpp
|
@ -215,10 +215,14 @@ EX namespace elec {
|
|||
if(c->wall == waSea || c->wall == waGrounded) return ecGrounded;
|
||||
if(c->wall == waSandstone || c->wall == waDeadTroll ||
|
||||
c->wall == waDeadTroll2 ||
|
||||
among(c->wall, waBigTree, waSmallTree, waExplosiveBarrel, waRed1, waRed2, waRed3) ||
|
||||
c->wall == waExplosiveBarrel ||
|
||||
c->wall == waVinePlant ||
|
||||
c->wall == waMetal || isAlchAny(c))
|
||||
return isElectricLand(c) ? ecConductor : ecGrounded;
|
||||
if(c->wall == waBigTree || c->wall == waSmallTree)
|
||||
return ecGrounded;
|
||||
if(among(c->wall, waRed1, waRed2, waRed3, waRubble, waDeadfloor2))
|
||||
return ecIsolator;
|
||||
if(c->wall == waBarrier)
|
||||
return ecIsolator;
|
||||
if(c->wall == waChasm)
|
||||
|
@ -644,7 +648,7 @@ struct info {
|
|||
if(newdist == OUT_OF_PRISON && princess::challenge) {
|
||||
addMessage(XLAT("Congratulations! Your score is %1.", its(i->value)));
|
||||
achievement_gain_once("PRINCESS2", rg::princess);
|
||||
if(!cheater) achievement_score(36, i->value);
|
||||
if(!cheater) achievement_score(LB_PRINCESS, i->value);
|
||||
LATE( showMissionScreen(); )
|
||||
}
|
||||
}
|
||||
|
@ -738,7 +742,7 @@ struct info {
|
|||
if(m == moPrincess)
|
||||
addMessage(XLAT("\"I want my revenge. Stun a guard and leave him for me!\"", m));
|
||||
else
|
||||
addMessage(XLAT("\"That felt great. Thanks!\"", m));
|
||||
addMessage(XLAT("\"I wouldn't say killing that guard was not pleasant...\"", m));
|
||||
}
|
||||
else if(msgid == 2 && d >= 70 && inpalace) {
|
||||
addMessage(XLAT("\"Bring me out of here please!\"", m));
|
||||
|
@ -907,6 +911,9 @@ EX namespace clearing {
|
|||
c->mondir = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(c->land == laClearing && ls::horodisk_structure() && celldistAlt(c) >= -1) return;
|
||||
if(c->land == laClearing && ls::voronoi_structure() && celldistAlt(c) >= -20) return;
|
||||
|
||||
if(!eubinary && !horo_ok()) return;
|
||||
// cell *oc = c;
|
||||
|
@ -1172,14 +1179,14 @@ EX namespace whirlpool {
|
|||
EX namespace mirror {
|
||||
|
||||
#if HDR
|
||||
static const int SPINSINGLE = 1;
|
||||
static const int SPINMULTI = 2;
|
||||
static const int GO = 4;
|
||||
static const int ATTACK = 8;
|
||||
static constexpr int SPINSINGLE = 1;
|
||||
static constexpr int SPINMULTI = 2;
|
||||
static constexpr int GO = 4;
|
||||
static constexpr int ATTACK = 8;
|
||||
#endif
|
||||
|
||||
EX bool build(cell *c) {
|
||||
if(kite::in() || sol) return false;
|
||||
if(aperiodic || sol) return false;
|
||||
#if CAP_GP
|
||||
if(GOLDBERG) {
|
||||
if(c == c->master->c7) {
|
||||
|
@ -1210,6 +1217,7 @@ EX namespace mirror {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* int is the owner's cpid */
|
||||
EX vector<pair<int, cellwalker>> mirrors;
|
||||
#if HDR
|
||||
constexpr int LIGHTNING = -1; // passed instead of cpid
|
||||
|
@ -1311,7 +1319,7 @@ EX namespace mirror {
|
|||
|
||||
EX void createMirrors(cellwalker cw, int cpid) {
|
||||
|
||||
if(kite::in() || sol) return;
|
||||
if(aperiodic || sol) return;
|
||||
|
||||
#if CAP_ARCM
|
||||
if(arcm::in()) {
|
||||
|
@ -1453,7 +1461,7 @@ EX namespace mirror {
|
|||
if(c2->monst) {
|
||||
c->monst = moMimic;
|
||||
eMonster m2 = c2->monst;
|
||||
if(!peace::on && canAttack(c,moMimic,c2,m2, 0)) {
|
||||
if(!peace::on && !bow::crossbow_mode() && canAttack(c,moMimic,c2,m2, 0)) {
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG, moMimic);
|
||||
if(!fwd) produceGhost(c2, m2, moMimic);
|
||||
sideAttack(c, m.second.spin, m2, 0);
|
||||
|
@ -1633,8 +1641,8 @@ EX namespace mirror {
|
|||
return cw;
|
||||
}
|
||||
|
||||
static const int CACHESIZE = 1<<12; // must be a power of 2
|
||||
static const int CACHEMASK = CACHESIZE-1;
|
||||
static constexpr int CACHESIZE = 1<<12; // must be a power of 2
|
||||
static constexpr int CACHEMASK = CACHESIZE-1;
|
||||
|
||||
pair<cell*, cellwalker> cache[CACHESIZE];
|
||||
int nextcache;
|
||||
|
@ -1680,6 +1688,7 @@ EX namespace hive {
|
|||
|
||||
EX eMonster randomHyperbug() {
|
||||
int h = hivehard();
|
||||
if(h && markOrb(itOrbLuck)) h /= 4;
|
||||
if(hrand(200) < h)
|
||||
return moBug2;
|
||||
return eMonster(moBug0 + hrand(BUGCOLORS));
|
||||
|
@ -1990,21 +1999,23 @@ EX namespace hive {
|
|||
if(ls::any_chaos() && getDistLimit() <= 5) radius = 4;
|
||||
if(getDistLimit() <= 3) radius = 3;
|
||||
|
||||
for(int i=(ls::any_chaos()?0:2); i<radius; i++)
|
||||
for(int i=(ls::any_chaos()?0:2); i<radius; i++) {
|
||||
bf += revstep;
|
||||
if(ls::hv_structure()) moreBigStuff(bf.at);
|
||||
}
|
||||
cell *citycenter = bf.at;
|
||||
buginfo.clear();
|
||||
|
||||
|
||||
// mark the area with BFS
|
||||
bugcitycell(citycenter, 0);
|
||||
for(int i=0; i<isize(buginfo); i++) {
|
||||
buginfo_t& b(buginfo[i]);
|
||||
cell *c = b.where;
|
||||
int d = b.dist[0];
|
||||
if(ls::hv_structure()) moreBigStuff(c);
|
||||
// ERRORS!
|
||||
if(c->land != laHive && c->land != laNone) return;
|
||||
if(c->bardir != NODIR) return;
|
||||
if(ls::horodisk_structure() ? c->bardir != NOBARRIERS : c->bardir != NODIR) return;
|
||||
if(c->land == laHive && c->landparam >= 100) return;
|
||||
// bfs
|
||||
if(d < radius) for(int t=0; t<c->type; t++)
|
||||
|
@ -2018,7 +2029,8 @@ EX namespace hive {
|
|||
int d = b.dist[0];
|
||||
if(d <= 1 && c->wall == waNone)
|
||||
c->item = itRoyalJelly;
|
||||
preventbarriers(c);
|
||||
if(ls::horodisk_structure()) c->bardir = NOBARRIERS2;
|
||||
else preventbarriers(c);
|
||||
if(d == 9 || d == 6 || d == 3)
|
||||
c->barleft = eLand(d/3),
|
||||
c->barright = eLand(k);
|
||||
|
@ -2119,6 +2131,8 @@ EX namespace heat {
|
|||
if(c->monst == moDesertman) hmod += 4 * xrate;
|
||||
if(c->monst == moAngryDie) hmod += 4 * xrate;
|
||||
if(c->monst == moMonkey) hmod += xrate;
|
||||
if(c->wall == waCharged) hmod += xrate * .25;
|
||||
if(c->wall == waGrounded) hmod -= xrate * .25;
|
||||
if(c->wall == waDeadTroll) hmod -= 2 * xrate;
|
||||
if(c->wall == waDeadTroll2) hmod -= 1.5 * xrate;
|
||||
if(c->wall == waBigStatue) hmod -= .5 * xrate;
|
||||
|
@ -2471,7 +2485,9 @@ EX void livecaves() {
|
|||
if(hv > 0 && c->wall == waNone) {
|
||||
if(c->item && c->cpdist == 1 && markOrb(itOrbWater)) {
|
||||
bool saf = c->item == itOrbSafety;
|
||||
eItem it = c->item;
|
||||
collectItem(c, c);
|
||||
if(it && !c->item) animate_item_throw(c, cwt.at, it);
|
||||
if(saf) return;
|
||||
}
|
||||
c->wall = waSea;
|
||||
|
@ -2506,6 +2522,7 @@ EX namespace tortoise {
|
|||
EX map<cell*, int> emap;
|
||||
EX map<cell*, int> babymap;
|
||||
EX int last;
|
||||
EX int last21tort;
|
||||
|
||||
#if HDR
|
||||
enum tflag {
|
||||
|
@ -2709,6 +2726,7 @@ EX namespace dragon {
|
|||
total += c->hitpoints;
|
||||
if(c->mondir == NODIR) return total;
|
||||
c = c->move(c->mondir);
|
||||
if(!c) return total;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
@ -2737,6 +2755,7 @@ EX namespace dragon {
|
|||
}
|
||||
while(c->mondir != NODIR) {
|
||||
c = c->move(c->mondir);
|
||||
if(!c) return;
|
||||
c->stuntime = 2;
|
||||
}
|
||||
break;
|
||||
|
@ -2794,7 +2813,7 @@ EX namespace sword {
|
|||
};
|
||||
|
||||
/** dimensions available to the Sword */
|
||||
#define SWORDDIM (hybri ? 2 : WDIM)
|
||||
#define SWORDDIM (mhybrid ? 2 : WDIM)
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -2827,7 +2846,7 @@ EX namespace sword {
|
|||
|
||||
EX cell *pos2(cell *c, int s) {
|
||||
int t = c->type;
|
||||
if(hybri) t -= 2;
|
||||
if(mhybrid) t -= 2;
|
||||
s *= 2;
|
||||
s += sword_angles/t;
|
||||
s %= (2 * sword_angles);
|
||||
|
@ -2885,7 +2904,7 @@ EX namespace sword {
|
|||
neighborId(c2, c1);
|
||||
if(s1 < 0 || s2 < 0) return d;
|
||||
if(SWORDDIM == 2) {
|
||||
int sub = (hybri) ? 2 : 0;
|
||||
int sub = (mhybrid) ? 2 : 0;
|
||||
int t2 = c2->type - sub;
|
||||
int t1 = c1->type - sub;
|
||||
if(t1 == 0 || t2 == 0) return d;
|
||||
|
@ -2934,6 +2953,8 @@ EX }
|
|||
|
||||
EX namespace kraken {
|
||||
|
||||
EX map<cell*, bool> half_killed;
|
||||
|
||||
EX cell *head(cell *c) {
|
||||
if(c->monst == moKrakenH) return c;
|
||||
if(c->monst == moKrakenT) return c->move(c->mondir);
|
||||
|
@ -2979,7 +3000,6 @@ EX namespace kraken {
|
|||
}
|
||||
|
||||
EX void attacks() {
|
||||
pathdata pd(2);
|
||||
bool offboat[MAXPLAYER];
|
||||
for(int i=0; i<MAXPLAYER; i++) offboat[i] = false;
|
||||
for(int i=0; i<isize(dcal); i++) {
|
||||
|
@ -3036,10 +3056,13 @@ EX namespace kraken {
|
|||
c3->monst = moNone;
|
||||
}
|
||||
c->monst = moKrakenH;
|
||||
if(half_killed.count(c2)) { half_killed[c] = half_killed[c2]; half_killed.erase(c2); }
|
||||
vector<pair<cell*, cell*> > acells;
|
||||
acells.push_back(make_pair(c2, c));
|
||||
forCellIdEx(c3, i, c) {
|
||||
c3->monst = moKrakenT, c3->mondir = c->c.spin(i), c3->monmirror = c->monmirror ^ c->c.mirror(i), onpath(c3, 0);
|
||||
c3->monst = moKrakenT;
|
||||
c3->mondir = c->c.spin(i);
|
||||
c3->monmirror = c->monmirror ^ c->c.mirror(i);
|
||||
int i0 = (i+c->c.spin(c->mondir)-c->mondir+96+c->type/2) % c2->type;
|
||||
c3->hitpoints = hpcount[i0];
|
||||
acells.push_back(make_pair(c2->move(i0), c3));
|
||||
|
@ -3071,7 +3094,6 @@ EX namespace kraken {
|
|||
}
|
||||
commitAnimations(LAYER_BIG);
|
||||
sleep(c);
|
||||
onpath(c, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3174,49 +3196,63 @@ EX namespace prairie {
|
|||
|
||||
#define RLOW (sphere?(PURE?7:6):PURE?4:2)
|
||||
#define RHIGH (sphere?(PURE?8:9):PURE?11:13)
|
||||
|
||||
EX int get_val(cell *c) {
|
||||
if(ls::hv_structure()) {
|
||||
int a = celldistAlt(c);
|
||||
if(a >= 2) a = 2;
|
||||
a = gmod(18 - a, 20);
|
||||
return a;
|
||||
}
|
||||
return c->LHU.fi.rval;
|
||||
}
|
||||
|
||||
EX bool no_worms(cell *c) {
|
||||
if(c->land != laPrairie) return false;
|
||||
int rv = c->LHU.fi.rval;
|
||||
int rv = get_val(c);
|
||||
return rv > RLOW+1 && rv < RHIGH-1;
|
||||
}
|
||||
|
||||
EX bool isriver(cell *c) {
|
||||
return c->land == laPrairie && c->LHU.fi.rval <= RHIGH && c->LHU.fi.rval >= RLOW;
|
||||
int rv = get_val(c);
|
||||
return c->land == laPrairie && rv <= RHIGH && rv >= RLOW;
|
||||
}
|
||||
|
||||
bool mainriver(cell *c) {
|
||||
return c->LHU.fi.rval <= 8 && c->LHU.fi.rval >= 7;
|
||||
int rv = get_val(c);
|
||||
return rv <= 8 && rv >= 7;
|
||||
}
|
||||
|
||||
EX bool nearriver(cell *c) {
|
||||
return c->LHU.fi.rval == RHIGH+1 || c->LHU.fi.rval == RLOW-1;
|
||||
int rv = get_val(c);
|
||||
return rv == RHIGH+1 || rv == RLOW-1;
|
||||
}
|
||||
|
||||
cell *enter;
|
||||
|
||||
bool opposite(cell *c) {
|
||||
return (c->LHU.fi.rval ^ enter->LHU.fi.rval) & 8;
|
||||
return (get_val(c) ^ get_val(enter)) & 8;
|
||||
}
|
||||
|
||||
bool isleft(cell *c) {
|
||||
return c->LHU.fi.rval & 8;
|
||||
return get_val(c) & 8;
|
||||
}
|
||||
|
||||
int towerleft(cell *c) {
|
||||
return c->LHU.fi.rval;
|
||||
return get_val(c);
|
||||
}
|
||||
|
||||
int towerright(cell *c) {
|
||||
return 15^c->LHU.fi.rval;
|
||||
return 15^get_val(c);
|
||||
}
|
||||
|
||||
EX cell *next(cell *c, int pv IS(1)) {
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c1 = createMov(c, i);
|
||||
cell *c2 = createMov(c, (i+pv+c->type)%c->type);
|
||||
if(c1 && c1->LHU.fi.rval == c->LHU.fi.rval)
|
||||
if(c2 && c2->LHU.fi.rval == c->LHU.fi.rval+1)
|
||||
int rv = get_val(c);
|
||||
if(c1 && get_val(c1) == rv)
|
||||
if(c2 && get_val(c2) == rv+1)
|
||||
if(isNeighbor(c1,c2))
|
||||
return c1;
|
||||
}
|
||||
|
@ -3320,20 +3356,37 @@ EX namespace prairie {
|
|||
return true;
|
||||
}
|
||||
|
||||
EX void generateTreasure_here(cell *c) {
|
||||
int hr = hrand(100);
|
||||
if(hr == 0 && items[itGreenGrass] >= 10 && !inv::on) {
|
||||
c->item = itOrbBull;
|
||||
// orbs.push_back(c);
|
||||
}
|
||||
else if(hr < 1+PRIZEMUL) {
|
||||
placePrizeOrb(c);
|
||||
// if(c->item) orbs.push_back(c);
|
||||
}
|
||||
else if(!ls::hv_structure())
|
||||
tchoices.push_back(c);
|
||||
}
|
||||
|
||||
EX void generateTreasure(cell *c) {
|
||||
// if(nearriver(c) && op
|
||||
if(enter && nearriver(c) && opposite(c) && thisriver(c)) {
|
||||
int hr = hrand(100);
|
||||
if(hr == 0 && items[itGreenGrass] >= 10 && !inv::on) {
|
||||
c->item = itOrbBull;
|
||||
// orbs.push_back(c);
|
||||
if(ls::hv_structure()) {
|
||||
if(get_val(c) == RHIGH + 1) {
|
||||
int cd = celldist(c);
|
||||
int min_cd = cd;
|
||||
cell *c1;
|
||||
c1 = c; for(int a=0; a<3; a++) { forCellEx(c2, c1) setdist(c2, 9, nullptr); c1 = next(c1); if(!c1) return; min_cd = min(min_cd, celldist(c1)); }
|
||||
c1 = c; for(int a=0; a<3; a++) { forCellEx(c2, c1) setdist(c2, 9, nullptr); c1 = prev(c1); if(!c1) return; min_cd = min(min_cd, celldist(c1)); }
|
||||
if(min_cd >= cd-1) forCellEx(c1, c) if(isriver(c1) && celldist(c1) < cd)
|
||||
c->item = itGreenGrass;
|
||||
}
|
||||
else if(hr < 1+PRIZEMUL) {
|
||||
placePrizeOrb(c);
|
||||
// if(c->item) orbs.push_back(c);
|
||||
}
|
||||
else tchoices.push_back(c);
|
||||
}
|
||||
if(get_val(c) == 18 && hrand(100) < 50) c->item = itOrbSafety;
|
||||
if(get_val(c) == 17) generateTreasure_here(c);
|
||||
return;
|
||||
}
|
||||
if(enter && nearriver(c) && opposite(c) && thisriver(c)) generateTreasure_here(c);
|
||||
}
|
||||
|
||||
EX void treasures() {
|
||||
|
@ -3367,7 +3420,7 @@ namespace prairie {
|
|||
|
||||
EX namespace ca {
|
||||
EX ld prob = .2;
|
||||
static const int MAX_NEIGHBOR = 60; /* may be larger than MAX_EDGE due to mineadj */
|
||||
static constexpr int MAX_NEIGHBOR = 60; /* may be larger than MAX_EDGE due to mineadj */
|
||||
string carule[MAX_NEIGHBOR][2];
|
||||
|
||||
EX eWall wlive = waFloorA;
|
||||
|
@ -3454,6 +3507,7 @@ EX namespace ca {
|
|||
}
|
||||
for(int i=0; i<dcs; i++) {
|
||||
cell *c = allcells[i];
|
||||
if(c->land != laCA) continue;
|
||||
auto last = c->wall;
|
||||
c->wall = willlive[i] ? wlive : waNone;
|
||||
if(c->wall != last) {
|
||||
|
@ -3475,6 +3529,7 @@ auto ccm = addHook(hooks_clearmemory, 0, [] () {
|
|||
clearing::stats.clear();
|
||||
clearing::score.clear();
|
||||
tortoise::emap.clear();
|
||||
kraken::half_killed.clear();
|
||||
tortoise::babymap.clear();
|
||||
dragon::target = NULL;
|
||||
#if CAP_FIELD
|
||||
|
@ -3506,6 +3561,8 @@ auto ccm = addHook(hooks_clearmemory, 0, [] () {
|
|||
}) +
|
||||
addHook(hooks_removecells, 0, [] () {
|
||||
for(cell *c: removed_cells) clearing::score.erase(c);
|
||||
for(auto& am: adj_memo) am.clear();
|
||||
for(cell *c: removed_cells) kraken::half_killed.erase(c);
|
||||
eliminate_if(heat::offscreen_heat, is_cell_removed);
|
||||
eliminate_if(heat::offscreen_fire, is_cell_removed);
|
||||
eliminate_if(princess::infos, [] (princess::info*& i) {
|
||||
|
@ -3539,8 +3596,8 @@ int windcodes5676[] = {152,138,172,172,141,158,157,124,119,130,125,143,190,206,2
|
|||
EX namespace windmap {
|
||||
|
||||
#if HDR
|
||||
static const int NOWINDBELOW = 8;
|
||||
static const int NOWINDFROM = 120;
|
||||
static constexpr int NOWINDBELOW = 8;
|
||||
static constexpr int NOWINDFROM = 120;
|
||||
#endif
|
||||
|
||||
map<int, int> getid;
|
||||
|
@ -3578,6 +3635,7 @@ EX namespace windmap {
|
|||
EX void create() {
|
||||
if(disable_bigstuff) return;
|
||||
if(cgflags & qPORTALSPACE) return;
|
||||
if(hat::in()) return;
|
||||
samples.clear();
|
||||
neighbors.clear();
|
||||
getid.clear();
|
||||
|
@ -3587,7 +3645,7 @@ EX namespace windmap {
|
|||
// cw.spin = 0;
|
||||
neighbors.emplace_back();
|
||||
auto &v = neighbors.back();
|
||||
if(NONSTDVAR && !sphere && !arcm::in() && !hybri && !INVERSE)
|
||||
if(NONSTDVAR && !sphere && !arcm::in() && !mhybrid && !INVERSE)
|
||||
for(int l=0; l<S7; l++) {
|
||||
v.push_back(getId(cw + cth + l + wstep + cth));
|
||||
}
|
||||
|
@ -3604,7 +3662,7 @@ EX namespace windmap {
|
|||
if(N == 18920) precomp = windcodes18920;
|
||||
if(N == 5676) precomp = windcodes5676;
|
||||
|
||||
if(precomp && (hyperbolic || hybri) && isize(currfp.matrices)) {
|
||||
if(precomp && (hyperbolic || mhybrid) && isize(currfp.matrices)) {
|
||||
int randval = hrand(isize(currfp.matrices));
|
||||
for(int i=0; i<N; i++)
|
||||
windcodes[i] = precomp[getid[fieldpattern::fieldval_uniq_rand(samples[i].at, randval)]-1];
|
||||
|
@ -3992,12 +4050,25 @@ EX }
|
|||
|
||||
EX namespace dungeon {
|
||||
|
||||
/* use coastvalEdge normally, but celldistAlt in hv_structure */
|
||||
int cvfun(cell *c) {
|
||||
if(ls::hv_structure()) return celldistAltPlus(c);
|
||||
return coastvalEdge(c);
|
||||
}
|
||||
|
||||
void towerError(cell *c) {
|
||||
// only care in the standard geometry -- weird ones are intentionally left buggy
|
||||
if(!weirdhyperbolic && !sphere && !quotient)
|
||||
if(!weirdhyperbolic && !sphere && !quotient && !ls::hv_structure())
|
||||
raiseBuggyGeneration(c, "ivory tower/dungeon generation error");
|
||||
}
|
||||
|
||||
/** for some reason standard generate_around does not work in hv_structure */
|
||||
void gen_around(cell *c) {
|
||||
if(ls::hv_structure()) {
|
||||
forCellEx(c2, c) setdist(c2, 8, c);
|
||||
}
|
||||
else generate_around(c);
|
||||
}
|
||||
void buildIvoryTower(cell *c) {
|
||||
/* if(int(c->landparam) % 5 == 0)
|
||||
c->wall = waCamelot;
|
||||
|
@ -4044,27 +4115,27 @@ EX namespace dungeon {
|
|||
cl.add(c);
|
||||
for(int i=0; i<isize(cl.lst); i++) {
|
||||
cell *c1 = cl.lst[i];
|
||||
generate_around(c1);
|
||||
if(coastvalEdge(c1) == coastvalEdge(c) - 3) {
|
||||
gen_around(c1);
|
||||
if(cvfun(c1) == cvfun(c) - 3) {
|
||||
if(c1->landflags == 3) cnt++;
|
||||
continue;
|
||||
}
|
||||
if(c1->landflags == 3) below++;
|
||||
forCellEx(c2, c1) if(coastvalEdge(c2) < coastvalEdge(c1))
|
||||
forCellEx(c2, c1) if(cvfun(c2) < cvfun(c1))
|
||||
cl.add(c2);
|
||||
}
|
||||
if(cnt) c->wall = waPlatform;
|
||||
else if(below && coastvalEdge(c) < 3) c->wall = waPlatform;
|
||||
else if(below && cvfun(c) < 3) c->wall = waPlatform;
|
||||
}
|
||||
|
||||
|
||||
else if(true) {
|
||||
|
||||
|
||||
cell *c2 = c;
|
||||
cell *c3 = c;
|
||||
|
||||
bool rdepths[5];
|
||||
for(int i=0; i<5; i++) {
|
||||
if(coastvalEdge(c2) == 0) {
|
||||
if(cvfun(c2) == 0) {
|
||||
rdepths[i] = false;
|
||||
}
|
||||
else {
|
||||
|
@ -4074,10 +4145,11 @@ EX namespace dungeon {
|
|||
c4 = c2->move(i);
|
||||
}
|
||||
rdepths[i] = c2 && c3 && c4 && (c2->landflags == 3 || c3->landflags == 3 || c4->landflags == 3);
|
||||
if(c2) generate_around(c2);
|
||||
if(c3) generate_around(c3);
|
||||
c2 = ts::left_parent(c2, coastvalEdge);
|
||||
c3 = ts::right_parent(c3, coastvalEdge);
|
||||
if(c2) gen_around(c2);
|
||||
if(c3) gen_around(c3);
|
||||
|
||||
c2 = ts::left_parent(c2, cvfun);
|
||||
c3 = ts::right_parent(c3, cvfun);
|
||||
if(!c2) { towerError(c); return; }
|
||||
if(!c3) { towerError(c); return; }
|
||||
}
|
||||
|
@ -4085,27 +4157,26 @@ EX namespace dungeon {
|
|||
|
||||
if(rdepths[3]) {
|
||||
c->wall = waPlatform;
|
||||
// if(!c4->item) c4->item = itPalace;
|
||||
}
|
||||
else if(!rdepths[2] && !rdepths[4] && !rdepths[1]) {
|
||||
c2 = c;
|
||||
c3 = c;
|
||||
generate_around(c);
|
||||
cell *c4 = ts::left_of(c, coastvalEdge);
|
||||
cell *c5 = ts::right_of(c, coastvalEdge);
|
||||
gen_around(c);
|
||||
cell *c4 = ts::left_of(c, cvfun);
|
||||
cell *c5 = ts::right_of(c, cvfun);
|
||||
for(int i=0; i<3; i++) {
|
||||
if(coastvalEdge(c2) == 0) break;
|
||||
for(cell *cx: {c2, c3, c4, c5}) if(cx) generate_around(cx);
|
||||
if(cvfun(c2) == 0) break;
|
||||
for(cell *cx: {c2, c3, c4, c5}) if(cx) gen_around(cx);
|
||||
|
||||
if(c2 && c4 && c4->landflags == 3 && c2->landflags != 3 && c4 == ts::left_of(c2, coastvalEdge))
|
||||
if(c2 && c4 && c4->landflags == 3 && c2->landflags != 3 && c4 == ts::left_of(c2, cvfun))
|
||||
c->wall = waLadder;
|
||||
if(c3 && c5 && c5->landflags == 3 && c3->landflags != 3 && c5 == ts::right_of(c3, coastvalEdge))
|
||||
if(c3 && c5 && c5->landflags == 3 && c3->landflags != 3 && c5 == ts::right_of(c3, cvfun))
|
||||
c->wall = waLadder;
|
||||
buildEquidistant(c4); buildEquidistant(c5);
|
||||
if(c2) c2 = ts::left_parent(c2, coastvalEdge);
|
||||
if(c3) c3 = ts::right_parent(c3, coastvalEdge);
|
||||
if(c4) c4 = ts::left_parent(c4, coastvalEdge);
|
||||
if(c5) c5 = ts::right_parent(c5, coastvalEdge);
|
||||
if(!ls::hv_structure()) { buildEquidistant(c4); buildEquidistant(c5); }
|
||||
if(c2) c2 = ts::left_parent(c2, cvfun);
|
||||
if(c3) c3 = ts::right_parent(c3, cvfun);
|
||||
if(c4) c4 = ts::left_parent(c4, cvfun);
|
||||
if(c5) c5 = ts::right_parent(c5, cvfun);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4123,16 +4194,17 @@ EX namespace dungeon {
|
|||
|
||||
manual_celllister cl;
|
||||
cl.add(c);
|
||||
int d = coastvalEdge(c);
|
||||
int d = cvfun(c);
|
||||
|
||||
for(int i=0; i<isize(cl.lst); i++) {
|
||||
cell *c1 = cl.lst[i];
|
||||
if(ls::hv_structure()) forCellEx(c4, c1) moreBigStuff(c4);
|
||||
generate_around(c1);
|
||||
int d1 = d - coastvalEdge(c);
|
||||
int d1 = d - cvfun(c);
|
||||
if(c1->landflags == 3) rdepths[d1] = true;
|
||||
if(c1->landflags == 1) switchcount++;
|
||||
if(d1 == 4) break;
|
||||
forCellEx(c2, c1) if(coastvalEdge(c2) < coastvalEdge(c1))
|
||||
forCellEx(c2, c1) if(cvfun(c2) < cvfun(c1))
|
||||
cl.add(c2);
|
||||
}
|
||||
}
|
||||
|
@ -4143,7 +4215,7 @@ EX namespace dungeon {
|
|||
cell *c3 = c;
|
||||
|
||||
for(int i=0; i<5; i++) {
|
||||
if(coastvalEdge(c2) == 0) {
|
||||
if(cvfun(c2) == 0) {
|
||||
rdepths[i] = false;
|
||||
}
|
||||
else {
|
||||
|
@ -4155,10 +4227,14 @@ EX namespace dungeon {
|
|||
rdepths[i] = c2 && c3 && c4 && (c2->landflags == 3 || c3->landflags == 3 || c4->landflags == 3);
|
||||
if((c2&&c2->landflags == 1) || (c3&&c3->landflags == 1) || (c4&&c4->landflags == 1))
|
||||
switchcount++;
|
||||
if(ls::hv_structure()) {
|
||||
forCellEx(c4, c2) moreBigStuff(c4);
|
||||
forCellEx(c4, c3) moreBigStuff(c3);
|
||||
}
|
||||
generate_around(c2);
|
||||
generate_around(c3);
|
||||
c2 = ts::left_parent(c2, coastvalEdge);
|
||||
c3 = ts::right_parent(c3, coastvalEdge);
|
||||
c2 = ts::left_parent(c2, cvfun);
|
||||
c3 = ts::right_parent(c3, cvfun);
|
||||
if(!c2) { towerError(c); return 0; }
|
||||
if(!c3) { towerError(c); return 0; }
|
||||
}
|
||||
|
@ -4194,6 +4270,7 @@ EX namespace dungeon {
|
|||
}
|
||||
|
||||
cell *random_child(cell *c, const cellfunction& cf) {
|
||||
if(ls::hv_structure()) forCellEx(c4, c) moreBigStuff(c4);
|
||||
generate_around(c);
|
||||
vector<cell*> children;
|
||||
forCellEx(c2, c) if(cf(c2) > cf(c)) children.push_back(c2);
|
||||
|
@ -4208,7 +4285,7 @@ EX namespace dungeon {
|
|||
|
||||
if(true) {
|
||||
|
||||
if(coastvalEdge(c) == 1) forCellEx(c2, c)
|
||||
if(cvfun(c) == 1) forCellEx(c2, c)
|
||||
if(c2->land != laBarrier && c2->land != laDungeon) {
|
||||
c->wall = waLadder;
|
||||
c->wparam = 3;
|
||||
|
@ -4217,9 +4294,10 @@ EX namespace dungeon {
|
|||
int df = dungeonFlags(c);
|
||||
|
||||
if(df&1) {
|
||||
if(ls::hv_structure()) forCellEx(c4, c) moreBigStuff(c4);
|
||||
generate_around(c);
|
||||
int df1 = WDIM == 3 ? 0 : dungeonFlags(ts::left_of(c, coastvalEdge));
|
||||
int df2 = WDIM == 3 ? 0 : dungeonFlags(ts::right_of(c, coastvalEdge));
|
||||
int df1 = WDIM == 3 ? 0 : dungeonFlags(ts::left_of(c, cvfun));
|
||||
int df2 = WDIM == 3 ? 0 : dungeonFlags(ts::right_of(c, cvfun));
|
||||
|
||||
c->wparam = 0;
|
||||
if(hrand(100) < (c->landparam % 5 == 0 ? 80 : 20)) {
|
||||
|
@ -4239,11 +4317,11 @@ EX namespace dungeon {
|
|||
|
||||
if(c->wparam) {
|
||||
cell *c2 =
|
||||
WDIM == 3 ? random_child(c, coastvalEdge) :
|
||||
c->wparam == 1 ? ts::add(c, 1, 2, coastvalEdge) :
|
||||
c->wparam == 2 ? ts::add(c, -1, -2, coastvalEdge) :
|
||||
c->wparam == 3 ? ts::add(c, 1, 3, coastvalEdge) :
|
||||
c->wparam == 4 ? ts::add(c, -1, -3, coastvalEdge) :
|
||||
WDIM == 3 ? random_child(c, cvfun) :
|
||||
c->wparam == 1 ? ts::add(c, 1, 2, cvfun) :
|
||||
c->wparam == 2 ? ts::add(c, -1, -2, cvfun) :
|
||||
c->wparam == 3 ? ts::add(c, 1, 3, cvfun) :
|
||||
c->wparam == 4 ? ts::add(c, -1, -3, cvfun) :
|
||||
NULL;
|
||||
|
||||
if(c2) {
|
||||
|
@ -4265,7 +4343,7 @@ EX namespace dungeon {
|
|||
int neargateEq = 0;
|
||||
int qup = 0;
|
||||
forCellEx(c2, c) {
|
||||
int d = coastvalEdge(c2) - coastvalEdge(c);
|
||||
int d = cvfun(c2) - cvfun(c);
|
||||
if(isGate(c2->wall)) {
|
||||
neargate++;
|
||||
if(d>0) neargateDown++;
|
||||
|
|
59
complex2.cpp
59
complex2.cpp
|
@ -44,7 +44,7 @@ EX namespace brownian {
|
|||
c->landparam += val;
|
||||
}
|
||||
|
||||
static const int FAT = (-100); // less than 0
|
||||
static constexpr int FAT = (-100); // less than 0
|
||||
|
||||
void recurse(cell *c, int fatten_from) {
|
||||
int dl = getDistLimit();
|
||||
|
@ -161,16 +161,16 @@ EX namespace brownian {
|
|||
|
||||
if(!hyperbolic) c->wall = waNone, c->landparam = 256;
|
||||
|
||||
if(c->landparam == 0 && ls::single()) c->land = laOcean;
|
||||
if(c->landparam == 0 && (ls::single() || ls::hv_structure())) c->land = laOcean;
|
||||
|
||||
ONEMPTY {
|
||||
if(hrand(10000) < min(250, 100 + 2 * PT(kills[moAcidBird] + kills[moBrownBug], 50)) * (25 + min(items[itBrownian], 100)) / 25 && c->landparam >= 4 && c->landparam < 24)
|
||||
c->item = itBrownian;
|
||||
if(hrand_monster(8000) < 15 + items[itBrownian])
|
||||
if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian])
|
||||
c->monst = moAcidBird;
|
||||
else if(hrand_monster(8000) < 15)
|
||||
else if(hrand_monster_in(laBrownian, 8000) < 15)
|
||||
c->monst = moAlbatross;
|
||||
else if(hrand_monster(8000) < 15 + items[itBrownian]) {
|
||||
else if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian]) {
|
||||
c->monst = moBrownBug;
|
||||
c->hitpoints = 3;
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ extern array<feature, 21> features;
|
|||
|
||||
#define VF [] (cell *c)
|
||||
|
||||
bool hrand_var(int i) { return hrand_monster(i) < 25 + items[itVarTreasure] + yendor::hardness(); }
|
||||
bool hrand_var(int i) { return hrand_monster_in(laVariant, i) < 25 + items[itVarTreasure] + yendor::hardness(); }
|
||||
|
||||
array<feature, 21> features {{
|
||||
feature{(color_t)(-0x202020), 5, moNecromancer, VF {
|
||||
|
@ -354,6 +354,8 @@ vector<string> knight_names = {
|
|||
"JeLomun", "kip", "Warmonger", "Fooruman", "Zyalin", "Prezombie", "ashley89", "bjobae", "MFErtre", "Roaringdragon2", "howilovepi", "Yulgash", "Sir Endipitous", "Roshlev",
|
||||
"BTernaryTau", "HiGuy", "coper", "Tirear", "qoala _", "Tyzone", "Tiegon", "Airin", "Metroid26", "Sklorg", "Fumblestealth", "Toph", "Tzaphqiel", "jruderman", "ray",
|
||||
"Deathroll", "Sinquetica", "mootmoot", "Noobinator", "freeofme", "Helyea", "Snakebird Priestess", "brisingre", "Khashishi", "Shiny", "kabado", "Berenthas", "Misery", "Altripp", "Aldrenean",
|
||||
// via itch.io and reports on Discord
|
||||
"AntiRogue"
|
||||
};
|
||||
|
||||
map<cell*, int> knight_id;
|
||||
|
@ -905,6 +907,12 @@ EX void ambush(cell *c, int dogs) {
|
|||
addMessage(XLAT("You are ambushed!"));
|
||||
}
|
||||
|
||||
EX void guard_attack() {
|
||||
addMessage(XLAT("%The1 alarms other dogs as it dies!", moHunterDog));
|
||||
for(cell *c: dcal) if(c->monst == moHunterGuard) c->monst = moHunterDog;
|
||||
ambush(cwt.at, 7);
|
||||
}
|
||||
|
||||
EX }
|
||||
|
||||
EX namespace dice {
|
||||
|
@ -1197,7 +1205,8 @@ EX namespace dice {
|
|||
|
||||
int si = dw->facesides;
|
||||
|
||||
if(c == lmouseover_distant) {
|
||||
if(inHighQual) ;
|
||||
else if(c == lmouseover_distant) {
|
||||
set<cell*> visited;
|
||||
struct celldata_t {
|
||||
cell* c;
|
||||
|
@ -1239,7 +1248,7 @@ EX namespace dice {
|
|||
}
|
||||
}
|
||||
|
||||
shiftmatrix V1 = V * ddspin(c, dir) * spin(M_PI);
|
||||
shiftmatrix V1 = V * ddspin(c, dir, M_PI);
|
||||
if(dd.mirrored) V1 = V1 * MirrorY;
|
||||
|
||||
// loop:
|
||||
|
@ -1260,8 +1269,8 @@ EX namespace dice {
|
|||
|
||||
if(1) {
|
||||
dynamicval<eGeometry> g(geometry, gSphere);
|
||||
ld alpha = 360 * degree / dw->order;
|
||||
ld beta = 180 * degree / dw->facesides;
|
||||
ld alpha = TAU / dw->order;
|
||||
ld beta = M_PI / dw->facesides;
|
||||
inradius = edge_of_triangle_with_angles(alpha, beta, beta);
|
||||
outradius = edge_of_triangle_with_angles(beta, alpha, beta);
|
||||
}
|
||||
|
@ -1273,11 +1282,13 @@ EX namespace dice {
|
|||
dynamicval<eGeometry> g(geometry, gSphere);
|
||||
hyperpoint de = direct_exp(log_shift);
|
||||
S = rgpushxto0(de);
|
||||
#if MAXMDIM >= 4
|
||||
if(GDIM == 3) {
|
||||
for(int i=0; i<4; i++) swap(S[i][2], S[i][3]);
|
||||
for(int i=0; i<4; i++) swap(S[2][i], S[3][i]);
|
||||
for(int i=0; i<MAXMDIM; i++) swap(S[i][2], S[i][3]);
|
||||
for(int i=0; i<MAXMDIM; i++) swap(S[2][i], S[3][i]);
|
||||
}
|
||||
for(int i=0; i<4; i++) S[i][1] *= -1;
|
||||
#endif
|
||||
for(int i=0; i<MAXMDIM; i++) S[i][1] *= -1;
|
||||
}
|
||||
|
||||
add_to_queue(S, val);
|
||||
|
@ -1320,7 +1331,7 @@ EX namespace dice {
|
|||
|
||||
for(int d=0; d<si; d++) {
|
||||
dynamicval<eGeometry> g(geometry, highdim);
|
||||
add_to_queue(T * cspin(0, 1, 2*M_PI*d/si) * cspin(2, 0, inradius) * cspin(0, 1, M_PI-2*M_PI*dw->spins[ws][d]/si), dw->sides[ws][d]);
|
||||
add_to_queue(T * cspin(0, 1, TAU*d/si) * cspin(2, 0, inradius) * cspin(0, 1, M_PI-TAU*dw->spins[ws][d]/si), dw->sides[ws][d]);
|
||||
}
|
||||
|
||||
if(1) {
|
||||
|
@ -1348,22 +1359,28 @@ EX namespace dice {
|
|||
auto sphere_to_space = [&] (hyperpoint h) {
|
||||
if(fpp) return h;
|
||||
if(osphere) {
|
||||
h[2] = 1 - h[2]; h[3] = 0;
|
||||
h[2] = 1 - h[2];
|
||||
#if MAXMDIM > 3
|
||||
h[3] = 0;
|
||||
#endif
|
||||
return h;
|
||||
}
|
||||
if(oeuclid) { h[2] = 1-h[2]; return h; }
|
||||
ld z = asin_auto(h[2]);
|
||||
h = zpush(-z) * h;
|
||||
h[2] = h[3]; h[3] = 0;
|
||||
#if MAXMDIM > 3
|
||||
h[2] = h[3];
|
||||
h[3] = 0;
|
||||
#endif
|
||||
dynamicval<eGeometry> g(geometry, orig);
|
||||
return zshift(h, geom3::scale_at_lev(z));
|
||||
return orthogonal_move(h, z);
|
||||
};
|
||||
|
||||
for(int d=0; d<=si; d++) {
|
||||
hyperpoint h, hs;
|
||||
if(1) {
|
||||
dynamicval<eGeometry> g(geometry, highdim);
|
||||
h = zpush(base_to_base) * T * cspin(0, 1, 2*M_PI*(d+.5)/si) * cspin(2, 0, outradius) * zpush0(dieradius);
|
||||
h = zpush(base_to_base) * T * cspin(0, 1, TAU*(d+.5)/si) * cspin(2, 0, outradius) * zpush0(dieradius);
|
||||
if(d < si) face[d] = h;
|
||||
hs = sphere_to_space(h);
|
||||
}
|
||||
|
@ -1393,7 +1410,7 @@ EX namespace dice {
|
|||
cy = face[1] - (face[3] + face[4]) * .4;
|
||||
}
|
||||
|
||||
queuecurve(V1, 0xFFFFFFFF, color & 0xFFFFFF9F, prio);
|
||||
queuecurve(V1, (poly_outline == OUTLINE_NONE) ? 0xFFFFFFFF : poly_outline, color & 0xFFFFFF9F, prio);
|
||||
|
||||
#if !CAP_EXTFONT
|
||||
if(!vid.usingGL) continue;
|
||||
|
@ -1461,5 +1478,9 @@ EX namespace dice {
|
|||
EX bool swap_forbidden(cell *a, cell *b) { return false; }
|
||||
EX void chaos_swap(cellwalker wa, cellwalker wb) {}
|
||||
EX }
|
||||
|
||||
EX namespace mine {
|
||||
EX bool in_minesweeper() { return false; }
|
||||
EX }
|
||||
#endif
|
||||
}
|
||||
|
|
2641
config.cpp
2641
config.cpp
File diff suppressed because it is too large
Load Diff
150
content.cpp
150
content.cpp
|
@ -260,7 +260,7 @@ MONSTER( 'T', 0x00FFFF, "Fjord Troll", moFjordTroll, CF_FACE_UP | CF_TROLL, RESE
|
|||
MONSTER( 'E', 0x0000FF, "Water Elemental", moWaterElemental, CF_FACE_UP | CF_NOBLOW | CF_NONLIVING | CF_HIGH_THREAT, RESERVED, moWaterElemental,
|
||||
"Wherever this powerful being goes, the living fjord "
|
||||
"sinks below water, non-magical boats are destroyed, and fires are extinguished.\n\n"
|
||||
"As a special case, you can attack the Water Elemental from the water, without drowning immediately."
|
||||
"As a special case, you can attack the Water Elemental from the water with your blade, without drowning immediately."
|
||||
)
|
||||
MONSTER( 'M', 0xD0D0D0, "Mouse", moMouse, CF_FACE_SIDE | CF_NOGHOST | CF_GOK | CF_FRIENDLY | CF_FACING | CF_UNARMED | CF_IGNORE_PLATE, RESERVED, moNone, princessdesc)
|
||||
MONSTER( 'M', 0xD0D0D0, "Mouse", moMouseMoved, CF_FACE_SIDE | CF_NOGHOST | CF_GOK | CF_FRIENDLY | CF_FACING | CF_UNARMED | CF_MOVED, RESERVED, moNone, princessdesc)
|
||||
|
@ -295,7 +295,7 @@ MONSTER( 'F', 0xC35817, "Giant Fox", moRedFox, CF_FACE_SIDE | CF_HIGH_THREAT, RE
|
|||
MONSTER( 'C', 0x8080FF, "Wind Crow", moWindCrow, CF_FACE_SIDE | CF_BIRD | CF_FLYING | CF_IGNORE_PLATE | CF_HIGH_THREAT, RESERVED, moEagle,
|
||||
"A large bird who likes strong winds. Just as you, it can fly quickly in the wind."
|
||||
)
|
||||
MONSTER( 'G', 0xC0FFC0, "Friendly Ghost", moFriendlyGhost, CF_FACE_SIDE | CF_NOGHOST | CF_GOK | CF_FRIENDLY | CF_FACING | CF_GHOST | CF_FLYING | CF_ATTACK_THRU_VINE | CF_ATTACK_NONADJACENT | CF_IGNORE_PLATE, RESERVED, moFriendlyGhost,
|
||||
MONSTER( 'G', 0xC0FFC0, "Friendly Ghost", moFriendlyGhost, CF_FACE_SIDE | CF_NOGHOST | CF_GOK | CF_FRIENDLY | CF_FACING | CF_GHOST | CF_FLYING | CF_ATTACK_THRU_VINE | CF_ATTACK_NONADJACENT | CF_IGNORE_PLATE | CF_NONLIVING, RESERVED, moFriendlyGhost,
|
||||
"Friendly ghosts are friendly beings who can go through any obstacles. However, "
|
||||
"unlike most friends, they tend to fly away from you."
|
||||
)
|
||||
|
@ -458,7 +458,7 @@ ITEM( '*', 0x8080FF, "Ice Sapphire", itSapphire, IC_TREASURE, ZERO, RESERVED, os
|
|||
ITEM( '*', 0xEEFF20, "Hyperstone", itHyperstone, IC_TREASURE, ZERO, RESERVED, osNone,
|
||||
"These bright yellow gems can be found only by those who have mastered the Crossroads."
|
||||
)
|
||||
ITEM( '[', 0x8080FF, "Key", itKey, IC_OTHER, ZERO, RESERVED, osNone,
|
||||
ITEM( '[', 0x8080FF, "Key", itKey, IC_OTHER, ZERO | IF_FIREPROOF, RESERVED, osNone,
|
||||
"That's all you need to unlock the Orb of Yendor! Well... as long as you are able to return to the Orb that this key unlocks...\n\n"
|
||||
"Each key unlocks only the Orb of Yendor which led you to it."
|
||||
)
|
||||
|
@ -873,8 +873,8 @@ WALL( '#', 0x8080FF, "ice wall", waIcewall, WF_WALL | WF_HIGHWALL | WF_HEATCOLOR
|
|||
"Ice Walls melt after some time has passed."
|
||||
)
|
||||
WALL( '#', 0xC06000, "great wall", waBarrier, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, barrierhelp)
|
||||
WALL( '+', 0x900030, "red slime", waFloorA, ZERO | WF_ALCHEMY, RESERVED, 0, sgFloorA, slimehelp )
|
||||
WALL( '+', 0x300090, "blue slime", waFloorB, ZERO | WF_ALCHEMY, RESERVED, 0, sgFloorB, slimehelp )
|
||||
WALL( '+', 0x900030, "red slime", waFloorA, ZERO | WF_ALCHEMY | WF_ON, RESERVED, 0, sgFloorA, slimehelp )
|
||||
WALL( '+', 0x300090, "blue slime", waFloorB, ZERO | WF_ALCHEMY | WF_ON, RESERVED, 0, sgFloorB, slimehelp )
|
||||
WALL( '#', 0xA0D0A0, "living wall", waCavewall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgCave, cavehelp)
|
||||
WALL( '.', 0x306060, "living floor", waCavefloor, ZERO, RESERVED, 0, sgNone,cavehelp)
|
||||
WALL( '#', 0xD03030, "dead rock troll", waDeadTroll, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, trollhelp)
|
||||
|
@ -888,13 +888,13 @@ WALL( '%', 0xFFC0C0, "Cloud of Mirage", waCloud, WF_WALL, RESERVED, 0, sgNone,
|
|||
"Tiny droplets of magical water. You see images of yourself inside them. "
|
||||
"Go inside the cloud, to make these images help you.")
|
||||
WALL( '^', 0x8D694F, "Thumper", waThumperOff, WF_WALL | WF_ACTIVABLE | WF_THUMPER, RESERVED, 0, sgNone, thumpdesc)
|
||||
WALL( '^', 0x804000, "Fire", waFire, WF_FIRE | WF_TIMEOUT, RESERVED, 0, sgNone,
|
||||
WALL( '^', 0x804000, "Fire", waFire, WF_FIRE | WF_TIMEOUT | WF_ON, RESERVED, 0, sgNone,
|
||||
"This cell is on fire. Most beings and items cannot survive."
|
||||
)
|
||||
WALL( '+', 0xC0C0C0, "ancient grave", waAncientGrave, WF_WALL | WF_HIGHWALL | WF_GRAVE, RESERVED, 0, sgNone,
|
||||
WALL( '+', 0xC0C0C0, "ancient grave", waAncientGrave, WF_WALL | WF_HIGHWALL | WF_GRAVE | WF_NONBLOCK, RESERVED, 0, sgNone,
|
||||
"An ancient grave."
|
||||
)
|
||||
WALL( '+', 0xD0D080, "fresh grave", waFreshGrave, WF_WALL | WF_HIGHWALL | WF_GRAVE, RESERVED, 0, sgNone,
|
||||
WALL( '+', 0xD0D080, "fresh grave", waFreshGrave, WF_WALL | WF_HIGHWALL | WF_GRAVE | WF_NONBLOCK, RESERVED, 0, sgNone,
|
||||
"A fresh grave. Necromancers like those."
|
||||
)
|
||||
WALL( '#', 0x00FFFF, "column", waColumn, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone,
|
||||
|
@ -917,10 +917,10 @@ WALL( '#', 0x006000, "tree", waSmallTree, WF_WALL | WF_HIGHWALL | WF_STDTREE | W
|
|||
WALL( '#', 0x421C52*2, "vine", waVinePlant, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgVine, vinehelp)
|
||||
WALL( ':', 0x006000, "vine", waVineHalfA, ZERO | WF_NOFLIGHT | WF_HALFVINE, RESERVED, 0, sgVine, hvinehelp)
|
||||
WALL( ';', 0x006000, "vine", waVineHalfB, ZERO | WF_NOFLIGHT | WF_HALFVINE, RESERVED, 0, sgVine, hvinehelp)
|
||||
WALL( '^', 0x804000, "partial fire", waPartialFire, WF_FIRE | WF_TIMEOUT, RESERVED, 0, sgNone, "This cell is partially on fire.")
|
||||
WALL( '#', 0xA07070, "dead wall", waDeadwall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgCave, deadcavehelp)
|
||||
WALL( '.', 0x401010, "dead floor", waDeadfloor, ZERO, RESERVED, 0, sgNone,deadcavehelp)
|
||||
WALL( '.', 0x905050, "rubble", waDeadfloor2, ZERO, RESERVED, 1, sgNone, "Dead floor, with some rubble.")
|
||||
WALL( '^', 0x804000, "partial fire", waPartialFire, WF_FIRE | WF_TIMEOUT | WF_ON, RESERVED, 0, sgNone, "This cell is partially on fire.")
|
||||
WALL( '#', 0xA07070, "dead wall", waDeadwall, WF_WALL | WF_HIGHWALL | WF_ON, RESERVED, 0, sgCave, deadcavehelp)
|
||||
WALL( '.', 0x401010, "dead floor", waDeadfloor, ZERO | WF_ON, RESERVED, 0, sgNone,deadcavehelp)
|
||||
WALL( '.', 0x905050, "rubble", waDeadfloor2, ZERO | WF_ON, RESERVED, 1, sgNone, "Dead floor, with some rubble.")
|
||||
WALL( '#', 0xD0D010, "weird rock", waWaxWall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone,
|
||||
"A weirdly colored rock. Hyperentomologists claim that the "
|
||||
"Hyperbug armies use these rocks to navigate back home after a victorious battle."
|
||||
|
@ -932,7 +932,7 @@ WALL( '#', 0x8080C0, "crystal cabinet", waGlass, WF_WALL, RESERVED, 0, sgNone,
|
|||
"using an Orb of Aether, your Aether power will be completely drained."
|
||||
)
|
||||
WALL( '#', 0xC0C0C0, "wall of Camelot", waCamelot, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, camelothelp )
|
||||
WALL( '+', 0xA06000, "Round Table", waRoundTable, WF_WALL, RESERVED, 1, sgNone, camelothelp )
|
||||
WALL( '+', 0xA06000, "Round Table", waRoundTable, WF_WALL | WF_NONBLOCK | WF_ON, RESERVED, 1, sgNone, camelothelp )
|
||||
WALL( '=', 0x0000A0, "moat of Camelot", waCamelotMoat, WF_WATER, RESERVED, 0, sgWater, camelothelp)
|
||||
WALL( '+', 0x606060, "big statue of Cthulhu", waBigStatue, WF_WALL, RESERVED, 0, sgNone,
|
||||
"These statues of Cthulhu are too large to carry, and they don't look too "
|
||||
|
@ -941,24 +941,24 @@ WALL( '+', 0x606060, "big statue of Cthulhu", waBigStatue, WF_WALL, RESERVED, 0,
|
|||
"a statue, you push the statue to the cell you left.\n"
|
||||
)
|
||||
WALL( '=', 0x0000A0, "sea", waSea, WF_WATER, RESERVED, 0, sgWater, caribbeanhelp)
|
||||
WALL( '+', 0x0000A0, "boat", waBoat, ZERO | WF_BOAT | WF_NOFLIGHT, RESERVED, 0, sgNone,
|
||||
WALL( '+', 0x0000A0, "boat", waBoat, ZERO | WF_BOAT | WF_NOFLIGHT | WF_ON, RESERVED, 0, sgNone,
|
||||
"Hyperbolic pirates do not need huge ships, since so many lands to conquest "
|
||||
"are so close. These small boats are enough for them.\n\n"
|
||||
"Boats allow you to go through water. If you are in a boat, you can move into "
|
||||
"a water cell (and the boat will come with you)."
|
||||
)
|
||||
WALL( '.', 0x00FF00, "island", waCIsland, ZERO | WF_CISLAND, RESERVED, 0, sgNone, cislandhelp)
|
||||
WALL( '.', 0x80C060, "island", waCIsland2, ZERO | WF_CISLAND, RESERVED, 0, sgNone, cislandhelp)
|
||||
WALL( '.', 0x00FF00, "island", waCIsland, ZERO | WF_CISLAND | WF_ON, RESERVED, 0, sgNone, cislandhelp)
|
||||
WALL( '.', 0x80C060, "island", waCIsland2, ZERO | WF_CISLAND | WF_ON, RESERVED, 0, sgNone, cislandhelp)
|
||||
WALL( '#', 0x006000, "tree", waCTree, WF_WALL | WF_HIGHWALL | WF_CONE | WF_CISLAND, RESERVED, 0, sgTree,
|
||||
"The forests of Caribbean are too dense to be traversed by humans, "
|
||||
"and they are hard to burn. Many colorful parrots can be found there."
|
||||
)
|
||||
WALL( ',', 0x800000, "rock I", waRed1, ZERO | WF_RED, RESERVED, 1, sgNone, redrockhelp)
|
||||
WALL( ':', 0xC00000, "rock II", waRed2, ZERO | WF_RED, RESERVED, 2, sgNone, redrockhelp)
|
||||
WALL( ';', 0xFF0000, "rock III", waRed3, ZERO | WF_RED, RESERVED, 3, sgNone, redrockhelp)
|
||||
WALL( ',', 0x800000, "rock I", waRed1, ZERO | WF_RED | WF_ON, RESERVED, 1, sgNone, redrockhelp)
|
||||
WALL( ':', 0xC00000, "rock II", waRed2, ZERO | WF_RED | WF_ON, RESERVED, 2, sgNone, redrockhelp)
|
||||
WALL( ';', 0xFF0000, "rock III", waRed3, ZERO | WF_RED | WF_ON, RESERVED, 3, sgNone, redrockhelp)
|
||||
WALL( '.', 0xD0D0D0, "minefield", waMineUnknown, ZERO, RESERVED, 0, sgNone, minedesc)
|
||||
WALL( '.', 0xD0D0D0, "minefield", waMineMine, ZERO, RESERVED, 0, sgNone, minedesc)
|
||||
WALL( '.', 0x909090, "cell without mine", waMineOpen, ZERO, RESERVED, 0, sgNone, minedesc)
|
||||
WALL( '.', 0x909090, "cell without mine", waMineOpen, ZERO | WF_ON, RESERVED, 0, sgNone, minedesc)
|
||||
WALL( '+', 0x808000, "stranded boat", waStrandedBoat, ZERO | WF_BOAT | WF_NOFLIGHT, RESERVED, 0, sgNone,
|
||||
"This boat cannot go through the sand. But if you sit inside and "
|
||||
"wait for the tide, you will be able to use it to travel through the Ocean."
|
||||
|
@ -966,17 +966,17 @@ WALL( '+', 0x808000, "stranded boat", waStrandedBoat, ZERO | WF_BOAT | WF_NOFLIG
|
|||
WALL( '#', 0xFFD500, "palace wall", waPalace, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, palacedesc )
|
||||
WALL( '+', 0xFFFFFF, "closed gate", waClosedGate, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, gatedesc )
|
||||
WALL( '-', 0x404040, "open gate", waOpenGate, ZERO, RESERVED, 0, sgNone, gatedesc )
|
||||
WALL( '_', 0xC00000, "closing plate", waClosePlate, ZERO, RESERVED, 0, sgNone, gatedesc )
|
||||
WALL( '_', 0x00C050, "opening plate", waOpenPlate, ZERO, RESERVED, 0, sgNone, gatedesc )
|
||||
WALL( '_', 0x202020, "trapdoor", waTrapdoor, ZERO, RESERVED, 0, sgNone, "This floor will fall after someone goes there. Go quickly!" )
|
||||
WALL( '+', 0xFF0000, "giant rug", waGiantRug, ZERO, RESERVED, 0, sgNone,
|
||||
WALL( '_', 0xC00000, "closing plate", waClosePlate, ZERO | WF_ON, RESERVED, 0, sgNone, gatedesc )
|
||||
WALL( '_', 0x00C050, "opening plate", waOpenPlate, ZERO | WF_ON, RESERVED, 0, sgNone, gatedesc )
|
||||
WALL( '_', 0x202020, "trapdoor", waTrapdoor, ZERO | WF_ON, RESERVED, 0, sgNone, "This floor will fall after someone goes there. Go quickly!" )
|
||||
WALL( '+', 0xFF0000, "giant rug", waGiantRug, ZERO | WF_ON, RESERVED, 0, sgNone,
|
||||
"This is the biggest Hypersian Rug you have ever seen! "
|
||||
"Unfortunately, it is too large to take it as a trophy." )
|
||||
WALL( '#', 0xfffff0, "platform", waPlatform, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "You can stand here.")
|
||||
WALL( '#', 0x909090, "stone gargoyle", waGargoyle, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, gargdesc)
|
||||
WALL( '.', 0xB0B0B0, "stone gargoyle floor", waGargoyleFloor, ZERO, RESERVED, 1, sgNone, gargdesc)
|
||||
WALL( '.', 0x909090, "rubble", waRubble, ZERO, RESERVED, 1, sgNone, "Some rubble.")
|
||||
WALL( '+', 0x804000, "ladder", waLadder, ZERO, RESERVED, 0, sgNone,
|
||||
WALL( '#', 0x909090, "stone gargoyle", waGargoyle, WF_WALL | WF_HIGHWALL | WF_NONBLOCK, RESERVED, 0, sgNone, gargdesc)
|
||||
WALL( '.', 0xB0B0B0, "stone gargoyle floor", waGargoyleFloor, ZERO | WF_ON, RESERVED, 1, sgNone, gargdesc)
|
||||
WALL( '.', 0x909090, "rubble", waRubble, ZERO | WF_ON, RESERVED, 1, sgNone, "Some rubble.")
|
||||
WALL( '+', 0x804000, "ladder", waLadder, ZERO | WF_ON, RESERVED, 0, sgNone,
|
||||
"You can use this ladder to climb the Tower."
|
||||
)
|
||||
WALL( '#', 0xC0C0C0, "limestone wall", waStone, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "Simply a wall. Mostly.")
|
||||
|
@ -985,13 +985,13 @@ WALL( '^', 0x804000, "Bonfire", waBonfireOff, WF_WALL | WF_ACTIVABLE, RESERVED,
|
|||
)
|
||||
WALL( '^', 0x8D694F, "Thumper", waThumperOn, WF_WALL | WF_TIMEOUT | WF_PUSHABLE | WF_THUMPER, RESERVED, 0, sgNone,
|
||||
"A device that attracts sandworms and other enemies. You need to activate it.")
|
||||
WALL( '^', 0x804000, "Eternal Fire", waEternalFire, WF_FIRE, RESERVED, 0, sgNone,
|
||||
WALL( '^', 0x804000, "Eternal Fire", waEternalFire, WF_FIRE | WF_ON, RESERVED, 0, sgNone,
|
||||
"This fire never burns out."
|
||||
)
|
||||
WALL( '.', 0x909090, "stone gargoyle bridge", waGargoyleBridge, ZERO, RESERVED, 1, sgNone, gargdesc)
|
||||
WALL( '.', 0x909090, "stone gargoyle bridge", waGargoyleBridge, ZERO | WF_ON, RESERVED, 1, sgNone, gargdesc)
|
||||
WALL( '#', 0x309060, "temporary wall", waTempWall, WF_WALL | WF_HIGHWALL | WF_TIMEOUT, RESERVED, 0, sgNone, twdesc)
|
||||
WALL( '.', 0x309060, "temporary floor", waTempFloor, ZERO | WF_TIMEOUT, RESERVED, 1, sgNone, twdesc)
|
||||
WALL( '.', 0x309060, "temporary bridge", waTempBridge, ZERO | WF_TIMEOUT, RESERVED, 1, sgNone, twdesc)
|
||||
WALL( '.', 0x309060, "temporary floor", waTempFloor, ZERO | WF_TIMEOUT | WF_ON, RESERVED, 1, sgNone, twdesc)
|
||||
WALL( '.', 0x309060, "temporary bridge", waTempBridge, ZERO | WF_TIMEOUT | WF_ON, RESERVED, 1, sgNone, twdesc)
|
||||
WALL( '#', 0x3030FF, "charged wall", waCharged, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, elecdesc)
|
||||
WALL( '#', 0xFF3030, "grounded wall", waGrounded, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, elecdesc)
|
||||
WALL( '#', 0xA0A060, "sandstone wall", waSandstone, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, elecdesc)
|
||||
|
@ -1009,8 +1009,8 @@ WALL( '#', 0x764e7c, "rosebush", waRose, WF_WALL | WF_HIGHWALL | WF_THORNY, RESE
|
|||
WALL( '#', 0xC0C000, "warp gate", waWarpGate, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone,
|
||||
"This gate separates the warped area from the normal land.")
|
||||
WALL( '+', 0x804000, "trunk", waTrunk, ZERO | WF_NOFLIGHT, RESERVED, 0, sgNone, "The skeleton of a tree.")
|
||||
WALL( '-', 0x402000, "solid branch", waSolidBranch, ZERO, RESERVED, 0, sgNone, "Branches here could bear your weight easily.")
|
||||
WALL( ':', 0x804000, "weak branch", waWeakBranch, ZERO, RESERVED, 0, sgNone,
|
||||
WALL( '-', 0x402000, "solid branch", waSolidBranch, ZERO | WF_ON, RESERVED, 0, sgNone, "Branches here could bear your weight easily.")
|
||||
WALL( ':', 0x804000, "weak branch", waWeakBranch, ZERO | WF_ON, RESERVED, 0, sgNone,
|
||||
"Branches here will bear you weight, but if you use them to move (not fall) to an unstable place, they will break.")
|
||||
WALL( '+', 0x60C060, "canopy", waCanopy, ZERO, RESERVED, 0, sgNone,
|
||||
"Only thin twigs and leaves here. They may bear fruits, but for you, these cells count "
|
||||
|
@ -1018,33 +1018,33 @@ WALL( '+', 0x60C060, "canopy", waCanopy, ZERO, RESERVED, 0, sgNone,
|
|||
)
|
||||
WALL( '#', 0xD0C060, "barrow wall", waBarrowWall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "This wall is quite strong. You will need another way in.")
|
||||
WALL( '#', 0x90A060, "barrow", waBarrowDig, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "Your Orb of the Sword can be used to dig here.")
|
||||
WALL( '#', 0xE0E0E0, "stone statue", waPetrified, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, "A petrified creature.")
|
||||
WALL( '#', 0xE0E0E0, "stone statue", waPetrified, WF_WALL | WF_HIGHWALL | WF_NONBLOCK, RESERVED, 0, sgNone, "A petrified creature.")
|
||||
WALL( '.', 0xE8E8E8, "tower of Camelot", waTower, ZERO, RESERVED, 3, sgNone, camelothelp)
|
||||
WALL( '-', 0x402000, "big bush", waBigBush, ZERO | WF_NOFLIGHT, RESERVED, 0, sgNone,
|
||||
WALL( '-', 0x402000, "big bush", waBigBush, ZERO | WF_NOFLIGHT | WF_ON, RESERVED, 0, sgNone,
|
||||
"You can hold this bush to climb the Lost Mountain. "
|
||||
"Bushes block the movement of birds."
|
||||
)
|
||||
WALL( ':', 0x804000, "small bush", waSmallBush, ZERO | WF_NOFLIGHT, RESERVED, 0, sgNone,
|
||||
WALL( ':', 0x804000, "small bush", waSmallBush, ZERO | WF_NOFLIGHT | WF_ON, RESERVED, 0, sgNone,
|
||||
"You can hold this bush to climb the Lost Mountain, "
|
||||
"but it is not very strong -- it will get destroyed "
|
||||
"if you climb from it into an unstable location. "
|
||||
"Bushes block the movement of birds.")
|
||||
WALL( '.', 0xFFFF00, "Reptile floor", waReptile, ZERO | WF_REPTILE, RESERVED, 0, sgNone, reptiledesc)
|
||||
WALL( '.', 0xFFFF00, "Reptile bridge", waReptileBridge, ZERO | WF_REPTILE, RESERVED, 0, sgNone, reptiledesc)
|
||||
WALL( '.', 0xFFFF00, "invisible floor", waInvisibleFloor, ZERO, RESERVED, 0, sgNone, NODESCYET)
|
||||
WALL( '.', 0xFFFF00, "Reptile floor", waReptile, ZERO | WF_REPTILE | WF_ON, RESERVED, 0, sgNone, reptiledesc)
|
||||
WALL( '.', 0xFFFF00, "Reptile bridge", waReptileBridge, ZERO | WF_REPTILE | WF_ON, RESERVED, 0, sgNone, reptiledesc)
|
||||
WALL( '.', 0xFFFF00, "invisible floor", waInvisibleFloor, ZERO | WF_ON, RESERVED, 0, sgNone, NODESCYET)
|
||||
WALL( '#', 0xC0C0FF, "mirror wall", waMirrorWall, WF_WALL, RESERVED, 0, sgNone, mirroreddesc)
|
||||
WALL( '.', 0xE0E0E0, "stepping stones", waPetrifiedBridge, ZERO, RESERVED, 1, sgNone, "A petrified creature.")
|
||||
WALL( '.', 0xE0E0E0, "stepping stones", waPetrifiedBridge, WF_ON, RESERVED, 1, sgNone, "A petrified creature.")
|
||||
WALL( '#', 0x309060, "temporary wall", waTempBridgeBlocked, WF_WALL | WF_HIGHWALL | WF_TIMEOUT, RESERVED, 0, sgNone, twdesc)
|
||||
WALL( 'S', 0xB0B0B0, "warrior statue", waTerraWarrior, WF_WALL, RESERVED, 0, sgNone, terradesc)
|
||||
WALL( '=', 0xB0B0B0, "bubbling slime", waBubble, ZERO | WF_CHASM, RESERVED, 0, sgNone, NODESC)
|
||||
WALL( '^', 0xD00000, "arrow trap", waArrowTrap, ZERO, RESERVED, 0, sgNone, arrowtrapdesc)
|
||||
WALL( '^', 0xD00000, "arrow trap", waArrowTrap, WF_ON, RESERVED, 0, sgNone, arrowtrapdesc)
|
||||
WALL( '=', 0xE2E2E2, "mercury river", waMercury, ZERO | WF_CHASM, RESERVED, 0, sgNone, "A river of mercury.")
|
||||
WALL( '&', 0xD00000, "lava", waMagma, ZERO, RESERVED, 1, sgNone, lavadesc)
|
||||
WALL( '=', 0x804000, "dock", waDock, ZERO, RESERVED, 0, sgNone, "A dock.")
|
||||
WALL( '^', 0xFF8000, "burning dock", waBurningDock, WF_FIRE | WF_TIMEOUT, RESERVED, 0, sgNone, "A burning dock.")
|
||||
WALL( '=', 0x804000, "dock", waDock, ZERO | WF_ON, RESERVED, 0, sgNone, "A dock.")
|
||||
WALL( '^', 0xFF8000, "burning dock", waBurningDock, WF_FIRE | WF_TIMEOUT | WF_ON, RESERVED, 0, sgNone, "A burning dock.")
|
||||
WALL( '#', 0xE04030, "ruin wall", waRuinWall, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, ruindesc)
|
||||
WALL( '#', 0xA04060, "Brownian generator", waBrownian, WF_WALL | WF_HIGHWALL, RESERVED, 0, sgNone, NODESC)
|
||||
WALL( '^', 0xC05000, "fire trap", waFireTrap, ZERO, RESERVED, 0, sgNone,
|
||||
WALL( '^', 0xC05000, "fire trap", waFireTrap, ZERO | WF_ON, RESERVED, 0, sgNone,
|
||||
"This trap will explode when stepped on, setting all the adjacent cells on fire. However, this happens on the next turn, "
|
||||
"so you can safely escape if you are fast enough.")
|
||||
WALL( '^', 0xFD692F, "Explosive Barrel", waExplosiveBarrel, WF_WALL | WF_PUSHABLE, RESERVED, 0, sgNone,
|
||||
|
@ -1256,7 +1256,7 @@ LAND( 0x606060, "Zebra", laZebra, ZERO, itZebra, RESERVED, "Everything in this L
|
|||
NATIVE((m == moOrangeDog) ? 2 : 0)
|
||||
REQ(GOLD(R30) ITEMS(itFeather, U10))
|
||||
|
||||
LAND( 0xC08080, "Plane of Fire", laEFire, ZERO | LF_ELEMENTAL, itElemental, RESERVED, elemdesc)
|
||||
LAND( 0xFFA080, "Plane of Fire", laEFire, ZERO | LF_ELEMENTAL, itElemental, RESERVED, elemdesc)
|
||||
NATIVE(m == moFireElemental ? 2 : isNative(laElementalWall, m))
|
||||
REQAS(laElementalWall,)
|
||||
|
||||
|
@ -1276,7 +1276,7 @@ LAND( 0x4040FF, "Crossroads III", laCrossroads3, ZERO, itHyperstone, RESERVED,
|
|||
"An alternate layout of the Crossroads. Great Walls cross here at right angles."
|
||||
)
|
||||
NATIVE(0)
|
||||
REQ(NUMBER(orbsUnlocked(), lands_for_hell(), XLAT("Finished lands required: %1 (collect %2 treasure)\n", "9", its(R10))))
|
||||
REQ(NUMBER(orbsUnlocked(), lands_for_cr3(), XLAT("Finished lands required: %1 (collect %2 treasure)\n", "9", its(R10))))
|
||||
|
||||
LAND( 0x4040C0, "Sea Border", laOceanWall, ZERO | LF_TECHNICAL | LF_SEA, itNone, RESERVED, "Border between seas.")
|
||||
// REQAS(laOcean,)
|
||||
|
@ -1285,7 +1285,12 @@ LAND( 0x4040C0, "Sea Border", laOceanWall, ZERO | LF_TECHNICAL | LF_SEA, itNone,
|
|||
|
||||
LAND( 0x4040C0, "Elemental Planes", laElementalWall, ZERO | LF_ELEMENTAL, itElemental, RESERVED, elemdesc)
|
||||
NATIVE((m == moAirElemental || m == moEarthElemental || m == moWaterElemental || m == moFireElemental) ? 1 : 0)
|
||||
REQ(KILL(moAirElemental, laWhirlwind) KILL(moWaterElemental, laLivefjord) KILL(moEarthElemental, laDeadCaves) KILL(moFireElemental, laDragon))
|
||||
REQ(
|
||||
IFINGAME(laWhirlwind, KILL(moAirElemental, laWhirlwind), ITEMS(itDiamond, U10))
|
||||
IFINGAME(laLivefjord, KILL(moWaterElemental, laLivefjord), ITEMS(itElixir, U10))
|
||||
IFINGAME(laDeadCaves, KILL(moEarthElemental, laDeadCaves), ITEMS(itGold, U10))
|
||||
IFINGAME(laDragon, KILL(moFireElemental, laDragon), ITEMS(itSpice, U10))
|
||||
)
|
||||
|
||||
LAND( 0xE08020, "Canvas", laCanvas, ZERO | LF_TECHNICAL, itNone, RESERVED, "A fake Land with colored floors.")
|
||||
NATIVE(0)
|
||||
|
@ -1293,11 +1298,11 @@ LAND( 0xE08020, "Canvas", laCanvas, ZERO | LF_TECHNICAL, itNone, RESERVED, "A fa
|
|||
|
||||
LAND( 0x00C000, "Palace Quest", laPrincessQuest, ZERO, itSavedPrincess, RESERVED, princessdesc) // fake
|
||||
NATIVE(isNative(laPalace, m))
|
||||
REQ(ACCONLY(laPalace) KILL(moVizier, laPalace))
|
||||
REQ(ACCONLY(laPalace) INMODE(princess::challenge) KILL(moVizier, laPalace))
|
||||
|
||||
LAND( 0xD0D060, "Wild West", laWildWest, ZERO, itBounty, RESERVED, wildwestdesc)
|
||||
NATIVE((m == moOutlaw) ? 2 : 0)
|
||||
REQ( NEVER )
|
||||
REQ( ALWAYS )
|
||||
|
||||
LAND( 0x80A080, "Land of Storms", laStorms, ZERO | LF_TROLL | LF_ELECTRIC, itFulgurite, RESERVED, elecdesc)
|
||||
NATIVE((m == moMetalBeast || m == moMetalBeast2 || m == moStormTroll) ? 1 : 0)
|
||||
|
@ -1388,7 +1393,14 @@ LAND( 0x90A548, "Trollheim", laTrollheim, ZERO, itTrollEgg, RESERVED,
|
|||
"these Trolls yourself?"
|
||||
)
|
||||
NATIVE(isTroll(m) ? 1 : 0)
|
||||
REQ( KILL(moTroll, laCaves) KILL(moDarkTroll, laDeadCaves) KILL(moRedTroll, laRedRock) KILL(moStormTroll, laStorms) KILL(moForestTroll, laOvergrown) KILL(moFjordTroll, laLivefjord) )
|
||||
REQ(
|
||||
IFINGAME(laCaves, KILL(moTroll, laCaves), ITEMS(itSpice, 10))
|
||||
IFINGAME(laDeadCaves, KILL(moDarkTroll, laDeadCaves), ITEMS(itGold, 10))
|
||||
IFINGAME(laRedRock, KILL(moRedTroll, laRedRock), ITEMS(itSpice, 10))
|
||||
IFINGAME(laStorms, KILL(moStormTroll, laStorms), ITEMS(itElixir, 10))
|
||||
IFINGAME(laOvergrown, KILL(moForestTroll, laOvergrown), ITEMS(itRuby, 10))
|
||||
IFINGAME(laLivefjord, KILL(moFjordTroll, laLivefjord), ITEMS(itGold, 10))
|
||||
)
|
||||
|
||||
LAND( 0xFF7518, "Halloween", laHalloween, ZERO, itTreat, RESERVED, halloweendesc)
|
||||
NATIVE((m == moGhost || m == moZombie || m == moWitch ||
|
||||
|
@ -1400,13 +1412,16 @@ LAND( 0xFF7518, "Halloween", laHalloween, ZERO, itTreat, RESERVED, halloweendesc
|
|||
m == moLancer || m == moFireFairy ||
|
||||
m == moBomberbird || m == moRatlingAvenger ||
|
||||
m == moVineBeast || m == moDragonHead || m == moDragonTail) ? 1 : 0)
|
||||
REQ( NEVER )
|
||||
REQ( ALWAYS )
|
||||
|
||||
LAND( 0x605040, "Dungeon", laDungeon, ZERO | LF_GRAVITY | LF_EQUI, itSlime, RESERVED,
|
||||
"The result of a collaboration of the Great Vizier and the Wizard of the Ivory Tower."
|
||||
)
|
||||
NATIVE(m == moBat ? 2 : m == moSkeleton || m == moGhost ? 1 : 0)
|
||||
REQ(ITEMS(itPalace, U5) ITEMS(itIvory, U5))
|
||||
REQ(
|
||||
IFINGAME(laPalace, ITEMS(itPalace, U5), ITEMS(itDiamond, U10))
|
||||
IFINGAME(laIvoryTower, ITEMS(itIvory, U5), ITEMS(itElixir, U10))
|
||||
)
|
||||
|
||||
LAND( 0x603000, "Lost Mountain", laMountain, ZERO | LF_GRAVITY | LF_CYCLIC, itAmethyst, RESERVED,
|
||||
"Gravitational anomalies in the Jungle create mountains "
|
||||
|
@ -1415,7 +1430,11 @@ LAND( 0x603000, "Lost Mountain", laMountain, ZERO | LF_GRAVITY | LF_CYCLIC, itAm
|
|||
"Cells adjacent to Ivies count as stable (but Ivies "
|
||||
"cannot climb themselves or other Ivies).")
|
||||
NATIVE(m == moEagle || m == moMonkey || isIvy(m) || m == moFriendlyIvy ? 1 : 0)
|
||||
REQ(ITEMS(itRuby, U5) ITEMS(itIvory, U5) ACCONLY(laJungle))
|
||||
REQ(
|
||||
ITEMS(itRuby, U5)
|
||||
IFINGAME(laIvoryTower, ITEMS(itIvory, U5), ITEMS(itElixir, U10))
|
||||
ACCONLY(laJungle)
|
||||
)
|
||||
|
||||
LAND( 0xFFFF00, "Reptiles", laReptile, ZERO, itDodeca, RESERVED, reptiledesc)
|
||||
NATIVE(m == moReptile ? 1 : 0)
|
||||
|
@ -1435,7 +1454,7 @@ LAND( 0xC000C0, "Crossroads V", laCrossroads5, ZERO, itHyperstone, RESERVED, "Ex
|
|||
|
||||
LAND( 0xC0C0C0, "Cellular Automaton", laCA, ZERO | LF_TECHNICAL, itNone, RESERVED, cadesc)
|
||||
NATIVE(0)
|
||||
REQ(NEVER)
|
||||
REQ(ALWAYS)
|
||||
|
||||
LAND( 0xC0C0FF, "Mirror Wall", laMirrorWall, ZERO | LF_TECHNICAL | LF_INMIRRORORWALL, itShard, RESERVED, mirroreddesc)
|
||||
NATIVE(isNative(laMirror, m))
|
||||
|
@ -1463,7 +1482,7 @@ LAND( 0xA06000, "Volcanic Wasteland", laVolcano, ZERO, itLavaLily, RESERVED, lav
|
|||
|
||||
LAND( 0x8080FF, "Blizzard", laBlizzard, ZERO | LF_ICY, itBlizzard, RESERVED, blizzarddesc)
|
||||
NATIVE((m == moVoidBeast || m == moIceGolem) ? 2 : 0)
|
||||
REQ(ITEMS(itDiamond, U5) ITEMS(itWindstone, U5))
|
||||
REQ(IFINGAME(laWhirlwind, ITEMS(itDiamond, U5) ITEMS(itWindstone, U5), ITEMS(itDiamond, 10) GOLD(R60)))
|
||||
|
||||
LAND( 0x207068, "Hunting Ground", laHunting, ZERO, itHunting, RESERVED, huntingdesc)
|
||||
NATIVE(m == moHunterDog ? 1 : 0)
|
||||
|
@ -1491,7 +1510,9 @@ LAND( 0x80FF00, "Docks", laDocks, ZERO | LF_SEA, itDock, RESERVED, NODESCYET)
|
|||
|
||||
LAND( 0x306030, "Ruined City", laRuins, ZERO, itRuins, RESERVED, ruindesc)
|
||||
NATIVE(among(m, moPair, moHexDemon, moAltDemon, moMonk, moCrusher) ? 2 : m == moSkeleton ? 1 : 0)
|
||||
REQ(KILL(moSkeleton, laPalace))
|
||||
REQ(
|
||||
IFINGAME(laPalace, KILL(moSkeleton, laPalace), ITEMS(itRuby, U10))
|
||||
)
|
||||
|
||||
LAND( 0x306030, "Magnetosphere", laMagnetic, ZERO, itMagnet, RESERVED, NODESCYET)
|
||||
NATIVE(isMagneticPole(m) ? 2 : 0)
|
||||
|
@ -1548,9 +1569,9 @@ LAND( 0x30FF30, "Irradiated Field", laVariant, ZERO, itVarTreasure, RESERVED,
|
|||
|
||||
LAND( 0x202020, "Space Rocks", laAsteroids, ZERO, itAsteroid, RESERVED, rock_description)
|
||||
ITEM( '!', 0xFFD0D0, "Fuel", itAsteroid, IC_TREASURE, ZERO, RESERVED, osNone, rock_description)
|
||||
MONSTER('A', 0x606040, "Space Rock", moAsteroid, ZERO, RESERVED, moAsteroid, rock_description)
|
||||
MONSTER('A', 0x606040, "Space Rock", moAsteroid, ZERO, RESERVED, moYeti, rock_description)
|
||||
NATIVE(m == moAsteroid ? 2 : 0)
|
||||
REQ( NEVER )
|
||||
REQ( ALWAYS )
|
||||
|
||||
LAND( 0x00C0C0, "Wetland", laWet, ZERO, itWet, RESERVED,
|
||||
"Some people have definitely drowned in this treacherous area. Better be careful!"
|
||||
|
@ -1591,7 +1612,7 @@ ITEM( 'o', 0x808080, "Orb of Impact", itOrbImpact, IC_ORB, ZERO, RESERVED, osUti
|
|||
"Whenever you use a ranged Orb to achieve an effect, all the single-tile monsters adjacent to the target "
|
||||
"location are stunned."
|
||||
)
|
||||
WALL( '#', 0x00C000, "shrub", waShrub, WF_WALL | WF_HIGHWALL | WF_STDTREE | WF_CONE, RESERVED, 0, sgNone,
|
||||
WALL( '#', 0x00C000, "shrub", waShrub, WF_WALL | WF_HIGHWALL | WF_STDTREE | WF_CONE | WF_NONBLOCK, RESERVED, 0, sgNone,
|
||||
"A strange small tree that cannot be attacked with mundane weapons nor phased though. "
|
||||
"It can be vaulted over, though."
|
||||
)
|
||||
|
@ -1638,7 +1659,7 @@ WALL( '$', 0xFD692F, "Crate", waCrateCrate, WF_WALL | WF_PUSHABLE, RESERVED, 0,
|
|||
"These crates can be pushed."
|
||||
)
|
||||
|
||||
WALL( '.', 0x40FD40, "Target", waCrateTarget, 0, RESERVED, 0, sgNone,
|
||||
WALL( '.', 0x40FD40, "Target", waCrateTarget, 0 | WF_ON, RESERVED, 0, sgNone,
|
||||
"Push all your crates on targets."
|
||||
)
|
||||
|
||||
|
@ -1729,6 +1750,11 @@ MONSTER('d', 0x901020, "Angry Die", moAngryDie, ZERO, RESERVED, moAnimatedDie,
|
|||
"You have made a die unhappy. Taste the revenge! This one won't forgive you, no matter what you do."
|
||||
)
|
||||
|
||||
ITEM('}', 0xFFFF80, "Crossbow", itCrossbow, IC_NAI, ZERO, RESERVED, osNone,
|
||||
"Your crossbow. Press 'f' or click it in the inventory to toggle firing mode. In firing mode, select a tile to see the trajectory, then "
|
||||
"click again to fire. After firing, the crossbow takes some time to reload."
|
||||
)
|
||||
|
||||
//shmupspecials
|
||||
MONSTER( '@', 0xC0C0C0, "Rogue", moPlayer, CF_FACE_UP | CF_PLAYER, RESERVED, moNone, "In the Shoot'em Up mode, you are armed with thrown Knives.")
|
||||
MONSTER( '*', 0xC0C0C0, "Knife", moBullet, ZERO | CF_BULLET, RESERVED, moNone, "A simple, but effective, missile, used by rogues.")
|
||||
|
@ -1771,3 +1797,5 @@ MONSTER( '*', 0, "vertex", moRogueviz, ZERO | CF_TECHNICAL, RESERVED, moN
|
|||
#undef ACCONLY2
|
||||
#undef ACCONLY3
|
||||
#undef ACCONLYF
|
||||
#undef IFINGAME
|
||||
#undef INMODE
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
[Desktop Entry]
|
||||
Name=HyperRogue
|
||||
Comment=Roguelike in a non-euclidean world
|
||||
Exec=hyperrogue
|
||||
Icon=hyperrogue
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Game;AdventureGame;
|
204
control.cpp
204
control.cpp
|
@ -26,6 +26,7 @@ EX bool holdmouse;
|
|||
EX int getcstat, lgetcstat;
|
||||
EX ld getcshift;
|
||||
EX bool inslider;
|
||||
EX bool invslider;
|
||||
EX int slider_x;
|
||||
|
||||
EX function <void(int sym, int uni)> keyhandler = [] (int sym, int uni) {};
|
||||
|
@ -33,7 +34,7 @@ EX function <bool(SDL_Event &ev)> joyhandler = [] (SDL_Event &ev) {return false;
|
|||
|
||||
#if HDR
|
||||
// what part of the compass does 'skip turn'
|
||||
static const auto SKIPFAC = .4;
|
||||
static constexpr auto SKIPFAC = .4;
|
||||
#endif
|
||||
|
||||
// is the player using mouse? (used for auto-cross)
|
||||
|
@ -66,6 +67,7 @@ EX ld shiftmul = 1;
|
|||
|
||||
EX cell *mouseover, *mouseover2, *lmouseover, *lmouseover_distant;
|
||||
EX ld modist, modist2;
|
||||
EX shiftmatrix mouseoverV;
|
||||
|
||||
EX int lastt;
|
||||
|
||||
|
@ -82,7 +84,7 @@ EX bool mouseout2() {
|
|||
EX movedir vectodir(hyperpoint P) {
|
||||
|
||||
transmatrix U = unshift(ggmatrix(cwt.at));
|
||||
if(GDIM == 3 && WDIM == 2) U = current_display->radar_transform * U;
|
||||
if(embedded_plane && cgi.emb->is_same_in_same()) U = current_display->radar_transform_post * current_display->radar_transform * U;
|
||||
|
||||
P = direct_exp(lp_iapply(P));
|
||||
|
||||
|
@ -93,12 +95,13 @@ EX movedir vectodir(hyperpoint P) {
|
|||
|
||||
vector<ld> dirdist(cwt.at->type);
|
||||
|
||||
auto TC0 = tile_center();
|
||||
|
||||
for(int i=0; i<cwt.at->type; i++) {
|
||||
transmatrix T = currentmap->adj(cwt.at, (cwt + i).spin);
|
||||
ld d1 = geo_dist(U * T * C0, Centered * P);
|
||||
ld d2 = geo_dist(U * T * C0, Centered * C0);
|
||||
ld d1 = geo_dist(U * T * TC0, Centered * P);
|
||||
ld d2 = geo_dist(U * T * TC0, Centered * C0);
|
||||
dirdist[i] = d1 - d2;
|
||||
//xspinpush0(-i * 2 * M_PI /cwt.at->type, .5), P);
|
||||
}
|
||||
|
||||
movedir res;
|
||||
|
@ -117,15 +120,13 @@ EX movedir vectodir(hyperpoint P) {
|
|||
}
|
||||
|
||||
EX void remission() {
|
||||
if(!canmove && (cmode & sm::NORMAL)) showMissionScreen();
|
||||
if(!canmove && (cmode & sm::NORMAL) && !game_keys_scroll) showMissionScreen();
|
||||
}
|
||||
|
||||
EX hyperpoint move_destination_vec(int d) {
|
||||
if(WDIM == 2) return spin(-d * M_PI/4) * smalltangent();
|
||||
// else if(WDIM == 2 && pmodel == mdPerspective) return cspin(0, 2, d * M_PI/4) * tC0(pushone());
|
||||
// else if(WDIM == 2) return spin(-d * M_PI/4) * tC0(pushone());
|
||||
else if(d&1) return cspin(0, 1, d > 4 ? M_PI/2 : -M_PI/2) * smalltangent();
|
||||
else return cspin(0, 2, d * M_PI/4) * smalltangent();
|
||||
if(WDIM == 2 && (!embedded_plane || cgi.emb->is_same_in_same())) return spin(-d * 45._deg) * smalltangent();
|
||||
else if(d&1) return cspin(0, 1, d > 4 ? 45._deg : -45._deg) * smalltangent();
|
||||
else return cspin(0, 2, d * 45._deg) * smalltangent();
|
||||
}
|
||||
|
||||
EX void movepckeydir(int d) {
|
||||
|
@ -211,16 +212,30 @@ EX void mousemovement() {
|
|||
EX SDL_Joystick* sticks[8];
|
||||
EX int numsticks;
|
||||
|
||||
EX void initJoysticks() {
|
||||
EX bool joysticks_initialized;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
|
||||
{
|
||||
printf("Failed to initialize joysticks.\n");
|
||||
numsticks = 0;
|
||||
return;
|
||||
#if HDR
|
||||
enum eJoystickInit { jiNoJoystick, jiFast, jiWait };
|
||||
#endif
|
||||
EX eJoystickInit joy_init = jiFast;
|
||||
|
||||
#if CAP_THREAD
|
||||
EX std::thread *joythread;
|
||||
std::atomic<bool> joystick_done(false);
|
||||
#endif
|
||||
|
||||
EX void initJoysticks_async() {
|
||||
if(joy_init == jiNoJoystick) return;
|
||||
#if CAP_THREAD
|
||||
if(joy_init == jiWait) { initJoysticks(); return; }
|
||||
joythread = new std::thread([] { initJoysticks(); joystick_done = true; });
|
||||
#else
|
||||
initJoysticks();
|
||||
#endif
|
||||
}
|
||||
|
||||
DEBB(DF_INIT, ("init joysticks"));
|
||||
EX void countJoysticks() {
|
||||
DEBB(DF_INIT, ("opening joysticks"));
|
||||
numsticks = SDL_NumJoysticks();
|
||||
if(numsticks > 8) numsticks = 8;
|
||||
for(int i=0; i<numsticks; i++) {
|
||||
|
@ -234,6 +249,22 @@ EX void initJoysticks() {
|
|||
}
|
||||
}
|
||||
|
||||
EX void initJoysticks() {
|
||||
|
||||
DEBBI(DF_INIT, ("init joystick"));
|
||||
|
||||
DEBB(DF_INIT, ("init joystick subsystem"));
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
|
||||
{
|
||||
printf("Failed to initialize joysticks.\n");
|
||||
numsticks = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
countJoysticks();
|
||||
joysticks_initialized = true;
|
||||
}
|
||||
|
||||
EX void closeJoysticks() {
|
||||
DEBB(DF_INIT, ("close joysticks"));
|
||||
for(int i=0; i<numsticks; i++) {
|
||||
|
@ -356,17 +387,26 @@ EX void full_forward_camera(ld t) {
|
|||
}
|
||||
}
|
||||
|
||||
EX void full_strafe_camera(ld t) {
|
||||
EX void full_cstrafe_camera(int dir, ld t) {
|
||||
if(GDIM == 3) {
|
||||
shift_view(ctangent(0, t * camera_speed));
|
||||
shift_view(ctangent(dir, t * camera_speed));
|
||||
didsomething = true;
|
||||
playermoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
EX void full_strafe_camera(ld t) { full_cstrafe_camera(0, t); }
|
||||
|
||||
EX void full_ystrafe_camera(ld t) {
|
||||
if(walking::on) { walking::eye_level += t; if(walking::eye_level < 1e-3) walking::eye_level = 1e-3; }
|
||||
else full_cstrafe_camera(1, t);
|
||||
}
|
||||
|
||||
|
||||
EX ld third_person_rotation = 0;
|
||||
|
||||
EX void full_rotate_camera(int dir, ld val) {
|
||||
if(!val) return;
|
||||
if(rug::rug_control() && lshiftclick) {
|
||||
val *= camera_rot_speed;
|
||||
hyperpoint h;
|
||||
|
@ -392,7 +432,8 @@ EX void full_rotate_camera(int dir, ld val) {
|
|||
else if(GDIM == 3) {
|
||||
val *= camera_rot_speed;
|
||||
if(third_person_rotation) shift_view(ctangent(2, -third_person_rotation)), didsomething = true, playermoved = false;
|
||||
ld max_angle = quarter_circle - 1e-4;
|
||||
ld max_angle = 90._deg - 1e-4;
|
||||
ld max_angle1 = 90._deg - 0.5e-4;
|
||||
if(walking::on && dir == 1) {
|
||||
max_angle /= degree;
|
||||
walking::eye_angle += val * walking::eye_angle_scale / degree;
|
||||
|
@ -403,9 +444,9 @@ EX void full_rotate_camera(int dir, ld val) {
|
|||
hyperpoint vv = vertical_vector();
|
||||
ld alpha = -atan2(vv[2], vv[1]);
|
||||
rotate_view(cspin(2, 1, alpha));
|
||||
if(dir == 1 && alpha + val > max_angle)
|
||||
if(dir == 1 && alpha <= max_angle1 && alpha + val > max_angle)
|
||||
val = max_angle - alpha;
|
||||
if(dir == 1 && alpha + val < -max_angle)
|
||||
if(dir == 1 && alpha >= -max_angle1 && alpha + val < -max_angle)
|
||||
val = -max_angle - alpha;
|
||||
rotate_view(cspin(dir, 2, val));
|
||||
rotate_view(cspin(1, 2, alpha));
|
||||
|
@ -421,9 +462,9 @@ EX void full_rotate_camera(int dir, ld val) {
|
|||
|
||||
EX void full_rotate_view(ld h, ld v) {
|
||||
if(history::on && !rug::rug_control())
|
||||
models::rotation += h * camera_rot_speed;
|
||||
models::rotation = spin(h * camera_rot_speed) * models::rotation;
|
||||
else {
|
||||
rotate_view(spin(v * camera_rot_speed));
|
||||
rotate_view(cspin(0, 1, v * camera_rot_speed));
|
||||
didsomething = true;
|
||||
if(isGravityLand(cwt.at->land) && !rug::rug_control())
|
||||
playermoved = false;
|
||||
|
@ -452,8 +493,8 @@ EX void handlePanning(int sym, int uni) {
|
|||
}
|
||||
#endif
|
||||
if(!smooth_scrolling) {
|
||||
if(sym == SDLK_PAGEUP) full_rotate_view(1, M_PI/cgi.S21/2*shiftmul);
|
||||
if(sym == SDLK_PAGEDOWN) full_rotate_view(-1, -M_PI/cgi.S21/2*shiftmul);
|
||||
if(sym == SDLK_PAGEUP) full_rotate_view(1, cgi.S_step*shiftmul);
|
||||
if(sym == SDLK_PAGEDOWN) full_rotate_view(-1, -cgi.S_step*shiftmul);
|
||||
if(sym == SDLK_PAGEUP || sym == SDLK_PAGEDOWN)
|
||||
if(isGravityLand(cwt.at->land) && !rug::rug_control()) playermoved = false;
|
||||
}
|
||||
|
@ -512,9 +553,9 @@ EX void handleKeyNormal(int sym, int uni) {
|
|||
if(handleTune(sym, uni)) return;
|
||||
#endif
|
||||
|
||||
if(!(uni >= 'A' && uni <= 'Z') && DEFAULTCONTROL) {
|
||||
if(!(uni >= 'A' && uni <= 'Z') && DEFAULTCONTROL && !game_keys_scroll) {
|
||||
for(int i=0; i<8; i++)
|
||||
if(among(sym, keys_vi[i], keys_wasd[i], keys_numpad[i]))
|
||||
if(among(sym, keys_vi[i], keys_wasd[i], (uni >= '0' && uni <= '9' && !ISMAC) ? -1 : keys_numpad[i]))
|
||||
movepckeydir(i);
|
||||
}
|
||||
|
||||
|
@ -535,22 +576,24 @@ EX void handleKeyNormal(int sym, int uni) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if(DEFAULTCONTROL) {
|
||||
if(DEFAULTCONTROL && !game_keys_scroll) {
|
||||
if(sym == '.' || sym == 's') movepcto(-1, 1);
|
||||
if((sym == SDLK_DELETE || sym == SDLK_KP_PERIOD || sym == 'g') && uni != 'G' && uni != 'G'-64)
|
||||
movepcto(MD_DROP, 1);
|
||||
if(sym == 't' && uni != 'T' && uni != 'T'-64 && canmove) {
|
||||
if(sym == 't' && uni != 'T' && uni != 'T'-64 && canmove) {
|
||||
cell *target = GDIM == 3 ? mouseover : centerover;
|
||||
if(playermoved && items[itStrongWind]) {
|
||||
cell *c = whirlwind::jumpDestination(cwt.at);
|
||||
if(c) target = c;
|
||||
}
|
||||
targetRangedOrb(target, roKeyboard);
|
||||
if(bow::fire_mode) bow::add_fire(target);
|
||||
else targetRangedOrb(target, roKeyboard);
|
||||
sym = 0; uni = 0;
|
||||
}
|
||||
if(sym == 'f') bow::switch_fire_mode();
|
||||
}
|
||||
|
||||
if(sym == SDLK_KP5 && DEFAULTCONTROL) movepcto(-1, 1);
|
||||
if(sym == SDLK_KP5 && DEFAULTCONTROL && !game_keys_scroll) movepcto(-1, 1);
|
||||
|
||||
if(sym == SDLK_F5) {
|
||||
#if CAP_DAILY
|
||||
|
@ -563,7 +606,9 @@ EX void handleKeyNormal(int sym, int uni) {
|
|||
}
|
||||
|
||||
if(sym == SDLK_ESCAPE) {
|
||||
if(viewdists)
|
||||
if(bow::fire_mode)
|
||||
bow::switch_fire_mode();
|
||||
else if(viewdists)
|
||||
viewdists = false;
|
||||
else
|
||||
showMissionScreen();
|
||||
|
@ -580,7 +625,7 @@ EX void handleKeyNormal(int sym, int uni) {
|
|||
|
||||
if(uni == 'o' && DEFAULTNOR(sym)) get_o_key().second();
|
||||
#if CAP_INV
|
||||
if(uni == 'i' && DEFAULTNOR(sym) && inv::on)
|
||||
if(uni == 'i' && DEFAULTNOR(sym) && inv::on && !game_keys_scroll)
|
||||
pushScreen(inv::show);
|
||||
#endif
|
||||
|
||||
|
@ -604,9 +649,13 @@ EX void handleKeyNormal(int sym, int uni) {
|
|||
actonrelease = false;
|
||||
|
||||
multi::cpid = 0;
|
||||
if(mouseover &&
|
||||
if(bow::fire_mode) {
|
||||
if(mouseover) bow::add_fire(mouseover);
|
||||
}
|
||||
else if(mouseover &&
|
||||
targetclick && (shmup::on ? numplayers() == 1 && !shmup::pc[0]->dead : true) && targetRangedOrb(mouseover, forcetarget ? roMouseForce : roMouse)) {
|
||||
}
|
||||
else if(bow::fire_on_mouse(mouseover)) ;
|
||||
else if(forcetarget)
|
||||
;
|
||||
else if(rug::rugged && rug::renderonce)
|
||||
|
@ -665,6 +714,9 @@ EX void resize_screen_to(int x, int y);
|
|||
EX void mainloopiter() { printf("(compiled without SDL -- no action)\n"); quitmainloop = true; }
|
||||
#endif
|
||||
|
||||
/* visualization only -- the HyperRogue movement keys should move the camera */
|
||||
EX bool game_keys_scroll;
|
||||
|
||||
#if CAP_SDL
|
||||
|
||||
// Warning: a very long function! todo: refactor
|
||||
|
@ -689,13 +741,15 @@ EX void resize_screen_to(int x, int y) {
|
|||
|
||||
int lastframe;
|
||||
|
||||
EX int sc_ticks;
|
||||
EX int sc_ticks, sc_ticks2;
|
||||
|
||||
EX bool mouseaiming(bool shmupon) {
|
||||
return
|
||||
(GDIM == 3 && !shmupon) || (rug::rugged && (lctrlclick ^ rug::mouse_control_rug));
|
||||
(GDIM == 3 && !shmupon) || (rug::rugged && (lctrlclick ^ rug::mouse_control_rug)) || (cmode & sm::MOUSEAIM);
|
||||
}
|
||||
|
||||
EX purehookset hooks_control;
|
||||
|
||||
EX void mainloopiter() {
|
||||
GLWRAP;
|
||||
DEBB(DF_GRAPH, ("main loop\n"));
|
||||
|
@ -707,7 +761,10 @@ EX void mainloopiter() {
|
|||
|
||||
#if CAP_VR
|
||||
vrhr::vr_shift();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
|
||||
optimizeview();
|
||||
|
||||
|
@ -736,6 +793,7 @@ EX void mainloopiter() {
|
|||
|
||||
mousepan = cmode & sm::NORMAL;
|
||||
if((cmode & sm::PANNING) && !hiliteclick) mousepan = true;
|
||||
if(cmode & sm::MOUSEAIM) mousepan = true;
|
||||
if(cmode & sm::SHOWCURSOR) mousepan = false;
|
||||
mousepan = mousepan && mouseaiming(false) && mouseaim_sensitivity;
|
||||
if(mousepan != oldmousepan) {
|
||||
|
@ -758,7 +816,7 @@ EX void mainloopiter() {
|
|||
SDL_ShowCursor(SDL_ENABLE);
|
||||
SDL_WarpMouse(vid.xres/2, vid.yres/2);
|
||||
#endif
|
||||
mouseaim_x = mouseaim_y = 0;
|
||||
mouseaim_x = mouseaim_y = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -845,7 +903,7 @@ EX void mainloopiter() {
|
|||
targetclick = pandora_leftclick | pandora_rightclick;
|
||||
pandora_leftclick = pandora_rightclick = 0;
|
||||
#else
|
||||
targetclick = keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT];
|
||||
targetclick = keystate[SDL12(SDLK_RSHIFT, SDL_SCANCODE_RSHIFT)] | keystate[SDL12(SDLK_LSHIFT, SDL_SCANCODE_LSHIFT)];
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@ -890,7 +948,7 @@ EX void mainloopiter() {
|
|||
}
|
||||
#endif
|
||||
|
||||
if(mouseaiming(shmup::on)) {
|
||||
if(mouseaiming(shmup::on) && !(cmode & sm::MOUSEAIM)) {
|
||||
#if CAP_MOUSEGRAB
|
||||
rug::using_rugview urv;
|
||||
dynamicval<bool> ds(didsomething, didsomething);
|
||||
|
@ -907,19 +965,16 @@ EX void mainloopiter() {
|
|||
lastticks = ticks;
|
||||
|
||||
#if CAP_SDL2
|
||||
const Uint8 *keystate = SDL_GetKeyboardState(NULL);
|
||||
|
||||
if(keystate[SDL_SCANCODE_END] && GDIM == 3 && DEFAULTNOR(SDL_SCANCODE_END)) full_forward_camera(-t);
|
||||
if(keystate[SDL_SCANCODE_HOME] && GDIM == 3 && DEFAULTNOR(SDL_SCANCODE_HOME)) full_forward_camera(t);
|
||||
if(keystate[SDL_SCANCODE_RIGHT] && DEFAULTNOR(SDL_SCANCODE_RIGHT)) full_rotate_camera(0, -t);
|
||||
if(keystate[SDL_SCANCODE_LEFT] && DEFAULTNOR(SDL_SCANCODE_LEFT)) full_rotate_camera(0, t);
|
||||
if(keystate[SDL_SCANCODE_UP] && DEFAULTNOR(SDL_SCANCODE_UP)) full_rotate_camera(1, t);
|
||||
if(keystate[SDL_SCANCODE_DOWN] && DEFAULTNOR(SDL_SCANCODE_DOWN)) full_rotate_camera(1, -t);
|
||||
if(keystate[SDL_SCANCODE_PAGEUP] && DEFAULTNOR(SDL_SCANCODE_PAGEUP)) full_rotate_view(t * 180 / M_PI, t);
|
||||
if(keystate[SDL_SCANCODE_PAGEDOWN] && DEFAULTNOR(SDL_SCANCODE_PAGEDOWN)) full_rotate_view(-t * 180 / M_PI, -t);
|
||||
if(keystate[SDL_SCANCODE_PAGEUP] && DEFAULTNOR(SDL_SCANCODE_PAGEUP)) full_rotate_view(t / degree, t);
|
||||
if(keystate[SDL_SCANCODE_PAGEDOWN] && DEFAULTNOR(SDL_SCANCODE_PAGEDOWN)) full_rotate_view(-t / degree, -t);
|
||||
|
||||
#else
|
||||
Uint8 *keystate = SDL_GetKeyState(NULL);
|
||||
|
||||
if(keystate[SDLK_END] && GDIM == 3 && DEFAULTNOR(SDLK_END)) full_forward_camera(-t);
|
||||
if(keystate[SDLK_HOME] && GDIM == 3 && DEFAULTNOR(SDLK_HOME)) full_forward_camera(t);
|
||||
|
@ -927,17 +982,43 @@ EX void mainloopiter() {
|
|||
if(keystate[SDLK_LEFT] && DEFAULTNOR(SDLK_LEFT)) full_rotate_camera(0, t);
|
||||
if(keystate[SDLK_UP] && DEFAULTNOR(SDLK_UP)) full_rotate_camera(1, t);
|
||||
if(keystate[SDLK_DOWN] && DEFAULTNOR(SDLK_DOWN)) full_rotate_camera(1, -t);
|
||||
if(keystate[SDLK_PAGEUP] && DEFAULTNOR(SDLK_PAGEUP)) full_rotate_view(t * 180 / M_PI, t);
|
||||
if(keystate[SDLK_PAGEDOWN] && DEFAULTNOR(SDLK_PAGEDOWN)) full_rotate_view(-t * 180 / M_PI, -t);
|
||||
if(keystate[SDLK_PAGEUP] && DEFAULTNOR(SDLK_PAGEUP)) full_rotate_view(t / degree, t);
|
||||
if(keystate[SDLK_PAGEDOWN] && DEFAULTNOR(SDLK_PAGEDOWN)) full_rotate_view(-t / degree, -t);
|
||||
#endif
|
||||
}
|
||||
else sc_ticks = ticks;
|
||||
|
||||
if(game_keys_scroll && !shmup::on && (cmode & sm::NORMAL) && !keystate[SDL12(SDLK_LALT, SDL_SCANCODE_LALT)] && !keystate[SDL12(SDLK_RALT, SDL_SCANCODE_RALT)]) {
|
||||
rug::using_rugview urv;
|
||||
auto& lastticks = sc_ticks2;
|
||||
ld t = (ticks - lastticks) * shiftmul / 1000.;
|
||||
lastticks = ticks;
|
||||
|
||||
#define dkey(x) keystate[int(x)] && DEFAULTNOR(x)
|
||||
|
||||
if(dkey('d')) full_rotate_camera(0, -t);
|
||||
if(dkey('a')) full_rotate_camera(0, t);
|
||||
if(dkey('w')) full_rotate_camera(1, t);
|
||||
if(dkey('s')) full_rotate_camera(1, -t);
|
||||
if(dkey('q')) full_rotate_view(t / degree, t);
|
||||
if(dkey('e')) full_rotate_view(-t / degree, -t);
|
||||
|
||||
if(GDIM == 3 && dkey('i')) full_forward_camera(-t);
|
||||
if(GDIM == 3 && dkey('k')) full_forward_camera(t);
|
||||
if(GDIM == 3 && dkey('l')) full_strafe_camera(-t);
|
||||
if(GDIM == 3 && dkey('j')) full_strafe_camera(t);
|
||||
if(GDIM == 3 && dkey('h')) full_ystrafe_camera(-t);
|
||||
if(GDIM == 3 && dkey('y')) full_ystrafe_camera(t);
|
||||
#undef dkey
|
||||
}
|
||||
|
||||
#if CAP_VR
|
||||
vrhr::vr_control();
|
||||
#endif
|
||||
achievement_pump();
|
||||
|
||||
callhooks(hooks_control);
|
||||
|
||||
for(auto d: dialog::key_queue) {
|
||||
println(hlog, "handling key ", d);
|
||||
handlekey(d, d);
|
||||
|
@ -949,6 +1030,7 @@ EX void mainloopiter() {
|
|||
fix_mouseh();
|
||||
#if CAP_SDLJOY
|
||||
if(joydir.d != -1) checkjoy();
|
||||
if(joystick_done && joythread) { joythread->join(); delete joythread; joystick_done = false; }
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -964,8 +1046,7 @@ EX void handle_event(SDL_Event& ev) {
|
|||
/* if(ev.type == SDL_JOYDEVICEADDED || ev.type == SDL_JOYDEVICEREMOVED) {
|
||||
joyx = joyy = 0;
|
||||
panjoyx = panjoyy = 0;
|
||||
closeJoysticks();
|
||||
initJoysticks();
|
||||
countJoysticks();
|
||||
} */
|
||||
|
||||
#if CAP_SDL2
|
||||
|
@ -1050,6 +1131,17 @@ EX void handle_event(SDL_Event& ev) {
|
|||
sym = ev.key.keysym.sym;
|
||||
#if CAP_SDL2
|
||||
uni = ev.key.keysym.sym;
|
||||
if(uni == '=' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '+';
|
||||
if(uni == '1' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '!';
|
||||
if(uni == '2' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '@';
|
||||
if(uni == '3' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '#';
|
||||
if(uni == '4' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '$';
|
||||
if(uni == '5' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '%';
|
||||
if(uni == '6' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '^';
|
||||
if(uni == '7' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '&';
|
||||
if(uni == '8' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '*';
|
||||
if(uni == '9' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = '(';
|
||||
if(uni == '0' && (ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) uni = ')';
|
||||
if(uni >= 'a' && uni <= 'z') {
|
||||
if(ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) uni -= 32;
|
||||
else if(ev.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) uni -= 96;
|
||||
|
@ -1084,13 +1176,14 @@ EX void handle_event(SDL_Event& ev) {
|
|||
which_pointer = 0;
|
||||
bool was_holdmouse = holdmouse;
|
||||
holdmouse = false;
|
||||
invslider = false;
|
||||
|
||||
bool down = ev.type == SDL_MOUSEBUTTONDOWN SDL12(, || ev.type == SDL_MOUSEWHEEL);
|
||||
bool up = ev.type == SDL_MOUSEBUTTONUP;
|
||||
|
||||
bool act = false;
|
||||
|
||||
if(vid.quickmouse) {
|
||||
if(vid.quickmouse || getcstat == PSEUDOKEY_LIST_SLIDER) {
|
||||
act = down;
|
||||
}
|
||||
else {
|
||||
|
@ -1107,7 +1200,7 @@ EX void handle_event(SDL_Event& ev) {
|
|||
if(ev.button.button == SDL_BUTTON_LEFT) {
|
||||
if(ISPANDORA ? pandora_rightclick : lctrlclick)
|
||||
ev.button.button = SDL_BUTTON_MIDDLE;
|
||||
else if((ISPANDORA ? pandora_leftclick : lshiftclick) && !(vid.shifttarget&1))
|
||||
else if((ISPANDORA ? pandora_leftclick : lshiftclick) && !(vid.shifttarget&1) && !(cmode & sm::MAP))
|
||||
ev.button.button = SDL_BUTTON_RIGHT;
|
||||
}
|
||||
|
||||
|
@ -1253,7 +1346,10 @@ EX void displayabutton(int px, int py, string s, int col) {
|
|||
int rad = (int) realradius();
|
||||
if(vid.stereo_mode == sLR) rad = 99999;
|
||||
int vrx = min(rad, vid.xres/2 - 40);
|
||||
int vry = min(rad, min(current_display->ycenter, vid.yres - current_display->ycenter) - 20);
|
||||
int maxy = min(current_display->ycenter, vid.yres - current_display->ycenter);
|
||||
int vry = min(rad, maxy - 20);
|
||||
vrx = max(vrx, vid.xres/3);
|
||||
vry = max(vry, maxy * 2/3);
|
||||
int x = current_display->xcenter + px * vrx;
|
||||
int y = current_display->ycenter + py * (vry - siz/2);
|
||||
int vrr = int(hypot(vrx, vry) * sqrt(2.));
|
||||
|
|
|
@ -0,0 +1,553 @@
|
|||
// Hyperbolic Rogue
|
||||
// Copyright (C) 2011-2019 Zeno Rogue
|
||||
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
/** \file crossbow.cpp
|
||||
* \brief implementation of the crossbow mode
|
||||
*/
|
||||
|
||||
#include "hyper.h"
|
||||
|
||||
namespace hr {
|
||||
|
||||
EX namespace bow {
|
||||
|
||||
#if HDR
|
||||
enum eWeapon { wBlade, wCrossbow };
|
||||
enum eCrossbowStyle { cbBull, cbGeodesic, cbGeometric };
|
||||
const string bowName[] = { "bull", "geod", "geom" };
|
||||
#endif
|
||||
|
||||
EX eWeapon weapon;
|
||||
EX eCrossbowStyle style;
|
||||
EX bool bump_to_shoot = true;
|
||||
|
||||
EX bool crossbow_mode() { return weapon == wCrossbow; }
|
||||
|
||||
#if HDR
|
||||
struct bowpoint {
|
||||
cellwalker prev, next;
|
||||
flagtype flags;
|
||||
bowpoint() {}
|
||||
};
|
||||
|
||||
struct bowscore {
|
||||
int total;
|
||||
cellwalker last;
|
||||
int turns;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if HDR
|
||||
static constexpr flagtype bpFIRST = 1;
|
||||
static constexpr flagtype bpLAST = 2;
|
||||
static constexpr flagtype bpCOPIED = 4;
|
||||
#endif
|
||||
|
||||
EX vector<bowpoint> bowpath;
|
||||
|
||||
EX map<cell*, vector<bowpoint>> bowpath_map;
|
||||
|
||||
EX map<int, cell*> target_at;
|
||||
|
||||
EX int loading_time() {
|
||||
return style == cbBull ? 3 : 4;
|
||||
}
|
||||
|
||||
EX bool blocks(cell *c) {
|
||||
if(items[itOrbAether]) return false;
|
||||
if(isWall(c) && !among(c->wall, waMirrorWall, waMirror, waCloud) && !isNonblock(c->wall)) return true;
|
||||
// if(c->monst && isMultitile(c->monst)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
EX int qadd(cellwalker a, cellwalker b) {
|
||||
hassert(a.at == b.at);
|
||||
for(int i=0; i<a.at->type; i++) if(a+i == b) return i;
|
||||
return NODIR;
|
||||
}
|
||||
|
||||
int best_score_res;
|
||||
|
||||
EX int bolt_score(cellwalker cw2) {
|
||||
int d = cw2.at->cpdist;
|
||||
int ntotal = 2;
|
||||
if(inmirror(cw2.at)) cw2 = mirror::reflect(cw2);
|
||||
if(blocks(cw2.cpeek())) return -1;
|
||||
if(thruVine(cw2.at, cw2.cpeek())) return -1;
|
||||
if(nonAdjacent(cw2.at, cw2.cpeek())) return -1;
|
||||
|
||||
if(cw2.at->monst) {
|
||||
flagtype attackflags = AF_BOW;
|
||||
if(items[itOrbSpeed]&1) attackflags |= AF_FAST;
|
||||
if(items[itOrbSlaying]) attackflags |= AF_CRUSH;
|
||||
if(items[itCurseWeakness]) attackflags |= AF_WEAK;
|
||||
if(canAttack(cw2.cpeek(), moPlayer, cw2.at, cw2.at->monst, attackflags)) {
|
||||
ntotal += 10000; ntotal += 1280 >> d;
|
||||
}
|
||||
}
|
||||
|
||||
for(int t=0; t<cw2.at->type; t++) {
|
||||
cell *c1 = cw2.at->cmove(t);
|
||||
if(!logical_adjacent(cw2.cpeek(), moPlayer, c1)) continue;
|
||||
if(canAttack(cw2.cpeek(),moPlayer,c1,c1->monst,AF_STAB)) {
|
||||
ntotal += 10000; ntotal += 1280 >> d;
|
||||
}
|
||||
}
|
||||
|
||||
return ntotal;
|
||||
}
|
||||
|
||||
EX vector<int> create_dirseq() {
|
||||
map<cell*, bowscore> scores;
|
||||
scores[cwt.at].total = 0;
|
||||
|
||||
int best_score = -1; cell* best_score_at = cwt.at;
|
||||
|
||||
for(cell *c: dcal) {
|
||||
cell *c1 = target_at[c->cpdist];
|
||||
if(c1 && c != c1) continue;
|
||||
if(c == c1) { best_score = -1; }
|
||||
bowscore best;
|
||||
best.total = -1;
|
||||
forCellIdEx(c1, i, c) if(c1->cpdist < c->cpdist && scores.count(c1)) {
|
||||
auto& last = scores[c1];
|
||||
auto ocw2 = cellwalker(c, i);
|
||||
int bonus = bolt_score(ocw2);
|
||||
if(bonus < 0) continue;
|
||||
int ntotal = last.total + bonus;
|
||||
|
||||
int dir = 0;
|
||||
if(c->cpdist > 1) {
|
||||
dir = qadd(last.last, ocw2+wstep);
|
||||
int d = abs(szgmod(dir, c1->type));
|
||||
if(d != c1->type / 2) {
|
||||
if(style == cbGeodesic) ntotal--;
|
||||
if(style == cbBull) continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dir = qadd(cwt, ocw2+wstep);
|
||||
}
|
||||
if(ntotal > best.total) {
|
||||
best.total = ntotal;
|
||||
best.last = ocw2;
|
||||
best.turns = dir;
|
||||
}
|
||||
best.total = max(best.total, ntotal);
|
||||
}
|
||||
if(best.total > best_score) { best_score = best.total; best_score_at = c; }
|
||||
if(best.total > -1) scores[c] = best;
|
||||
}
|
||||
|
||||
if(best_score == -1) return {};
|
||||
|
||||
vector<int> dirseq = { NODIR };
|
||||
while(best_score_at != cwt.at) {
|
||||
auto& at = scores[best_score_at];
|
||||
dirseq.push_back(at.turns);
|
||||
best_score_at = at.last.cpeek();
|
||||
}
|
||||
reverse(dirseq.begin(), dirseq.end());
|
||||
|
||||
best_score_res = best_score;
|
||||
return dirseq;
|
||||
}
|
||||
|
||||
EX vector<int> create_dirseq_geometric() {
|
||||
cell *tgt = nullptr;
|
||||
for(auto t: target_at) tgt = t.second;
|
||||
if(!tgt) return {};
|
||||
hyperpoint h = tC0(currentmap->relative_matrix(tgt, cwt.at, C0));
|
||||
transmatrix T = spintox(h);
|
||||
|
||||
best_score_res = 0;
|
||||
cellwalker at = cwt;
|
||||
vector<int> dirseq;
|
||||
while(true) {
|
||||
int best_i = -1;
|
||||
ld best_y = HUGE_VAL;
|
||||
for(int i=0; i<at.at->type; i++) {
|
||||
cellwalker at1 = at + i;
|
||||
if(at1.cpeek()->cpdist != at.at->cpdist + 1) continue;
|
||||
transmatrix U = T * currentmap->adj(at.at, at1.spin);
|
||||
hyperpoint U0 = tC0(U);
|
||||
hyperpoint T0 = tC0(T);
|
||||
if(U0[0] < T0[0] + 1e-6) continue;
|
||||
ld y;
|
||||
if(GDIM == 3) y = hypot(U0[1], U0[2]); else y = abs(U0[1]) + (U0[1] > 0 ? 1e-6 : 0);
|
||||
if(y < best_y) { best_y = y; best_i = i; }
|
||||
}
|
||||
if(best_i < 0) {
|
||||
dirseq.push_back(NODIR);
|
||||
break;
|
||||
}
|
||||
at = at + best_i;
|
||||
int bonus = bolt_score(at + wstep);
|
||||
best_score_res += bonus;
|
||||
dirseq.push_back(best_i);
|
||||
if(bonus < 0) break;
|
||||
T = T * currentmap->adj(at.at, at.spin);
|
||||
at = at + wstep;
|
||||
}
|
||||
|
||||
return dirseq;
|
||||
}
|
||||
|
||||
EX int create_path() {
|
||||
auto dirseq = style == cbGeometric ? create_dirseq_geometric() : create_dirseq();
|
||||
if(dirseq.empty()) return -1;
|
||||
|
||||
struct bolt {
|
||||
cellwalker at;
|
||||
flagtype flags;
|
||||
bolt(cellwalker cw, flagtype f) { at = cw; flags = f; }
|
||||
};
|
||||
|
||||
bowpath.clear();
|
||||
vector<bolt> bolts = { bolt(cwt, 0) };
|
||||
for(auto m: mirror::mirrors) bolts.emplace_back(m.second, bpCOPIED);
|
||||
|
||||
set<cell*> broken_mirrors;
|
||||
|
||||
for(auto d: dirseq) {
|
||||
bool first = bowpath.empty();
|
||||
vector<bolt> nbolts;
|
||||
set<cell*> next_broken_mirrors = broken_mirrors;
|
||||
for(auto bolt: bolts) {
|
||||
bowpath.emplace_back();
|
||||
auto& p = bowpath.back();
|
||||
p.prev = bolt.at;
|
||||
p.flags = bolt.flags;
|
||||
if(first) p.flags |= bpFIRST;
|
||||
if(d == NODIR || blocks(bolt.at.at)) { p.next = bolt.at; p.flags |= bpLAST; }
|
||||
else {
|
||||
if(inmirror(bolt.at.at) || (bolt.at.at->wall == waMirrorWall && inmirror((bolt.at+d).cpeek())))
|
||||
bolt.at = mirror::reflect(bolt.at);
|
||||
bolt.at += d;
|
||||
p.next = bolt.at;
|
||||
bolt.at += wstep;
|
||||
if(among(bolt.at.at->wall, waCloud, waMirror) && !broken_mirrors.count(bolt.at.at)) {
|
||||
auto &mir = mirror::mirrors;
|
||||
vector<pair<int, cellwalker>> bmir;
|
||||
swap(mir, bmir);
|
||||
mirror::createHere(bolt.at, 0);
|
||||
swap(mir, bmir);
|
||||
for(auto b: bmir) nbolts.emplace_back(b.second, bolt.flags);
|
||||
next_broken_mirrors.insert(bolt.at.at);
|
||||
}
|
||||
nbolts.push_back(bolt);
|
||||
}
|
||||
}
|
||||
bolts = nbolts;
|
||||
broken_mirrors = next_broken_mirrors;
|
||||
}
|
||||
|
||||
return best_score_res;
|
||||
}
|
||||
|
||||
EX void clear_bowpath() {
|
||||
bowpath_map.clear();
|
||||
}
|
||||
|
||||
EX void gen_bowpath_map() {
|
||||
bowpath_map = {};
|
||||
for(auto& b: bowpath) bowpath_map[b.next.at].push_back(b);
|
||||
}
|
||||
|
||||
EX bool auto_path() {
|
||||
target_at = {};
|
||||
target_at[1] = cwt.cpeek();
|
||||
return create_path() >= 10000;
|
||||
}
|
||||
|
||||
EX bool fire_mode;
|
||||
|
||||
EX void switch_fire_mode() {
|
||||
if(!crossbow_mode()) { addMessage(XLAT("You fire an angry glance at your enemies.")); return; }
|
||||
if(!fire_mode) {
|
||||
addMessage(items[itCrossbow] ? XLAT("Note: cannot fire again yet. Turns to reload: %1.", its(items[itCrossbow])) : XLAT("Fire crossbow! Click to aim, click again to confirm."));
|
||||
fire_mode = true;
|
||||
clear_bowpath();
|
||||
target_at = {};
|
||||
}
|
||||
else if(fire_mode) {
|
||||
addMessage(items[itCrossbow] ? XLAT("Fire mode disabled.") : XLAT("Firing cancelled."));
|
||||
fire_mode = false;
|
||||
clear_bowpath();
|
||||
}
|
||||
}
|
||||
|
||||
EX void add_fire(cell *c) {
|
||||
bool emp = target_at.empty();
|
||||
auto& t = target_at[c->cpdist];
|
||||
if(t == c && !bow::bowpath.empty()) {
|
||||
if(items[itCrossbow]) {
|
||||
clear_bowpath();
|
||||
addMessage(XLAT("Cannot fire again yet. Turns to reload: %1.", its(items[itCrossbow])));
|
||||
fire_mode = false;
|
||||
return;
|
||||
}
|
||||
clear_bowpath();
|
||||
checked_move_issue.type = miVALID;
|
||||
pcmove pcm;
|
||||
pcm.checkonly = false;
|
||||
changes.init(false);
|
||||
addMessage(XLAT("Fire!"));
|
||||
bool b = pcm.try_shooting(false);
|
||||
if(!b) changes.rollback();
|
||||
fire_mode = false;
|
||||
}
|
||||
else {
|
||||
t = c;
|
||||
if(style == cbGeometric) { target_at = {}; target_at[c->cpdist] = c; }
|
||||
int res = create_path();
|
||||
if(res == -1) {
|
||||
if(!emp) {
|
||||
target_at = {};
|
||||
add_fire(c);
|
||||
}
|
||||
else {
|
||||
addMessage(XLAT("No way to hit this place."));
|
||||
bow::bowpath = {};
|
||||
}
|
||||
}
|
||||
gen_bowpath_map();
|
||||
}
|
||||
}
|
||||
|
||||
#if HDR
|
||||
enum eMouseFireMode { mfmNone, mfmPriority, mfmAlways };
|
||||
#endif
|
||||
|
||||
EX eMouseFireMode mouse_fire_mode = mfmPriority;
|
||||
|
||||
EX bool fire_on_mouse(cell *c) {
|
||||
if(!crossbow_mode()) return false;
|
||||
if(mouse_fire_mode == mfmNone) return false;
|
||||
if(!mouseover) return false;
|
||||
if(!mouseover->monst) return false;
|
||||
if(shmup::on) return false;
|
||||
if(items[itCrossbow]) {
|
||||
if(mouse_fire_mode == mfmAlways) {
|
||||
addMessage(XLAT("Cannot fire again yet. Turns to reload: %1.", its(items[itCrossbow])));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
target_at = {};
|
||||
target_at[mouseover->cpdist] = mouseover;
|
||||
int res = create_path();
|
||||
if(res <= 0) {
|
||||
if(mouse_fire_mode == mfmAlways) {
|
||||
addMessage(XLAT("Shooting impossible."));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
gen_bowpath_map();
|
||||
checked_move_issue.type = miVALID;
|
||||
pcmove pcm;
|
||||
pcm.checkonly = false;
|
||||
changes.init(false);
|
||||
addMessage(XLAT("Fire!"));
|
||||
bool b = pcm.try_shooting(false);
|
||||
if(!b) changes.rollback();
|
||||
if(mouse_fire_mode == mfmAlways) return true;
|
||||
return b;
|
||||
}
|
||||
|
||||
EX int rusalka_curses = 0;
|
||||
|
||||
EX void shoot() {
|
||||
flagtype attackflags = AF_BOW;
|
||||
if(items[itOrbSpeed]&1) attackflags |= AF_FAST;
|
||||
if(items[itOrbSlaying]) attackflags |= AF_CRUSH;
|
||||
if(items[itCurseWeakness]) attackflags |= AF_WEAK;
|
||||
|
||||
vector<bowpoint> pushes;
|
||||
|
||||
// for achievements
|
||||
set<eMonster> kills;
|
||||
vector<pair<cell*, int>> healthy_dragons;
|
||||
map<cell*, pair<int, int>> kraken_hits;
|
||||
int dragon_hits = 0;
|
||||
rusalka_curses = 0;
|
||||
|
||||
// for achievements
|
||||
for(auto& mov: bowpath) {
|
||||
cell *c = mov.prev.at;
|
||||
if(c->monst == moDragonHead) {
|
||||
bool healthy = true;
|
||||
cell *c1 = c;
|
||||
int qty = 0;
|
||||
for(int i=0; i<iteration_limit; i++) {
|
||||
if(!isDragon(c1)) break;
|
||||
if(!c1->hitpoints) { healthy = false; break; }
|
||||
if(c1->mondir == NODIR) break;
|
||||
c1 = c1->move(c1->mondir);
|
||||
qty++;
|
||||
}
|
||||
if(healthy) healthy_dragons.emplace_back(c, qty);
|
||||
}
|
||||
if(c->monst == moKrakenT && c->hitpoints) {
|
||||
kraken_hits[kraken::head(c)].first++;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& mov: bowpath) {
|
||||
cell *c = mov.prev.at;
|
||||
cell *cf = mov.prev.cpeek();
|
||||
if(!c) continue;
|
||||
eMonster who = (mov.flags & bpCOPIED) ? moMimic : moPlayer;
|
||||
|
||||
if(c != cf) for(int t=0; t<cf->type; t++) {
|
||||
cell *c1 = cf->cmove(t);
|
||||
if(!c) continue;
|
||||
|
||||
bool stabthere = false;
|
||||
if(logical_adjacent(c, moPlayer, c1)) stabthere = true;
|
||||
|
||||
if(stabthere && canAttack(cf,who,c1,c1->monst,AF_STAB)) {
|
||||
hit_anything = true;
|
||||
changes.ccell(c1);
|
||||
eMonster m = c->monst;
|
||||
if(attackMonster(c1, AF_STAB | AF_MSG, who)) {
|
||||
achievement_count("STAB", 1, 0);
|
||||
spread_plague(c1, cf, t, moPlayer);
|
||||
produceGhost(c, m, moPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mirror::breakMirror(mov.next, -1);
|
||||
eMonster m = c->monst;
|
||||
if(!m || isMimic(m)) continue;
|
||||
if(m == moKrakenH) continue;
|
||||
|
||||
if(!canAttack(cf, who, c, m, attackflags)) {
|
||||
if(among(m, moSleepBull, moHerdBull)) {
|
||||
addMessage(XLAT("%The1 is enraged!", m));
|
||||
c->monst = moRagingBull;
|
||||
hit_anything = true;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pcmove pcm; pcm.mi = movei(mov.prev).rev();
|
||||
pcm.tell_why_cannot_attack();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
changes.ccell(c);
|
||||
|
||||
bool push = (items[itCurseWeakness] || (isStunnable(c->monst) && c->hitpoints > 1));
|
||||
push = push && (!(mov.flags & bpLAST) && monsterPushable(c));
|
||||
|
||||
// for achievements
|
||||
if(isDragon(m)) dragon_hits++;
|
||||
if(m == moKrakenT && c->hitpoints) kraken_hits[kraken::head(c)].second++;
|
||||
|
||||
if(m && attackMonster(c, attackflags | AF_MSG, who)) hit_anything = true;
|
||||
|
||||
if(m == moRusalka) rusalka_curses++;
|
||||
|
||||
if(!c->monst || isAnyIvy(m)) {
|
||||
spread_plague(cf, c, movei(mov.prev).rev().d, moPlayer);
|
||||
produceGhost(c, m, moPlayer);
|
||||
kills.insert(m);
|
||||
}
|
||||
|
||||
if(push) pushes.push_back(mov);
|
||||
}
|
||||
|
||||
while(!pushes.empty()) {
|
||||
auto& mov = pushes.back();
|
||||
cell *c = mov.prev.at;
|
||||
cell *ct = mov.next.cpeek();
|
||||
bool can_push = passable(ct, c, P_BLOW);
|
||||
if(can_push) {
|
||||
hit_anything = true;
|
||||
changes.ccell(c);
|
||||
changes.ccell(ct);
|
||||
pushMonster(mov.next);
|
||||
}
|
||||
pushes.pop_back();
|
||||
}
|
||||
|
||||
reverse(bowpath.begin(), bowpath.end());
|
||||
|
||||
// three achievements:
|
||||
achievement_count("BOWVARIETY", kills.size(), 0);
|
||||
|
||||
for(auto p: healthy_dragons) {
|
||||
cell *c = p.first;
|
||||
if(c->monst != moDragonHead && dragon_hits >= p.second)
|
||||
achievement_gain_once("BOWDRAGON");
|
||||
}
|
||||
|
||||
for(auto kh: kraken_hits) {
|
||||
if(kh.second.first == 3 && kh.second.second == 3) {
|
||||
if(kraken::half_killed[kh.first]) achievement_gain_once("BOWKRAKEN");
|
||||
else kraken::half_killed[kh.first] = true;
|
||||
}
|
||||
}
|
||||
|
||||
gen_bowpath_map();
|
||||
}
|
||||
|
||||
EX bool have_bow_target() {
|
||||
dynamicval<decltype(bowpath)> bp(bowpath);
|
||||
dynamicval<decltype(bowpath_map)> bpm(bowpath_map);
|
||||
|
||||
for(int i=0; i<isize(dcal); i++) {
|
||||
cell *c = dcal[i];
|
||||
target_at = {};
|
||||
target_at[c->cpdist] = {c};
|
||||
|
||||
int res = create_path();
|
||||
if(res == -1) continue;
|
||||
|
||||
checked_move_issue.type = miVALID;
|
||||
pcmove pcm;
|
||||
pcm.checkonly = true;
|
||||
changes.init(true);
|
||||
bool b = pcm.try_shooting(false);
|
||||
changes.rollback();
|
||||
|
||||
if(b) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EX void showMenu() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen();
|
||||
dialog::init(XLAT("weapon selection"));
|
||||
add_edit(weapon);
|
||||
if(crossbow_mode()) {
|
||||
add_edit(style);
|
||||
add_edit(bump_to_shoot);
|
||||
add_edit(bow::mouse_fire_mode);
|
||||
}
|
||||
else dialog::addBreak(200);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
EX }
|
||||
|
||||
}
|
||||
|
39
crystal.cpp
39
crystal.cpp
|
@ -11,8 +11,8 @@ namespace hr {
|
|||
EX namespace crystal {
|
||||
|
||||
#if HDR
|
||||
static const int MAXDIM = 7;
|
||||
static const int MAX_EDGE_CRYSTAL = 2 * MAXDIM;
|
||||
static constexpr int MAXDIM = 7;
|
||||
static constexpr int MAX_EDGE_CRYSTAL = 2 * MAXDIM;
|
||||
|
||||
struct coord : public array<int, MAXDIM> {
|
||||
coord operator + (coord b) { for(int i=0; i<MAXDIM; i++) b[i] += self[i]; return b; }
|
||||
|
@ -20,7 +20,7 @@ struct coord : public array<int, MAXDIM> {
|
|||
coord operator * (int x) { coord res; for(int i=0; i<MAXDIM; i++) res[i] = x * self[i]; return res; }
|
||||
};
|
||||
|
||||
static const coord c0 = {};
|
||||
static constexpr coord c0 = {};
|
||||
|
||||
struct ldcoord : public array<ld, MAXDIM> {
|
||||
friend ldcoord operator + (ldcoord a, ldcoord b) { ldcoord r; for(int i=0; i<MAXDIM; i++) r[i] = a[i] + b[i]; return r; }
|
||||
|
@ -30,7 +30,7 @@ struct ldcoord : public array<ld, MAXDIM> {
|
|||
friend ld operator | (ldcoord a, ldcoord b) { ld r=0; for(int i=0; i<MAXDIM; i++) r += a[i] * b[i]; return r; }
|
||||
};
|
||||
|
||||
static const ldcoord ldc0 = {};
|
||||
static constexpr ldcoord ldc0 = {};
|
||||
#endif
|
||||
|
||||
#if CAP_CRYSTAL
|
||||
|
@ -325,7 +325,7 @@ ld sqhypot2(crystal_structure& cs, ldcoord co1, ldcoord co2) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static const int Modval = 64;
|
||||
static constexpr int Modval = 64;
|
||||
|
||||
struct east_structure {
|
||||
map<coord, int> data;
|
||||
|
@ -801,7 +801,7 @@ EX colortable coordcolors = {0xD04040, 0x40D040, 0x4040D0, 0xFFD500, 0xF000F0, 0
|
|||
|
||||
EX ld compass_angle() {
|
||||
bool bitr = ginf[gCrystal].vertex == 3;
|
||||
return (bitr ? M_PI/8 : 0) - master_to_c7_angle();
|
||||
return (bitr ? 22.5_deg : 0) - master_to_c7_angle();
|
||||
}
|
||||
|
||||
EX bool crystal_cell(cell *c, shiftmatrix V) {
|
||||
|
@ -813,7 +813,7 @@ EX bool crystal_cell(cell *c, shiftmatrix V) {
|
|||
queuestr(V, 0.3, its(d), 0xFFFFFF, 1);
|
||||
}
|
||||
|
||||
if(view_coordinates && WDIM == 2 && cheater) {
|
||||
if(view_coordinates && WDIM == 2 && (cheater || tour::on)) {
|
||||
|
||||
auto m = crystal_map();
|
||||
|
||||
|
@ -822,7 +822,7 @@ EX bool crystal_cell(cell *c, shiftmatrix V) {
|
|||
ld dist = cellgfxdist(c, 0);
|
||||
|
||||
for(int i=0; i<S7; i++) {
|
||||
shiftmatrix T = V * spin(compass_angle() - 2 * M_PI * i / S7) * xpush(dist*.3);
|
||||
shiftmatrix T = V * spin(compass_angle() - TAU * i / S7) * xpush(dist*.3);
|
||||
|
||||
auto co = m->hcoords[c->master];
|
||||
auto lw = m->makewalker(co, i);
|
||||
|
@ -884,7 +884,7 @@ EX vector<cell*> build_shortest_path(cell *c1, cell *c2) {
|
|||
}
|
||||
}
|
||||
|
||||
println(hlog, "Error: path not found");
|
||||
println(hlog, "Error: path not found, steps = ", steps);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -1118,8 +1118,9 @@ EX void init_rotation() {
|
|||
|
||||
if(ho & 1) {
|
||||
for(int i=(draw_cut ? 2 : cs.dim-1); i>=1; i--) {
|
||||
ld c = cos(M_PI / 2 / (i+1));
|
||||
ld s = sin(M_PI / 2 / (i+1));
|
||||
ld alpha = 90._deg / (i+1);
|
||||
ld c = cos(alpha);
|
||||
ld s = sin(alpha);
|
||||
for(int j=0; j<cs.dim; j++)
|
||||
tie(crug_rotation[j][0], crug_rotation[j][i]) =
|
||||
make_pair(
|
||||
|
@ -1317,9 +1318,7 @@ EX void set_crystal(int sides) {
|
|||
set_variation(eVariation::pure);
|
||||
ginf[gCrystal].sides = sides;
|
||||
ginf[gCrystal].vertex = 4;
|
||||
static char buf[20];
|
||||
sprintf(buf, "{%d,4}", sides);
|
||||
ginf[gCrystal].tiling_name = buf;
|
||||
ginf[gCrystal].tiling_name = hr::format("{%d,4}", sides);
|
||||
ginf[gCrystal].distlimit = distlimit_table[min(sides, MAX_EDGE_CRYSTAL-1)];
|
||||
}
|
||||
|
||||
|
@ -1499,7 +1498,7 @@ EX void show() {
|
|||
dialog::add_action([]() {
|
||||
draw_cut = true;
|
||||
dialog::editNumber(cut_level, -1, 1, 0.1, 0, XLAT("cut level"), "");
|
||||
dialog::extra_options = [] {
|
||||
dialog::get_di().extra_options = [] {
|
||||
dialog::addItem(XLAT("disable"), 'D');
|
||||
dialog::add_action([] { draw_cut = false; popScreen(); });
|
||||
};
|
||||
|
@ -1511,7 +1510,7 @@ EX void show() {
|
|||
dialog::add_action([] {
|
||||
dialog::editNumber(crystal_period, 0, 16, 2, 0, XLAT("Crystal torus"),
|
||||
XLAT("Z_k^d instead of Z^d. Only works with k even."));
|
||||
dialog::reaction_final = [] {
|
||||
dialog::get_di().reaction_final = [] {
|
||||
if(cryst) stop_game();
|
||||
set_crystal_period_flags();
|
||||
if(cryst) start_game();
|
||||
|
@ -1561,7 +1560,7 @@ struct shift_data {
|
|||
|
||||
bignum& compute(ld rad2) {
|
||||
if(result.count(rad2)) return result[rad2];
|
||||
// println(hlog, "compute ", format("%p", this), " [shift=", shift, "], r2 = ", rad2);
|
||||
// println(hlog, "compute ", hr::format("%p", this), " [shift=", shift, "], r2 = ", rad2);
|
||||
// indenter i(2);
|
||||
auto& b = result[rad2];
|
||||
if(!parent) {
|
||||
|
@ -1596,7 +1595,7 @@ EX string get_table_volume() {
|
|||
if(co[i] < mincoord) mincoord = co[i];
|
||||
if(co[i] > maxcoord) maxcoord = co[i];
|
||||
}
|
||||
static const ld eps = 1e-4;
|
||||
static constexpr ld eps = 1e-4;
|
||||
if(mincoord >= 0-eps && maxcoord < PERIOD-eps) {
|
||||
ld my_rad2 = rad2;
|
||||
auto cshift = (co - m->camelot_coord) / PERIOD;
|
||||
|
@ -1724,8 +1723,8 @@ void transform_crystal_to_euclid () {
|
|||
|
||||
clearAnimations();
|
||||
cwt.spin = neighborId(cwt.at, infront);
|
||||
View = iddspin(cwt.at, cwt.spin, M_PI/2);
|
||||
if(!flipplayer) View = cspin(0, 2, M_PI) * View;
|
||||
View = iddspin(cwt.at, cwt.spin, 90._deg);
|
||||
if(!flipplayer) View = cspin180(0, 2) * View;
|
||||
|
||||
if(pmodel == mdDisk) pmodel = mdPerspective;
|
||||
}
|
||||
|
|
37
debug.cpp
37
debug.cpp
|
@ -280,7 +280,7 @@ int bitfield_v;
|
|||
template<class T> void bitfield_editor(int val, T setter, string help = "") {
|
||||
bitfield_v = val;
|
||||
dialog::editNumber(bitfield_v, 0, 100, 1, bitfield_v, help, "");
|
||||
dialog::reaction = [setter] () { setter(bitfield_v); };
|
||||
dialog::get_di().reaction = [setter] () { setter(bitfield_v); };
|
||||
}
|
||||
|
||||
struct debugScreen {
|
||||
|
@ -308,8 +308,6 @@ struct debugScreen {
|
|||
#if CAP_SHAPES
|
||||
queuepoly(gmatrix[what], cgi.shAsymmetric, 0x80808080);
|
||||
#endif
|
||||
char buf[200];
|
||||
sprintf(buf, "%p", hr::voidp(what));
|
||||
dialog::addSelItem("mpdist", its(what->mpdist), 'd');
|
||||
dialog::add_action([what] () {
|
||||
bitfield_editor(what->mpdist, [what] (int i) { what->mpdist = 0; }, "generation level");
|
||||
|
@ -326,7 +324,7 @@ struct debugScreen {
|
|||
static ld d = HEAT(what);
|
||||
dialog::editNumber(d, -2, 2, 0.1, d, "landparam",
|
||||
"Extra value that is important in some lands. The specific meaning depends on the land.");
|
||||
dialog::reaction = [what] () { HEAT(what) = d; };
|
||||
dialog::get_di().reaction = [what] () { HEAT(what) = d; };
|
||||
});
|
||||
dialog::addSelItem("land flags", its(what->landflags)+"/"+itsh2(what->landflags), 'f');
|
||||
dialog::add_action([what] () {
|
||||
|
@ -390,7 +388,7 @@ struct debugScreen {
|
|||
dialog::addBreak(50);
|
||||
|
||||
if(show_debug_data) {
|
||||
dialog::addSelItem("pointer", s0+buf+"/"+index_pointer(what), 0);
|
||||
dialog::addSelItem("pointer", s0+hr::format("%p", hr::voidp(what))+"/"+index_pointer(what), 0);
|
||||
dialog::addSelItem("cpdist", its(what->cpdist), 0);
|
||||
dialog::addSelItem("celldist", its(celldist(what)), 0);
|
||||
dialog::addSelItem("celldistance", its(celldistance(cwt.at, what)), 0);
|
||||
|
@ -421,7 +419,7 @@ struct debugScreen {
|
|||
dialog::add_action([what] () {
|
||||
bitfield_editor(what->mondir, [what] (int i) { what->mondir = i; },
|
||||
"monster direction");
|
||||
dialog::extra_options = [what] () {
|
||||
dialog::get_di().extra_options = [what] () {
|
||||
dialog::addBoolItem(XLAT("mirrored"), what->monmirror, 'M');
|
||||
};
|
||||
});
|
||||
|
@ -611,8 +609,8 @@ int read_cheat_args() {
|
|||
else if(argis("-g")) {
|
||||
/* debugging mode */
|
||||
if(curphase == 1) {
|
||||
/* use a separate score file */
|
||||
scorefile = "xx";
|
||||
/* use no score file */
|
||||
scorefile = "";
|
||||
/* set seed for reproducible results */
|
||||
if(!fixseed) {
|
||||
fixseed = true; autocheat = true;
|
||||
|
@ -641,6 +639,11 @@ int read_cheat_args() {
|
|||
else if(argis("-W2")) {
|
||||
shift(); cheatdest = readland(args()); cheat();
|
||||
showstartmenu = false;
|
||||
cheatdest_list.clear();
|
||||
}
|
||||
else if(argis("-W3")) {
|
||||
shift(); cheatdest_list.push_back(readland(args())); cheat();
|
||||
showstartmenu = false;
|
||||
}
|
||||
else if(argis("-I")) {
|
||||
PHASE(3) cheat();
|
||||
|
@ -657,6 +660,9 @@ int read_cheat_args() {
|
|||
PHASEFROM(2);
|
||||
shift(); vid.stereo_mode = eStereo(argi());
|
||||
}
|
||||
else if(argis("-save-cheats")) {
|
||||
save_cheats = true;
|
||||
}
|
||||
else if(argis("-cmove")) {
|
||||
PHASE(3); shift();
|
||||
for(char c: args()) cheat_move(c);
|
||||
|
@ -716,6 +722,16 @@ int read_cheat_args() {
|
|||
if(itemclass(eItem(i)) == IC_TREASURE)
|
||||
items[i] = q;
|
||||
}
|
||||
else if(argis("-each-random")) {
|
||||
PHASEFROM(2); start_game(); cheat();
|
||||
for(int i=0; i<ittypes; i++)
|
||||
if(itemclass(eItem(i)) == IC_TREASURE) {
|
||||
items[i] = 10 + hrand(21);
|
||||
if(i == itElemental) items[i] = 12;
|
||||
}
|
||||
else
|
||||
items[i] = 0;
|
||||
}
|
||||
else if(argis("-viewall")) {
|
||||
PHASE(3); start_game();
|
||||
viewall();
|
||||
|
@ -733,12 +749,12 @@ int read_cheat_args() {
|
|||
shift(); int index = argi();
|
||||
shift(); whateveri[index] = argi();
|
||||
}
|
||||
else if(argis("-W3")) {
|
||||
else if(argis("-W4")) {
|
||||
shift(); top_land = readland(args()); cheat();
|
||||
showstartmenu = false;
|
||||
}
|
||||
else if(argis("-top")) {
|
||||
PHASE(3); View = View * spin(-M_PI/2);
|
||||
PHASE(3); View = View * spin(-90._deg);
|
||||
}
|
||||
else if(argis("-idv")) {
|
||||
PHASE(3); View = Id;
|
||||
|
@ -799,7 +815,6 @@ int read_cheat_args() {
|
|||
}
|
||||
else if(argis("-lands")) {
|
||||
PHASEFROM(2);
|
||||
cheat();
|
||||
stop_game();
|
||||
shift(); land_structure = (eLandStructure) (argi());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
336h: D29C2418 p=3, f=3, n=10, q=5,1
|
||||
336h: 7769A558 p=5, f=25, n=650, q=50
|
||||
336h: 640FB3D4 p=7, f=7, n=28, q=14,1
|
||||
336h: C734F868 p=7, f=7, n=28, q=14,1
|
||||
336h: E3F6B7BC p=7, f=49, n=672, q=336,28,16
|
||||
336h: 885F1184 p=7, f=49, n=672, q=336,42,28,16
|
||||
|
||||
344h: B23AF1F4 p=3, f=3, n=5, q=1
|
||||
344h: 4F9920E0 p=3, f=3, n=5, q=1
|
||||
344h: 6DBBAAA0 p=3, f=3, n=10, q=5,1
|
||||
344h: F81E97B0 p=3, f=3, n=10, q=5,1
|
||||
344h: F790CEA4 p=3, f=3, n=30, q=6,3
|
||||
344h: C95EC8B8 p=3, f=3, n=30, q=3
|
||||
344h: 16518434 p=3, f=9, n=16, q=8,4,2
|
||||
344h: 558C8ED0 p=5, f=5, n=600, q=20,25
|
||||
344h: 1EC39944 p=5, f=5, n=600, q=20,25
|
||||
344h: AF042EA8 p=5, f=25, n=2400, q=1200,600,60,40
|
||||
344h: EC29DCEC p=5, f=25, n=2600, q=1300,650,100
|
||||
344h: D26948E0 p=5, f=25, n=2600, q=1300,650,100
|
||||
|
||||
345h: F978E264 p=3, f=3, n=30, q=6,3
|
||||
345h: 02ADCAA4 p=3, f=3, n=30, q=6,3
|
||||
345h: 7EFE8D98 p=5, f=25, n=650, q=50,25
|
||||
345h: F447F75C p=11, f=11, n=55, q=5
|
||||
345h: 58A698B8 p=19, f=19, n=285, q=15
|
||||
345h: 6FA03030 p=19, f=19, n=285, q=57,15
|
||||
|
||||
353h: 1566EBAC p=5, f=25, n=130, q=10
|
||||
353h: 5A2E2B88 p=11, f=11, n=11, q=1
|
||||
|
||||
354h: 58A8E850 p=5, f=5, n=2, q=1
|
||||
354h: 363D8DA4 p=11, f=11, n=22, q=11,2
|
||||
354h: 9CD5E744 p=11, f=11, n=22, q=11,2
|
||||
354h: F04BA28C p=19, f=19, n=114, q=57,6
|
||||
|
||||
355h: AF448B14 p=5, f=5, n=1
|
||||
355h: F42F2904 p=5, f=5, n=1
|
||||
355h: 47F0C740 p=5, f=5, n=120, q=6,4
|
||||
355h: 7BAFB45C p=11, f=11, n=11, q=1
|
||||
355h: 6453A3FC p=11, f=11, n=11, q=1
|
||||
|
||||
435h: EB201050 p=5, f=25, n=650, q=25
|
||||
435h: 65CE0C00 p=11, f=11, n=55, q=11,5
|
||||
435h: 5641E95C p=11, f=11, n=55, q=11,5
|
||||
|
||||
436h: 235F7508 p=2, f=4, n=2, q=1
|
||||
436h: C02F2A80 p=2, f=4, n=2, q=1
|
||||
436h: DFC6B8C0 p=2, f=4, n=8, q=4,2
|
||||
436h: 4D3C8B14 p=3, f=9, n=8, q=1
|
||||
436h: FF82A214 p=5, f=25, n=650, q=50,25
|
||||
436h: 4546E270 p=5, f=25, n=650, q=25
|
||||
436h: C4884090 p=7, f=7, n=28, q=14,4,2
|
||||
436h: 5230B364 p=7, f=7, n=28, q=14,2
|
||||
436h: 2D051038 p=7, f=7, n=14, q=7,2
|
||||
436h: F0997060 p=7, f=7, n=14, q=7,2
|
||||
436h: 1D1227CC p=7, f=49, n=672, q=336,112,42,14,12
|
||||
436h: B2B4B3D4 p=7, f=49, n=672, q=336,14,12
|
||||
436h: 6C29B2A4 p=13, f=13, n=91, q=13,7
|
||||
436h: 06F4054C p=13, f=13, n=91, q=13,7
|
||||
436h: DE4912E0 p=13, f=13, n=182, q=91,13,7
|
||||
436h: 417466F0 p=13, f=13, n=182, q=91,13,7
|
||||
|
||||
534h: 0C62E214 p=5, f=25, n=130, q=10
|
||||
534h: 72414D0C p=5, f=25, n=260, q=10
|
||||
534h: 831E2D74 p=11, f=11, n=22, q=2
|
||||
534h: 5FC4CFF0 p=11, f=11, n=22, q=2
|
||||
|
||||
535h: DCC3CACE p=5, f=5, n=1
|
||||
535h: F78E1C56 p=5, f=5, n=1
|
||||
535h: 9EF7A9C4 p=5, f=5, n=120, q=10,8,6,4
|
||||
535h: 5254DA16 p=19, f=19, n=57, q=3
|
||||
535h: A5C8752E p=19, f=19, n=57, q=3
|
||||
|
||||
536h: BB5AEE10 p=5, f=5, n=120, q=8,6,4
|
||||
536h: 61385498 p=5, f=5, n=2, q=1
|
||||
536h: B009EB44 p=5, f=5, n=2, q=1
|
||||
536h: 3BA5C5A4 p=5, f=25, n=130, q=10
|
||||
536h: 9FDE7B38 p=5, f=25, n=260, q=130,10
|
||||
536h: 885F1184 p=7, f=49, n=672, q=336,28,16
|
||||
|
|
@ -191,7 +191,7 @@ void gentrans() {
|
|||
DIR *d;
|
||||
struct dirent *dir;
|
||||
|
||||
println(hlog, "// checking all the files");
|
||||
println(hlog, "\n\n// checking all the files");
|
||||
|
||||
d = opendir(".");
|
||||
|
||||
|
@ -204,11 +204,11 @@ void gentrans() {
|
|||
closedir(d);
|
||||
}
|
||||
|
||||
println(hlog, "// checking configurables");
|
||||
println(hlog, "\n\n// checking configurables");
|
||||
|
||||
for(auto& fs: params) {
|
||||
auto& sett = fs.second;
|
||||
if(sett->menu_item_name != sett->config_name)
|
||||
if(sett->menu_item_name_modified)
|
||||
check_ex(sett->menu_item_name, "menu_item_name for " + sett->parameter_name);
|
||||
check_ex(sett->help_text, "help_text for " + sett->parameter_name);
|
||||
auto ls = dynamic_cast<list_setting*> ( (setting*) &*sett);
|
||||
|
@ -222,6 +222,6 @@ void gentrans() {
|
|||
exit(0);
|
||||
}
|
||||
|
||||
auto ar = arg::add3("-gentrans", gentrans);
|
||||
auto gtar = arg::add3("-gentrans", gentrans);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,516 @@
|
|||
/**
|
||||
* This program was used to generate the rule tables in apeirodic-hat.cpp.
|
||||
*
|
||||
* Some data was generated by this program itself, based on manual keyboard+mouse control.
|
||||
* Some of minor manual control tools have been removed, but the process was as follows:
|
||||
*
|
||||
* * Run with `-symbol "12,6,4" -dual -canvas 101010 -smart 1 stamplen=0` and draw the hat shape, the table output is hatcorners
|
||||
* * Place hats into clusters as shown in the paper, obtaining the table hats[0]
|
||||
* * Place clusters into superclusters as shown in the paper, obtaining the table hats[1]
|
||||
* * Repeat for hats[2], hats[3], hats[4] and hats[5] (the paper does not specify precisely the coordinates to arrange the clusters; but we can multiply the previous hats by scaling factor
|
||||
* * for an approximate, and fix manually so that it matches)
|
||||
* * 'CON Lx' lines state the rules deduced; the rules should be the same for L1 and L2 (except the matrix codes returned by matcode), so we conjecture that this set of rules is complete
|
||||
* * Fill the table `hatid` to declare the correspondence between L1 and L2 matrices
|
||||
* * Run again, and we get rules (prefixed by RULE1 and RULE0)
|
||||
|
||||
**/
|
||||
|
||||
#include "../rogueviz/rogueviz.h"
|
||||
|
||||
namespace rogueviz {
|
||||
|
||||
int toplev = 5;
|
||||
|
||||
vector<hyperpoint> hatcorners_add;
|
||||
|
||||
vector<hyperpoint> hatcorners[2];
|
||||
|
||||
vector<transmatrix> hats[8];
|
||||
|
||||
vector<int> hattype;
|
||||
|
||||
hyperpoint pt(ld x, ld y) { return hpxy(x, y); }
|
||||
|
||||
transmatrix rot;
|
||||
|
||||
transmatrix sca;
|
||||
|
||||
transmatrix U;
|
||||
|
||||
transmatrix mt(ld a, ld b, ld c, ld d, ld e, ld f, ld g, ld h, ld i) {
|
||||
transmatrix T = Id;
|
||||
T[0][0] = a;
|
||||
T[0][1] = b;
|
||||
T[0][2] = c;
|
||||
T[1][0] = d;
|
||||
T[1][1] = e;
|
||||
T[1][2] = f;
|
||||
T[2][0] = g;
|
||||
T[2][1] = h;
|
||||
T[2][2] = i;
|
||||
return T;
|
||||
}
|
||||
|
||||
map<string, int> hatid;
|
||||
|
||||
void init() {
|
||||
rot = Id;
|
||||
hatcorners[0] = {
|
||||
pt(-1.1160254038,1.4330127019),
|
||||
pt(-0.0915063509,2.0245190528),
|
||||
pt(0.2500000000,1.4330127019),
|
||||
pt(-0.0915063509,0.8415063509),
|
||||
pt(0.9330127019,0.2500000000),
|
||||
pt(0.9330127019,-0.9330127019),
|
||||
pt(0.2500000000,-0.9330127019),
|
||||
pt(-0.0915063509,-1.5245190528),
|
||||
pt(-1.1160254038,-0.9330127019),
|
||||
pt(-2.1405444566,-1.5245190528),
|
||||
pt(-2.4820508076,-0.9330127019),
|
||||
pt(0,0),
|
||||
pt(-1.7990381057,0.2500000000),
|
||||
pt(-1.1160254038,0.2500000000),
|
||||
};
|
||||
hatcorners[0][11] = mid(hatcorners[0][10], hatcorners[0][12]);
|
||||
hatcorners[1] = hatcorners[0];
|
||||
for(auto& h: hatcorners[1]) h = MirrorX * h;
|
||||
reverse(hatcorners[1].begin(), hatcorners[1].end());
|
||||
|
||||
hats[0] = {
|
||||
mt(0.5000000000,-0.8660254038,-1.3660254038, -0.8660254038,-0.5000000000,-0.0000000000, 0.0000000000,0.0000000000,1.0000000000) * MirrorX,
|
||||
mt(0.5000000000,-0.8660254038,0.6830127019, 0.8660254038,0.5000000000,1.6830127019, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-1.0000000000,0.0000000000,-2.2320508076, -0.0000000000,-1.0000000000,-1.8660254038, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,-0.8660254038,-4.5310889132, 0.8660254038,-0.5000000000,-1.6160254038, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,-0.8660254038,-3.4150635095, 0.8660254038,0.5000000000,1.6830127019, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,-0.0000000000,-2.0490381057, 0.0000000000,1.0000000000,3.5490381057, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,0.8660254038,0.2500000000, -0.8660254038,0.5000000000,3.2990381057, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,-0.8660254038,-5.4641016151, 0.8660254038,0.5000000000,0.5000000000, 0.0000000000,0.0000000000,1.0000000000),
|
||||
};
|
||||
|
||||
hats[1] = {
|
||||
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,0.8660254038,-0.8660254038, -0.8660254038,-0.5000000000,7.0980762114, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,0.8660254038,-5.8971143170, -0.8660254038,0.5000000000,4.4820508076, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,-0.0000000000,-6.1471143170, 0.0000000000,1.0000000000,-1.1830127019, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,-0.8660254038,-4.5310889132, 0.8660254038,-0.5000000000,-3.9820508076, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,-0.8660254038,-9.5621778265, 0.8660254038,0.5000000000,-6.5980762114, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,-0.0000000000,-14.3432667397, 0.0000000000,1.0000000000,-3.5490381057, 0.0000000000,0.0000000000,1.0000000000),
|
||||
};
|
||||
hattype = {7, 8, 8, 8, 8, 8, 8};
|
||||
|
||||
ld q7 = 1, q8 = 0;
|
||||
ld val;
|
||||
for(int a=0; a<100; a++) {
|
||||
ld nq7 = q7 + q8;
|
||||
ld nq8 = q7 * 5 + q8 * 6;
|
||||
println(hlog, hr::format("%.20f", val = (nq7 + nq8) / (q7 + q8)));
|
||||
q7 = nq7; q8 = nq8;
|
||||
}
|
||||
val = sqrt(val);
|
||||
println(hlog, "root: ", hr::format("%.20f", val));
|
||||
for(int a=-50; a<50; a++)
|
||||
for(int b=1; b<50; b++)
|
||||
for(int c=-50; c<50; c++)
|
||||
for(int d=1; d<50; d++) {
|
||||
ld err = abs(a*1./b + c * sqrt(1./d) - val);
|
||||
if(err < 1e-6)
|
||||
println(hlog, tie(a,b,c,d), " : ", err);
|
||||
}
|
||||
val = (3 + sqrt(5)) / 2; // scaling each axis
|
||||
|
||||
sca = Id; sca[0][0] = sca[1][1] = val;
|
||||
|
||||
hats[2] = {
|
||||
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,0.8660254038,1.1830127025, -0.8660254038,-0.5000000000,15.3791651251, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,0.8660254038,-12.0442286339, -0.8660254038,0.5000000000,10.3971143173, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-14.3432667399, 0.0000000000,1.0000000000,-3.5490381057, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,-0.8660254038,-12.7272413356, 0.8660254038,-0.5000000000,-13.4461524228, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,-0.8660254038,-25.9544826718, 0.8660254038,0.5000000000,-18.4282032304, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-36.8826859024, 0.0000000000,1.0000000000,-9.4641016152, 0.0000000000,0.0000000000,1.0000000000),
|
||||
};
|
||||
|
||||
hats[3] = {
|
||||
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,0.8660254038,7.3301270200, -0.8660254038,-0.5000000000,37.8564064623, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,0.8660254038,-28.4365334803, -0.8660254038,0.5000000000,26.9592921447, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-36.8826859027, 0.0000000000,1.0000000000,-9.4641016152, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,-0.8660254038,-33.2176223915, 0.8660254038,-0.5000000000,-39.4724318658, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,-0.8660254038,-68.9842828915, 0.8660254038,0.5000000000,-50.3695461828, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-96.3047909683, 0.0000000000,1.0000000000,-24.8432667403, 0.0000000000,0.0000000000,1.0000000000),
|
||||
};
|
||||
|
||||
hats[4] = {
|
||||
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,0.8660254038,23.7224318656, -0.8660254038,-0.5000000000,97.0070415601, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,0.8660254038,-71.4663337016, -0.8660254038,0.5000000000,70.7307621167, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-96.3047909682, 0.0000000000,1.0000000000,-24.8432667399, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,-0.8660254038,-86.4926131352, 0.8660254038,-0.5000000000,-108.0871685769, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,-0.8660254038,-181.6813787030, 0.8660254038,0.5000000000,-134.3634480195, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-252.0316870025, 0.0000000000,1.0000000000,-65.0656986057, 0.0000000000,0.0000000000,1.0000000000),
|
||||
};
|
||||
|
||||
hats[5] = {
|
||||
mt(1.0000000000,0.0000000000,0.0000000000, 0.0000000000,1.0000000000,0.0000000000, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,0.8660254038,66.7522320948, -0.8660254038,-0.5000000000,251.9817055201, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,0.8660254038,-184.1634295166, -0.8660254038,0.5000000000,185.4829942043, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-252.0316870019, 0.0000000000,1.0000000000,-65.0656986045, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(-0.5000000000,-0.8660254038,-225.8272043260, 0.8660254038,-0.5000000000,-287.9050992716, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(0.5000000000,-0.8660254038,-476.7428659331, 0.8660254038,0.5000000000,-354.4038105811, 0.0000000000,0.0000000000,1.0000000000),
|
||||
mt(1.0000000000,0.0000000000,-659.7902700392, 0.0000000000,1.0000000000,-170.3538290768, 0.0000000000,0.0000000000,1.0000000000),
|
||||
};
|
||||
|
||||
hats[6] = hats[5];
|
||||
|
||||
auto acs = inverse(sca);
|
||||
|
||||
println(hlog, "shifts:");
|
||||
indenter ind(2);
|
||||
for(int i=0; i<7; i++) {
|
||||
|
||||
transmatrix S = gpushxto0(hats[1][i] * C0) * hats[1][i];
|
||||
// println(hlog, "S = ", kz(S));
|
||||
transmatrix S0 = inverse(S);
|
||||
// transmatrix S1 = S;
|
||||
|
||||
auto& t = hats[6][i];
|
||||
auto& t3 = hats[5][i];
|
||||
auto& t2 = hats[4][i];
|
||||
auto& t1 = hats[3][i];
|
||||
|
||||
hyperpoint fix2 = t2 * C0 - sca * t1 * C0;
|
||||
|
||||
hyperpoint cfix3 = acs * fix2;
|
||||
|
||||
hyperpoint rfix3 = t3 * C0 - sca * t2 * C0;
|
||||
|
||||
t = sca * t * acs * acs * rgpushxto0(rfix3) * sca;
|
||||
|
||||
println(hlog, kz(rfix3-cfix3), " from ", fix2, " .. ", S0 * cfix3 - acs * fix2);
|
||||
|
||||
// t = t * rgpushxto0(sca * (t3 * C0 - bt3 * C0));
|
||||
// t = t *
|
||||
}
|
||||
|
||||
hatid["R0A000L0.000"] = -1;
|
||||
int nextid = 8;
|
||||
|
||||
hatid["R0A011L6.147"] = hatid["R0A014L14.343"] = nextid++;
|
||||
hatid["R0A016L8.196"] = hatid["R0A015L22.539"] = nextid++;
|
||||
hatid["R0A016L8.196"] = hatid["R0A015L22.539"] = nextid++;
|
||||
hatid["R0A191L6.147"] = hatid["R0A194L14.343"] = nextid++;
|
||||
hatid["R0A196L8.196"] = hatid["R0A195L22.539"] = nextid++;
|
||||
hatid["R1A023L6.903"] = hatid["R1A019L15.060"] = nextid++;
|
||||
hatid["R1A126L5.555"] = hatid["R1A131L15.741"] = nextid++;
|
||||
hatid["R1A185L7.579"] = hatid["R1A191L21.879"] = nextid++;
|
||||
hatid["R1A238L3.558"] = hatid["R1A232L11.654"] = nextid++;
|
||||
hatid["R1A327L4.885"] = hatid["R1A320L10.974"] = nextid++;
|
||||
hatid["R2A037L6.054"] = hatid["R2A025L14.053"] = nextid++;
|
||||
hatid["R2A092L2.046"] = hatid["R2A096L3.188"] = nextid++;
|
||||
hatid["R2A138L8.858"] = hatid["R2A145L25.101"] = nextid++;
|
||||
hatid["R2A221L4.953"] = hatid["R2A226L12.883"] = nextid++;
|
||||
hatid["R2A300L2.571"] = hatid["R2A279L2.571"] = nextid++;
|
||||
hatid["R3A226L7.005"] = hatid["R3A233L16.845"] = nextid++;
|
||||
hatid["R4A000L5.143"] = hatid["R4A339L10.197"] = nextid++;
|
||||
hatid["R4A097L4.093"] = hatid["R4A085L4.171"] = nextid++;
|
||||
hatid["R4A152L9.906"] = hatid["R4A156L21.728"] = nextid++;
|
||||
hatid["R4A198L11.809"] = hatid["R4A205L27.793"] = nextid++;
|
||||
hatid["R4A281L4.171"] = hatid["R4A286L6.625"] = nextid++;
|
||||
hatid["R5A087L5.006"] = hatid["R5A080L5.503"] = nextid++;
|
||||
hatid["R5A143L7.731"] = hatid["R5A139L13.041"] = nextid++;
|
||||
hatid["R5A246L6.309"] = hatid["R5A251L9.388"] = nextid++;
|
||||
hatid["R5A305L6.626"] = hatid["R5A311L15.426"] = nextid++;
|
||||
hatid["R5A358L8.119"] = hatid["R5A352L19.349"] = nextid++;
|
||||
|
||||
println(hlog, "nextid = ", nextid);
|
||||
};
|
||||
|
||||
void draw_cross(hyperpoint h) {
|
||||
transmatrix T = rgpushxto0(h);
|
||||
shiftmatrix sId = shiftless(Id);
|
||||
for(int i=0; i<12; i++)
|
||||
queueline(sId * T * C0, sId * T * xspinpush0(30._deg * i, 0.1), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void draw_shape(transmatrix T, vector<hyperpoint> sh, color_t lc, color_t fc) {
|
||||
for(hyperpoint h: sh) curvepoint(h);
|
||||
curvepoint(sh[0]);
|
||||
queuecurve(shiftless(Id) * T, lc, fc, PPR::LINE);
|
||||
}
|
||||
|
||||
/*
|
||||
void draw_superhat(transmatrix T, const vector<transmatrix>& ms, int q, color_t lc, color_t fc) {
|
||||
for(auto& m: ms)
|
||||
draw_shape(T * m, hatcorners, lc, fc);
|
||||
}
|
||||
*/
|
||||
|
||||
hyperpoint sh;
|
||||
|
||||
color_t coltables[8] = { 0xFF000080, 0x00FF0080, 0x0000FF80, 0xFFFF0080, 0xFF00FF80, 0x00FFFF80, 0xFFFFFF80, 0x4080C080 };
|
||||
|
||||
vector<int> curlabel;
|
||||
|
||||
ld ldist = 9999;
|
||||
|
||||
hyperpoint hfound, hfound1;
|
||||
|
||||
int connection_mode = 0;
|
||||
|
||||
int found_pairs, found_pairs_swap;
|
||||
|
||||
using pthash = int;
|
||||
|
||||
pthash makehash(hyperpoint h) {
|
||||
return int(floor(h[0] * 10 + .31)) + int(floor(h[1] * 10 + .31)) * 10000;
|
||||
}
|
||||
|
||||
map<pair<pthash, pthash>, vector<int> > seen_edges;
|
||||
|
||||
string name(int x) { return s0 + char('A' + x); }
|
||||
|
||||
string matcode(transmatrix T) {
|
||||
vector<ld> res(3);
|
||||
hyperpoint h = kz(T * C0);
|
||||
|
||||
transmatrix S = gpushxto0(T * C0) * T;
|
||||
ld alpha = atan2(S * xpush0(1)) / degree;
|
||||
int ialpha = gmod(floor(alpha + .5), 360);
|
||||
|
||||
int hangle = gmod(floor(atan2(h) / degree + .3), 360);
|
||||
|
||||
h[2] = ialpha/60;
|
||||
swap(h[1], h[2]); swap(h[0], h[1]);
|
||||
// return lalign(0, h);
|
||||
|
||||
return hr::format("R%dA%03dL%.3f", ialpha/60, hangle, hypot_d(2, h));
|
||||
}
|
||||
|
||||
int ghatid(string s) {
|
||||
if(hatid.count(s)) return hatid[s];
|
||||
return -999;
|
||||
}
|
||||
|
||||
void edge_connect(vector<int> l1, vector<int> l2) {
|
||||
transmatrix T1 = Id;
|
||||
transmatrix T2 = Id;
|
||||
transmatrix W = Id;
|
||||
int idx = 0;
|
||||
for(int i=toplev; i>0; i--) {
|
||||
T1 = T1 * hats[i][l1[idx]];
|
||||
T2 = T2 * hats[i][l2[idx]];
|
||||
transmatrix W1 = inverse(T1) * T2;
|
||||
if(!eqmatrix(W1, Id))
|
||||
println(hlog, "CON L", i, " ", matcode(W1), " :: ", matcode(W), " ", tie(l1[idx], l2[idx]), " REV ", matcode(inverse(W1)));
|
||||
if(i == 1) println(hlog, "RULE1 {", l1[idx], ", ", l2[idx], ", ", ghatid(matcode(W1)), ", ", ghatid(matcode(W)), ", ", ghatid(matcode(inverse(W1))), "},");
|
||||
W = W1;
|
||||
idx++;
|
||||
}
|
||||
|
||||
println(hlog, "CON L0 ", make_pair(make_pair(l1[idx], name(l1[idx+1])), make_pair(l2[idx], name(l2[idx+1]))), " :: ", matcode(W));
|
||||
println(hlog, "RULE0 {", l1[idx], ", ", l1[idx+1], ", ", l2[idx], ", ", l2[idx+1], ", ", ghatid(matcode(W)), "},");
|
||||
}
|
||||
|
||||
vector<pair<hyperpoint, hyperpoint> > extedges;
|
||||
|
||||
void edge_label(vector<int>& lbl, hyperpoint a, hyperpoint b) {
|
||||
auto ha = makehash(a);
|
||||
auto hb = makehash(b);
|
||||
|
||||
if(connection_mode >= 2) return;
|
||||
|
||||
if(connection_mode == 1) {
|
||||
if(seen_edges.count({ha, hb})) {
|
||||
extedges.emplace_back(a, b);
|
||||
/* vid.linewidth *= 10;
|
||||
queueline(shiftless(Id) * a, shiftless(Id) * b, 0xFF00FF80);
|
||||
vid.linewidth /= 10;
|
||||
*/
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(seen_edges.count({hb, ha})) {
|
||||
edge_connect(lbl, seen_edges[{hb, ha}]);
|
||||
edge_connect(seen_edges[{hb, ha}], lbl);
|
||||
seen_edges.erase({hb, ha});
|
||||
found_pairs++;
|
||||
return;
|
||||
}
|
||||
if(seen_edges.count({ha, hb})) {
|
||||
println(hlog, "CON ", lbl, " TO ", seen_edges[{hb, ha}], " SWAP");
|
||||
seen_edges.erase({ha, hb});
|
||||
found_pairs_swap++;
|
||||
return;
|
||||
}
|
||||
seen_edges[{ha, hb}] = lbl;
|
||||
}
|
||||
|
||||
void point_label(vector<int>& lbl, hyperpoint h) {
|
||||
if(lbl == curlabel) draw_cross(h);
|
||||
ld dist = hdist(unshift(mouseh), h);
|
||||
if(dist < ldist) {
|
||||
ldist = dist;
|
||||
curlabel = lbl;
|
||||
hfound = h;
|
||||
println(hlog, "found: ", lbl, " at: ", dist);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_superhat_label(transmatrix T, const vector<transmatrix>& ms, int q, color_t lc, color_t fc, vector<int>& label) {
|
||||
for(int i=0; i<q; i++) {
|
||||
auto& hc = hatcorners[i == 0];
|
||||
for(int j=0; j<isize(hc); j++) {
|
||||
|
||||
label.push_back(i);
|
||||
label.push_back(j);
|
||||
point_label(label, T * ms[i] * hc[j]);
|
||||
|
||||
edge_label(label, T * ms[i] * hc[j], T * ms[i] * hc[(j+1)%isize(hc)]);
|
||||
label.pop_back();
|
||||
label.pop_back();
|
||||
}
|
||||
}
|
||||
for(int i=0; i<q; i++) {
|
||||
auto& hc = hatcorners[i == 0];
|
||||
draw_shape(T * ms[i], hc, lc, fc);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_recurse_label(transmatrix T, int levs, int t, color_t col, vector<int>& label) {
|
||||
if(levs == 0) {
|
||||
draw_superhat_label(T, hats[0], t, 0xFFFFFFFF, col, label);
|
||||
return;
|
||||
}
|
||||
|
||||
if(connection_mode == 2 && levs == toplev-1) {
|
||||
int eid = 0;
|
||||
for(auto e: extedges) {
|
||||
queueline(shiftless(Id) * T * e.first, shiftless(Id) * T * e.second, col);
|
||||
label.push_back(eid++);
|
||||
point_label(label, T * e.first);
|
||||
label.pop_back();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
transmatrix scap = Id;
|
||||
for(int i=1; i<levs; i++) scap = scap * sca;
|
||||
scap = inverse(scap);
|
||||
|
||||
for(int i=0; i<t-1; i++) {
|
||||
auto col1 = col;
|
||||
if(col == 0) col1 = coltables[i];
|
||||
label.push_back(i);
|
||||
draw_recurse_label(T * hats[levs][i], levs-1, hattype[i], col1, label);
|
||||
label.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
int next_hattype = 7;
|
||||
|
||||
void hatframe() {
|
||||
if(isize(hatcorners_add) >= 2) draw_shape(Id, hatcorners_add, 0xFF0000FF, 0xFF000080);
|
||||
|
||||
transmatrix B = rgpushxto0( unshift(ggmatrix(cwt.at)) * C0 );
|
||||
|
||||
vector<int> glabel;
|
||||
|
||||
draw_recurse_label(B, toplev, 8, 0, glabel);
|
||||
if(connection_mode == 0) {
|
||||
println(hlog, "CON found = ", found_pairs, " swap = ", found_pairs_swap, " not found = ", isize(seen_edges));
|
||||
// seen_edges.clear(); found_pairs = 0;
|
||||
connection_mode = 1;
|
||||
}
|
||||
else if(connection_mode == 1) {
|
||||
connection_mode = 2;
|
||||
toplev++;
|
||||
}
|
||||
|
||||
draw_cross(C0);
|
||||
}
|
||||
|
||||
string writematrix(transmatrix T) {
|
||||
return hr::format("mt(%.10f,%.10f,%.10f, %.10f,%.10f,%.10f, %.10f,%.10f,%.10f)",
|
||||
T[0][0],
|
||||
T[0][1],
|
||||
T[0][2],
|
||||
T[1][0],
|
||||
T[1][1],
|
||||
T[1][2],
|
||||
T[2][0],
|
||||
T[2][1],
|
||||
T[2][2]
|
||||
);
|
||||
}
|
||||
|
||||
void hatter() {
|
||||
cmode = sm::NORMAL | sm::CENTER | sm::PANNING;
|
||||
clearMessages();
|
||||
dialog::init();
|
||||
gamescreen();
|
||||
|
||||
shiftpoint s = mapeditor::full_mouseh();
|
||||
sh = unshift(s);
|
||||
|
||||
dialog::add_key_action('a', [] {
|
||||
hatcorners_add.push_back(sh);
|
||||
println(hlog, "hatcorners = {");
|
||||
for(auto h: hatcorners_add) println(hlog, hr::format(" pt(%.10f,%.10f),", h[0], h[1]));
|
||||
println(hlog, " }");
|
||||
});
|
||||
|
||||
/* dialog::add_key_action('b', [] {
|
||||
if(hats.empty()) return;
|
||||
hats.pop_back();
|
||||
hattype.pop_back();
|
||||
}); */
|
||||
|
||||
dialog::add_key_action('[', [] {
|
||||
// hyperpoint h = currentmap->get_corner(cwt.at, 0);
|
||||
// rot = rot * gpushxto0(h);
|
||||
rot = rot * spin(60._deg);
|
||||
// rot = rot * rgpushxto0(h);
|
||||
});
|
||||
|
||||
dialog::add_key_action(']', [] {
|
||||
// hyperpoint h = currentmap->get_corner(cwt.at, 0);
|
||||
// rot = rot * gpushxto0(h);
|
||||
rot = MirrorX * rot;
|
||||
// rot = rot * rgpushxto0(h);
|
||||
});
|
||||
|
||||
dialog::add_key_action('7', [] { next_hattype = 7; });
|
||||
dialog::add_key_action('8', [] { next_hattype = 8; });
|
||||
|
||||
dialog::add_key_action('f', [] { hfound1 = hfound; });
|
||||
dialog::add_key_action('b', [] {
|
||||
int id = curlabel[0];
|
||||
hats[toplev][id] = rgpushxto0(hfound1 - hfound) * hats[toplev][id];
|
||||
|
||||
println(hlog, "hats[", toplev, "] = {");
|
||||
for(auto h: hats[toplev]) println(hlog, " ", writematrix(h), ",");
|
||||
println(hlog, " }");
|
||||
});
|
||||
|
||||
dialog::add_key_action('q', [] {
|
||||
exit(0);
|
||||
});
|
||||
|
||||
dialog::add_key_action('g', [] {
|
||||
ldist = 9999;
|
||||
});
|
||||
|
||||
keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); };
|
||||
}
|
||||
|
||||
void enable_hatter() {
|
||||
init();
|
||||
mapeditor::snapping = true;
|
||||
rv_hook(hooks_frame, 100, hatframe);
|
||||
pushScreen(hatter);
|
||||
}
|
||||
|
||||
auto hathook = arg::add3("-hatter", enable_hatter);
|
||||
|
||||
}
|
|
@ -379,7 +379,7 @@ void do_recording() {
|
|||
ticks = i * 1000 / mrec_fps;
|
||||
|
||||
if(i >= mrec_first && i < mrec_last) {
|
||||
string s = format(mrec_file.c_str(), i);
|
||||
string s = hr::format(mrec_file.c_str(), i);
|
||||
println(hlog, "recording frame ", i, "/", isize(saved), " to ", s);
|
||||
shot::take(s);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
// a float-like type to count operations
|
||||
|
||||
namespace reps {
|
||||
|
||||
std::map<std::string, int> counts;
|
||||
|
||||
#define C(x) {}
|
||||
|
||||
std::array<int, 16> cbc;
|
||||
|
||||
constexpr int cbcAdd = 1;
|
||||
constexpr int cbcMul = 2;
|
||||
constexpr int cbcDiv = 3;
|
||||
constexpr int cbcTrig = 4;
|
||||
|
||||
struct countfloat {
|
||||
ld x;
|
||||
|
||||
countfloat() {}
|
||||
explicit countfloat(ld _x) : x(_x) {}
|
||||
explicit operator ld() { return x; }
|
||||
operator bool() { return x != 0; }
|
||||
|
||||
countfloat operator +(countfloat a) const { C("plus"); cbc[1]++; return countfloat(x + a.x); }
|
||||
countfloat operator -(countfloat a) const { C("plus"); cbc[1]++; return countfloat(x + a.x); }
|
||||
countfloat operator -() const { return countfloat(-x); }
|
||||
countfloat operator +() const { return countfloat(+x); }
|
||||
countfloat operator *(countfloat a) const { C("mul"); cbc[2]++; return countfloat(x * a.x); }
|
||||
countfloat operator /(countfloat a) const { C("div"); cbc[3]++; return countfloat(x / a.x); }
|
||||
|
||||
bool operator <(countfloat a) const { return x < a.x; }
|
||||
bool operator >(countfloat a) const { return x > a.x; }
|
||||
bool operator <=(countfloat a) const { return x <= a.x; }
|
||||
bool operator >=(countfloat a) const { return x >= a.x; }
|
||||
|
||||
countfloat& operator +=(countfloat a) { C("plus"); cbc[1]++; x += a.x; return self; }
|
||||
countfloat& operator -=(countfloat a) { C("plus"); cbc[1]++; x -= a.x; return self; }
|
||||
countfloat& operator *=(countfloat a) { C("mul"); cbc[2]++; x *= a.x; return self; }
|
||||
countfloat& operator /=(countfloat a) { C("mul"); cbc[2]++; x /= a.x; return self; }
|
||||
countfloat& operator *=(int a) { if(a != 1 && a != -1) C("mul"+hr::its(a)); x *= a; return self; }
|
||||
countfloat& operator /=(int a) { if(a != 1 && a != -1) C("div"+hr::its(a)); x /= a; return self; }
|
||||
|
||||
friend countfloat sin(countfloat a) { cbc[4]++; C("sin"); return countfloat(sin(a.x)); }
|
||||
friend countfloat cos(countfloat a) { cbc[4]++; C("cos"); return countfloat(cos(a.x)); }
|
||||
friend countfloat tan(countfloat a) { cbc[4]++; C("tan"); return countfloat(tan(a.x)); }
|
||||
friend countfloat sinh(countfloat a) { cbc[4]++; C("sinh"); return countfloat(sinh(a.x)); }
|
||||
friend countfloat cosh(countfloat a) { cbc[4]++; C("cosh"); return countfloat(cosh(a.x)); }
|
||||
friend countfloat tanh(countfloat a) { cbc[4]++; C("cosh"); return countfloat(tanh(a.x)); }
|
||||
friend countfloat asinh(countfloat a) { cbc[4]++; C("asinh"); return countfloat(asinh(a.x)); }
|
||||
friend countfloat acosh(countfloat a) { cbc[4]++; C("acosh"); return countfloat(acosh(a.x)); }
|
||||
friend countfloat acos(countfloat a) { cbc[4]++; C("acos"); return countfloat(acos(a.x)); }
|
||||
friend countfloat exp(countfloat a) { cbc[4]++; C("exp"); return countfloat(exp(a.x)); }
|
||||
friend countfloat log(countfloat a) { cbc[4]++; C("log"); return countfloat(log(a.x)); }
|
||||
friend countfloat sqrt(countfloat a) { cbc[4]++; C("sqrt"); return countfloat(sqrt(a.x)); }
|
||||
friend countfloat atan2(countfloat a, countfloat b) { cbc[4]++; C("atan"); return countfloat(atan2(a.x, b.x)); }
|
||||
friend countfloat pow(countfloat a, ld b) { cbc[4]++; C("pow" + hr::fts(b)); return countfloat(pow(a.x, b)); }
|
||||
friend countfloat abs(countfloat a) { return countfloat(abs(a.x)); }
|
||||
countfloat operator *(int a) const { if(a != 1 && a != -1) C("mul" + hr::its(a)); return countfloat(x * a); }
|
||||
countfloat operator /(int a) const { if(a != 1 && a != -1) C("div" + hr::its(a)); return countfloat(x / a); }
|
||||
|
||||
friend bool isinf(countfloat a) { return isinf(a.x); }
|
||||
friend bool isnan(countfloat a) { return isnan(a.x); }
|
||||
};
|
||||
|
||||
template<> countfloat get_deg<countfloat> (int deg) { return countfloat( M_PI * deg / 180 ); }
|
||||
|
||||
}
|
||||
|
||||
namespace hr {
|
||||
void print(hr::hstream& hs, ::reps::countfloat b) {
|
||||
print(hs, b.x);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
namespace reps {
|
||||
|
||||
TD struct mvector {
|
||||
array<typename D::Number, D::Dim> values;
|
||||
typename D::Number& operator [] (int i) { return values[i]; }
|
||||
const typename D::Number& operator [] (int i) const { return values[i]; }
|
||||
mvector operator + (const mvector& M) const {
|
||||
mvector result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = self[i] + M[i];
|
||||
return result;
|
||||
}
|
||||
mvector operator - (const mvector& M) const {
|
||||
mvector result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = self[i] - M[i];
|
||||
return result;
|
||||
}
|
||||
mvector operator * (const typename D::Number& x) const {
|
||||
mvector result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = self[i] * x;
|
||||
return result;
|
||||
}
|
||||
mvector operator / (const typename D::Number& x) const {
|
||||
mvector result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = self[i] / x;
|
||||
return result;
|
||||
}
|
||||
mvector operator * (int x) const {
|
||||
mvector result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = self[i] * x;
|
||||
return result;
|
||||
}
|
||||
mvector operator / (int x) const {
|
||||
mvector result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = self[i] / x;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
TD struct matrix {
|
||||
array<array<typename D::Number, D::Dim>, D::Dim> values;
|
||||
array<typename D::Number, D::Dim>& operator [] (int i) { return values[i]; }
|
||||
const array<typename D::Number, D::Dim>& operator [] (int i) const { return values[i]; }
|
||||
matrix operator * (const matrix& M) const {
|
||||
matrix result;
|
||||
for(int i=0; i<D::Dim; i++)
|
||||
for(int k=0; k<D::Dim; k++) {
|
||||
result[i][k] = typename D::Number(0);
|
||||
for(int j=0; j<D::Dim; j++) result[i][k] += self[i][j] * M[j][k];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
mvector<D> operator * (const mvector<D>& V) const {
|
||||
mvector<D> result;
|
||||
for(int i=0; i<D::Dim; i++) {
|
||||
result[i] = typename D::Number(0);
|
||||
for(int j=0; j<D::Dim; j++) result[i] += self[i][j] * V[j];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
matrix operator * (const typename D::Number& x) const {
|
||||
matrix result;
|
||||
for(int i=0; i<D::Dim; i++) for(int j=0; j<D::Dim; j++) result[i][j] = self[i][j] * x;
|
||||
return result;
|
||||
}
|
||||
matrix operator / (const typename D::Number& x) const {
|
||||
matrix result;
|
||||
for(int i=0; i<D::Dim; i++) for(int j=0; j<D::Dim; j++) result[i][j] = self[i][j] / x;
|
||||
return result;
|
||||
}
|
||||
matrix operator * (int x) const {
|
||||
matrix result;
|
||||
for(int i=0; i<D::Dim; i++) for(int j=0; j<D::Dim; j++) result[i][j] = self[i][j] * x;
|
||||
return result;
|
||||
}
|
||||
matrix operator / (int x) const {
|
||||
matrix result;
|
||||
for(int i=0; i<D::Dim; i++) for(int j=0; j<D::Dim; j++) result[i][j] = self[i][j] / x;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
TD constexpr mvector<D> zero_vector() {
|
||||
mvector<D> result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = typename D::Number(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
TD constexpr mvector<D> unit_vector(int id) {
|
||||
mvector<D> result;
|
||||
for(int i=0; i<D::Dim; i++) result[i] = typename D::Number(0);
|
||||
result[id] = typename D::Number(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
TD struct multivector_data {
|
||||
using Number = typename D::Number;
|
||||
static constexpr int Dim = 1<<D::Dim;
|
||||
static constexpr int Flipped = -1;
|
||||
};
|
||||
|
||||
TD using multivector = mvector<multivector_data<D>>;
|
||||
|
||||
TD std::string nz(const multivector<D>& a) {
|
||||
constexpr int mdim = 1<<D::Dim;
|
||||
using Number = typename D::Number;
|
||||
hr::shstream str;
|
||||
for(int i=0; i<mdim; i++) if(abs(a[i]) > Number(1e-10)) {
|
||||
if(str.s != "") print(str, " ");
|
||||
if(a[i] > Number(0)) print(str, "+");
|
||||
print(str, a[i]);
|
||||
for(int u=0; u<D::Dim; u++) if(i & (1<<u)) print(str, hr::s0 + char('A'+u));
|
||||
}
|
||||
if(str.s == "") return "0";
|
||||
return str.s;
|
||||
}
|
||||
|
||||
TD constexpr multivector<D> unit(const typename D::Number& a) {
|
||||
auto res = zero_vector<multivector_data<D>>();
|
||||
res[0] = a;
|
||||
return res;
|
||||
}
|
||||
|
||||
TD constexpr multivector<D> embed(const mvector<D>& a) {
|
||||
auto res = zero_vector<multivector_data<D>>();
|
||||
for(int i=0; i<D::Dim; i++) res[1<<i] = a[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
TD constexpr mvector<D> unembed(const multivector<D>& a) {
|
||||
mvector<D> res;
|
||||
for(int i=0; i<D::Dim; i++) res[i] = a[1<<i];
|
||||
return res;
|
||||
}
|
||||
|
||||
/* for clarity */
|
||||
using mvindex = int;
|
||||
using signtype = int;
|
||||
/* mvindex decimal 10 (binary 1010) corresponds to unit_vector(1) * unit_vector(3) */
|
||||
|
||||
TD constexpr signtype conj_sign(mvindex mvid) {
|
||||
int b = __builtin_popcount(mvid);
|
||||
b = b * (b+1) / 2;
|
||||
return (b&1) ? -1 : 1;
|
||||
}
|
||||
|
||||
TD constexpr signtype tra_sign(mvindex mvid) {
|
||||
int b = __builtin_popcount(mvid);
|
||||
b = b * (b-1) / 2;
|
||||
return (b&1) ? -1 : 1;
|
||||
}
|
||||
|
||||
TD constexpr signtype mul_sign(mvindex a, mvindex b) {
|
||||
int flips = 0;
|
||||
for(int i=0; i<D::Dim; i++) if(b & (1<<i)) {
|
||||
// we will need to swap it with that many 1-bits of a
|
||||
flips += __builtin_popcount(a & ((1<<i)-1));
|
||||
if((i == D::Flipped) && (a & (1<<i))) flips++;
|
||||
}
|
||||
return (flips&1) ? -1 : 1;
|
||||
}
|
||||
|
||||
TD struct all {
|
||||
static constexpr bool check(mvindex a) { return true; }
|
||||
static constexpr bool isflat(mvindex a) { return false; }
|
||||
};
|
||||
|
||||
TD struct even {
|
||||
static constexpr bool check(mvindex a) { return __builtin_popcount(a) % 2 == 0; }
|
||||
static constexpr bool isflat(mvindex a) { return false; }
|
||||
};
|
||||
|
||||
TD struct flat_even {
|
||||
static constexpr bool check(mvindex a) { return __builtin_popcount(a) % 2 == 0; }
|
||||
static constexpr bool isflat(mvindex a) { return nm == nmFlatten && a == 0; }
|
||||
};
|
||||
|
||||
TD struct odd {
|
||||
static constexpr bool check(mvindex a) { return __builtin_popcount(a) % 2 == 1; }
|
||||
static constexpr bool isflat(mvindex a) { return false; }
|
||||
};
|
||||
|
||||
TD struct units {
|
||||
static constexpr bool check(mvindex a) { return a == 0; }
|
||||
static constexpr bool isflat(mvindex a) { return false; }
|
||||
};
|
||||
|
||||
TD struct rotational {
|
||||
static constexpr bool check(mvindex a) { return __builtin_popcount(a) % 2 == 0 && a < (1<<(D::Dim-1)); }
|
||||
static constexpr bool isflat(mvindex a) { return false; }
|
||||
};
|
||||
|
||||
TD struct underling {
|
||||
static constexpr bool check(mvindex a) { return __builtin_popcount(a) == 1; }
|
||||
static constexpr bool isflat(mvindex a) { return false; }
|
||||
};
|
||||
|
||||
TD struct flat_underling {
|
||||
static constexpr bool check(mvindex a) { return __builtin_popcount(a) == 1; }
|
||||
static constexpr bool isflat(mvindex a) { return nm == nmFlatten && a == 1<<(D::Dim-1); }
|
||||
};
|
||||
|
||||
TD struct poincare {
|
||||
static constexpr bool check(mvindex a) { return __builtin_popcount(a ^ (1<<(D::Dim-1))) == 1; }
|
||||
static constexpr bool isflat(mvindex a) { return false; }
|
||||
};
|
||||
|
||||
TD multivector<D> multimul(const multivector<D>& a, const multivector<D>& b) {
|
||||
constexpr int mdim = 1<<D::Dim;
|
||||
auto res = zero_vector<multivector_data<D>>();
|
||||
for(mvindex i=0; i<mdim; i++)
|
||||
for(mvindex j=0; j<mdim; j++) {
|
||||
res[i^j] += a[i] * b[j] * mul_sign<D>(i, j);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class A, class B, class C, class D>
|
||||
multivector<D> chkmul(const multivector<D>& a, const multivector<D>& b) {
|
||||
constexpr int mdim = 1<<D::Dim;
|
||||
auto res = zero_vector<multivector_data<D>>();
|
||||
|
||||
/* we initialize with 0s and then add stuff, so one add per component is not necessary */
|
||||
for(mvindex i=0; i<mdim; i++) if(C::check(i)) cbc[cbcAdd]--;
|
||||
|
||||
for(mvindex i=0; i<mdim; i++) if(A::check(i))
|
||||
for(mvindex j=0; j<mdim; j++) if(B::check(j) && C::check(i^j)) {
|
||||
if(A::isflat(i))
|
||||
res[i^j] += b[j] * mul_sign<D>(i, j);
|
||||
else if(B::isflat(j))
|
||||
res[i^j] += a[i] * mul_sign<D>(i, j);
|
||||
else
|
||||
res[i^j] += a[i] * b[j] * mul_sign<D>(i, j);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TD multivector<D> conjugate(const multivector<D>& a) {
|
||||
constexpr int mdim = 1<<D::Dim;
|
||||
auto res = a;
|
||||
for(int i=0; i<mdim; i++) res[i] *= conj_sign<D>(i);
|
||||
return res;
|
||||
}
|
||||
|
||||
TD multivector<D> transpose(const multivector<D>& a) {
|
||||
constexpr int mdim = 1<<D::Dim;
|
||||
auto res = a;
|
||||
for(int i=0; i<mdim; i++) res[i] *= tra_sign<D>(i);
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class C, class D> multivector<D> apply_nm(multivector<D> a);
|
||||
|
||||
TD using poincare_rotation = std::pair<multivector<D>, multivector<D>>;
|
||||
|
||||
/** decompose o into the poincare part and the rotational component */
|
||||
TD poincare_rotation<D> despin2(const multivector<D>& a) {
|
||||
auto p = a;
|
||||
for(int i=(1<<(D::Dim-1)); i<(1<<(D::Dim)); i++) p[i] = typename D::Number(0);
|
||||
p = p * pow(chkmul<rotational<D>,rotational<D>,units<D>>(p, conjugate(p))[0], -0.5);
|
||||
auto p1 = chkmul<even<D>,rotational<D>,poincare<D>>(a, conjugate(p));
|
||||
return {apply_nm<poincare<D>, D>(p1), p};
|
||||
}
|
||||
|
||||
/** remove the rotational component of a, leaving only the poincare part */
|
||||
TD multivector<D> despin(const multivector<D>& a) {
|
||||
auto p = a;
|
||||
for(int i=(1<<(D::Dim-1)); i<(1<<(D::Dim)); i++) p[i] = typename D::Number(0);
|
||||
auto p1 = chkmul<even<D>,rotational<D>,poincare<D>>(a, conjugate(p));
|
||||
if(nm == nmInvariant) return p1 * pow(chkmul<rotational<D>,rotational<D>,units<D>>(p, conjugate(p))[0], -0.5);
|
||||
return apply_nm<poincare<D>, D>(p1);
|
||||
}
|
||||
|
||||
TD std::string nzv(const mvector<D>& a) { return "vector(" + nz(embed(a)) + ")"; }
|
||||
TD std::string nzv(const matrix<D>& a) { return "<matrix>"; }
|
||||
|
||||
template<class C, class D>
|
||||
typename D::Number sqnorm(multivector<D> a) {
|
||||
using N = typename D::Number;
|
||||
auto res = chkmul<C, C, units<D>>(a, conjugate(a))[0];
|
||||
if(res <= N(0) || isinf(res) || isnan(res)) res = N(1);
|
||||
return res;
|
||||
}
|
||||
|
||||
TD typename D::Number sqnorm(mvector<D> a) {
|
||||
using N = typename D::Number;
|
||||
N res(0);
|
||||
for(int i=0; i<D::Dim; i++) res += a[i] * a[i] * (i == D::Flipped ? -1:1);
|
||||
if(D::Flipped != -1) res = -res;
|
||||
if(nm ==nmWeak && (res <= N(0) || isinf(res) || isnan(res))) res = N(1);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** if nm is set to nmFlatten or nmForced or nmBinary, apply the requested operation */
|
||||
|
||||
template<class C, class D> multivector<D> flatten(multivector<D> a) {
|
||||
using N = typename D::Number;
|
||||
auto divby = a[0]; a[0] = N(1);
|
||||
for(int i=1; i<(1<<D::Dim); i++) if(C::check(i)) a[i] /= divby;
|
||||
return a;
|
||||
}
|
||||
|
||||
template<class C, class D>
|
||||
multivector<D> apply_nm(multivector<D> a) {
|
||||
if(nm == nmFlatten) return flatten<C>(a);
|
||||
if(nm == nmForced || nm == nmWeak) return a * pow(sqnorm<C,D>(a), -0.5);
|
||||
if(nm == nmBinary) { while(a[0] >= 2) { a = a / 2; } while(a[0] > 0 && a[0] < 0.5) { a = a * 2; } }
|
||||
return a;
|
||||
}
|
||||
|
||||
TD mvector<D> apply_nm(mvector<D> a) {
|
||||
if(nm == nmFlatten) { cbc[cbcDiv]--; return a / a[D::Dim-1]; }
|
||||
if(nm == nmForced || nm == nmWeak) return a * pow(sqnorm<D>(a), -0.5);
|
||||
if(nm == nmBinary) { while(a[D::Dim-1] >= 2) { a = a / 2; } while(a[D::Dim-1] > 0 && a[D::Dim-1] < 0.5) { a = a * 2; } }
|
||||
return a;
|
||||
}
|
||||
|
||||
/** get b which is a coordinate of a, but in normalized form. That is, if a is normalized simply return b, otherwise, multiply b appropriately */
|
||||
|
||||
template<class C, class D, class E> E get_normalized(multivector<D> a, E b) {
|
||||
if(nm != nmInvariant && nm != nmForced) return b * pow(sqnorm<C,D>(a), -0.5);
|
||||
return b;
|
||||
}
|
||||
|
||||
template<class D, class E> E get_normalized(mvector<D> a, E b) {
|
||||
if(nm != nmInvariant && nm != nmForced) return b * pow(sqnorm<D>(a), -0.5);
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/** representation based on the halfplane model; assumes Dim=3 */
|
||||
|
||||
namespace reps {
|
||||
|
||||
template<class F> struct sl2 : public array<F, 4> {
|
||||
|
||||
sl2(F a, F b, F c, F d) { self[0] = a; self[1] = b; self[2] = c; self[3] = d; }
|
||||
|
||||
sl2 operator * (const sl2& sec) const {
|
||||
return sl2(
|
||||
self[0] * sec[0] + self[1] * sec[2],
|
||||
self[0] * sec[1] + self[1] * sec[3],
|
||||
self[2] * sec[0] + self[3] * sec[2],
|
||||
self[2] * sec[1] + self[3] * sec[3]
|
||||
);
|
||||
}
|
||||
|
||||
std::string print() {
|
||||
return hr::lalign(0, "[", self[0], ",", self[1], ";", self[2], ",", self[3], "]");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TD sl2<typename D::Number> split_quaternion_to_sl2(const multivector<D>& h) {
|
||||
auto h3 = h[0], h2 = h[1 | 2], h1 = h[1 | 4], h0 = h[2 | 4];
|
||||
return sl2(h3 - h1, h2 + h0, -h2 + h0, h3 + h1);
|
||||
}
|
||||
|
||||
TD multivector<D> sl2_to_split_quaternion(const sl2<typename D::Number>& e) {
|
||||
auto h0 = (e[1] + e[2]) / 2;
|
||||
auto h3 = (e[0] + e[3]) / 2;
|
||||
auto h1 = (e[3] - e[0]) / 2;
|
||||
auto h2 = (e[1] - e[2]) / 2;
|
||||
auto res = zero_vector<multivector_data<D>>();
|
||||
res[0] = h3; res[1 | 2] = h2; res[1 | 4] = h1; res[2 | 4] = h0;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class N> using sl2c = sl2<std::complex<N>>;
|
||||
|
||||
TD sl2c<typename D::Number> split_biquaternion_to_sl2c(const multivector<D>& h) {
|
||||
using cn = std::complex<typename D::Number>;
|
||||
return sl2(cn(h[0]-h[9], h[15]-h[6]), cn(h[3]+h[10], -h[5]-h[12]), cn(h[10]-h[3], h[12]-h[5]), cn(h[0]+h[9], h[6]+h[15]));
|
||||
}
|
||||
|
||||
TD multivector<D> sl2c_to_split_biquaternion(const sl2c<typename D::Number>& e) {
|
||||
auto res = zero_vector<multivector_data<D>>();
|
||||
res[0] = +(real(e[0]) + real(e[3])) / 2;
|
||||
res[3] = +(real(e[1]) - real(e[2])) / 2;
|
||||
res[5] = -(imag(e[1]) + imag(e[2])) / 2;
|
||||
res[6] = +(imag(e[3]) - imag(e[0])) / 2;
|
||||
res[9] = +(real(e[3]) - real(e[0])) / 2;
|
||||
res[10] = +(real(e[1]) + real(e[2])) / 2;
|
||||
res[12] = +(imag(e[2]) - imag(e[1])) / 2;
|
||||
res[15] = +(imag(e[0]) + imag(e[3])) / 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
TD struct rep_halfplane {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
using point = std::complex<N>;
|
||||
using isometry = sl2<N>;
|
||||
|
||||
static isometry cspin(int i, int j, N alpha) {
|
||||
// return split_quaternion_to_sl2( rep_clifford<D>::cspin(i, j, alpha) );
|
||||
if(i>j) std::swap(i, j), alpha = -alpha; alpha /= 2;
|
||||
auto ca = cos(alpha), sa = sin(alpha);
|
||||
return isometry(ca, -sa, sa, ca);
|
||||
}
|
||||
static isometry cspin90(int i, int j, N alpha) {
|
||||
// return split_quaternion_to_sl2( rep_clifford<D>::cspin(i, j, alpha) );
|
||||
auto ca = sqrt(N(2)), sa = sqrt(N(2));
|
||||
if(i>j) std::swap(i, j), sa = -sa;
|
||||
return isometry(ca, -sa, sa, ca);
|
||||
}
|
||||
static isometry lorentz(int i, int j, N alpha) {
|
||||
// return split_quaternion_to_sl2( rep_clifford<D>::lorentz(i, j, alpha) );
|
||||
if(i>j) std::swap(i, j); alpha /= 2;
|
||||
if(i == 0) return isometry(exp(-alpha), N(0), N(0), exp(alpha));
|
||||
if(i == 1) {
|
||||
auto ca = cosh(alpha), sa = sinh(alpha);
|
||||
return isometry(ca, sa, sa, ca);
|
||||
}
|
||||
throw hr::hr_exception("bad lorentz");
|
||||
}
|
||||
static isometry id() { return isometry(N(1),N(0),N(0),N(1)); };
|
||||
static point center() { return point(N(0), N(1)); };
|
||||
static point apply(const isometry& T, const point& x) {
|
||||
return (T[0] * x + T[1] * 1) / (T[2] * x + T[3] * 1);
|
||||
};
|
||||
static isometry apply(const isometry& T, const isometry& U) { return T * U; };
|
||||
|
||||
static typename rep_clifford<D>::point to_poincare(const point& x) {
|
||||
auto a = real(x), b = imag(x);
|
||||
|
||||
auto tmp = isometry(sqrt(b), a/sqrt(b), N(0), N(1)/sqrt(b));
|
||||
auto sq = sl2_to_split_quaternion<D>(tmp);
|
||||
|
||||
// sq[0] = (sqrt(b) + 1/sqrt(b)) / 2;; sq[1 | 2] = a/sqrt(b)/2; sq[1 | 4] = (1/sqrt(b) - sqrt(b)) / 2; sq[2 | 4] = a/sqrt(b)/2;
|
||||
|
||||
sq = despin(sq);
|
||||
return typename rep_clifford<D>::point({{sq}});
|
||||
}
|
||||
|
||||
static isometry inverse(isometry T) { return isometry(T[3], -T[1], -T[2], T[0]); }
|
||||
static isometry push(const point& p) { return split_quaternion_to_sl2<D>(to_poincare(p)[0]); }
|
||||
|
||||
static N dist0(const point& x) { return rep_clifford<D>::dist0(to_poincare(x)); }
|
||||
static N angle(const point& x) { return rep_clifford<D>::angle(to_poincare(x)); }
|
||||
static N get_coord(const point& x, int i) { return rep_clifford<D>::get_coord(to_poincare(x), i); }
|
||||
|
||||
// imag may be very small and still important, so do not use the default complex print
|
||||
static std::string print(const point& x) { return hr::lalign(0, "{real:", real(x), " imag:", imag(x), "}"); }
|
||||
static std::string print(const isometry& x) { return x.print(); }
|
||||
};
|
||||
|
||||
TD struct rep_halfspace {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
struct point { std::complex<N> xy; N z; };
|
||||
using isometry = sl2c<N>;
|
||||
|
||||
static isometry cspin(int i, int j, N alpha) {
|
||||
return split_biquaternion_to_sl2c( rep_clifford<D>::cspin(i, j, alpha) );
|
||||
}
|
||||
static isometry cspin90(int i, int j) {
|
||||
return split_biquaternion_to_sl2c( rep_clifford<D>::cspin90(i, j) );
|
||||
}
|
||||
static isometry lorentz(int i, int j, N alpha) {
|
||||
return split_biquaternion_to_sl2c( rep_clifford<D>::lorentz(i, j, alpha) );
|
||||
}
|
||||
static isometry id() { return isometry(N(1),N(0),N(0),N(1)); }
|
||||
static point center() { return point{ .xy = N(0), .z = N(1) }; }
|
||||
static point apply(const isometry& T, const point& x) {
|
||||
auto nom = T[0] * x.xy + T[1] * N(1);
|
||||
auto nomz= T[0] * x.z;
|
||||
auto den = T[2] * x.xy + T[3] * N(1);
|
||||
auto denz= T[2] * x.z;
|
||||
// D = den + denz * j
|
||||
auto dnorm = std::norm(den) + std::norm(denz);
|
||||
using std::conj;
|
||||
// conj(D) = conj(den) - denz * j
|
||||
// N / D = (nom + nomz * j) / (den + denz * j) =
|
||||
// = (nom + nomz * j) * (conj(den) - denz * j) / dnorm
|
||||
|
||||
// auto rxy = (nom * conj(den) - nomz * j * denz * j);
|
||||
// auto rz*j = (-nom * denz * j + nomz * j * conj(den))
|
||||
|
||||
// apply the formula: j * a = conj(a) * j
|
||||
|
||||
auto rxy = (nom * conj(den) + nomz * conj(denz));
|
||||
auto rz = (nomz * den - nom * denz); // todo only real part
|
||||
// println(hlog, "imag of rz = ", imag(rz));
|
||||
return point { .xy = rxy / dnorm, .z = real(rz) / dnorm };
|
||||
};
|
||||
static isometry apply(const isometry& T, const isometry& U) { return T * U; };
|
||||
|
||||
static typename rep_clifford<D>::point to_poincare(const point& x) {
|
||||
auto tmp = isometry(sqrt(x.z), x.xy/sqrt(x.z), N(0), N(1)/sqrt(x.z));
|
||||
auto sq = sl2c_to_split_biquaternion<D>(tmp);
|
||||
sq = despin(sq);
|
||||
return typename rep_clifford<D>::point({{sq}});
|
||||
}
|
||||
|
||||
static isometry inverse(isometry T) { return isometry(T[3], -T[1], -T[2], T[0]); }
|
||||
static isometry push(const point& p) { return split_biquaternion_to_sl2c<D>(to_poincare(p)[0]); }
|
||||
|
||||
static N dist0(const point& x) { return rep_clifford<D>::dist0(to_poincare(x)); }
|
||||
static N angle(const point& x) { return rep_clifford<D>::angle(to_poincare(x)); }
|
||||
static N get_coord(const point& x, int i) { return rep_clifford<D>::get_coord(to_poincare(x), i); }
|
||||
|
||||
// imag may be very small and still important, so do not use the default complex print
|
||||
static std::string print(const point& x) { return hr::lalign(0, "{x:", real(x.xy), " y:", imag(x.xy), " z:", x.z, "}"); }
|
||||
static std::string print(const isometry& x) { return x.print(); }
|
||||
};
|
||||
|
||||
template<class D> using rep_half = typename std::conditional<D::Dim==3, rep_halfplane<D>, rep_halfspace<D>>::type;
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
namespace reps {
|
||||
|
||||
/* pull the HyperRogue representation; assumes HyperRogue geometry is set correctly, Number = ld, and Dim=3 or 4 */
|
||||
TD struct rep_hr {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
using point = hr::hyperpoint;
|
||||
using isometry = hr::transmatrix;
|
||||
|
||||
static constexpr isometry cspin(int i, int j, N alpha) { return hr::cspin(i, j, ld(alpha)); }
|
||||
static constexpr isometry cspin90(int i, int j) { return hr::cspin90(i, j); }
|
||||
static constexpr isometry lorentz(int i, int j, N alpha) { return hr::lorentz(i, j, ld(alpha)); }
|
||||
static isometry id() { return hr::Id; };
|
||||
static point center() { return D::Dim == 4 ? hr::C03 : hr::C02; };
|
||||
static point apply(const isometry& T, const point& x) { return T * x; };
|
||||
static isometry apply(const isometry& T, const isometry& U) { return T * U; };
|
||||
static ld dist0(const point& x) { return hdist0(x); }
|
||||
static ld angle(const point& x) { return atan2(x[1], x[0]); }
|
||||
static ld get_coord(const point& x, int i) { return x[i]; }
|
||||
static isometry inverse(const isometry& T) { return iso_inverse(T); }
|
||||
static isometry push(const point& p) { return rgpushxto0(p); }
|
||||
|
||||
static std::string print(point p) { return hr::lalign(0, p); }
|
||||
static std::string print(isometry p) { return hr::lalign(0, p); }
|
||||
};
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
namespace reps {
|
||||
|
||||
TD typename D::Number acos_auto(typename D::Number x) {
|
||||
using N = typename D::Number;
|
||||
if(hyperbolic) {
|
||||
if(x < N(1)) return N(0);
|
||||
return acosh(x);
|
||||
}
|
||||
if(sphere) {
|
||||
if(x > N(1)) return N(0);
|
||||
return acos(x);
|
||||
}
|
||||
throw hr::hr_exception("error");
|
||||
}
|
||||
|
||||
/* use the linear representation, as in HyperRogue, but DO NOT apply nm, for comparison */
|
||||
TD struct rep_linear_nn {
|
||||
|
||||
using data = D;
|
||||
using point = mvector<data>;
|
||||
using isometry = matrix<data>;
|
||||
using N = typename D::Number;
|
||||
|
||||
static constexpr isometry id() {
|
||||
matrix<D> result;
|
||||
for(int i=0; i<D::Dim; i++)
|
||||
for(int j=0; j<D::Dim; j++)
|
||||
result[i][j] = N(i == j);
|
||||
return result;
|
||||
};
|
||||
|
||||
static constexpr isometry cspin(int i, int j, typename D::Number angle) {
|
||||
auto res = id();
|
||||
auto ca = cos(angle), sa = sin(angle);
|
||||
res[i][i] = ca;
|
||||
res[j][j] = ca;
|
||||
res[i][j] = sa;
|
||||
res[j][i] = -sa;
|
||||
return res;
|
||||
};
|
||||
|
||||
static constexpr isometry cspin90(int i, int j) {
|
||||
auto res = id();
|
||||
res[i][i] = 0;
|
||||
res[j][j] = 0;
|
||||
res[i][j] = 1;
|
||||
res[j][i] = -1;
|
||||
return res;
|
||||
};
|
||||
|
||||
static constexpr isometry lorentz(int i, int j, typename D::Number angle) {
|
||||
auto res = id();
|
||||
auto ca = cosh(angle), sa = sinh(angle);
|
||||
res[i][i] = ca;
|
||||
res[j][j] = ca;
|
||||
res[i][j] = sa;
|
||||
res[j][i] = sa;
|
||||
return res;
|
||||
}
|
||||
|
||||
static constexpr point center() { return unit_vector<data>(D::Dim-1); }
|
||||
static point apply(const isometry& T, const point& x) { return T * x; };
|
||||
static isometry apply(const isometry& T, const isometry& U) { return T * U; };
|
||||
static typename D::Number dist0(point x) {
|
||||
return acos_auto<D> (x[D::Dim-1]);
|
||||
}
|
||||
static typename D::Number angle(const point& x) { return atan2(x[1], x[0]); }
|
||||
static typename D::Number get_coord(point x, int i) { return x[i]; }
|
||||
|
||||
static isometry inverse(isometry T) {
|
||||
for(int i=0; i<D::Dim; i++)
|
||||
for(int j=0; j<i; j++) std::swap(T[i][j], T[j][i]);
|
||||
if constexpr(D::Flipped != -1) {
|
||||
for(int i=0; i<D::Dim-1; i++) T[i][D::Dim-1] = -T[i][D::Dim-1];
|
||||
for(int i=0; i<D::Dim-1; i++) T[D::Dim-1][i] = -T[D::Dim-1][i];
|
||||
}
|
||||
return T;
|
||||
}
|
||||
static isometry push(const point& p) {
|
||||
auto res = id();
|
||||
// to do: for spherical!
|
||||
N fac = N(1)/(p[D::Dim-1]+N(1));
|
||||
for(int i=0; i<D::Dim-1; i++)
|
||||
for(int j=0; j<D::Dim-1; j++)
|
||||
res[i][j] += p[i] * p[j] * fac;
|
||||
|
||||
for(int d=0; d<D::Dim-1; d++)
|
||||
res[d][D::Dim-1] = p[d],
|
||||
res[D::Dim-1][d] = p[d];
|
||||
res[D::Dim-1][D::Dim-1] = p[D::Dim-1];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string print(point p) { return nzv(p); }
|
||||
static std::string print(isometry p) { return nzv(p); }
|
||||
};
|
||||
|
||||
TD mvector<D> get_column(matrix<D> a, int id) {
|
||||
mvector<D> tmp;
|
||||
for(int i=0; i<D::Dim; i++) tmp[i] = a[i][id];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
TD typename D::Number inner(mvector<D> a, mvector<D> b) {
|
||||
using N = typename D::Number;
|
||||
N res(0);
|
||||
for(int i=0; i<D::Dim; i++) res += a[i] * b[i] * (i==D::Flipped?-1:1);
|
||||
if(isnan(res) || isinf(res)) return N(0);
|
||||
return res;
|
||||
}
|
||||
|
||||
TD void set_column(matrix<D>& a, int id, mvector<D> v) {
|
||||
for(int i=0; i<D::Dim; i++) a[i][id] = v[i];
|
||||
}
|
||||
|
||||
TD typename D::Number sqnorm(matrix<D> a) { return sqnorm<D>(get_column<D>(a, D::Dim-1)); }
|
||||
|
||||
bool fix_matrices;
|
||||
|
||||
TD matrix<D> apply_nm(matrix<D> a) {
|
||||
using N = typename D::Number;
|
||||
// normalize first
|
||||
auto& lead = a[D::Dim-1][D::Dim-1];
|
||||
if(nm == nmFlatten) a = a / lead, cbc[cbcDiv]--;
|
||||
if(nm == nmForced || nm == nmWeak) a = a * pow(sqnorm<D>(a), -0.5);
|
||||
if(nm == nmBinary) {
|
||||
while(lead >= 2 && !isinf(lead)) { a = a / 2; } while(lead > 0 && lead < 0.5) { a = a * 2; }
|
||||
}
|
||||
// fixmatrix later
|
||||
if(!fix_matrices) return a;
|
||||
auto divby = (nm == nmBinary || nm == nmWeak || nm == nmCareless || nm == nmFlatten) ? sqnorm<D>(a) : N(1);
|
||||
for(int i=D::Dim-2; i>=0; i--) {
|
||||
auto ro = get_column(a, i);
|
||||
auto last = get_column(a, D::Dim-1);
|
||||
ro = ro + last * inner(ro, last) / divby;
|
||||
for(int j=i+1; j<D::Dim-1; j++) {
|
||||
auto next = get_column(a, j);
|
||||
ro = ro - next * inner(ro, next) / divby;
|
||||
}
|
||||
auto in = inner(ro, ro);
|
||||
if(in > N(0)) ro = ro * (pow(in*in, -.5) * divby);
|
||||
set_column(a, i, ro);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/* use the linear representation, as in HyperRogue */
|
||||
TD struct rep_linear {
|
||||
|
||||
using data = D;
|
||||
using point = mvector<data>;
|
||||
using isometry = matrix<data>;
|
||||
using N = typename D::Number;
|
||||
|
||||
static constexpr isometry cspin(int i, int j, typename D::Number angle) {
|
||||
return apply_nm<D>( rep_linear_nn<D>::cspin(i, j, angle) );
|
||||
}
|
||||
static constexpr isometry cspin90(int i, int j) {
|
||||
return rep_linear_nn<D>::cspin90(i, j);
|
||||
}
|
||||
static constexpr isometry lorentz(int i, int j, typename D::Number angle) {
|
||||
return apply_nm<D>( rep_linear_nn<D>::lorentz(i, j, angle) );
|
||||
}
|
||||
static isometry id() { return rep_linear_nn<D>::id(); };
|
||||
static constexpr point center() { return unit_vector<data>(D::Dim-1); }
|
||||
static point apply(const isometry& T, const point& x) { return apply_nm(T * x); };
|
||||
static isometry apply(const isometry& T, const isometry& U) { return apply_nm(T * U); };
|
||||
static typename D::Number dist0(point x) {
|
||||
return acos_auto<D> (get_normalized(x, x[D::Dim-1]));
|
||||
}
|
||||
static typename D::Number angle(const point& x) { return atan2(x[1], x[0]); }
|
||||
static typename D::Number get_coord(point x, int i) {
|
||||
return get_normalized(x, x[i]); }
|
||||
|
||||
static isometry inverse(isometry T) {
|
||||
return rep_linear_nn<D>::inverse(T);
|
||||
}
|
||||
static isometry push(const point& p) {
|
||||
return apply_nm( rep_linear_nn<D>::push(get_normalized(p, p)) );
|
||||
}
|
||||
|
||||
static std::string print(point p) { return nzv(p); }
|
||||
static std::string print(isometry p) { return nzv(p); }
|
||||
};
|
||||
|
||||
/* use the linear representation of points and the multivector representation of isometries */
|
||||
|
||||
TD struct rep_mixed {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
|
||||
using point = mvector<data>;
|
||||
using isometry = multivector<data>;
|
||||
|
||||
static isometry cspin(int i, int j, typename data::Number alpha, bool noflat = false) {
|
||||
/* auto u = unit_vector<multivector_data<data>> (0);
|
||||
auto ui = unit_vector<data> (i);
|
||||
auto uj = unit_vector<data> (j);
|
||||
return u * cos(alpha/2) + multimul(embed(ui), embed(uj)) * sin(alpha/2); */
|
||||
auto res = zero_vector<multivector_data<data>> ();
|
||||
if(nm == nmFlatten && !noflat) {
|
||||
res[0] = N(1);
|
||||
res[(1<<i) | (1<<j)] = tan(alpha/2) * (i > j ? 1 : -1);
|
||||
return res;
|
||||
}
|
||||
res[0] = cos(alpha/2);
|
||||
res[(1<<i) | (1<<j)] = sin(alpha/2) * (i > j ? 1 : -1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static isometry cspin90(int i, int j, bool noflat = false) {
|
||||
auto res = zero_vector<multivector_data<data>> ();
|
||||
if(nm == nmFlatten && !noflat) {
|
||||
res[0] = N(1);
|
||||
res[(1<<i) | (1<<j)] = N(i > j ? 1 : -1);
|
||||
return res;
|
||||
}
|
||||
res[0] = sqrt(N(.5));
|
||||
res[(1<<i) | (1<<j)] = sqrt(N(.5)) * (i > j ? 1 : -1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static isometry lorentz(int i, int j, typename data::Number alpha) {
|
||||
/* // j must be time coordinate
|
||||
auto u = unit_vector<multivector_data<data>> (0);
|
||||
auto ui = unit_vector<data> (i);
|
||||
auto uj = unit_vector<data> (j);
|
||||
return u * cosh(alpha/2) + multimul(embed(uj), embed(ui)) * sinh(alpha/2); */
|
||||
auto res = zero_vector<multivector_data<data>> ();
|
||||
if(nm == nmFlatten) {
|
||||
res[0] = N(1);
|
||||
res[(1<<i) | (1<<j)] = tanh(alpha/2);
|
||||
return res;
|
||||
}
|
||||
res[0] = cosh(alpha/2);
|
||||
res[(1<<i) | (1<<j)] = sinh(alpha/2);
|
||||
return res;
|
||||
}
|
||||
static isometry id() { return unit_vector<multivector_data<data>> (0); };
|
||||
static constexpr point center() { return unit_vector<data>(D::Dim-1); }
|
||||
static point apply(const isometry& T, const point& x) {
|
||||
// return unembed(multimul(multimul(T, embed(x)), conjugate(T)));
|
||||
return apply_nm(unembed(chkmul<odd<D>,flat_even<D>,underling<D>>(chkmul<flat_even<D>,flat_underling<D>,odd<D>>(T, embed(x)), conjugate(T))));
|
||||
};
|
||||
static isometry apply(const isometry& T, const isometry& U) {
|
||||
auto res = apply_nm<even<D>, D>(chkmul<flat_even<D>,flat_even<D>,even<D>>(T, U));
|
||||
return res;
|
||||
}
|
||||
|
||||
static isometry inverse(isometry T) { return conjugate(T); }
|
||||
static isometry push(const point& p) {
|
||||
auto pm = get_normalized(p, p);
|
||||
pm[D::Dim-1] = pm[D::Dim-1] + N(1);
|
||||
// since p was normalized, sqnorm of pm is 2 * pm[D::Dim-1]
|
||||
pm = pm * pow(2 * pm[D::Dim-1], -0.5);
|
||||
multivector<data> v1 = embed(pm);
|
||||
multivector<data> v2 = unit_vector<multivector_data<data>>(1<<(D::Dim-1));
|
||||
multivector<data> v3 = chkmul<underling<D>,underling<D>,poincare<D>>(v1, v2);
|
||||
v3 = apply_nm<poincare<D>, D>(v3);
|
||||
return v3;
|
||||
}
|
||||
|
||||
static typename D::Number dist0(point x) { return acos_auto<D> (get_normalized(x, x[D::Dim-1])); }
|
||||
static typename D::Number angle(const point& x) { return atan2(x[1], x[0]); }
|
||||
static typename D::Number get_coord(point x, int i) { return get_normalized(x, x[i]); }
|
||||
|
||||
static std::string print(point p) { return nzv(p); }
|
||||
static std::string print(isometry p) { return nz(p); }
|
||||
};
|
||||
|
||||
/* use the hyperboloid-Poincare representation of points and the multivector representation of isometries */
|
||||
|
||||
TD struct rep_clifford {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
|
||||
using point = array< multivector<data>, 1>;
|
||||
using isometry = multivector<data>;
|
||||
|
||||
static isometry cspin(int i, int j, typename data::Number alpha) { return rep_mixed<D>::cspin(i, j, alpha); }
|
||||
static isometry cspin90(int i, int j) { return rep_mixed<D>::cspin90(i, j); }
|
||||
// j must be the neg coordinate!
|
||||
static isometry lorentz(int i, int j, N alpha) { return rep_mixed<D>::lorentz(i, j, alpha); }
|
||||
static isometry id() { return rep_mixed<D>::id(); }
|
||||
static constexpr point center() { return point{{ id() }}; }
|
||||
static point apply(const isometry& T, const point& x) { return point{{ despin(chkmul<even<D>,poincare<D>,even<D>>(T, x[0])) }}; }
|
||||
static isometry apply(const isometry& T, const isometry& U) { return apply_nm<even<D>,D>( chkmul<even<D>,even<D>,even<D>>(T, U) ); }
|
||||
|
||||
static isometry inverse(isometry T) { return conjugate(T); }
|
||||
static isometry push(const point& p) { return p[0]; }
|
||||
|
||||
static typename D::Number dist0(const point& ax) {
|
||||
return acos_auto<D>(get_normalized<poincare<D>, D, N>(ax[0], ax[0][0]))*2;
|
||||
}
|
||||
static constexpr int mvlast = 1<<(D::Dim-1);
|
||||
static typename D::Number angle(const point& x) {
|
||||
return atan2(x[0][2 | mvlast], x[0][1 | mvlast]);
|
||||
}
|
||||
static typename D::Number get_coord(const point& x, int i) {
|
||||
auto x1 = multimul(multimul(x[0], unit_vector<multivector_data<data>> (mvlast)), conjugate(x[0]));
|
||||
auto x2 = unembed(x1);
|
||||
return get_normalized(x2, x2[i]);
|
||||
}
|
||||
|
||||
static std::string print(point p) { return nz(p[0]); }
|
||||
static std::string print(isometry p) { return nz(p); }
|
||||
};
|
||||
|
||||
/* split isometries into the poincare and rotational part */
|
||||
|
||||
TD struct rep_gyro {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
|
||||
using point = multivector<data>;
|
||||
using isometry = poincare_rotation<data>;
|
||||
|
||||
static isometry cspin(int i, int j, typename data::Number alpha) { return { rep_mixed<D>::id(), rep_mixed<D>::cspin(i, j, alpha, true) }; }
|
||||
static isometry cspin90(int i, int j, typename data::Number alpha) { return { rep_mixed<D>::id(), rep_mixed<D>::cspin90(i, j, alpha, true) }; }
|
||||
static isometry lorentz(int i, int j, typename data::Number alpha) { return {rep_mixed<D>::lorentz(i, j, alpha), rep_mixed<D>::id() }; }
|
||||
static isometry id() { return { rep_mixed<D>::id(), rep_mixed<D>::id() }; }
|
||||
static constexpr point center() { return rep_mixed<D>::id(); }
|
||||
static point apply(const isometry& T, const point& x) { return despin(chkmul<poincare<D>,poincare<D>,even<D>>(T.first, chkmul<rotational<D>,poincare<D>,poincare<D>>(T.second, x))); }
|
||||
static isometry apply(const isometry& T, const isometry& U) {
|
||||
auto R1 = apply_nm<rotational<D>, poincare<D>, poincare<D>> (T.second, U.first);
|
||||
auto R2 = apply_nm<poincare<D>, poincare<D>, even<D>> (T.first, R1);
|
||||
auto R3 = despin2(R2);
|
||||
return { R3.first, apply_nm<rotational<D>, rotational<D>, rotational<D>> (R3.second, U.second) };
|
||||
}
|
||||
|
||||
static isometry inverse(isometry T) { return { conjugate(T.first), conjugate(T.second) }; }
|
||||
static isometry push(const point& p) { return { p, rep_mixed<D>::id() }; }
|
||||
|
||||
static typename D::Number dist0(const point& ax) {
|
||||
return acos_auto<D>(get_normalized<poincare<D>, D, N>(ax, ax[0]))*2;
|
||||
}
|
||||
static constexpr int mvlast = 1<<(D::Dim-1);
|
||||
static typename D::Number angle(const point& x) {
|
||||
return atan2(x[0][2 | mvlast], x[0][1 | mvlast]);
|
||||
}
|
||||
static typename D::Number get_coord(const point& x, int i) {
|
||||
auto x1 = multimul(multimul(x[0], unit_vector<multivector_data<data>> (mvlast)), conjugate(x[0]));
|
||||
auto x2 = unembed(x1);
|
||||
return get_normalized(x2, x2[i]);
|
||||
}
|
||||
|
||||
static std::string print(point p) { return nz(p[0]); }
|
||||
static std::string print(isometry p) { return "["+nz(p.first)+","+nz(p.second)+"]"; }
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
bool polar_mod = true, polar_choose = true;
|
||||
|
||||
namespace reps {
|
||||
|
||||
template<class N> static void cyclefix(N& a) {
|
||||
while(a > + get_deg<N>(180)) a -= get_deg<N>(360);
|
||||
while(a < - get_deg<N>(180)) a += get_deg<N>(360);
|
||||
}
|
||||
|
||||
template<class N> static N cyclefix_on(N a) { cyclefix(a); return a; }
|
||||
|
||||
/** the Taylor polynomial for 1-sqrt(1-y*y) */
|
||||
template<class N> N ssqrt(N y) {
|
||||
return y*y/2 + y*y*y*y/8 + y*y*y*y*y*y*y/16 + y*y*y*y*y*y*y*y*y/128;
|
||||
}
|
||||
|
||||
TD struct rep_polar2 {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
|
||||
struct point { N phi, r; };
|
||||
struct isometry { N psi, phi, r; }; // spin by psi first
|
||||
|
||||
static isometry cspin(int i, int j, N alpha) {
|
||||
if(i>j) std::swap(i, j), alpha = -alpha;
|
||||
return isometry{.psi = -alpha, .phi = N(0), .r = N(0) };
|
||||
}
|
||||
static isometry cspin90(int i, int j) { return cspin(i, j, get_deg<N>(90)); }
|
||||
static isometry lorentz(int i, int j, N alpha) {
|
||||
if(i>j) std::swap(i, j);
|
||||
if(i == 0) return isometry{.psi = N(0), .phi = N(0), .r = alpha};
|
||||
if(i == 1) return isometry{.psi = N(0), .phi = get_deg<N>(90), .r = alpha};
|
||||
throw hr::hr_exception("bad lorentz");
|
||||
}
|
||||
static isometry id() { return isometry{.psi = N(0), .phi = N(0), .r = N(0)}; };
|
||||
static point center() { return point{.phi = N(0), .r = N(0)}; };
|
||||
|
||||
static std::string print(isometry T) {
|
||||
return hr::lalign(0, "{phi=", T.phi, " r=", T.r, " psi=", T.psi, "}");
|
||||
}
|
||||
|
||||
static std::string print(point T) {
|
||||
return hr::lalign(0, "{phi=", T.phi, " r=", T.r, "}");
|
||||
}
|
||||
|
||||
static isometry apply(isometry T, isometry U, bool need_psi = true) {
|
||||
if(T.r == 0) return isometry {.psi = T.psi+U.psi, .phi = T.psi+U.phi, .r = U.r};
|
||||
if(U.r == 0) return isometry {.psi = T.psi+U.psi, .phi = T.phi, .r = T.r};
|
||||
N alpha = U.phi + T.psi - T.phi;
|
||||
if(polar_mod) cyclefix(alpha);
|
||||
isometry res;
|
||||
N y1 = sinh(U.r) * sin(alpha);
|
||||
|
||||
auto ca = cos(alpha);
|
||||
auto sa = sin(alpha);
|
||||
N x1, x2;
|
||||
|
||||
// choose the appropriate method
|
||||
if(polar_choose && ca >= N(0.5)) {
|
||||
N u = ca >= N(.999999) ? ssqrt(sa) : N(1) - ca;
|
||||
res.r = cosh(T.r + U.r) - u * sinh(T.r) * sinh(U.r);
|
||||
x1 = sinh(T.r + U.r) - u * cosh(T.r) * sinh(U.r);
|
||||
if(need_psi) x2 = sinh(T.r + U.r) - u * cosh(U.r) * sinh(T.r);
|
||||
}
|
||||
else if(polar_choose && ca <= N(-0.5)) {
|
||||
N u = ca <= N(-.999999) ? ssqrt(-sa) : ca + N(1);
|
||||
res.r = cosh(T.r - U.r) + u * sinh(T.r) * sinh(U.r);
|
||||
x1 = sinh(T.r - U.r) + u * cosh(T.r) * sinh(U.r);
|
||||
if(need_psi) x2 = sinh(U.r - T.r) + u * cosh(U.r) * sinh(T.r);
|
||||
}
|
||||
else {
|
||||
res.r = sinh(T.r) * sinh(U.r) * ca + cosh(T.r) * cosh(U.r);
|
||||
x1 = cosh(T.r) * sinh(U.r) * ca + cosh(U.r) * sinh(T.r);
|
||||
if(need_psi) x2 = cosh(U.r) * sinh(T.r) * ca + cosh(T.r) * sinh(U.r);
|
||||
}
|
||||
|
||||
if(res.r < N(1)) res.r = N(0); else res.r = acosh(res.r);
|
||||
|
||||
N beta = (y1 || x1) ? atan2(y1, x1) : N(0);
|
||||
res.phi = T.phi + beta;
|
||||
if(polar_mod) cyclefix(res.phi);
|
||||
|
||||
if(need_psi) {
|
||||
N y2 = sinh(T.r) * sin(alpha);
|
||||
N gamma = (y2 || x2) ? atan2(y2, x2) : N(0);
|
||||
res.psi = T.psi + U.psi + beta + gamma - alpha;
|
||||
if(polar_mod) cyclefix(res.psi);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
static point apply(const isometry& T, const point& x) {
|
||||
isometry x1 = apply(T, push(x), false);
|
||||
return point { .phi = x1.phi, .r = x1.r};
|
||||
};
|
||||
|
||||
static isometry inverse(isometry T) { return isometry{.psi = -T.psi, .phi = cyclefix_on<N>(get_deg<N>(180)+T.phi-T.psi), .r=T.r }; };
|
||||
static isometry push(const point& p) { return isometry{.psi = N(0), .phi = p.phi, .r = p.r}; }
|
||||
|
||||
static N dist0(const point& x) { return x.r; }
|
||||
static N angle(const point& x) { return x.phi; }
|
||||
static N get_coord(const point& x, int i) {
|
||||
if(i == 0) return cos(x.phi) * sinh(x.r);
|
||||
if(i == 1) return sin(x.phi) * sinh(x.r);
|
||||
if(i == 2) return cosh(x.r);
|
||||
throw hr::hr_exception("bad get_coord");
|
||||
}
|
||||
};
|
||||
|
||||
TD struct rep_high_polar {
|
||||
|
||||
using data = D;
|
||||
using N = typename D::Number;
|
||||
|
||||
struct sphere_data {
|
||||
using Number = N;
|
||||
static constexpr int Dim = D::Dim-1;
|
||||
static constexpr int Flipped = -1;
|
||||
};
|
||||
|
||||
using subsphere = rep_linear_nn<sphere_data>;
|
||||
|
||||
struct point { typename subsphere::point phi; N r; };
|
||||
struct isometry { typename subsphere::isometry psi; typename subsphere::point phi; N r; };
|
||||
|
||||
static isometry cspin(int i, int j, N alpha) {
|
||||
return isometry{.psi = subsphere::cspin(i, j, alpha), .phi = subsphere::center(), .r = N(0) };
|
||||
}
|
||||
static isometry cspin90(int i, int j) {
|
||||
return isometry{.psi = subsphere::cspin90(i, j), .phi = subsphere::center(), .r = N(0) };
|
||||
}
|
||||
static isometry lorentz(int i, int j, N alpha) {
|
||||
if(i>j) std::swap(i, j);
|
||||
auto is = isometry{.psi = subsphere::id(), .phi = subsphere::center(), .r = alpha};
|
||||
is.phi[D::Dim-2] = N(0);
|
||||
is.phi[i] = N(1);
|
||||
return is;
|
||||
}
|
||||
static isometry id() { return isometry{.psi = subsphere::id(), .phi = subsphere::center(), .r = N(0)}; }
|
||||
static point center() { return point{.phi = subsphere::center(), .r = N(0)}; };
|
||||
|
||||
static std::string print(isometry T) {
|
||||
return hr::lalign(0, "{phi=", subsphere::print(T.phi), " r=", T.r, " psi=", hr::kz(T.psi.values), "}");
|
||||
}
|
||||
|
||||
static std::string print(point T) {
|
||||
return hr::lalign(0, "{phi=", subsphere::print(T.phi), " r=", T.r, "}");
|
||||
}
|
||||
|
||||
static isometry apply(isometry T, isometry U, bool need_psi = true) {
|
||||
auto apsi = need_psi ? T.psi * U.psi : subsphere::id();
|
||||
if(T.r == 0) return isometry {.psi = apsi, .phi = T.psi*U.phi, .r = U.r};
|
||||
if(U.r == 0) return isometry {.psi = apsi, .phi = T.phi, .r = T.r};
|
||||
auto aphi = T.psi * U.phi;
|
||||
auto cos_alpha = inner<sphere_data>(aphi, T.phi);
|
||||
auto& ca = cos_alpha;
|
||||
|
||||
isometry res;
|
||||
|
||||
N x1, x2;
|
||||
|
||||
auto orth = (aphi - T.phi * ca);
|
||||
N sin_alpha;
|
||||
if(ca > N(0.999999) || ca < N(0.999999))
|
||||
sin_alpha = pow(sqnorm<sphere_data>(orth), .5);
|
||||
else
|
||||
sin_alpha = pow(N(1) - ca * ca, .5);
|
||||
|
||||
if(sin_alpha == N(0)) {
|
||||
if(ca >= N(1)) {
|
||||
return isometry{.psi = apsi, .phi = T.phi, .r = T.r + U.r };
|
||||
}
|
||||
if(ca <= N(-1)) {
|
||||
if(T.r >= U.r) {
|
||||
return isometry{.psi = apsi, .phi = T.phi, .r = T.r - U.r };
|
||||
}
|
||||
else {
|
||||
return isometry{.psi = apsi, .phi = T.phi*-1, .r = U.r - T.r };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orth = orth / sin_alpha;
|
||||
N y1 = sinh(U.r) * sin_alpha;
|
||||
|
||||
// choose the appropriate method
|
||||
if(polar_choose && ca >= N(0.5)) {
|
||||
N u = ca >= N(.999999) ? ssqrt(sin_alpha) : N(1) - ca;
|
||||
res.r = cosh(T.r + U.r) - u * sinh(T.r) * sinh(U.r);
|
||||
x1 = sinh(T.r + U.r) - u * cosh(T.r) * sinh(U.r);
|
||||
if(need_psi) x2 = sinh(T.r + U.r) - u * cosh(U.r) * sinh(T.r);
|
||||
}
|
||||
else if(polar_choose && ca <= N(-0.5)) {
|
||||
N u = ca <= N(-.999999) ? ssqrt(sin_alpha) : ca + N(1); // ca = u - 1
|
||||
res.r = cosh(T.r - U.r) + u * sinh(T.r) * sinh(U.r);
|
||||
x1 = sinh(T.r - U.r) + u * cosh(T.r) * sinh(U.r);
|
||||
if(need_psi) x2 = sinh(U.r - T.r) + u * cosh(U.r) * sinh(T.r);
|
||||
}
|
||||
else {
|
||||
res.r = sinh(T.r) * sinh(U.r) * ca + cosh(T.r) * cosh(U.r);
|
||||
x1 = cosh(T.r) * sinh(U.r) * ca + cosh(U.r) * sinh(T.r);
|
||||
if(need_psi) x2 = cosh(U.r) * sinh(T.r) * ca + cosh(T.r) * sinh(U.r);
|
||||
}
|
||||
|
||||
if(res.r < N(1)) res.r = N(0); else res.r = acosh(res.r);
|
||||
|
||||
auto h1 = pow(x1*x1+y1*y1, -0.5);
|
||||
N cos_beta = x1*h1, sin_beta = y1*h1;
|
||||
|
||||
res.phi = T.phi * cos_beta + orth * sin_beta;
|
||||
|
||||
if(need_psi) {
|
||||
N y2 = sinh(T.r) * sin_alpha;
|
||||
auto h2 = pow(x2*x2+y2*y2, -0.5);
|
||||
N cos_gamma = x2*h2, sin_gamma = y2*h2;
|
||||
|
||||
// delta = beta + gamma - alpha
|
||||
|
||||
auto cos_beta_gamma = cos_beta * cos_gamma - sin_beta * sin_gamma;
|
||||
auto sin_beta_gamma = cos_beta * sin_gamma + sin_beta * cos_gamma;
|
||||
|
||||
auto cos_delta = cos_beta_gamma * cos_alpha + sin_beta_gamma * sin_alpha;
|
||||
auto sin_delta = sin_beta_gamma * cos_alpha - cos_beta_gamma * sin_alpha;
|
||||
|
||||
auto phi1 = T.phi * cos_delta + orth * sin_delta;
|
||||
auto orth1 = orth * cos_delta - T.phi * sin_delta;
|
||||
|
||||
auto phi2 = phi1 - T.phi;
|
||||
auto orth2 = orth1 - orth;
|
||||
typename subsphere::isometry spinner = subsphere::id();
|
||||
|
||||
// Tv = v + <v, phi> * (phi'-phi) + <v, orth> * (orth'-orth)
|
||||
|
||||
for(int i=0; i<D::Dim-1; i++)
|
||||
for(int j=0; j<D::Dim-1; j++)
|
||||
spinner[i][j] += phi2[i] * T.phi[j] + orth2[i] * orth[j];
|
||||
|
||||
res.psi = spinner * apsi;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
static point apply(const isometry& T, const point& x) {
|
||||
isometry x1 = apply(T, push(x), false);
|
||||
return point { .phi = x1.phi, .r = x1.r};
|
||||
};
|
||||
|
||||
static isometry inverse(isometry T) { return isometry{.psi = subsphere::inverse(T.psi), .phi = subsphere::inverse(T.psi)*T.phi*-1, .r=T.r }; };
|
||||
static isometry push(const point& p) { return isometry{.psi = subsphere::id(), .phi = p.phi, .r = p.r}; }
|
||||
|
||||
static N dist0(const point& x) { return x.r; }
|
||||
static N angle(const point& x) { return subsphere::angle(x.phi); }
|
||||
static N get_coord(const point& x, int i) { if(i == D::Dim-1) return cosh(x.r); else return x.phi[i] * sinh(x.r); }
|
||||
};
|
||||
|
||||
template<class D> using rep_polar = typename std::conditional<D::Dim==3, rep_polar2<D>, rep_high_polar<D>>::type;
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#include <boost/multiprecision/mpfr.hpp>
|
||||
|
||||
#include "../../hyper.h"
|
||||
|
||||
#define TD template<class D>
|
||||
#undef sl2
|
||||
|
||||
namespace reps {
|
||||
|
||||
using namespace boost::multiprecision;
|
||||
using big = mpfr_float_50;
|
||||
}
|
||||
|
||||
namespace hr {
|
||||
void print(hr::hstream& hs, ::reps::big b) {
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(10);
|
||||
ss << b; string u; ss >> u; print(hs, u);
|
||||
}
|
||||
}
|
||||
|
||||
namespace reps {
|
||||
using std::array;
|
||||
using std::vector;
|
||||
|
||||
using hr::cell;
|
||||
using hr::print;
|
||||
using hr::hlog;
|
||||
using hr::celldistance;
|
||||
using hr::ld;
|
||||
using hr::ginf;
|
||||
using hr::geometry;
|
||||
using hr::gcHyperbolic;
|
||||
using hr::gcSphere;
|
||||
using hr::C02;
|
||||
using hr::C03;
|
||||
using hr::qANYQ;
|
||||
|
||||
template <class N> N get_deg(int deg);
|
||||
template<> ld get_deg<ld> (int deg) { return M_PI*deg/180; }
|
||||
template<> big get_deg<big> (int deg) { return atan(big(1))*deg/45; }
|
||||
|
||||
enum eNormalizeMode {
|
||||
nmInvariant, // if the input was normalized, the output will be normalized too
|
||||
nmForced, // normalize the output
|
||||
nmWeak, // weakly normalize the output
|
||||
nmCareless, // do not try to keep the output normalized
|
||||
nmFlatten, // flatten the representation
|
||||
nmBinary // try to avoid overflow
|
||||
};
|
||||
|
||||
eNormalizeMode nm;
|
||||
|
||||
}
|
||||
|
||||
#include "counter.cpp"
|
||||
#include "multivector.cpp"
|
||||
#include "rep-hr.cpp"
|
||||
#include "rep-multi.cpp"
|
||||
#include "rep-halfplane.cpp"
|
||||
#include "rep-polar.cpp"
|
||||
#include "tests.cpp"
|
||||
|
||||
namespace reps {
|
||||
|
||||
// -- tests ---
|
||||
|
||||
void test_systems() {
|
||||
run_all_tests();
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void set_repgeo() {
|
||||
if(test_dim == 3) { hr::set_geometry(hr::gNormal); hr::set_variation(hr::eVariation::pure); }
|
||||
if(test_dim == 4) { hr::set_geometry(hr::gSpace435); }
|
||||
}
|
||||
|
||||
int a = hr::arg::add1("-test-reps", test_systems) + hr::arg::add1("-repgeo", set_repgeo);
|
||||
|
||||
}
|
|
@ -0,0 +1,733 @@
|
|||
# What is it
|
||||
|
||||
This is a study of numerical precision errors in various representations of 2D hyperbolic geometry.
|
||||
It is generally the best to combine a representation with tiling; the tests take this into
|
||||
account.
|
||||
|
||||
# Representations studied
|
||||
|
||||
The following representations are studied:
|
||||
|
||||
* **linear**: points in the hyperboloid model; isometries as linear transformation matrices.
|
||||
|
||||
* **mixed**: points in the hyperboloid model; isometries using Clifford algebras. (Clifford algebras
|
||||
are a generalization of 'quaternions' commonly used in 3D graphics.)
|
||||
|
||||
* **clifford**: points are also represented using Clifford algebras, that is, p is represented as
|
||||
the isometry u such as u(C0) = p and u does not introduce extra rotations.
|
||||
|
||||
* **halfplane (2D)**: points are represented using the half-plane model; isometries are represented using
|
||||
SL(2,R).
|
||||
|
||||
* **halfspace (3D)**: points are represented using the half-space model; isometries are represented using
|
||||
SL(2,C).
|
||||
|
||||
* **polar 2D**: points are represented using polar coordinates; isometries need one extra angle.
|
||||
|
||||
* **general polar**: like polar 2D, but instead of angles, we use rotated unit vectors and rotation
|
||||
matrices; this also makes it work in higher dimension.
|
||||
|
||||
## Variations
|
||||
|
||||
Both in linear and Clifford representations, there is the correct "normalized" representation;
|
||||
if the normalized representation is multiplied by some factor x, most formulas still work,
|
||||
and for those which do not, it is easy to compute x. This yields the following variations:
|
||||
|
||||
* **invariant**: keep the invariant that the points and isometries are normalized
|
||||
(that is: output is normalized under the assumption that the input is normalized)
|
||||
|
||||
* **careless**: do not care about normalization
|
||||
(advantages: some computations are avoided; possible to represent ultra-ideal points in
|
||||
linear representations)
|
||||
|
||||
* **forced**: normalize the output after every computation
|
||||
(might be a good idea for points/isometries close to the center, but generally a bad
|
||||
idea if they are far away -- in that case, the norm generally cannot be computed, but
|
||||
distances and angles still tend to be correct in the invariant computations)
|
||||
|
||||
* **weakly forced**: like forced, but do not normalize if the norm could not be computed
|
||||
due to precision errors
|
||||
|
||||
* **flatten**: instead of normal normalization, make the leading coordinate equal to 1.
|
||||
The leading coordinate is the 'timelike' coordinate of linear representations
|
||||
of points, and the 'unit' coordinate of Clifford representations.
|
||||
(advantage: save memory: H2 represented only 2 coordinates instead of 3;
|
||||
disadvantage: might not represent ultra-ideal points if they would be infinite)
|
||||
|
||||
* **binary**: in careless, values may easily explode and cause underflow/overflow; avoid this
|
||||
by making the leading coordinate in \[0.5, 2) range (by multiplying by powers of 2, which is
|
||||
presumably fast)
|
||||
|
||||
Furthermore:
|
||||
* in linear, matrices can be **fixed** by replacing them by a correct orthogonal matrix close
|
||||
to the current computation
|
||||
* in (non-general) polar, forcing angles into [-pi,pi] may be needed to prevent explosion
|
||||
* in **improved** polar, one of three variants of the cosine rule can be used, depending on the angle,
|
||||
to improve the numerical precision; also even more precise computation to avoid numerical
|
||||
precision errors for angles very close to 0 or pi
|
||||
* in the Clifford representation, the **gyro** variant splits the isometries into
|
||||
the translational part (which is flattened, making it equivalent to the Poincare disk model)
|
||||
and the rotational part (for which 'invariant' is used). This fixes the problem
|
||||
with full flattening where rotations by 180° are flattened to infinity. (AFAIK
|
||||
Hyperbolica uses roughly this)
|
||||
|
||||
## Observations
|
||||
|
||||
* except linear, all the methods of representing isometries can only represent
|
||||
orientation-preserving ones
|
||||
|
||||
* Clifford isometries of H2 is essentially the same as SL(2,R) of halfplane -- it is
|
||||
just the change of the basis
|
||||
|
||||
* linear/Clifford representations are not that good at representing points close to the
|
||||
boundary of the disk (invariant can somewhat tell the distance but flattened cannot);
|
||||
halfplane is better here
|
||||
|
||||
# Tests
|
||||
|
||||
## test_loop_iso
|
||||
|
||||
In this test, for each i, we construct a path in the tiling by always moving to a random
|
||||
adjacent tile, until we get to a tile i afar; then, we return to the start (also randomly,
|
||||
may stray further from the path). We compose all the relative tile isometries into T and see
|
||||
if T(C0) = C0. The score is the first i for which it fails.
|
||||
|
||||
Discussion: This makes rep_mixed worse than rep_lorentz.
|
||||
|
||||
## test_loop_point
|
||||
|
||||
Same as test_loop_iso but we apply the consecutive isometries to point right away.
|
||||
|
||||
Discussion: This makes rep_mixed worse than rep_lorentz.
|
||||
|
||||
## test_angledist
|
||||
|
||||
For each i (skipping some), construct a path outwards in the tiling, compose isometries,
|
||||
and see if the distance and angle to that tile have been computed correctly.
|
||||
|
||||
Discussion: Invariant representations have no problem with this, even if the points obtained are beyond the precision otherwise.
|
||||
|
||||
## test_similarity, test_dissimilarity, test_other
|
||||
|
||||
For each i, compute the distance between two points in distance i from the starting point.
|
||||
The angle between them is very small (test_similarity), close to 180° (test_dissimilarity),
|
||||
close to 1° (test_other).
|
||||
|
||||
Discussion: Similarity is obviously the most difficult. Halfplane is surprisingly powerful in all cases.
|
||||
|
||||
## test_walk
|
||||
|
||||
This is essentially walking in a straight line in HyperRogue. After some time, it can be often clearly observed that we
|
||||
have 'deviated' from the original straight line. This test checks how long we can walk.
|
||||
|
||||
We construct an isometry T representing a random direction. In each step, we compose this isometry with a translation (T := T * translate(1/16)).
|
||||
Whenever the point T * C0 is closer to the center of another tile, we rebase to that new tile.
|
||||
|
||||
For a test, we actually do this in parallel with two isometries T0 and T1, where T1 = T0 * translate(1/32). We count the number of steps
|
||||
until the paths diverge. Numbers over 1000 are not actually that good, 1000+n means that, after n steps, the implementation no longer detects tile
|
||||
changes. Numbers of 10000 signify that some even weirder problem happened.
|
||||
|
||||
Discussion: Since the isometry matrices are always small (constrained to tiles), fixing definitely helps here. Without fixing, T stops
|
||||
being an isometry (an effect visible in HyperRogue when fixing is disabled).
|
||||
|
||||
## test_close
|
||||
|
||||
Here we see whether small errors accumulate when moving close to the center. In test i, we move randomly until we reach distance i+1,
|
||||
after which we return to the start (always reducing the distance). After each return to the start, we check if the representation is
|
||||
still fine (if not, we restart with the original representation). The number given is the number of errors in 10000 steps.
|
||||
|
||||
Discussion: Errors do not appear to accumulate when we simply move close to the start (or rather, they accumulate very slowly).
|
||||
|
||||
## test_count
|
||||
|
||||
This simply computes the number of numerical operations performed for every geometric operation. Numerical operations are categorized as:
|
||||
* Addition/subtraction
|
||||
* Multiplication (multiplication by constant not counted)
|
||||
* Division (division by constant not counted)
|
||||
* Functions: exp, log, (a)sin/cos/tan(h), sqrt, inverse sqrt
|
||||
|
||||
Geometric operations are:
|
||||
* spin: return rotation by given angle in given axes
|
||||
* L0: return translation by given value in axis 0
|
||||
* L1: return translation by given value in axis 1
|
||||
* ip: apply isometry to point
|
||||
* ii: compose isometries
|
||||
* d0: compute the distance of point from 0
|
||||
* angle: compute the (2D) angle of point
|
||||
* inverse: compute the inverse of an isometry
|
||||
* push: convert a point into a translation
|
||||
|
||||
# Implementation notes
|
||||
|
||||
Note: the program currently assumes hyperbolic geometry (it was intended to support spherical
|
||||
geometry but not everywhere the correct handling is implemented).
|
||||
|
||||
# Results
|
||||
|
||||
## Results on the {7,3} tiling
|
||||
|
||||
```
|
||||
test_loop_iso
|
||||
linear+F invariant: (17,16,17,16,17,17,17,17,16,17,17,17,17,16,16,17,17,16,17,17)
|
||||
linear+F forced : (20,19,19,20,20,19,20,20,19,20,20,18,19,19,19,19,20,19,19,19)
|
||||
linear+F weak : (21,19,20,20,20,19,24,20,19,25,24,18,19,19,19,19,20,19,19,19)
|
||||
linear+F flatten : (19,19,21,20,20,20,20,20,19,19,19,21,19,20,19,19,19,19,19,20)
|
||||
linear+F careless : (19,19,19,19,20,19,20,20,19,20,18,18,19,18,19,19,19,19,19,19)
|
||||
linear+F binary : (19,19,19,19,20,19,20,20,19,20,18,18,19,18,19,19,19,19,19,19)
|
||||
linear-F invariant: (17,17,17,18,18,18,21,17,16,17,19,18,17,18,23,17,18,17,19,17)
|
||||
linear-F forced : (19,19,19,19,20,19,19,20,19,20,20,20,19,19,19,19,19,19,19,19)
|
||||
linear-F weak : (19,19,20,19,20,19,19,20,19,21,20,20,21,19,19,19,20,19,19,19)
|
||||
linear-F flatten : (20,19,20,20,21,19,20,18,19,19,20,21,19,21,20,19,19,19,19,20)
|
||||
linear-F careless : (20,19,19,21,19,19,20,17,19,20,19,20,19,19,19,19,19,19,19,20)
|
||||
linear-F binary : (20,19,19,21,19,19,20,17,19,20,19,20,19,19,19,19,19,19,19,20)
|
||||
mixed invariant: (34,35,34,36,34,35,34,34,36,35,34,35,36,34,35,34,33,35,32,36)
|
||||
mixed forced : (34,34,34,35,34,36,33,34,36,35,35,36,36,34,35,34,34,35,34,34)
|
||||
mixed weak : (34,34,34,35,34,36,33,34,36,35,35,36,36,34,35,34,34,35,34,34)
|
||||
mixed flatten : (20,5,18,13,13,13,4,13,9,29,25,9,36,22,19,30,5,35,14,2)
|
||||
mixed careless : (34,34,34,35,34,34,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
mixed binary : (34,34,34,35,34,34,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
Clifford invariant: (32,35,34,36,34,35,34,34,36,33,34,35,36,34,35,34,33,34,32,36)
|
||||
Clifford forced : (34,34,34,35,34,36,33,34,36,35,35,36,36,34,35,34,34,35,34,34)
|
||||
Clifford weak : (34,34,34,35,34,36,33,34,36,35,35,36,36,34,35,34,34,35,34,34)
|
||||
Clifford flatten : (34,34,34,35,34,36,35,34,36,35,35,36,37,34,35,34,36,35,34,34)
|
||||
Clifford careless : (34,34,34,35,34,34,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
Clifford binary : (34,34,34,35,34,34,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
Clifford gyro : (34,34,34,35,34,36,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
halfplane invariant: (34,34,34,35,34,36,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
polar basic : (34,34,34,35,34,34,33,34,36,35,35,24,36,34,35,34,35,35,34,34)
|
||||
polar improved : (34,34,34,34,33,36,35,33,36,35,35,36,35,34,35,34,34,35,34,35)
|
||||
polar F/F : (34,36,35,35,33,34,33,33,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
polar F/T : (34,34,34,34,33,36,35,33,36,35,35,36,35,34,35,34,34,35,34,35)
|
||||
polar T/F : (34,34,35,36,34,36,35,34,35,35,35,36,35,34,35,34,35,35,34,36)
|
||||
polar T/T : (34,36,35,34,34,36,35,34,36,35,35,36,35,34,35,34,34,35,34,35)
|
||||
test_loop_point
|
||||
linear+F invariant: (17,16,17,16,17,17,17,17,16,17,17,17,17,16,16,17,17,16,17,17)
|
||||
linear+F forced : (20,19,19,20,20,19,20,20,19,20,20,18,19,19,19,19,20,19,19,19)
|
||||
linear+F weak : (21,19,20,20,20,19,24,20,19,25,24,18,19,19,19,19,20,19,19,19)
|
||||
linear+F flatten : (19,19,21,20,20,20,20,20,19,19,19,21,19,20,19,19,19,19,19,20)
|
||||
linear+F careless : (19,19,19,19,20,19,20,20,19,20,18,18,19,18,19,19,19,19,19,19)
|
||||
linear+F binary : (19,19,19,19,20,19,20,20,19,20,18,18,19,18,19,19,19,19,19,19)
|
||||
linear-F invariant: (17,17,17,18,18,18,21,17,16,17,19,18,17,18,23,17,18,17,19,17)
|
||||
linear-F forced : (19,19,19,19,20,19,19,20,19,20,20,20,19,19,19,19,19,19,19,19)
|
||||
linear-F weak : (19,19,20,19,20,19,19,20,19,21,20,20,21,19,19,19,20,19,19,19)
|
||||
linear-F flatten : (20,19,20,20,21,19,20,18,19,19,20,21,19,21,20,19,19,19,19,20)
|
||||
linear-F careless : (20,19,19,21,19,19,20,17,19,20,19,20,19,19,19,19,19,19,19,20)
|
||||
linear-F binary : (20,19,19,21,19,19,20,17,19,20,19,20,19,19,19,19,19,19,19,20)
|
||||
mixed invariant: (18,17,17,19,20,18,19,19,17,17,18,17,17,16,16,18,25,17,17,19)
|
||||
mixed forced : (19,19,19,19,19,19,19,17,19,20,19,20,19,19,19,20,19,19,20,20)
|
||||
mixed weak : (19,23,19,19,19,19,21,17,19,23,19,20,24,20,19,20,22,19,23,20)
|
||||
mixed flatten : (20,19,19,20,19,19,19,18,20,20,19,18,18,19,18,20,19,19,19,19)
|
||||
mixed careless : (19,19,19,19,19,20,19,18,19,19,19,21,19,20,18,19,20,19,19,20)
|
||||
mixed binary : (19,19,19,19,19,20,19,18,19,19,19,21,19,20,18,19,20,19,19,20)
|
||||
Clifford invariant: (32,34,31,34,33,36,31,35,32,33,32,36,32,34,33,36,33,32,34,34)
|
||||
Clifford forced : (34,34,34,35,34,36,35,34,35,35,35,36,35,34,35,34,35,35,34,34)
|
||||
Clifford weak : (34,34,34,35,34,36,35,34,35,35,35,36,35,34,35,34,35,35,34,34)
|
||||
Clifford flatten : (34,34,34,35,34,36,35,34,36,35,34,36,36,34,35,34,35,35,34,34)
|
||||
Clifford careless : (3,1,3,2,2,2,2,2,2,3,2,2,3,2,2,3,2,2,1,3)
|
||||
Clifford binary : (34,34,34,35,34,34,35,34,36,35,35,36,35,34,35,34,35,35,34,34)
|
||||
Clifford gyro : (34,36,34,35,34,36,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
halfplane invariant: (34,36,34,35,34,36,35,34,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
polar basic : (34,34,34,35,34,34,33,34,36,35,35,24,36,34,35,34,35,35,34,34)
|
||||
polar improved : (34,34,34,34,33,36,35,33,36,35,35,36,35,34,35,34,34,35,34,35)
|
||||
polar F/F : (34,36,35,35,33,34,33,33,36,35,35,36,36,34,35,34,35,35,34,34)
|
||||
polar F/T : (34,34,34,34,33,36,35,33,36,35,35,36,35,34,35,34,34,35,34,35)
|
||||
polar T/F : (34,34,35,36,34,36,35,34,35,35,35,36,35,34,35,34,35,35,34,36)
|
||||
polar T/T : (34,36,35,34,34,36,35,34,36,35,35,36,35,34,35,34,34,35,34,35)
|
||||
test_angledist
|
||||
linear+F invariant: (767,767,767)
|
||||
linear+F forced : (21,21,21)
|
||||
linear+F weak : (21,21,21)
|
||||
linear+F flatten : (21,21,21)
|
||||
linear+F careless : (21,21,21)
|
||||
linear+F binary : (21,21,21)
|
||||
linear-F invariant: (767,767,767)
|
||||
linear-F forced : (21,21,21)
|
||||
linear-F weak : (21,21,21)
|
||||
linear-F flatten : (21,21,21)
|
||||
linear-F careless : (21,21,21)
|
||||
linear-F binary : (21,21,21)
|
||||
mixed invariant: (767,767,767)
|
||||
mixed forced : (21,21,21)
|
||||
mixed weak : (21,21,21)
|
||||
mixed flatten : (21,21,21)
|
||||
mixed careless : (21,21,21)
|
||||
mixed binary : (21,21,21)
|
||||
Clifford invariant: (767,767,767)
|
||||
Clifford forced : (39,39,47)
|
||||
Clifford weak : (39,39,39)
|
||||
Clifford flatten : (39,39,39)
|
||||
Clifford careless : (2,3,3)
|
||||
Clifford binary : (39,47,39)
|
||||
Clifford gyro : (39,47,39)
|
||||
halfplane invariant: (767,767,767)
|
||||
polar basic : (443,443,443)
|
||||
polar improved : (443,443,443)
|
||||
polar F/F : (767,767,767)
|
||||
polar F/T : (767,767,767)
|
||||
polar T/F : (767,767,767)
|
||||
polar T/T : (767,767,767)
|
||||
test_similarity
|
||||
linear+F invariant: (18,17,17,18,17,18,18,17,18,17,18,18,17,17,17,18,17,17,17,17)
|
||||
linear+F forced : (19,18,18,18,19,18,18,19,19,18,18,18,19,18,19,19,18,19,19,18)
|
||||
linear+F weak : (19,18,18,18,19,18,18,19,19,18,18,18,19,18,19,19,18,19,19,18)
|
||||
linear+F flatten : (18,19,18,18,18,19,19,19,19,18,18,18,19,18,19,19,19,19,18,19)
|
||||
linear+F careless : (19,18,19,18,19,18,18,19,19,18,18,18,19,19,19,19,18,18,19,18)
|
||||
linear+F binary : (19,18,19,18,19,18,18,19,19,18,18,18,19,19,19,19,18,18,19,18)
|
||||
linear-F invariant: (18,18,19,18,18,18,18,18,18,18,18,19,19,19,18,18,19,18,18,18)
|
||||
linear-F forced : (18,19,19,19,19,19,18,19,18,19,19,19,19,19,18,19,19,19,19,19)
|
||||
linear-F weak : (18,19,19,19,19,19,18,19,18,19,19,19,19,19,18,19,19,19,19,19)
|
||||
linear-F flatten : (19,18,19,19,19,19,19,19,18,19,19,19,19,19,18,19,19,19,19,19)
|
||||
linear-F careless : (18,19,19,19,19,19,19,19,18,19,19,19,19,19,19,19,19,19,19,19)
|
||||
linear-F binary : (18,19,19,19,19,19,19,19,18,19,19,19,19,19,19,19,19,19,19,19)
|
||||
mixed invariant: (18,19,18,19,18,18,18,18,18,19,19,19,18,19,18,18,18,19,19,18)
|
||||
mixed forced : (19,19,19,19,19,18,19,19,18,18,18,19,20,19,19,20,19,19,19,19)
|
||||
mixed weak : (19,19,19,19,19,18,19,19,18,18,19,19,21,20,19,19,19,20,19,20)
|
||||
mixed flatten : (19,19,19,19,19,19,19,19,20,18,19,19,19,19,20,19,19,19,19,19)
|
||||
mixed careless : (19,20,19,19,19,18,19,19,19,19,19,20,20,19,19,19,19,19,19,19)
|
||||
mixed binary : (19,20,19,19,19,18,19,19,19,19,19,20,20,19,19,19,19,19,19,19)
|
||||
Clifford invariant: (33,33,33,32,32,34,34,33,32,34,33,33,34,33,33,33,33,34,33,33)
|
||||
Clifford forced : (36,35,35,35,35,35,37,35,36,36,36,35,35,35,35,37,36,36,35,35)
|
||||
Clifford weak : (36,35,35,35,35,35,37,35,36,36,36,35,35,35,35,37,36,36,35,35)
|
||||
Clifford flatten : (35,37,36,35,36,35,35,38,36,37,36,35,37,35,37,38,36,38,35,36)
|
||||
Clifford careless : (37,35,36,35,35,36,35,35,37,35,38,36,38,35,37,36,35,35,35,37)
|
||||
Clifford binary : (37,35,36,35,35,36,35,35,37,35,38,36,38,35,37,36,35,35,35,37)
|
||||
Clifford gyro : (37,35,37,37,37,36,35,36,36,36,37,36,35,36,37,37,36,37,37,35)
|
||||
halfplane invariant: (35,36,36,36,36,35,35,37,37,37,37,36,35,36,38,37,36,36,37,35)
|
||||
polar basic : (19,18,18,18,19,18,18,18,18,18,18,18,18,19,18,18,18,18,18,18)
|
||||
polar improved : (37,37,37,37,37,38,38,37,37,36,37,37,38,39,38,37,37,39,37,38)
|
||||
polar F/F : (19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19)
|
||||
polar F/T : (35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35)
|
||||
polar T/F : (19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19)
|
||||
polar T/T : (35,35,35,35,35,36,35,35,35,36,36,35,35,35,35,35,35,35,35,36)
|
||||
test_dissimilarity
|
||||
linear+F invariant: (125,124,147,123,134,130,126,128,123,125,130,130,127,125,125,131,123,124,125,127)
|
||||
linear+F forced : (7,6,7,7,7,7,8,7,6,7,7,7,7,7,7,7,7,7,7,7)
|
||||
linear+F weak : (7,7,7,7,9,13,8,7,9,7,9,7,7,7,11,9,7,8,7,7)
|
||||
linear+F flatten : (7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7)
|
||||
linear+F careless : (7,7,7,7,7,7,7,7,6,7,8,7,7,7,7,7,7,7,7,7)
|
||||
linear+F binary : (7,7,7,7,7,7,7,7,6,7,8,7,7,7,7,7,7,7,7,7)
|
||||
linear-F invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
linear-F forced : (10,10,10,10,10,10,10,10,10,9,9,10,10,10,10,10,10,9,10,10)
|
||||
linear-F weak : (9,15,13,12,11,11,10,9,16,9,10,9,13,10,12,11,10,9,10,9)
|
||||
linear-F flatten : (9,10,10,10,10,10,9,9,10,10,10,10,10,10,9,10,10,10,10,10)
|
||||
linear-F careless : (10,10,10,9,10,9,10,10,10,10,9,10,10,9,9,10,9,10,10,9)
|
||||
linear-F binary : (10,10,10,9,10,9,10,10,10,10,9,10,10,9,9,10,9,10,10,9)
|
||||
mixed invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
mixed forced : (10,9,10,9,10,10,10,9,10,10,10,10,10,10,10,10,10,9,10,10)
|
||||
mixed weak : (10,9,12,9,9,10,10,11,10,9,12,11,10,9,11,11,11,9,11,10)
|
||||
mixed flatten : (10,9,10,10,9,10,10,10,10,10,10,10,10,10,9,10,10,10,10,10)
|
||||
mixed careless : (10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,10,10,10,10,9)
|
||||
mixed binary : (10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,10,10,10,10,9)
|
||||
Clifford invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
Clifford forced : (18,19,18,18,19,18,19,18,19,19,18,19,18,17,19,19,19,19,19,19)
|
||||
Clifford weak : (18,18,18,18,19,18,18,18,19,18,18,19,18,18,18,18,19,18,18,19)
|
||||
Clifford flatten : (18,19,18,19,19,18,18,18,19,19,18,18,19,19,18,18,18,19,19,18)
|
||||
Clifford careless : (19,18,19,18,18,19,19,18,18,18,18,18,19,18,19,19,19,18,19,18)
|
||||
Clifford binary : (19,18,19,18,18,19,19,18,18,18,18,18,19,18,19,19,19,18,19,18)
|
||||
Clifford gyro : (18,18,18,19,19,18,19,20,18,18,18,18,18,19,19,19,18,19,18,18)
|
||||
halfplane invariant: (35,35,35,35,35,35,35,35,34,36,37,34,35,36,35,35,35,35,36,35)
|
||||
polar basic : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar improved : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar F/F : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar F/T : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar T/F : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar T/T : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
test_other
|
||||
linear+F invariant: (97,97,101,107,97,97,126,107,101,101,112,112,99,101,112,131,107,97,97,94)
|
||||
linear+F forced : (10,10,10,10,10,10,10,10,11,10,10,10,10,11,10,11,10,10,10,10)
|
||||
linear+F weak : (10,11,10,11,12,13,11,11,13,14,10,10,10,11,11,11,12,10,13,10)
|
||||
linear+F flatten : (10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,10)
|
||||
linear+F careless : (10,11,10,10,10,10,10,10,10,10,10,10,10,11,10,10,10,10,10,10)
|
||||
linear+F binary : (10,11,10,10,10,10,10,10,10,10,10,10,10,11,10,10,10,10,10,10)
|
||||
linear-F invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
linear-F forced : (12,12,12,13,13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12)
|
||||
linear-F weak : (12,12,12,18,13,12,12,14,14,14,12,12,12,12,13,12,12,12,12,12)
|
||||
linear-F flatten : (12,12,12,12,12,12,12,12,12,12,13,12,12,12,12,12,12,12,12,12)
|
||||
linear-F careless : (12,12,13,12,12,12,13,12,13,13,12,12,12,12,12,12,12,12,12,12)
|
||||
linear-F binary : (12,12,13,12,12,12,13,12,13,13,12,12,12,12,12,12,12,12,12,12)
|
||||
mixed invariant: (359,360,359,359,359,359,359,359,359,359,359,359,359,359,360,359,359,359,359,359)
|
||||
mixed forced : (14,13,14,14,13,13,13,14,13,14,14,14,14,13,14,13,13,14,13,13)
|
||||
mixed weak : (13,13,14,14,13,13,13,14,13,18,13,16,14,13,15,14,13,14,13,13)
|
||||
mixed flatten : (13,14,14,14,14,14,13,14,14,14,13,14,13,14,14,13,13,14,14,13)
|
||||
mixed careless : (14,13,14,14,13,14,14,14,14,14,14,14,13,14,13,14,13,14,13,13)
|
||||
mixed binary : (14,13,14,14,13,14,14,14,14,14,14,14,13,14,13,14,13,14,13,13)
|
||||
Clifford invariant: (361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361)
|
||||
Clifford forced : (21,21,23,21,21,21,22,21,23,21,22,21,21,21,21,22,21,21,21,22)
|
||||
Clifford weak : (21,21,23,21,21,21,22,21,23,21,21,21,21,21,21,22,21,21,21,22)
|
||||
Clifford flatten : (21,21,22,21,22,22,21,23,21,21,22,22,22,22,22,21,21,22,22,22)
|
||||
Clifford careless : (21,22,22,21,21,22,22,23,21,21,21,22,22,21,21,21,22,22,22,23)
|
||||
Clifford binary : (21,22,22,21,21,22,22,23,21,21,21,22,22,21,21,21,22,22,22,23)
|
||||
Clifford gyro : (23,23,23,23,24,23,23,24,23,24,23,23,23,23,23,23,23,23,23,23)
|
||||
halfplane invariant: (35,35,35,35,36,38,37,35,36,36,37,36,35,36,35,36,36,38,38,35)
|
||||
polar basic : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar improved : (360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360)
|
||||
polar F/F : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar F/T : (360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360)
|
||||
polar T/F : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar T/T : (360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360)
|
||||
test_walk
|
||||
linear+F invariant: (658,606,622,603,606,608,667,620,615,616,616,619,631,609,613,614,632,635,592,612)
|
||||
linear+F forced : (632,617,606,617,608,607,607,628,627,632,626,627,596,652,623,639,615,617,615,616)
|
||||
linear+F weak : (613,626,622,636,606,605,640,594,609,615,592,639,625,607,613,600,635,620,622,604)
|
||||
linear+F flatten : (605,618,608,625,677,649,612,607,614,649,621,609,602,599,615,645,609,597,597,638)
|
||||
linear+F careless : (617,615,620,608,603,606,654,597,612,598,626,624,601,613,616,609,602,627,601,619)
|
||||
linear+F binary : (617,615,620,608,603,606,654,597,612,598,626,624,601,613,616,609,602,627,601,619)
|
||||
linear-F invariant: (309,298,341,329,349,304,302,301,292,314,305,310,322,307,314,1315,1312,295,10000,10000)
|
||||
linear-F forced : (1294,1290,1318,1308,1297,1287,1297,1295,1348,1304,1301,1309,1303,1318,292,1299,1294,1291,1288,1298)
|
||||
linear-F weak : (298,295,301,289,299,289,287,301,297,294,305,297,316,286,292,291,301,293,303,299)
|
||||
linear-F flatten : (297,1324,1299,1293,1315,1301,1313,1305,1305,306,1282,1310,1307,1309,1292,1306,1296,1315,1313,1289)
|
||||
linear-F careless : (1305,1310,1299,1298,1308,307,1318,1296,1293,1300,302,1306,1298,1287,1299,1315,1312,290,1290,1298)
|
||||
linear-F binary : (1305,1310,1299,1298,1308,307,1318,1296,1293,1300,302,1306,1298,1287,1299,1315,1312,290,1290,1298)
|
||||
mixed invariant: (622,634,587,620,607,619,609,612,599,646,607,623,616,590,615,592,637,636,659,613)
|
||||
mixed forced : (599,666,588,608,607,602,630,671,601,602,618,630,618,601,599,599,614,601,596,617)
|
||||
mixed weak : (599,666,588,608,607,602,630,671,601,602,618,630,618,601,599,599,614,601,596,617)
|
||||
mixed flatten : (611,616,607,605,610,603,595,605,593,614,617,593,602,642,610,616,625,593,636,617)
|
||||
mixed careless : (622,634,587,620,607,619,609,612,599,646,607,623,616,590,615,592,637,636,659,613)
|
||||
mixed binary : (622,634,587,620,607,619,609,612,599,646,607,623,616,590,615,592,637,636,659,613)
|
||||
Clifford invariant: (622,634,587,620,607,619,609,612,599,646,607,623,616,590,615,592,637,636,659,613)
|
||||
Clifford forced : (599,666,588,608,607,602,630,671,601,602,618,630,618,601,599,599,614,601,596,617)
|
||||
Clifford weak : (599,666,588,608,607,602,630,671,601,602,618,630,618,601,599,599,614,601,596,617)
|
||||
Clifford flatten : (611,616,607,605,610,603,595,605,593,614,617,593,602,642,610,616,625,593,636,617)
|
||||
Clifford careless : (622,634,587,620,607,619,609,612,599,646,607,623,616,590,615,592,637,636,659,613)
|
||||
Clifford binary : (622,634,587,620,607,619,609,612,599,646,607,623,616,590,615,592,637,636,659,613)
|
||||
Clifford gyro : (600,586,602,621,625,621,625,603,593,630,634,600,586,597,600,609,601,592,617,615)
|
||||
halfplane invariant: (600,586,602,621,625,621,625,603,593,630,634,600,586,597,600,609,601,592,617,615)
|
||||
polar basic : (1055,67,1078,66,72,1050,66,1073,70,1052,66,1070,66,67,71,73,1064,1070,67,66)
|
||||
polar improved : (71,1068,1073,1059,67,55,67,1071,65,1052,1067,1078,67,63,69,1067,57,66,69,1059)
|
||||
polar F/F : (605,566,605,563,566,583,565,591,578,616,591,568,601,569,584,559,621,579,589,601)
|
||||
polar F/T : (573,596,633,569,581,590,565,588,590,581,600,614,597,571,595,619,576,573,582,631)
|
||||
polar T/F : (594,662,662,598,591,686,590,610,593,592,588,588,600,581,598,572,618,578,589,588)
|
||||
polar T/T : (583,594,601,586,570,601,594,579,585,581,582,614,649,614,674,639,588,580,587,588)
|
||||
test_close
|
||||
linear+F invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,18,78,130,126,118)
|
||||
linear+F forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,11,70,110,118)
|
||||
linear+F weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,11,70,110,118)
|
||||
linear+F flatten : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,55,99,116)
|
||||
linear+F careless : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,67,107,113)
|
||||
linear+F binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,67,107,113)
|
||||
linear-F invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,89,117,118)
|
||||
linear-F forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,73,117,117)
|
||||
linear-F weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,73,117,116)
|
||||
linear-F flatten : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,15,49,103,115)
|
||||
linear-F careless : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,62,112,115)
|
||||
linear-F binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,62,112,115)
|
||||
mixed invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,36,101,117,115)
|
||||
mixed forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,72,114,117)
|
||||
mixed weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,72,114,115)
|
||||
mixed flatten : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,75,115,116)
|
||||
mixed careless : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,73,113,112)
|
||||
mixed binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,73,113,112)
|
||||
Clifford invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford flatten : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford careless : (1666,1698,1241,859,666,545,447,378,339,298,262,245,244,207,196,175,170,168,157,144)
|
||||
Clifford binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford gyro : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
halfplane invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar basic : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar improved : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar F/F : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar F/T : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar T/F : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar T/T : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
test_count
|
||||
linear+F invariant: (spin(24A 34M 9D 4F) L0(24A 34M 9D 4F) L1(24A 34M 9D 4F) ip(9A 9M) ii(51A 51M 9D) d0(1F) angle(1F) inverse() push(29A 42M 10D 2F))
|
||||
linear+F forced : (spin(27A 46M 9D 5F) L0(27A 46M 9D 5F) L1(27A 46M 9D 5F) ip(12A 15M 1F) ii(54A 73M 9D 3F) d0(1F) angle(1F) inverse() push(32A 54M 10D 3F))
|
||||
linear+F weak : (spin(30A 49M 9D 5F) L0(30A 49M 9D 5F) L1(30A 49M 9D 5F) ip(12A 15M 1F) ii(57A 76M 9D 3F) d0(3A 4M 2F) angle(1F) inverse() push(38A 63M 10D 4F))
|
||||
linear+F flatten : (spin(27A 37M 17D 4F) L0(27A 37M 17D 4F) L1(27A 37M 17D 4F) ip(9A 9M 2D) ii(54A 54M 17D) d0(3A 4M 2F) angle(1F) inverse() push(35A 51M 18D 3F))
|
||||
linear+F careless : (spin(27A 37M 9D 4F) L0(27A 37M 9D 4F) L1(27A 37M 9D 4F) ip(9A 9M) ii(54A 64M 9D 2F) d0(3A 4M 2F) angle(1F) inverse() push(35A 51M 10D 3F))
|
||||
linear+F binary : (spin(27A 37M 9D 4F) L0(27A 37M 9D 4F) L1(27A 37M 9D 4F) ip(9A 9M) ii(54A 64M 9D 2F) d0(3A 4M 2F) angle(1F) inverse() push(35A 51M 10D 3F))
|
||||
linear-F invariant: (spin(2F) L0(2F) L1(2F) ip(9A 9M) ii(27A 27M) d0(1F) angle(1F) inverse() push(5A 8M 1D))
|
||||
linear-F forced : (spin(3A 12M 3F) L0(3A 12M 3F) L1(3A 12M 3F) ip(12A 15M 1F) ii(30A 39M 1F) d0(1F) angle(1F) inverse() push(8A 20M 1D 1F))
|
||||
linear-F weak : (spin(3A 12M 3F) L0(3A 12M 3F) L1(3A 12M 3F) ip(12A 15M 1F) ii(30A 39M 1F) d0(3A 4M 2F) angle(1F) inverse() push(11A 26M 1D 2F))
|
||||
linear-F flatten : (spin(8D 2F) L0(8D 2F) L1(8D 2F) ip(9A 9M 2D) ii(27A 27M 8D) d0(3A 4M 2F) angle(1F) inverse() push(8A 14M 9D 1F))
|
||||
linear-F careless : (spin(2F) L0(2F) L1(2F) ip(9A 9M) ii(27A 27M) d0(3A 4M 2F) angle(1F) inverse() push(8A 14M 1D 1F))
|
||||
linear-F binary : (spin(2F) L0(2F) L1(2F) ip(9A 9M) ii(27A 27M) d0(3A 4M 2F) angle(1F) inverse() push(8A 14M 1D 1F))
|
||||
mixed invariant: (spin(2F) L0(2F) L1(2F) ip(17A 24M) ii(12A 16M) d0(1F) angle(1F) inverse() push(5A 7M))
|
||||
mixed forced : (spin(2F) L0(2F) L1(2F) ip(20A 30M 1F) ii(15A 28M 1F) d0(1F) angle(1F) inverse() push(7A 18M 1F))
|
||||
mixed weak : (spin(2F) L0(2F) L1(2F) ip(20A 30M 1F) ii(15A 28M 1F) d0(3A 4M 2F) angle(1F) inverse() push(10A 24M 2F))
|
||||
mixed flatten : (spin(1F) L0(1F) L1(1F) ip(17A 15M 2D) ii(12A 12M) d0(3A 4M 2F) angle(1F) inverse() push(8A 15M 1F))
|
||||
mixed careless : (spin(2F) L0(2F) L1(2F) ip(17A 24M) ii(12A 16M) d0(3A 4M 2F) angle(1F) inverse() push(8A 13M 1F))
|
||||
mixed binary : (spin(2F) L0(2F) L1(2F) ip(17A 24M) ii(12A 16M) d0(3A 4M 2F) angle(1F) inverse() push(8A 13M 1F))
|
||||
Clifford invariant: (spin(2F) L0(2F) L1(2F) ip(12A 28M 1F) ii(12A 16M) d0(1F) angle(1F) inverse() push())
|
||||
Clifford forced : (spin(2F) L0(2F) L1(2F) ip(13A 29M 1F) ii(15A 28M 1F) d0(1F) angle(1F) inverse() push())
|
||||
Clifford weak : (spin(2F) L0(2F) L1(2F) ip(13A 29M 1F) ii(15A 28M 1F) d0(2A 4M 2F) angle(1F) inverse() push())
|
||||
Clifford flatten : (spin(1F) L0(1F) L1(1F) ip(11A 20M) ii(12A 19M) d0(2A 4M 2F) angle(1F) inverse() push())
|
||||
Clifford careless : (spin(2F) L0(2F) L1(2F) ip(11A 18M) ii(12A 16M) d0(2A 4M 2F) angle(1F) inverse() push())
|
||||
Clifford binary : (spin(2F) L0(2F) L1(2F) ip(11A 18M) ii(12A 16M) d0(2A 4M 2F) angle(1F) inverse() push())
|
||||
Clifford gyro : (spin(2F) L0(2F) L1(2F) ip(5A 10M 2D) ii(4A 8M) d0(9A 12M 2D 5F) angle(7A 8M 2D 4F) inverse() push(11A 8M 2D 3F))
|
||||
halfplane invariant: (spin(2F) L0(2F) L1(2F) ip(5A 10M 2D) ii(4A 8M) d0(8A 16M 2D 5F) angle(8A 16M 2D 5F) inverse() push(12A 16M 2D 4F))
|
||||
polar basic : (spin(2F) L0() L1() ip(15A 25M 2D 12F) ii(53A 73M 2D 17F) d0() angle(1F) inverse(4A 4M) push())
|
||||
polar improved : (spin(2F) L0() L1() ip(20A 41M 2D 10F) ii(59A 88M 2D 15F) d0() angle(1F) inverse(4A 4M) push())
|
||||
polar F/F : (spin() L0() L1() ip(5A 7M 14F) ii(10A 11M 21F) d0() angle() inverse(14A) push())
|
||||
polar F/T : (spin() L0() L1() ip(5A 7M 14F) ii(14A 8M 18F) d0() angle() inverse(14A) push())
|
||||
polar T/F : (spin() L0() L1() ip(5A 7M 14F) ii(11A 11M 21F) d0() angle() inverse(2A) push())
|
||||
polar T/T : (spin() L0() L1() ip(5A 7M 14F) ii(15A 8M 18F) d0() angle() inverse(2A) push())
|
||||
```
|
||||
|
||||
## Results on the {4,3,5} honeycomb
|
||||
|
||||
```
|
||||
test_loop_iso
|
||||
linear+F invariant: (32,32,34,34,41,39,60,43,32,31,38,36,36,36,41,50,33,37,33,53)
|
||||
linear+F forced : (22,22,24,25,25,23,25,25,25,26,23,26,24,26,24,25,24,24,24,26)
|
||||
linear+F weak : (24,25,26,25,28,26,25,25,27,25,23,27,27,27,27,26,24,24,27,26)
|
||||
linear+F flatten : (22,22,24,25,25,23,27,26,25,26,25,26,24,26,26,26,24,24,24,26)
|
||||
linear+F careless : (26,25,26,25,25,26,27,25,26,26,23,26,27,27,26,26,25,24,27,26)
|
||||
linear+F binary : (26,25,26,25,25,26,27,25,26,26,23,26,27,27,26,26,25,24,27,26)
|
||||
linear-F invariant: (35,72,27,37,38,43,27,25,29,44,24,47,26,27,28,29,42,35,29,29)
|
||||
linear-F forced : (26,25,26,25,25,26,25,25,26,27,25,26,27,27,26,27,24,25,24,26)
|
||||
linear-F weak : (31,25,30,25,26,29,25,25,26,27,25,26,29,27,27,27,24,31,24,26)
|
||||
linear-F flatten : (22,22,26,25,25,23,25,26,25,26,23,24,24,26,24,27,24,24,24,26)
|
||||
linear-F careless : (22,22,24,25,26,23,25,25,25,26,23,24,27,26,24,26,24,24,27,26)
|
||||
linear-F binary : (22,22,24,25,26,23,25,25,25,26,23,24,27,26,24,26,24,24,27,26)
|
||||
mixed invariant: (49,47,44,47,42,44,47,45,46,47,45,49,46,50,45,49,42,48,49,45)
|
||||
mixed forced : (51,50,49,49,47,47,46,47,48,47,48,49,50,50,49,47,52,47,48,49)
|
||||
mixed weak : (51,50,49,49,47,47,46,47,48,47,48,49,50,50,49,47,52,47,48,49)
|
||||
mixed flatten : (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
|
||||
mixed careless : (51,50,46,50,47,47,48,47,48,47,48,49,50,50,49,51,52,51,48,49)
|
||||
mixed binary : (51,50,46,50,47,47,48,47,48,47,48,49,50,50,49,51,52,51,48,49)
|
||||
Clifford invariant: (46,47,44,44,42,44,47,45,45,46,45,50,46,50,45,39,42,44,49,45)
|
||||
Clifford forced : (51,50,49,49,47,47,46,47,48,47,48,49,50,50,49,47,52,47,48,49)
|
||||
Clifford weak : (51,50,49,49,47,47,46,47,48,47,48,49,50,50,49,47,52,47,48,49)
|
||||
Clifford flatten : (55,78,999,58,57,81,55,79,98,999,58,51,66,52,99,51,58,54,88,66)
|
||||
Clifford careless : (51,50,46,50,47,47,48,47,48,47,48,49,50,50,49,51,52,51,48,49)
|
||||
Clifford binary : (51,50,46,50,47,47,48,47,48,47,48,49,50,50,49,51,52,51,48,49)
|
||||
Clifford gyro : (51,50,49,50,50,47,48,47,51,47,50,49,50,50,49,51,52,54,50,51)
|
||||
halfplane invariant: (51,50,49,50,47,47,48,47,48,47,50,49,50,50,49,51,52,51,48,51)
|
||||
polar basic : (12,50,46,49,47,47,48,47,48,3,46,49,50,50,47,7,52,3,48,49)
|
||||
polar improved : (49,46,49,50,50,47,48,47,51,47,50,49,50,50,49,51,48,51,48,49)
|
||||
test_loop_point
|
||||
linear+F invariant: (999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999)
|
||||
linear+F forced : (22,22,24,25,25,23,25,25,25,26,23,26,24,26,24,25,24,24,24,26)
|
||||
linear+F weak : (24,25,26,25,28,26,25,25,27,25,23,27,27,27,27,26,24,24,27,26)
|
||||
linear+F flatten : (22,22,24,25,25,23,27,26,25,26,25,27,24,26,26,26,24,24,24,26)
|
||||
linear+F careless : (26,25,26,25,25,26,27,25,26,26,23,26,27,27,26,26,25,24,27,26)
|
||||
linear+F binary : (26,25,26,25,25,26,27,25,26,26,23,26,27,27,26,26,25,24,27,26)
|
||||
linear-F invariant: (35,72,27,37,38,43,27,25,29,44,24,47,26,27,28,29,42,35,29,29)
|
||||
linear-F forced : (26,25,26,25,25,26,25,25,26,27,25,26,27,27,26,27,24,25,24,26)
|
||||
linear-F weak : (31,25,30,25,26,29,25,25,26,27,25,26,29,27,27,27,24,31,24,26)
|
||||
linear-F flatten : (22,22,26,25,25,23,25,26,25,26,23,24,24,26,24,27,24,24,24,26)
|
||||
linear-F careless : (22,22,24,25,26,23,25,25,25,26,23,24,27,26,24,26,24,24,27,26)
|
||||
linear-F binary : (22,22,24,25,26,23,25,25,25,26,23,24,27,26,24,26,24,24,27,26)
|
||||
mixed invariant: (24,22,22,25,23,25,26,22,24,22,23,25,26,27,24,23,25,22,23,24)
|
||||
mixed forced : (26,25,26,25,25,23,25,25,26,27,23,26,27,26,26,26,25,24,24,26)
|
||||
mixed weak : (27,25,30,25,25,23,25,25,26,27,23,26,27,26,26,28,25,24,24,28)
|
||||
mixed flatten : (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
|
||||
mixed careless : (26,25,24,25,25,26,27,25,26,26,26,26,27,27,26,26,24,25,24,26)
|
||||
mixed binary : (26,25,24,25,25,26,27,25,26,26,26,26,27,27,26,26,24,25,24,26)
|
||||
Clifford invariant: (46,45,48,44,42,44,45,48,47,48,46,41,45,49,48,39,50,48,51,45)
|
||||
Clifford forced : (49,50,46,49,47,47,46,45,48,47,45,49,50,50,49,51,52,47,48,49)
|
||||
Clifford weak : (49,50,46,49,47,47,46,45,48,47,45,49,50,50,49,51,52,47,48,49)
|
||||
Clifford flatten : (50,48,46,49,47,46,48,47,48,47,45,47,50,50,49,47,42,47,48,49)
|
||||
Clifford careless : (3,3,1,2,2,2,2,2,3,3,3,2,3,2,1,2,3,3,1,3)
|
||||
Clifford binary : (51,48,49,49,47,47,48,47,48,47,45,49,50,50,49,47,52,47,48,49)
|
||||
Clifford gyro : (51,50,46,50,50,47,48,48,51,47,50,49,50,50,49,51,52,51,48,49)
|
||||
halfplane invariant: (49,50,46,49,47,47,48,47,51,47,50,49,50,50,49,51,52,51,48,49)
|
||||
polar basic : (12,50,46,49,47,47,48,47,48,3,46,49,50,50,47,7,52,3,48,49)
|
||||
polar improved : (49,46,49,50,50,47,48,47,51,47,50,49,50,50,49,51,48,51,48,49)
|
||||
test_angledist
|
||||
linear+F invariant: (999,999,999)
|
||||
linear+F forced : (26,26,32)
|
||||
linear+F weak : (26,32,32)
|
||||
linear+F flatten : (26,26,32)
|
||||
linear+F careless : (26,26,32)
|
||||
linear+F binary : (26,26,32)
|
||||
linear-F invariant: (999,999,999)
|
||||
linear-F forced : (26,26,32)
|
||||
linear-F weak : (32,26,32)
|
||||
linear-F flatten : (26,26,32)
|
||||
linear-F careless : (26,32,32)
|
||||
linear-F binary : (26,32,32)
|
||||
mixed invariant: (999,999,999)
|
||||
mixed forced : (26,26,32)
|
||||
mixed weak : (26,26,32)
|
||||
mixed flatten : (2,2,1)
|
||||
mixed careless : (26,26,32)
|
||||
mixed binary : (26,26,32)
|
||||
Clifford invariant: (999,999,999)
|
||||
Clifford forced : (57,57,47)
|
||||
Clifford weak : (69,57,47)
|
||||
Clifford flatten : (57,57,47)
|
||||
Clifford careless : (5,4,4)
|
||||
Clifford binary : (57,57,47)
|
||||
Clifford gyro : (57,69,57)
|
||||
halfplane invariant: (999,999,999)
|
||||
polar basic : (532,532,5)
|
||||
polar improved : (532,532,532)
|
||||
test_similarity
|
||||
linear+F invariant: (17,16,16,16,16,16,17,16,17,16,17,17,16,16,16,17,17,16,16,17)
|
||||
linear+F forced : (17,17,17,18,19,18,18,18,18,17,18,18,17,18,17,18,18,17,17,17)
|
||||
linear+F weak : (17,17,17,18,18,18,18,18,17,17,18,18,17,18,17,18,17,17,17,17)
|
||||
linear+F flatten : (17,17,17,18,18,18,18,18,17,17,18,18,17,18,17,18,18,17,17,17)
|
||||
linear+F careless : (17,17,17,18,19,18,17,18,17,17,18,18,17,18,17,17,18,17,17,17)
|
||||
linear+F binary : (17,17,17,18,19,18,17,18,17,17,18,18,17,18,17,17,18,17,17,17)
|
||||
linear-F invariant: (17,18,18,17,17,17,17,18,17,18,17,18,17,18,17,17,17,17,17,17)
|
||||
linear-F forced : (18,19,18,18,18,18,18,18,18,18,18,19,19,18,19,19,18,19,18,18)
|
||||
linear-F weak : (18,19,18,18,18,17,18,18,18,18,19,19,19,18,19,19,18,19,18,18)
|
||||
linear-F flatten : (19,18,19,18,18,18,18,20,18,19,18,18,20,19,19,19,18,19,18,18)
|
||||
linear-F careless : (19,18,18,18,19,18,18,20,19,18,18,19,19,19,18,18,19,18,18,18)
|
||||
linear-F binary : (19,18,18,18,19,18,18,20,19,18,18,19,19,19,18,18,19,18,18,18)
|
||||
mixed invariant: (18,19,19,19,19,19,18,19,19,18,18,19,19,19,19,19,19,18,19,18)
|
||||
mixed forced : (19,19,19,18,18,19,19,18,19,19,19,19,19,19,19,20,19,19,19,19)
|
||||
mixed weak : (19,19,19,18,18,19,19,18,18,19,19,19,19,20,19,18,19,18,18,19)
|
||||
mixed flatten : (19,19,18,19,19,18,19,20,18,19,19,20,19,19,20,18,19,19,19,20)
|
||||
mixed careless : (19,19,19,19,19,20,20,19,19,19,19,19,19,19,19,18,19,19,19,19)
|
||||
mixed binary : (19,19,19,19,19,20,20,19,19,19,19,19,19,19,19,18,19,19,19,19)
|
||||
Clifford invariant: (34,33,34,35,33,34,33,32,34,34,33,34,34,34,34,35,33,34,33,34)
|
||||
Clifford forced : (35,36,35,37,36,35,35,36,36,36,35,37,35,36,36,36,36,36,36,35)
|
||||
Clifford weak : (35,36,35,37,36,35,35,36,36,36,35,37,35,36,36,36,36,36,36,35)
|
||||
Clifford flatten : (35,36,35,35,36,36,37,37,36,36,36,36,36,36,38,35,37,36,37,36)
|
||||
Clifford careless : (36,36,38,36,37,35,35,37,36,36,37,35,37,35,35,35,35,37,36,38)
|
||||
Clifford binary : (36,36,38,36,37,35,35,37,36,36,37,35,37,35,35,35,35,37,36,38)
|
||||
Clifford gyro : (36,37,38,36,35,37,35,36,38,36,36,36,36,36,36,37,35,34,35,36)
|
||||
halfplane invariant: (36,35,36,36,37,38,38,36,37,36,37,36,35,36,35,37,35,36,36,35)
|
||||
polar basic : (17,18,18,17,17,17,17,18,18,18,17,17,17,18,17,17,17,17,17,17)
|
||||
polar improved : (34,37,35,36,37,36,34,36,35,35,35,34,36,35,36,36,35,35,35,35)
|
||||
test_dissimilarity
|
||||
linear+F invariant: (63,63,64,75,63,63,64,64,64,64,63,63,73,66,63,63,76,74,64,64)
|
||||
linear+F forced : (6,7,7,7,7,7,7,7,7,7,7,7,6,7,7,7,7,7,7,6)
|
||||
linear+F weak : (7,9,8,8,7,8,8,7,13,8,7,8,6,7,7,8,8,7,8,7)
|
||||
linear+F flatten : (8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,7,7,7)
|
||||
linear+F careless : (7,7,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6)
|
||||
linear+F binary : (7,7,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6)
|
||||
linear-F invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
linear-F forced : (10,10,10,10,10,10,10,10,10,10,10,9,9,10,9,10,10,9,10,9)
|
||||
linear-F weak : (12,9,9,14,10,9,9,11,11,11,11,13,9,12,10,13,9,10,15,10)
|
||||
linear-F flatten : (10,10,10,9,9,9,10,10,10,10,10,10,10,9,9,10,10,10,10,10)
|
||||
linear-F careless : (10,9,9,10,9,10,9,10,9,10,10,10,10,10,9,9,9,10,10,9)
|
||||
linear-F binary : (10,9,9,10,9,10,9,10,9,10,10,10,10,10,9,9,9,10,10,9)
|
||||
mixed invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
mixed forced : (10,10,10,10,10,10,10,10,9,10,10,10,10,10,9,9,9,10,9,10)
|
||||
mixed weak : (10,16,11,15,9,12,10,9,10,14,10,10,10,11,11,11,11,10,11,11)
|
||||
mixed flatten : (9,10,9,10,10,10,9,10,9,10,10,10,10,9,10,9,10,9,9,9)
|
||||
mixed careless : (10,9,9,10,10,10,10,9,10,10,9,10,10,10,10,10,9,9,9,10)
|
||||
mixed binary : (10,9,9,10,10,10,10,9,10,10,9,10,10,10,10,10,9,9,9,10)
|
||||
Clifford invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
Clifford forced : (18,17,17,19,20,17,18,18,19,19,18,18,17,19,18,18,19,18,19,18)
|
||||
Clifford weak : (19,17,17,18,19,17,18,18,17,18,18,18,17,18,18,17,18,18,19,19)
|
||||
Clifford flatten : (19,18,18,18,19,18,18,18,18,18,18,19,19,18,18,19,18,19,18,18)
|
||||
Clifford careless : (18,18,18,18,18,18,18,19,19,18,18,18,18,18,18,19,18,19,19,18)
|
||||
Clifford binary : (18,18,18,18,18,18,18,19,19,18,18,18,18,18,18,19,18,19,19,18)
|
||||
Clifford gyro : (18,17,18,19,19,19,18,19,18,19,18,18,19,19,19,19,18,18,19,17)
|
||||
halfplane invariant: (34,35,36,35,35,35,35,34,35,35,36,35,35,37,36,37,35,35,34,35)
|
||||
polar basic : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar improved : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
test_other
|
||||
linear+F invariant: (73,50,65,68,65,50,68,50,64,67,65,63,50,66,63,50,68,50,64,67)
|
||||
linear+F forced : (10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10)
|
||||
linear+F weak : (10,10,11,10,11,17,10,12,13,12,11,11,10,10,10,11,11,16,10,14)
|
||||
linear+F flatten : (10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10)
|
||||
linear+F careless : (10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10)
|
||||
linear+F binary : (10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10)
|
||||
linear-F invariant: (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
linear-F forced : (12,12,13,12,12,12,12,12,12,12,12,13,12,12,12,12,12,12,12,12)
|
||||
linear-F weak : (12,12,12,12,13,12,14,13,12,15,12,14,16,12,15,12,12,16,12,12)
|
||||
linear-F flatten : (12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12)
|
||||
linear-F careless : (13,12,13,12,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12)
|
||||
linear-F binary : (13,12,13,12,12,12,12,12,12,12,12,12,12,12,12,12,13,12,12,12)
|
||||
mixed invariant: (359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359)
|
||||
mixed forced : (14,14,14,13,14,13,14,13,14,14,13,14,14,13,13,14,13,14,14,13)
|
||||
mixed weak : (15,13,14,13,14,14,16,13,16,14,14,14,13,13,13,14,13,13,14,15)
|
||||
mixed flatten : (14,13,13,14,13,14,14,14,13,13,14,14,14,14,13,14,14,13,14,14)
|
||||
mixed careless : (14,14,13,13,13,13,13,13,14,14,13,14,14,13,13,14,13,13,14,13)
|
||||
mixed binary : (14,14,13,13,13,13,13,13,14,14,13,14,14,13,13,14,13,13,14,13)
|
||||
Clifford invariant: (361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361)
|
||||
Clifford forced : (22,21,21,21,22,21,22,22,22,22,22,21,21,22,22,22,22,21,21,22)
|
||||
Clifford weak : (22,21,21,21,22,21,22,22,22,22,22,21,21,22,22,22,22,21,21,22)
|
||||
Clifford flatten : (22,22,22,22,22,22,22,22,22,22,22,21,21,22,22,22,22,22,22,22)
|
||||
Clifford careless : (22,21,22,22,22,23,21,21,21,22,22,21,22,21,22,22,22,22,22,22)
|
||||
Clifford binary : (22,21,22,22,22,23,21,21,21,22,22,21,22,21,22,22,22,22,22,22)
|
||||
Clifford gyro : (23,24,23,23,23,24,23,23,23,23,23,23,23,23,23,23,23,24,23,23)
|
||||
halfplane invariant: (35,35,35,35,35,35,35,35,35,36,37,35,35,35,36,36,35,35,35,35)
|
||||
polar basic : (356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356)
|
||||
polar improved : (360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360,360)
|
||||
test_walk
|
||||
linear+F invariant: (614,576,600,601,581,579,609,600,596,565,596,610,583,588,595,606,591,592,579,614)
|
||||
linear+F forced : (598,653,583,603,584,597,581,582,618,568,608,621,586,596,636,604,584,619,585,586)
|
||||
linear+F weak : (606,604,616,593,604,592,583,611,598,576,597,579,603,584,575,591,584,587,600,591)
|
||||
linear+F flatten : (619,599,580,615,608,615,600,593,601,577,615,603,579,590,635,589,589,586,560,589)
|
||||
linear+F careless : (620,596,575,593,602,591,576,587,603,574,596,604,589,615,599,623,586,620,612,602)
|
||||
linear+F binary : (620,596,575,593,602,591,576,587,603,574,596,604,589,615,599,623,586,620,612,602)
|
||||
linear-F invariant: (293,291,289,304,1295,307,285,302,290,297,1311,289,320,292,305,289,285,2132,2137,284)
|
||||
linear-F forced : (1292,288,1303,1298,301,1288,1285,1290,297,288,304,298,293,299,1300,1291,1294,1276,1281,1288)
|
||||
linear-F weak : (288,288,284,300,301,291,286,294,297,288,304,288,293,299,300,286,291,10000,281,293)
|
||||
linear-F flatten : (1292,1297,1303,1311,1292,1285,1296,1297,10000,1299,1321,298,1311,1288,293,1315,1287,1280,1283,1286)
|
||||
linear-F careless : (1288,1292,1288,303,1295,1295,1285,1303,291,1290,1310,289,1321,1290,1298,1289,1284,1276,1282,1287)
|
||||
linear-F binary : (1288,1292,1288,303,1295,1295,1285,1303,291,1290,1310,289,1321,1290,1298,1289,1284,1276,1282,1287)
|
||||
mixed invariant: (592,582,592,572,580,598,589,597,594,567,595,600,605,591,602,611,596,580,589,587)
|
||||
mixed forced : (592,587,597,579,582,627,592,603,603,565,596,576,589,591,596,606,592,594,591,592)
|
||||
mixed weak : (592,587,597,579,582,627,592,603,603,565,596,576,589,591,596,606,592,594,591,592)
|
||||
mixed flatten : (28,363,52,303,296,336,292,316,288,287,308,298,298,298,310,314,293,371,353,324)
|
||||
mixed careless : (592,582,592,572,580,598,589,597,594,567,595,600,605,591,602,611,596,580,589,587)
|
||||
mixed binary : (592,582,592,572,580,598,589,597,594,567,595,600,605,591,602,611,596,580,589,587)
|
||||
Clifford invariant: (592,582,592,572,580,598,589,597,594,567,595,600,605,591,602,611,596,580,589,587)
|
||||
Clifford forced : (592,587,597,579,582,627,592,603,603,565,596,576,589,591,596,606,592,594,591,592)
|
||||
Clifford weak : (592,587,597,579,582,627,592,603,603,565,596,576,589,591,596,606,592,594,591,592)
|
||||
Clifford flatten : (614,604,595,598,570,595,589,587,599,573,599,585,603,602,634,602,596,600,584,596)
|
||||
Clifford careless : (592,582,592,572,580,598,589,597,594,567,595,600,605,591,602,611,596,580,589,587)
|
||||
Clifford binary : (592,582,592,572,580,598,589,597,594,567,595,600,605,591,602,611,596,580,589,587)
|
||||
Clifford gyro : (601,581,606,584,595,604,609,589,582,596,601,601,579,601,619,589,588,583,588,587)
|
||||
halfplane invariant: (576,614,594,596,580,604,594,600,610,566,593,584,603,597,606,608,588,579,575,590)
|
||||
polar basic : (25,1047,69,1045,1045,1033,59,1065,1041,67,1064,56,1044,1034,70,68,55,53,53,55)
|
||||
polar improved : (55,58,70,1045,1045,1057,56,1065,59,68,1065,55,1044,1034,1070,66,1056,53,52,58)
|
||||
test_close
|
||||
linear+F invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,22)
|
||||
linear+F forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear+F weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear+F flatten : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear+F careless : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear+F binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear-F invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,8)
|
||||
linear-F forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear-F weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear-F flatten : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
linear-F careless : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)
|
||||
linear-F binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)
|
||||
mixed invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)
|
||||
mixed forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)
|
||||
mixed weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)
|
||||
mixed flatten : (5000,2716,1760,1229,986,774,667,584,500,460,430,365,344,299,286,283,257,237,231,234)
|
||||
mixed careless : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
mixed binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford forced : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford weak : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford flatten : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford careless : (1666,1539,1427,1047,817,653,547,483,418,381,350,308,283,260,247,230,212,202,188,183)
|
||||
Clifford binary : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
Clifford gyro : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
halfplane invariant: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar basic : (0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
polar improved : (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
|
||||
test_count
|
||||
linear+F invariant: (spin(60A 78M 24D 5F) L0(60A 78M 24D 5F) L1(60A 78M 24D 5F) ip(16A 16M) ii(124A 142M 24D 3F) d0(1F) angle(1F) inverse() push(70A 96M 25D 3F))
|
||||
linear+F forced : (spin(64A 98M 24D 6F) L0(64A 98M 24D 6F) L1(64A 98M 24D 6F) ip(20A 24M 1F) ii(128A 162M 24D 4F) d0(1F) angle(1F) inverse() push(74A 116M 25D 4F))
|
||||
linear+F weak : (spin(68A 102M 24D 6F) L0(68A 102M 24D 6F) L1(68A 102M 24D 6F) ip(20A 24M 1F) ii(132A 166M 24D 4F) d0(4A 5M 2F) angle(1F) inverse() push(82A 128M 25D 5F))
|
||||
linear+F flatten : (spin(64A 82M 39D 5F) L0(64A 82M 39D 5F) L1(64A 82M 39D 5F) ip(16A 16M 3D) ii(128A 146M 39D 3F) d0(4A 5M 2F) angle(1F) inverse() push(78A 108M 40D 4F))
|
||||
linear+F careless : (spin(64A 82M 24D 5F) L0(64A 82M 24D 5F) L1(64A 82M 24D 5F) ip(16A 16M) ii(128A 146M 24D 3F) d0(4A 5M 2F) angle(1F) inverse() push(78A 108M 25D 4F))
|
||||
linear+F binary : (spin(64A 82M 24D 5F) L0(64A 82M 24D 5F) L1(64A 82M 24D 5F) ip(16A 16M) ii(128A 146M 24D 3F) d0(4A 5M 2F) angle(1F) inverse() push(78A 108M 25D 4F))
|
||||
linear-F invariant: (spin(2F) L0(2F) L1(2F) ip(16A 16M) ii(64A 64M) d0(1F) angle(1F) inverse() push(10A 18M 1D))
|
||||
linear-F forced : (spin(4A 20M 3F) L0(4A 20M 3F) L1(4A 20M 3F) ip(20A 24M 1F) ii(68A 84M 1F) d0(1F) angle(1F) inverse() push(14A 38M 1D 1F))
|
||||
linear-F weak : (spin(4A 20M 3F) L0(4A 20M 3F) L1(4A 20M 3F) ip(20A 24M 1F) ii(68A 84M 1F) d0(4A 5M 2F) angle(1F) inverse() push(18A 46M 1D 2F))
|
||||
linear-F flatten : (spin(15D 2F) L0(15D 2F) L1(15D 2F) ip(16A 16M 3D) ii(64A 64M 15D) d0(4A 5M 2F) angle(1F) inverse() push(14A 26M 16D 1F))
|
||||
linear-F careless : (spin(2F) L0(2F) L1(2F) ip(16A 16M) ii(64A 64M) d0(4A 5M 2F) angle(1F) inverse() push(14A 26M 1D 1F))
|
||||
linear-F binary : (spin(2F) L0(2F) L1(2F) ip(16A 16M) ii(64A 64M) d0(4A 5M 2F) angle(1F) inverse() push(14A 26M 1D 1F))
|
||||
mixed invariant: (spin(2F) L0(2F) L1(2F) ip(52A 64M) ii(56A 64M) d0(1F) angle(1F) inverse() push(7A 10M))
|
||||
mixed forced : (spin(2F) L0(2F) L1(2F) ip(56A 72M 1F) ii(63A 88M 1F) d0(1F) angle(1F) inverse() push(10A 30M 1F))
|
||||
mixed weak : (spin(2F) L0(2F) L1(2F) ip(56A 72M 1F) ii(63A 88M 1F) d0(4A 5M 2F) angle(1F) inverse() push(14A 38M 2F))
|
||||
mixed flatten : (spin(1F) L0(1F) L1(1F) ip(52A 49M 3D) ii(56A 56M) d0(4A 5M 2F) angle(1F) inverse() push(11A 21M 1F))
|
||||
mixed careless : (spin(2F) L0(2F) L1(2F) ip(52A 64M) ii(56A 64M) d0(4A 5M 2F) angle(1F) inverse() push(11A 18M 1F))
|
||||
mixed binary : (spin(2F) L0(2F) L1(2F) ip(52A 64M) ii(56A 64M) d0(4A 5M 2F) angle(1F) inverse() push(11A 18M 1F))
|
||||
Clifford invariant: (spin(2F) L0(2F) L1(2F) ip(39A 68M 1F) ii(56A 64M) d0(1F) angle(1F) inverse() push())
|
||||
Clifford forced : (spin(2F) L0(2F) L1(2F) ip(39A 68M 1F) ii(63A 88M 1F) d0(1F) angle(1F) inverse() push())
|
||||
Clifford weak : (spin(2F) L0(2F) L1(2F) ip(39A 68M 1F) ii(63A 88M 1F) d0(3A 5M 2F) angle(1F) inverse() push())
|
||||
Clifford flatten : (spin(1F) L0(1F) L1(1F) ip(36A 51M) ii(56A 71M) d0(3A 5M 2F) angle(1F) inverse() push())
|
||||
Clifford careless : (spin(2F) L0(2F) L1(2F) ip(36A 48M) ii(56A 64M) d0(3A 5M 2F) angle(1F) inverse() push())
|
||||
Clifford binary : (spin(2F) L0(2F) L1(2F) ip(36A 48M) ii(56A 64M) d0(3A 5M 2F) angle(1F) inverse() push())
|
||||
Clifford gyro : (spin(8A 1F) L0(8A 1F) L1(8A 1F) ip(23A 38M 1D) ii(24A 32M) d0(23A 26M 1D 5F) angle(20A 21M 1D 4F) inverse() push(28A 21M 1D 3F))
|
||||
halfplane invariant: (spin(8A 2F) L0(8A 2F) L1(8A 2F) ip(23A 38M 1D) ii(24A 32M) d0(23A 38M 1D 5F) angle(23A 38M 1D 5F) inverse() push(31A 38M 1D 4F))
|
||||
polar basic : (spin(2F) L0() L1() ip(24A 35M 3D 12F) ii(114A 135M 3D 17F) d0() angle(1F) inverse(9A 9M) push())
|
||||
polar improved : (spin(2F) L0() L1() ip(29A 51M 3D 10F) ii(120A 150M 3D 15F) d0() angle(1F) inverse(9A 9M) push())
|
||||
```
|
|
@ -0,0 +1,538 @@
|
|||
namespace reps {
|
||||
|
||||
constexpr int test_dim = 3;
|
||||
constexpr bool in_hyperbolic = true;
|
||||
|
||||
int edges, valence;
|
||||
|
||||
void prepare_tests() {
|
||||
hr::start_game();
|
||||
if(MDIM != test_dim) throw hr::hr_exception("fix your dimension");
|
||||
if(!(in_hyperbolic ? hyperbolic : sphere)) throw hr::hr_exception("fix your geometry");
|
||||
if(hr::variation != hr::eVariation::pure) throw hr::hr_exception("fix your variation");
|
||||
if(quotient) throw hr::hr_exception("fix your quotient");
|
||||
if(test_dim == 4) {
|
||||
if(cginf.tiling_name != "{4,3,5}") throw hr::hr_exception("only {4,3,5} implemented in 3D");
|
||||
edges = 4;
|
||||
valence = 5;
|
||||
}
|
||||
else {
|
||||
edges = hr::cwt.at->type;
|
||||
bool ok;
|
||||
valence = hr::get_valence(hr::cwt.at, 1, ok);
|
||||
}
|
||||
}
|
||||
|
||||
struct data {
|
||||
using Number = hr::ld;
|
||||
static constexpr int Dim = test_dim;
|
||||
static constexpr int Flipped = in_hyperbolic ? test_dim-1 : -1;
|
||||
};
|
||||
|
||||
struct countdata {
|
||||
using Number = countfloat;
|
||||
static constexpr int Dim = data::Dim;
|
||||
static constexpr int Flipped = data::Flipped;
|
||||
};
|
||||
|
||||
struct bigdata {
|
||||
using Number = big;
|
||||
static constexpr int Dim = data::Dim;
|
||||
static constexpr int Flipped = data::Flipped;
|
||||
};
|
||||
|
||||
using good = rep_linear_nn<bigdata>;
|
||||
|
||||
int debug; // 0 -- never, 1 -- only errors, 2 -- always
|
||||
|
||||
vector<cell*> randomwalk(std::mt19937& gen, cell *from, int dist) {
|
||||
vector<cell*> res = { from };
|
||||
while(celldistance(from, res.back()) < dist) {
|
||||
int i = gen() % res.back()->type;
|
||||
res.push_back(res.back()->cmove(i));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class N> N rand01(std::mt19937& gen) { return N(((gen() & HRANDMAX) | 1) / (HRANDMAX+1.)); }
|
||||
|
||||
vector<cell*> random_return(std::mt19937& gen, cell *from, cell *to, ld peq, ld pbad) {
|
||||
vector<cell*> res = { from };
|
||||
ld d = celldistance(to, from);
|
||||
while(to != res.back()) {
|
||||
int i = gen() % res.back()->type;
|
||||
cell *r1 = res.back()->cmove(i);
|
||||
ld d1 = celldistance(to, r1);
|
||||
bool ok = d1 < d ? true : d1 == d ? rand01<ld>(gen) < peq : rand01<ld>(gen) < pbad;
|
||||
if(ok) { res.push_back(r1); d = d1; }
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<cell*> vrev(vector<cell*> a) { reverse(a.begin(), a.end()); return a; }
|
||||
vector<cell*> vcon(vector<cell*> a, vector<cell*> b) { for(auto bi: b) a.push_back(bi); return a; }
|
||||
|
||||
template<class N> N edge_of_triangle_with_angles(N alpha, N beta, N gamma) {
|
||||
N of = (cos(alpha) + cos(beta) * cos(gamma)) / (sin(beta) * sin(gamma));
|
||||
if(hyperbolic) return acosh(of);
|
||||
return acos(of);
|
||||
}
|
||||
|
||||
template<class N> N get_edgelen() {
|
||||
N beta = get_deg<N>(360)/valence;
|
||||
return edge_of_triangle_with_angles<N> (beta, get_deg<N>(180)/edges, get_deg<N>(180)/edges);
|
||||
}
|
||||
|
||||
template<class T> typename T::isometry cpush(int c, typename T::data::Number distance) {
|
||||
return T::lorentz(c, T::data::Dim-1, distance);
|
||||
}
|
||||
|
||||
template<class T> struct cube_rotation_data_t {
|
||||
std::vector<std::pair<hr::transmatrix, typename T::isometry>> mapping;
|
||||
};
|
||||
|
||||
template<class T> cube_rotation_data_t<T> cube_rotation_data;
|
||||
|
||||
template<class T> cube_rotation_data_t<T>& build_cube_rotation() {
|
||||
auto& crd = cube_rotation_data<T>;
|
||||
auto& crdm = crd.mapping;
|
||||
// using N = typename T::data::Number;
|
||||
if(crdm.empty()) {
|
||||
crdm.emplace_back(hr::Id, T::id());
|
||||
for(int i=0; i<isize(crdm); i++)
|
||||
for(int j=0; j<3; j++) for(int k=0; k<3; k++) if(j != k) {
|
||||
hr::transmatrix U = crdm[i].first * hr::cspin90(j, k);
|
||||
bool is_new = true;
|
||||
for(int i0=0; i0<isize(crdm); i0++) if(hr::eqmatrix(U, crdm[i0].first)) is_new = false;
|
||||
// if(is_new) crdm.emplace_back(U, T::apply(crdm[i].second, T::cspin(j, k, get_deg<N>(90))));
|
||||
if(is_new) crdm.emplace_back(U, T::apply(crdm[i].second, T::cspin90(j, k)));
|
||||
}
|
||||
if(isize(crdm) != 24) {
|
||||
println(hlog, "the number of rotations found: ", isize(crdm));
|
||||
throw hr::hr_exception("wrong number of rotations");
|
||||
}
|
||||
}
|
||||
return crd;
|
||||
}
|
||||
|
||||
template<class T, class U> U apply_move(cell *a, cell *b, U to) {
|
||||
if(a == b) return to;
|
||||
using N = typename T::data::Number;
|
||||
if constexpr(test_dim == 4) {
|
||||
auto& crdm = build_cube_rotation<T>().mapping;
|
||||
int ida = neighborId(a, b);
|
||||
auto M = hr::currentmap->adj(a, ida);
|
||||
for(int i0=0; i0<isize(crdm); i0++)
|
||||
for(int i1=0; i1<isize(crdm); i1++)
|
||||
if(hr::eqmatrix(M, crdm[i0].first * hr::xpush(1.06128) * crdm[i1].first)) {
|
||||
to = T::apply(crdm[i1].second, to);
|
||||
to = T::apply(cpush<T>(0, get_edgelen<N>()), to);
|
||||
to = T::apply(crdm[i0].second, to);
|
||||
return to;
|
||||
}
|
||||
println(hlog, "tessf = ", hr::cgip->tessf);
|
||||
println(hlog, "len = ", get_edgelen<N>());
|
||||
throw hr::hr_exception("rotation not found");
|
||||
}
|
||||
int ida = neighborId(a, b);
|
||||
int idb = neighborId(b, a);
|
||||
auto P1 = T::cspin(0, 1, idb * get_deg<N>(360) / edges);
|
||||
to = T::apply(P1, to);
|
||||
auto P2 = cpush<T>(0, get_edgelen<N>());
|
||||
to = T::apply(P2, to);
|
||||
auto P3 = T::cspin(1, 0, get_deg<N>(180) + ida * get_deg<N>(360) / edges);
|
||||
to = T::apply(P3, to);
|
||||
return to;
|
||||
}
|
||||
|
||||
template<class T, class U> U apply_path(vector<cell*> path, U to) {
|
||||
for(int i=hr::isize(path)-2; i>=0; i--)
|
||||
to = apply_move<T, U> (path[i], path[i+1], to);
|
||||
return to;
|
||||
}
|
||||
|
||||
template<class T> double test_sanity(int i) {
|
||||
hr::indenter in(2);
|
||||
|
||||
ld d1 = 1.25, d2 = 1.5;
|
||||
|
||||
typename good::point gp = good::center();
|
||||
gp = good::apply(cpush<good>(0, d1), gp);
|
||||
gp = good::apply(cpush<good>(1, d2), gp);
|
||||
gp = good::apply(good::cspin(0, 1, get_deg<big>(72)), gp);
|
||||
|
||||
typename T::point p = T::center();
|
||||
p = T::apply(cpush<T>(0, d1), p);
|
||||
p = T::apply(cpush<T>(1, d2), p);
|
||||
p = T::apply(T::cspin(0, 1, get_deg<typename T::data::Number>(72)), p);
|
||||
|
||||
double res = 0;
|
||||
#define ADD(x, y) if(debug) println(hlog, "VS ", x, ",", y); res += pow( double(x-y), 2);
|
||||
#define ADDA(x, y) if(debug) println(hlog, "VS ", x, ",", y); res += pow( cyclefix_on(double(x-y)), 2);
|
||||
|
||||
if(debug) println(hlog, "p=", T::print(p));
|
||||
|
||||
ADD(T::get_coord(p, 0), good::get_coord(gp, 0));
|
||||
ADD(T::get_coord(p, 1), good::get_coord(gp, 1));
|
||||
ADD(T::get_coord(p, 2), good::get_coord(gp, 2));
|
||||
ADD(T::dist0(p), good::dist0(gp));
|
||||
ADDA(T::angle(p), good::angle(gp));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T> double test_consistency(int i) {
|
||||
double res = 0;
|
||||
using D = typename T::data;
|
||||
|
||||
auto a = cpush<T>(0, 1);
|
||||
auto b = cpush<T>(1, 1);
|
||||
auto c = cpush<T>(0, 1);
|
||||
|
||||
auto s = T::apply(T::apply(a, b), c);
|
||||
auto sp = T::apply(s, T::center());
|
||||
auto s1 = T::apply(a, T::apply(b, c));
|
||||
auto sp1 = T::apply(s1, T::center());
|
||||
auto sp2 = T::apply(a, T::apply(b, T::apply(c, T::center())));
|
||||
ADD(T::dist0(sp), T::dist0(sp1));
|
||||
ADD(T::dist0(sp), T::dist0(sp2));
|
||||
for(int i=0; i<D::Dim; i++) { ADD(T::get_coord(sp, i), T::get_coord(sp1, i)); }
|
||||
for(int i=0; i<D::Dim; i++) { ADD(T::get_coord(sp, i), T::get_coord(sp2, i)); }
|
||||
if(test_dim == 3) {
|
||||
ADDA(T::angle(sp), T::angle(sp1));
|
||||
ADDA(T::angle(sp), T::angle(sp2));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T> double test_tba(int id) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
for(int i=0; i<hr::cwt.at->type; i++) {
|
||||
vector<cell*> p = {hr::cwt.at, hr::cwt.at->cmove(i), hr::cwt.at};
|
||||
auto h = apply_path<T>(p, T::center());
|
||||
if(debug == 2) println(hlog, "i=", hr::lalign(3, i), " h = ", T::print(h), " distance =", T::dist0(h));
|
||||
if(T::dist0(h) >= 0 && T::dist0(h) < 0.1) continue;
|
||||
exit(1);
|
||||
}
|
||||
return 999;
|
||||
}
|
||||
|
||||
template<class T> double test_loop_point(int id) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
for(int i=0; i<100; i++) {
|
||||
auto p1 = randomwalk(testr, hr::cwt.at, i);
|
||||
auto p2 = random_return(testr, p1.back(), hr::cwt.at, 1/16., 1/32.);
|
||||
auto p = vcon(p1, p2);
|
||||
if(debug == 2) println(hlog, "path = ", p);
|
||||
auto h = apply_path<T>(vrev(p), T::center());
|
||||
if(debug == 2) println(hlog, "i=", hr::lalign(3, i), " h = ", T::print(h), " distance =", T::dist0(h));
|
||||
if(T::dist0(h) >= 0 && T::dist0(h) < 0.1) continue;
|
||||
return i;
|
||||
}
|
||||
return 999;
|
||||
}
|
||||
|
||||
template<class T> double test_loop_iso(int id) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
for(int i=0; i<100; i++) {
|
||||
auto p1 = randomwalk(testr, hr::cwt.at, i);
|
||||
auto p2 = random_return(testr, p1.back(), hr::cwt.at, 1/16., 1/32.);
|
||||
auto p = vcon(p1, p2);
|
||||
if(debug == 2) println(hlog, "path = ", p);
|
||||
auto h = apply_path<T>(vrev(p), T::id());
|
||||
auto hr = T::apply(h, T::center());
|
||||
// println(hlog, "i=", hr::lalign(3, i), " h=", hr);
|
||||
if(debug == 2) println(hlog, "i=", hr::lalign(3, i), " hr = ", T::print(hr), " distance = ", T::dist0(hr));
|
||||
if(T::dist0(hr) >= 0 && T::dist0(hr) < 0.1) continue;
|
||||
if(debug == 1) println(hlog, "i=", hr::lalign(3, i), " hr = ", T::print(hr), " distance = ", T::dist0(hr));
|
||||
return i;
|
||||
}
|
||||
return 999;
|
||||
}
|
||||
|
||||
template<class T, class F> vector<T> repeat_test(const F& f, int qty) {
|
||||
vector<T> res;
|
||||
for(int i=0; i<qty; i++) res.push_back(f(i));
|
||||
return res;
|
||||
}
|
||||
|
||||
template<class T> typename T::isometry random_rotation(std::mt19937& testr) {
|
||||
using D = typename T::data;
|
||||
using N = typename D::Number;
|
||||
|
||||
if(D::Dim == 3) {
|
||||
auto alpha = rand01<N>(testr) * get_deg<N>(360);
|
||||
return T::cspin(0, 1, alpha);
|
||||
}
|
||||
|
||||
auto x = T::id();
|
||||
for(int i=0; i<100; i++) {
|
||||
int c0 = testr() % (D::Dim-1);
|
||||
int c1 = testr() % (D::Dim-1);
|
||||
if(c0 == c1) continue;
|
||||
auto len = rand01<N>(testr) * get_deg<N>(360);
|
||||
x = T::apply(T::cspin(c0, c1, len), x);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template<class T> typename T::isometry random_iso(std::mt19937& testr) {
|
||||
auto x = T::id();
|
||||
using D = typename T::data;
|
||||
using N = typename D::Number;
|
||||
for(int i=0; i<100; i++) {
|
||||
int c0 = testr() % D::Dim;
|
||||
int c1 = testr() % D::Dim;
|
||||
if(c0 == c1) continue;
|
||||
if(c0 == D::Flipped) std::swap(c0, c1);
|
||||
N len = c1 < D::Flipped ? rand01<N>(testr) * get_deg<N>(360) : (rand01<N>(testr)-N(0.5)) * N(0.25);
|
||||
if(c1 == D::Flipped) x = T::apply(T::lorentz(c0, c1, len), x);
|
||||
else x = T::apply(T::cspin(c0, c1, len), x);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
template<class T> std::string test_count(int id) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
hr::shstream out;
|
||||
auto A = random_iso<T>(testr);
|
||||
auto B = random_iso<T>(testr);
|
||||
auto C = random_iso<T>(testr);
|
||||
auto P = T::apply(C, T::center());
|
||||
for(int i=0; i<9; i++) {
|
||||
counts.clear();
|
||||
for(auto& i: cbc) i = 0;
|
||||
std::string s;
|
||||
switch(i) {
|
||||
case 0: s = "spin"; T::cspin(0, 1, countfloat(.5)); break;
|
||||
case 1: s = "L0"; T::lorentz(0, T::data::Dim-1, countfloat(.5)); break;
|
||||
case 2: s = "L1"; T::lorentz(1, T::data::Dim-1, countfloat(.5)); break;
|
||||
case 3: s = "ip"; T::apply(A, P); break;
|
||||
case 4: s = "ii"; T::apply(A, B); break;
|
||||
case 5: s = "d0"; T::dist0(P); break;
|
||||
case 6: s = "angle"; T::angle(P); break;
|
||||
case 7: s = "inverse"; T::inverse(A); break;
|
||||
case 8: s = "push"; T::push(P); break;
|
||||
}
|
||||
if(i) print(out, " ");
|
||||
if(1) {
|
||||
print(out, s, "(");
|
||||
bool nsp = false;
|
||||
for(int i=1; i<5; i++) if(cbc[i]) {
|
||||
if(nsp) print(out, " ");
|
||||
print(out, cbc[i], hr::s0+".AMDF"[i]);
|
||||
nsp = true;
|
||||
}
|
||||
print(out, ")");
|
||||
}
|
||||
}
|
||||
return out.s;
|
||||
}
|
||||
|
||||
template<class A, class B> bool closeto(A a, B b) { return abs(a-b) < 0.1; }
|
||||
|
||||
template<class A, class B> bool closeto_angle(A a, B b) { return abs(cyclefix_on(double(a-b))) < 0.1; }
|
||||
|
||||
template<class T> double test_angledist(int id) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
for(int i=1; i<1000; i += (1 + i/5)) {
|
||||
|
||||
auto p = randomwalk(testr, hr::cwt.at, i);
|
||||
auto h = apply_path<T>(vrev(p), T::center());
|
||||
|
||||
auto gh = apply_path<good>(vrev(p), good::center());
|
||||
|
||||
if(debug == 2) {
|
||||
println(hlog, "good: ", good::print(gh), " dist = ", good::dist0(gh), " angle = ", good::angle(gh));
|
||||
println(hlog, "test: ", T::print(h), " dist = ", T::dist0(h), " angle = ", T::angle(h), " [i=", i, "]");
|
||||
}
|
||||
|
||||
if(closeto(good::dist0(gh), T::dist0(h)) && closeto_angle(good::angle(gh), T::angle(h))) continue;
|
||||
|
||||
if(debug == 1) {
|
||||
println(hlog, "good: ", good::print(gh), " dist = ", good::dist0(gh), " angle = ", good::angle(gh));
|
||||
println(hlog, "test: ", T::print(h), " dist = ", T::dist0(h), " angle = ", T::angle(h), " [i=", i, "]");
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
return 999;
|
||||
}
|
||||
|
||||
#define TEST_VARIANTS(x,D,q,t,rn, r) \
|
||||
nm = nmInvariant; println(hlog, rn, "invariant: ", repeat_test<t>(x<r<D>>, q)); \
|
||||
nm = nmForced; println(hlog, rn, "forced : ", repeat_test<t>(x<r<D>>, q)); \
|
||||
nm = nmWeak; println(hlog, rn, "weak : ", repeat_test<t>(x<r<D>>, q)); \
|
||||
nm = nmFlatten; println(hlog, rn, "flatten : ", repeat_test<t>(x<r<D>>, q)); \
|
||||
nm = nmCareless; println(hlog, rn, "careless : ", repeat_test<t>(x<r<D>>, q)); \
|
||||
nm = nmBinary; println(hlog, rn, "binary : ", repeat_test<t>(x<r<D>>, q));
|
||||
|
||||
/*
|
||||
#define TEST_ALL(x,D,q,t) \
|
||||
println(hlog, "HyperRogue: ", repeat_test<t>(x<rep_hr<D>>, q)); \
|
||||
polar_mod = polar_choose = false; println(hlog, "high polar: ", repeat_test<t>(x<rep_high_polar<D>>, q)); \
|
||||
if(test_dim == 3) { polar_mod = polar_choose = false; println(hlog, "low polar : ", repeat_test<t>(x<rep_polar2<D>>, q)); }
|
||||
*/
|
||||
|
||||
// println(hlog, "HyperRogue : ", repeat_test<t>(x<rep_hr<D>>, q));
|
||||
|
||||
#define TEST_ALL(x,D,q,t) \
|
||||
fix_matrices = true; TEST_VARIANTS(x,D,q,t,"linear+F ", rep_linear) \
|
||||
fix_matrices = false; TEST_VARIANTS(x,D,q,t,"linear-F ", rep_linear) \
|
||||
TEST_VARIANTS(x,D,q,t,"mixed ", rep_mixed) \
|
||||
TEST_VARIANTS(x,D,q,t,"Clifford ", rep_clifford) \
|
||||
nm = nmFlatten; println(hlog, "Clifford gyro : ", repeat_test<t>(x<rep_half<D>>, q)); \
|
||||
nm = nmInvariant; println(hlog, "halfplane invariant: ", repeat_test<t>(x<rep_half<D>>, q)); \
|
||||
polar_choose = false; println(hlog, "polar basic : ", repeat_test<t>(x<rep_high_polar<D>>, q)); \
|
||||
polar_choose = true; println(hlog, "polar improved : ", repeat_test<t>(x<rep_high_polar<D>>, q)); \
|
||||
if(test_dim == 3) { \
|
||||
polar_mod = false; polar_choose = false; println(hlog, "polar F/F : ", repeat_test<t>(x<rep_polar2<D>>, q)); \
|
||||
polar_mod = false; polar_choose = true; println(hlog, "polar F/T : ", repeat_test<t>(x<rep_polar2<D>>, q)); \
|
||||
polar_mod = true; polar_choose = false; println(hlog, "polar T/F : ", repeat_test<t>(x<rep_polar2<D>>, q)); \
|
||||
polar_mod = true; polar_choose = true; println(hlog, "polar T/T : ", repeat_test<t>(x<rep_polar2<D>>, q)); \
|
||||
}
|
||||
|
||||
template<class T> double test_distances(int id, int a) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
using N = typename T::data::Number;
|
||||
|
||||
for(int i=1; i<1000; i ++) {
|
||||
|
||||
auto R = random_rotation<T>(testr);
|
||||
auto dif = exp(N(-1) * i) + get_deg<N>(a);
|
||||
|
||||
auto p1 = T::apply(T::apply(R, cpush<T>(0, N(i))), T::center());
|
||||
auto p2 = T::apply(T::apply(R, T::apply(T::cspin(0, 1, dif), cpush<T>(0, N(i)))), T::center());
|
||||
auto pd = T::apply(T::inverse(T::push(p1)), p2);
|
||||
auto d = T::dist0(pd);
|
||||
|
||||
// for good we do not need R actually
|
||||
auto gp1 = good::apply(cpush<good>(0, N(i)), good::center());
|
||||
auto gp2 = good::apply(good::apply(good::cspin(0, 1, dif), cpush<good>(0, N(i))), good::center());
|
||||
auto gd = good::dist0(good::apply(good::inverse(good::push(gp1)), gp2));
|
||||
|
||||
if(debug == 2) println(hlog, T::print(p1), " ... ", T::print(p2), " = ", T::print(pd), " d=", d, " [i=", i, " dif=", dif, "]");
|
||||
|
||||
if(closeto(d, gd)) continue;
|
||||
|
||||
return i;
|
||||
}
|
||||
return 999;
|
||||
}
|
||||
|
||||
template<class T> double test_similarity(int id) { return test_distances<T>(id, 0); }
|
||||
template<class T> double test_dissimilarity(int id) { return test_distances<T>(id, 180); }
|
||||
template<class T> double test_other(int id) { return test_distances<T>(id, 1); }
|
||||
|
||||
template<class T> double test_walk(int id) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
|
||||
ld step = 1/16.;
|
||||
// mover-relative to cell-relative
|
||||
auto R0 = random_rotation<T>(testr);
|
||||
cell *c0 = hr::cwt.at;
|
||||
auto R1 = T::apply(R0, cpush<T>(0, step/2));
|
||||
cell *c1 = hr::cwt.at;
|
||||
|
||||
int i = 0;
|
||||
int lastchange = 0;
|
||||
while(i< lastchange + 1000 && i < 10000 && celldistance(c0, c1) < 3) {
|
||||
// println(hlog, "iteration ", i, " in ", c0, " vs ", c1);
|
||||
auto rebase = [&] (typename T::isometry& R, cell*& c, int id) {
|
||||
ld d = T::dist0(T::apply(R, T::center()));
|
||||
for(int dir=0; dir<c->type; dir++) {
|
||||
cell *altc = c->cmove(dir);
|
||||
auto altR = apply_move<T>(altc, c, R);
|
||||
ld altd = T::dist0(T::apply(altR, T::center()));
|
||||
if(altd < d + 1/256.) {
|
||||
R = altR; c = altc; lastchange = i; return;
|
||||
}
|
||||
}
|
||||
};
|
||||
R0 = T::apply(R0, cpush<T>(0, step)); rebase(R0, c0, 0);
|
||||
R1 = T::apply(R1, cpush<T>(0, step)); rebase(R1, c1, 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
template<class T> double test_close(int id) {
|
||||
std::mt19937 testr; testr.seed(id);
|
||||
|
||||
cell *c = hr::cwt.at;
|
||||
int phase = 0;
|
||||
auto p0 = T::apply(cpush<T>(0, 1/8.), T::center());
|
||||
auto p = p0;
|
||||
|
||||
int steps = 0;
|
||||
const int maxdist = id + 1;
|
||||
int errors = 0;
|
||||
|
||||
while(steps < 10000) {
|
||||
int d = testr() % c->type;
|
||||
cell *c1 = c->cmove(d);
|
||||
|
||||
bool do_move = false;
|
||||
|
||||
switch(phase) {
|
||||
case 0:
|
||||
/* always move */
|
||||
do_move = true;
|
||||
if(celldistance(c1, hr::cwt.at) == maxdist) phase = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* move only towards the center */
|
||||
int d0 = celldistance(c, hr::cwt.at);
|
||||
int d1 = celldistance(c1, hr::cwt.at);
|
||||
do_move = d1 < d0;
|
||||
if(d1 == 0) phase = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if(do_move) {
|
||||
p = apply_move<T>(c1, c, p); c = c1; steps++;
|
||||
if(debug == 2) println(hlog, "dist = ", celldistance(c, hr::cwt.at), " dist = ", T::dist0(p));
|
||||
if(c == hr::cwt.at) {
|
||||
auto d = T::dist0(p);
|
||||
auto a = T::angle(p);
|
||||
if(!closeto(d, 1/8.) || !closeto_angle(a, 0)) {
|
||||
errors++; phase = 0; c = hr::cwt.at; p = p0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
void run_all_tests() {
|
||||
prepare_tests();
|
||||
|
||||
// println(hlog, "test_sanity"); TEST_ALL(test_sanity, data, 1, ld);
|
||||
|
||||
// println(hlog, "test_consistency"); TEST_ALL(test_consistency, data, 1, ld);
|
||||
|
||||
println(hlog, "test_loop_iso"); TEST_ALL(test_loop_iso, data, 20, int);
|
||||
|
||||
println(hlog, "test_loop_point"); TEST_ALL(test_loop_point, data, 20, int);
|
||||
|
||||
println(hlog, "test_angledist"); TEST_ALL(test_angledist, data, 3, int);
|
||||
|
||||
println(hlog, "test_similarity"); TEST_ALL(test_similarity, data, 20, int);
|
||||
|
||||
println(hlog, "test_dissimilarity"); TEST_ALL(test_dissimilarity, data, 20, int);
|
||||
|
||||
println(hlog, "test_other"); TEST_ALL(test_other, data, 20, int);
|
||||
|
||||
println(hlog, "test_walk"); TEST_ALL(test_walk, data, 20, int);
|
||||
|
||||
println(hlog, "test_close"); TEST_ALL(test_close, data, 20, int);
|
||||
|
||||
println(hlog, "test_count"); TEST_ALL(test_count, countdata, 1, std::string);
|
||||
}
|
||||
|
||||
}
|
|
@ -239,7 +239,7 @@ void debug_menu() {
|
|||
}
|
||||
println(hlog, "parent_dir = ", c->parent_dir);
|
||||
c->parent_dir = MYSTERY;
|
||||
parent_debug = true;
|
||||
rulegen::rdebug_flags |= 16;
|
||||
try {
|
||||
twalker cw(c, 0);
|
||||
get_parent_dir(cw);
|
||||
|
@ -247,7 +247,7 @@ void debug_menu() {
|
|||
catch(rulegen_failure& f) {
|
||||
println(hlog, "catched: ", f.what());
|
||||
}
|
||||
parent_debug = false;
|
||||
rulegen::rdebug_flags &= ~16;
|
||||
println(hlog, "parent_dir = ", c->parent_dir);
|
||||
cleanup_protomap();
|
||||
});
|
||||
|
@ -505,12 +505,37 @@ void list_all_sequences(string tesname) {
|
|||
seq_stream->flush();
|
||||
}
|
||||
|
||||
void view_actual_seq(int max) {
|
||||
vector<int> gen_actual_seq(int max) {
|
||||
celllister cl(cwt.at, 1000, max, nullptr);
|
||||
vector<int> dlist(1000, 0);
|
||||
for(auto d: cl.dists) dlist[d]++;
|
||||
while(dlist.back() == 0) dlist.pop_back();
|
||||
println(hlog, "obtained dlist = ", dlist);
|
||||
return dlist;
|
||||
}
|
||||
|
||||
string unspace(const string& s) {
|
||||
string res;
|
||||
for(char c: s) if(c != ' ') res += c;
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<string> seq_as_stringlist() {
|
||||
auto& e = cgi.expansion;
|
||||
vector<string> res;
|
||||
for(int i=0; i<100; i++) res.push_back(unspace(e->get_descendants(i).get_str(1000)));
|
||||
return res;
|
||||
}
|
||||
|
||||
void view_seq_stats() {
|
||||
start_game();
|
||||
println(hlog, "SEQ rules ", seq_as_stringlist());
|
||||
println(hlog, "SEQ verify ", gen_actual_seq(100000));
|
||||
if(true) {
|
||||
stop_game();
|
||||
reg3::consider_rules = 0;
|
||||
start_game();
|
||||
println(hlog, "SEQ stupid ", gen_actual_seq(euclid ? 1000 : 100000));
|
||||
}
|
||||
}
|
||||
|
||||
void print_rules();
|
||||
|
@ -911,6 +936,7 @@ void test_current(string tesname) {
|
|||
status = "ACC";
|
||||
message = "OK";
|
||||
ok = true;
|
||||
rules_known_for = arb::current.name;
|
||||
}
|
||||
catch(rulegen_surrender& e) {
|
||||
println(hlog, "surrender: ** ", e.what());
|
||||
|
@ -1053,7 +1079,7 @@ void test_current(string tesname) {
|
|||
case 'O': Out("overts;oedges", lalign(0, count_vertex_orbits(), ";", count_edge_orbits()));
|
||||
case 'U': Out("vshapes;vverts;vedges;ushapes;uverts;uedges;xea;xeb;xec", count_uniform());
|
||||
case 'L': Out("mirror_rules", arb::current.mirror_rules);
|
||||
case 'B': Out("listshape;listvalence", format("%lld;%lld", get_shapelist(), get_valence_list()));
|
||||
case 'B': Out("listshape;listvalence", hr::format("%lld;%lld", get_shapelist(), get_valence_list()));
|
||||
case 'F': Out("maxdist", max_dist());
|
||||
|
||||
case 'f': Out("file", tesname);
|
||||
|
@ -1065,7 +1091,7 @@ void test_current(string tesname) {
|
|||
case '1': Out("single", single_live_branches);
|
||||
case '2': Out("double", double_live_branches);
|
||||
case 'p': Out("premini", states_premini);
|
||||
case 'K': Out("movecount", format("%ld", rulegen::movecount));
|
||||
case 'K': Out("movecount", hr::format("%ld", rulegen::movecount));
|
||||
}
|
||||
println(*test_out);
|
||||
test_out->flush();
|
||||
|
@ -1568,113 +1594,6 @@ void animate_to(int i) {
|
|||
println(hlog, "steps = ", steps);
|
||||
}
|
||||
|
||||
void genhoneycomb(string fname) {
|
||||
if(WDIM != 3) throw hr_exception("genhoneycomb not in honeycomb");
|
||||
|
||||
int qc = isize(t_origin);
|
||||
|
||||
vector<short> data;
|
||||
string side_data;
|
||||
|
||||
map<int, vector<int>> rev_roadsign_id;
|
||||
for(auto& rs: roadsign_id) rev_roadsign_id[rs.second] = rs.first;
|
||||
|
||||
int N = isize(treestates);
|
||||
using classdata = pair<vector<int>, int>;
|
||||
vector<classdata> nclassify(N);
|
||||
for(int i=0; i<N; i++) nclassify[i] = {{0}, i};
|
||||
|
||||
int numclass = 1;
|
||||
while(true) {
|
||||
println(hlog, "N = ", N, " numclass = ", numclass);
|
||||
for(int i=0; i<N; i++) {
|
||||
auto& ts = treestates[i];
|
||||
for(int j=0; j<isize(ts.rules); j++) {
|
||||
int j1 = gmod(j - ts.giver.spin, isize(ts.rules));
|
||||
auto r = ts.rules[j1];
|
||||
if(r < 0) nclassify[i].first.push_back(r);
|
||||
else nclassify[i].first.push_back(nclassify[r].first[0]);
|
||||
}
|
||||
}
|
||||
sort(nclassify.begin(), nclassify.end());
|
||||
vector<int> last = {}; int newclass = 0;
|
||||
for(int i=0; i<N; i++) {
|
||||
if(nclassify[i].first != last) {
|
||||
newclass++;
|
||||
last = nclassify[i].first;
|
||||
}
|
||||
nclassify[i].first = {newclass-1};
|
||||
}
|
||||
sort(nclassify.begin(), nclassify.end(), [] (const classdata& a, const classdata& b) { return a.second < b.second; });
|
||||
if(numclass == newclass) break;
|
||||
numclass = newclass;
|
||||
}
|
||||
vector<int> representative(numclass);
|
||||
for(int i=0; i<isize(treestates); i++) representative[nclassify[i].first[0]] = i;
|
||||
|
||||
println(hlog, "Minimized rules (", numclass, " states):");
|
||||
for(int i=0; i<numclass; i++) {
|
||||
auto& ts = treestates[representative[i]];
|
||||
print(hlog, lalign(4, i), ":");
|
||||
for(int j=0; j<isize(ts.rules); j++) {
|
||||
int j1 = gmod(j - ts.giver.spin, isize(ts.rules));
|
||||
auto r =ts.rules[j1];
|
||||
if(r == DIR_PARENT) print(hlog, " P");
|
||||
else if(r >= 0) print(hlog, " ", nclassify[r].first[0]);
|
||||
else print(hlog, " S", r);
|
||||
}
|
||||
println(hlog);
|
||||
}
|
||||
println(hlog);
|
||||
|
||||
for(int i=0; i<numclass; i++) {
|
||||
auto& ts = treestates[representative[i]];
|
||||
for(int j=0; j<isize(ts.rules); j++) {
|
||||
int j1 = gmod(j - ts.giver.spin, isize(ts.rules));
|
||||
auto r =ts.rules[j1];
|
||||
if(r == DIR_PARENT) {
|
||||
data.push_back(-1);
|
||||
side_data += ('A' + j);
|
||||
side_data += ",";
|
||||
}
|
||||
else if(r >= 0) {
|
||||
data.push_back(nclassify[r].first[0]);
|
||||
}
|
||||
else {
|
||||
data.push_back(-1);
|
||||
auto& str = rev_roadsign_id[r];
|
||||
bool next = true;
|
||||
for(auto ch: str) {
|
||||
if(next) side_data += ('a' + ch);
|
||||
next = !next;
|
||||
}
|
||||
side_data += ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shstream ss;
|
||||
|
||||
auto& fp = currfp;
|
||||
hwrite_fpattern(ss, fp);
|
||||
|
||||
vector<int> root(qc, 0);
|
||||
for(int i=0; i<qc; i++) root[i] = nclassify[get_treestate_id(t_origin[i]).second].first[0];
|
||||
println(hlog, "root = ", root);
|
||||
hwrite(ss, root);
|
||||
|
||||
println(hlog, "data = ", data);
|
||||
hwrite(ss, data);
|
||||
println(hlog, "side_data = ", side_data);
|
||||
hwrite(ss, side_data);
|
||||
|
||||
println(hlog, "compress_string");
|
||||
string s = compress_string(ss.s);
|
||||
|
||||
fhstream of(fname, "wb");
|
||||
print(of, s);
|
||||
}
|
||||
|
||||
void animate_steps(int i) {
|
||||
while(i--) {
|
||||
if(state != 1) break;
|
||||
|
@ -1728,10 +1647,6 @@ int testargs() {
|
|||
else if(argis("-trv")) {
|
||||
shift(); test_rotate_val = argi();
|
||||
}
|
||||
else if(argis("-ruleflag")) {
|
||||
shift();
|
||||
rulegen::flags ^= Flag(argi());
|
||||
}
|
||||
else if(argis("-ruleflag-sub")) {
|
||||
swap(rulegen::flags, sub_rulegen_flags);
|
||||
}
|
||||
|
@ -1817,10 +1732,6 @@ int testargs() {
|
|||
shift(); tesgen(args());
|
||||
}
|
||||
|
||||
else if(argis("-gen-honeycomb")) {
|
||||
shift(); genhoneycomb(args());
|
||||
}
|
||||
|
||||
else if(argis("-tes-animate")) {
|
||||
animate();
|
||||
}
|
||||
|
@ -1840,12 +1751,18 @@ int testargs() {
|
|||
}
|
||||
|
||||
else if(argis("-veb")) {
|
||||
view_examine_branch = true;
|
||||
rulegen::rdebug_flags |= 32;
|
||||
}
|
||||
|
||||
else if(argis("-act-seq")) {
|
||||
start_game();
|
||||
shift(); view_actual_seq(argi());
|
||||
shift();
|
||||
println(hlog, "obtained dlist = ", gen_actual_seq(argi()));
|
||||
}
|
||||
|
||||
else if(argis("-seq-stats")) {
|
||||
start_game();
|
||||
view_seq_stats();
|
||||
}
|
||||
|
||||
else if(argis("-dseek")) {
|
||||
|
@ -1860,15 +1777,23 @@ int testargs() {
|
|||
else
|
||||
println(hlog, "wrong dseek index");
|
||||
}
|
||||
|
||||
else if(argis("-urq")) {
|
||||
// -urq 7 to generate honeycombs
|
||||
stop_game();
|
||||
shift(); int i = argi();
|
||||
reg3::reg3_rule_available = (i & 8) ? 0 : 1;
|
||||
fieldpattern::use_rule_fp = (i & 1) ? 1 : 0;
|
||||
fieldpattern::use_quotient_fp = (i & 2) ? 1 : 0;
|
||||
reg3::minimize_quotient_maps = (i & 4) ? 1 : 0;
|
||||
|
||||
else if(argis("-fields")) {
|
||||
fieldpattern::fpattern fp(0);
|
||||
start_game();
|
||||
fp.force_hash = 1;
|
||||
fieldpattern::use_quotient_fp = true;
|
||||
set<unsigned> seen_hashes;
|
||||
addHook(fieldpattern::hooks_solve3, 100, [&] {
|
||||
if(seen_hashes.count(fp.hashv)) return;
|
||||
seen_hashes.insert(fp.hashv);
|
||||
println(hlog, "FOUND p=", fp.Prime, " f=", fp.Field, " hash = ", fp.hashv);
|
||||
});
|
||||
for(int p=2; p<100; p++) {
|
||||
println(hlog, "listing hashes for p=", p);
|
||||
fp.Prime = p;
|
||||
fp.solve();
|
||||
}
|
||||
}
|
||||
|
||||
else return 1;
|
||||
|
|
|
@ -235,11 +235,11 @@ void build_sols(int PRECX, int PRECY, int PRECZ) {
|
|||
auto xerr = solerror(v, nisot::numerical_exp(cand));
|
||||
|
||||
if(cand == fail) {
|
||||
println(hlog, format("[%2d %2d %2d] FAIL", iz, iy, ix));
|
||||
println(hlog, hr::format("[%2d %2d %2d] FAIL", iz, iy, ix));
|
||||
}
|
||||
|
||||
else if(xerr > 1e-3) {
|
||||
println(hlog, format("[%2d %2d %2d] ", iz, iy, ix));
|
||||
println(hlog, hr::format("[%2d %2d %2d] ", iz, iy, ix));
|
||||
println(hlog, "f(?) = ", v);
|
||||
println(hlog, "f(", cand, ") = ", nisot::numerical_exp(cand));
|
||||
println(hlog, "error = ", xerr);
|
||||
|
@ -265,7 +265,7 @@ void build_sols(int PRECX, int PRECY, int PRECZ) {
|
|||
}
|
||||
if(it < last_x && it < last_y) solve_at(it, it);
|
||||
std::lock_guard<std::mutex> fm(file_mutex);
|
||||
if(0) println(hlog, format("%2d: %2d", iz, it));
|
||||
if(0) println(hlog, hr::format("%2d: %2d", iz, it));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -469,7 +469,7 @@ void visualize_table(sn::tabled_inverses& tab, const string& s) {
|
|||
for(int i=0; i<3; i++)
|
||||
part(p, i) = 0x80 + 0x70 * tab.get_int(ix, iy, iz)[i];
|
||||
}
|
||||
SDL_SavePNG(rb.srf, format(s.c_str(), iz).c_str());
|
||||
SDL_SavePNG(rb.srf, hr::format(s.c_str(), iz).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
1011
dialogs.cpp
1011
dialogs.cpp
File diff suppressed because it is too large
Load Diff
417
drawing.cpp
417
drawing.cpp
|
@ -9,36 +9,37 @@
|
|||
namespace hr {
|
||||
|
||||
#if HDR
|
||||
static const int POLY_DRAWLINES = 1; // draw the lines
|
||||
static const int POLY_DRAWAREA = 2; // draw the area
|
||||
static const int POLY_INVERSE = 4; // draw the inverse -- useful in stereographic projection
|
||||
static const int POLY_ISSIDE = 8; // never draw in inverse
|
||||
static const int POLY_BEHIND = 16; // there are points behind the camera
|
||||
static const int POLY_TOOLARGE = 32; // some coordinates are too large -- best not to draw to avoid glitches
|
||||
static const int POLY_INFRONT = 64; // on the sphere (orthogonal projection), do not draw without any points in front
|
||||
static const int POLY_HASWALLS = 128; // floor shapes which have their sidewalls
|
||||
static const int POLY_PLAIN = 256; // plain floors
|
||||
static const int POLY_FULL = 512; // full floors
|
||||
static const int POLY_HASSHADOW = 1024; // floor shapes which have their shadows, or can use shFloorShadow
|
||||
static const int POLY_GP = 2048; // Goldberg shapes
|
||||
static const int POLY_VCONVEX = 4096; // Convex shape (vertex)
|
||||
static const int POLY_CCONVEX = 8192; // Convex shape (central)
|
||||
static const int POLY_CENTERIN = 16384; // new system of side checking
|
||||
static const int POLY_FORCEWIDE = (1<<15); // force wide lines
|
||||
static const int POLY_NOTINFRONT = (1<<16); // points not in front
|
||||
static const int POLY_NIF_ERROR = (1<<17); // points moved to the outline cross the image, disable
|
||||
static const int POLY_BADCENTERIN = (1<<18); // new system of side checking
|
||||
static const int POLY_PRECISE_WIDE = (1<<19); // precise width calculation
|
||||
static const int POLY_FORCE_INVERTED = (1<<20); // force inverted
|
||||
static const int POLY_ALWAYS_IN = (1<<21); // always draw this
|
||||
static const int POLY_TRIANGLES = (1<<22); // made of TRIANGLES, not TRIANGLE_FAN
|
||||
static const int POLY_INTENSE = (1<<23); // extra intense colors
|
||||
static const int POLY_DEBUG = (1<<24); // debug this shape
|
||||
static const int POLY_PRINTABLE = (1<<25); // these walls are printable
|
||||
static const int POLY_FAT = (1<<26); // fatten this model in WRL export (used for Rug)
|
||||
static const int POLY_SHADE_TEXTURE = (1<<27); // texture has 'z' coordinate for shading
|
||||
static const int POLY_ONE_LEVEL = (1<<28); // only one level of the universal cover in SL(2,R)
|
||||
static const int POLY_APEIROGONAL = (1<<29); // only vertices indexed up to she are drawn as the boundary
|
||||
static constexpr int POLY_DRAWLINES = 1; // draw the lines
|
||||
static constexpr int POLY_DRAWAREA = 2; // draw the area
|
||||
static constexpr int POLY_INVERSE = 4; // draw the inverse -- useful in stereographic projection
|
||||
static constexpr int POLY_ISSIDE = 8; // never draw in inverse
|
||||
static constexpr int POLY_BEHIND = 16; // there are points behind the camera
|
||||
static constexpr int POLY_TOOLARGE = 32; // some coordinates are too large -- best not to draw to avoid glitches
|
||||
static constexpr int POLY_INFRONT = 64; // on the sphere (orthogonal projection), do not draw without any points in front
|
||||
static constexpr int POLY_HASWALLS = 128; // floor shapes which have their sidewalls
|
||||
static constexpr int POLY_PLAIN = 256; // plain floors
|
||||
static constexpr int POLY_FULL = 512; // full floors
|
||||
static constexpr int POLY_HASSHADOW = 1024; // floor shapes which have their shadows, or can use shFloorShadow
|
||||
static constexpr int POLY_GP = 2048; // Goldberg shapes
|
||||
static constexpr int POLY_VCONVEX = 4096; // Convex shape (vertex)
|
||||
static constexpr int POLY_CCONVEX = 8192; // Convex shape (central)
|
||||
static constexpr int POLY_CENTERIN = 16384; // new system of side checking
|
||||
static constexpr int POLY_FORCEWIDE = (1<<15); // force wide lines
|
||||
static constexpr int POLY_NOTINFRONT = (1<<16); // points not in front
|
||||
static constexpr int POLY_NIF_ERROR = (1<<17); // points moved to the outline cross the image, disable
|
||||
static constexpr int POLY_BADCENTERIN = (1<<18); // new system of side checking
|
||||
static constexpr int POLY_PRECISE_WIDE = (1<<19); // precise width calculation
|
||||
static constexpr int POLY_FORCE_INVERTED = (1<<20); // force inverted
|
||||
static constexpr int POLY_ALWAYS_IN = (1<<21); // always draw this
|
||||
static constexpr int POLY_TRIANGLES = (1<<22); // made of TRIANGLES, not TRIANGLE_FAN
|
||||
static constexpr int POLY_INTENSE = (1<<23); // extra intense colors
|
||||
static constexpr int POLY_DEBUG = (1<<24); // debug this shape
|
||||
static constexpr int POLY_PRINTABLE = (1<<25); // these walls are printable
|
||||
static constexpr int POLY_FAT = (1<<26); // fatten this model in WRL export (used for Rug)
|
||||
static constexpr int POLY_SHADE_TEXTURE = (1<<27); // texture has 'z' coordinate for shading
|
||||
static constexpr int POLY_ONE_LEVEL = (1<<28); // only one level of the universal cover in SL(2,R)
|
||||
static constexpr int POLY_APEIROGONAL = (1<<29); // only vertices indexed up to she are drawn as the boundary
|
||||
static constexpr int POLY_NO_FOG = (1<<30); // disable fog for this
|
||||
|
||||
/** \brief A graphical element that can be drawn. Objects are not drawn immediately but rather queued.
|
||||
*
|
||||
|
@ -167,35 +168,40 @@ EX int texts_merged;
|
|||
EX int shapes_merged;
|
||||
|
||||
#if MINIMIZE_GL_CALLS
|
||||
color_t triangle_color, line_color;
|
||||
PPR lprio;
|
||||
ld m_shift;
|
||||
vector<glvertex> triangle_vertices;
|
||||
vector<glvertex> line_vertices;
|
||||
vector<glhr::colored_vertex> triangle_vertices;
|
||||
vector<glhr::colored_vertex> line_vertices;
|
||||
#endif
|
||||
|
||||
EX void glflush() {
|
||||
DEBBI(DF_GRAPH, ("glflush"));
|
||||
#if MINIMIZE_GL_CALLS
|
||||
current_display->set_all(0, m_shift);
|
||||
if(isize(triangle_vertices)) {
|
||||
// printf("%08X %08X | %d shapes, %d/%d vertices\n", triangle_color, line_color, shapes_merged, isize(triangle_vertices), isize(line_vertices));
|
||||
if(triangle_color) {
|
||||
// printf("%3d | %d shapes, %d/%d vertices\n", lprio, shapes_merged, isize(triangle_vertices), isize(line_vertices));
|
||||
current_display->next_shader_flags = GF_VARCOLOR;
|
||||
current_display->set_all(0, m_shift);
|
||||
if(true) {
|
||||
glhr::be_nontextured();
|
||||
glapplymatrix(Id);
|
||||
glhr::current_vertices = NULL;
|
||||
glhr::vertices(triangle_vertices);
|
||||
glhr::color2(triangle_color);
|
||||
glhr::prepare(triangle_vertices);
|
||||
glhr::color2(0xFFFFFFFF);
|
||||
glDrawArrays(GL_TRIANGLES, 0, isize(triangle_vertices));
|
||||
}
|
||||
triangle_vertices.clear();
|
||||
if(isize(line_vertices)) goto jump;
|
||||
}
|
||||
if(isize(line_vertices)) {
|
||||
if(line_color) {
|
||||
current_display->next_shader_flags = GF_VARCOLOR;
|
||||
current_display->set_all(0, m_shift);
|
||||
jump:
|
||||
if(true) {
|
||||
glhr::be_nontextured();
|
||||
glapplymatrix(Id);
|
||||
glhr::current_vertices = NULL;
|
||||
glhr::vertices(line_vertices);
|
||||
glhr::color2(line_color);
|
||||
glhr::prepare(line_vertices);
|
||||
glhr::color2(0xFFFFFFFF);
|
||||
glDrawArrays(GL_LINES, 0, isize(line_vertices));
|
||||
}
|
||||
line_vertices.clear();
|
||||
|
@ -223,7 +229,7 @@ EX void glflush() {
|
|||
|
||||
else
|
||||
#endif
|
||||
for(int ed = (current_display->stereo_active() && text_shift)?-1:0; ed<2; ed+=2) {
|
||||
for(int ed = (current_display->separate_eyes() && text_shift)?-1:0; ed<2; ed+=2) {
|
||||
glhr::set_modelview(glhr::translate(-ed*text_shift-current_display->xcenter,-current_display->ycenter, 0));
|
||||
current_display->set_mask(ed);
|
||||
drawer();
|
||||
|
@ -231,7 +237,7 @@ EX void glflush() {
|
|||
GLERR("print");
|
||||
}
|
||||
|
||||
if(current_display->stereo_active() && text_shift && !svg::in) current_display->set_mask(0);
|
||||
if(current_display->separate_eyes() && text_shift && !svg::in) current_display->set_mask(0);
|
||||
|
||||
texts_merged = 0;
|
||||
text_vertices.clear();
|
||||
|
@ -307,12 +313,11 @@ EX bool two_sided_model() {
|
|||
#endif
|
||||
if(GDIM == 3) return false;
|
||||
if(in_vr_sphere) return true;
|
||||
if(models::is_hyperboloid(pmodel)) return !euclid && !in_vr;
|
||||
if(pmodel == mdHemisphere || pmodel == mdHyperboloid) return !in_vr;
|
||||
// if(pmodel == mdHemisphere) return true;
|
||||
if(pmodel == mdDisk) return sphere || (hyperbolic && pconf.alpha < 0 && pconf.alpha > -1);
|
||||
if(pmodel == mdRetroLittrow) return sphere;
|
||||
if(pmodel == mdRetroHammer) return sphere;
|
||||
if(pmodel == mdHemisphere) return !in_vr;
|
||||
if(pmodel == mdRotatedHyperboles) return true;
|
||||
if(pmodel == mdSpiral && pconf.spiral_cone < 360) return true;
|
||||
return false;
|
||||
|
@ -347,13 +352,12 @@ EX int get_side(const hyperpoint& H) {
|
|||
}
|
||||
if(pmodel == mdRotatedHyperboles)
|
||||
return H[1] > 0 ? -1 : 1;
|
||||
if(pmodel == mdHyperboloid && hyperbolic)
|
||||
return (models::sin_ball * H[2] > -models::cos_ball * H[1]) ? -1 : 1;
|
||||
if(pmodel == mdHyperboloid && sphere)
|
||||
return (models::sin_ball * H[2] > models::cos_ball * H[1]) ? -1 : 1;
|
||||
if(pmodel == mdHyperboloid) {
|
||||
return det2(pconf.ball() * cspin90(2, 1) * rgpushxto0(H)) > 0 ? 1 : -1;
|
||||
}
|
||||
if(pmodel == mdHyperboloidFlat && sphere)
|
||||
return H[2] >= 0 ? 1 : -1;
|
||||
if(pmodel == mdHemisphere && hyperbolic) {
|
||||
if(pmodel == mdHemisphere && !sphere) {
|
||||
hyperpoint res;
|
||||
applymodel(shiftless(H), res);
|
||||
return res[2] < 0 ? -1 : 1;
|
||||
|
@ -363,8 +367,9 @@ EX int get_side(const hyperpoint& H) {
|
|||
int s = H1[2] > 0 ? 1 : -1;
|
||||
if(hemi_side && s != hemi_side) return -spherespecial;
|
||||
H1[0] /= H1[2]; H1[1] /= H1[2];
|
||||
H1[2] = s * sqrt(1 + H1[0]*H1[0] + H1[1] * H1[1]);
|
||||
return (models::sin_ball * H1[2] > models::cos_ball * H1[1]) ? 1 : -1;
|
||||
H1[2] = -s * sqrt(1 + H1[0]*H1[0] + H1[1] * H1[1]);
|
||||
dynamicval<geometryinfo1> g(cginf.g, giHyperb2);
|
||||
return det2(pconf.ball() * cspin90(2, 1) * rgpushxto0(H1)) > 0 ? 1 : -1;
|
||||
}
|
||||
if(pmodel == mdSpiral && pconf.spiral_cone < 360) {
|
||||
return cone_side(shiftless(H));
|
||||
|
@ -438,10 +443,10 @@ void addpoint(const shiftpoint& H) {
|
|||
if(sphere && pmodel == mdSpiral) {
|
||||
if(isize(glcoords)) {
|
||||
hyperpoint Hscr1;
|
||||
shiftpoint H1 = H; H1.shift += 2 * M_PI;
|
||||
shiftpoint H1 = H; H1.shift += TAU;
|
||||
applymodel(H1, Hscr1);
|
||||
if(hypot_d(2, Hlast-Hscr1) < hypot_d(2, Hlast-Hscr)) { Hscr = Hscr1; }
|
||||
H1.shift -= 4 * M_PI;
|
||||
H1.shift -= 2 * TAU;
|
||||
applymodel(H1, Hscr1);
|
||||
if(hypot_d(2, Hlast-Hscr1) < hypot_d(2, Hlast-Hscr)) { Hscr = Hscr1; }
|
||||
}
|
||||
|
@ -469,7 +474,7 @@ void addpoint(const shiftpoint& H) {
|
|||
void coords_to_poly() {
|
||||
polyi = isize(glcoords);
|
||||
for(int i=0; i<polyi; i++) {
|
||||
if(!current_display->stereo_active()) glcoords[i][2] = 0;
|
||||
if(!current_display->separate_eyes()) glcoords[i][2] = 0;
|
||||
|
||||
polyx[i] = current_display->xcenter + glcoords[i][0] - glcoords[i][2];
|
||||
polyxr[i] = current_display->xcenter + glcoords[i][0] + glcoords[i][2];
|
||||
|
@ -481,7 +486,11 @@ bool behind3(shiftpoint h) {
|
|||
if(pmodel == mdGeodesic)
|
||||
return lp_apply(inverse_exp(h))[2] < 0;
|
||||
if(pmodel == mdLiePerspective)
|
||||
return lp_apply(lie_log(unshift(h)))[2] < 0;
|
||||
return lp_apply(lie_log(h))[2] < 0;
|
||||
#if MAXMDIM >= 4
|
||||
if(pmodel == mdRelPerspective)
|
||||
return lp_apply(rel_log(h, false))[2] < 0;
|
||||
#endif
|
||||
return h[2] < 0;
|
||||
}
|
||||
|
||||
|
@ -499,7 +508,15 @@ void addpoly(const shiftmatrix& V, const vector<glvertex> &tab, int ofs, int cnt
|
|||
}
|
||||
tofix.clear(); knowgood = false;
|
||||
if(in_perspective()) {
|
||||
if(poly_flags & POLY_TRIANGLES) {
|
||||
if(get_shader_flags() & SF_SEMIDIRECT) {
|
||||
dynamicval<bool> d(computing_semidirect, true);
|
||||
for(int i=ofs; i<ofs+cnt; i++) {
|
||||
hyperpoint Hscr;
|
||||
applymodel(V * glhr::gltopoint(tab[i]), Hscr);
|
||||
add1(Hscr);
|
||||
}
|
||||
}
|
||||
else if(poly_flags & POLY_TRIANGLES) {
|
||||
for(int i=ofs; i<ofs+cnt; i+=3) {
|
||||
shiftpoint h0 = V * glhr::gltopoint(tab[i]);
|
||||
shiftpoint h1 = V * glhr::gltopoint(tab[i+1]);
|
||||
|
@ -646,26 +663,31 @@ void dqi_poly::gldraw() {
|
|||
int ioffset = offset;
|
||||
|
||||
#if MINIMIZE_GL_CALLS
|
||||
if(current_display->stereo_active() == 0 && !tinf && (color == 0 || ((flags & (POLY_VCONVEX | POLY_CCONVEX)) && !(flags & (POLY_INVERSE | POLY_FORCE_INVERTED))))) {
|
||||
if(color != triangle_color || outline != line_color || texts_merged || m_shift != V.shift) {
|
||||
if(current_display->separate_eyes() == 0 && !tinf && (color == 0 || ((flags & (POLY_VCONVEX | POLY_CCONVEX)) && !(flags & (POLY_INVERSE | POLY_FORCE_INVERTED))))) {
|
||||
if(lprio != prio || texts_merged || m_shift != V.shift) {
|
||||
glflush();
|
||||
triangle_color = color;
|
||||
line_color = outline;
|
||||
lprio = prio;
|
||||
m_shift = V.shift;
|
||||
}
|
||||
shapes_merged++;
|
||||
|
||||
if((flags & POLY_CCONVEX) && !(flags & POLY_VCONVEX)) {
|
||||
vector<glvertex> v2(cnt+1);
|
||||
for(int i=0; i<cnt+1; i++) v2[i] = glhr::pointtogl( V.T * glhr::gltopoint( v[offset+i-1] ) );
|
||||
vector<glhr::colored_vertex> v2(cnt+1);
|
||||
for(int i=0; i<cnt+1; i++) v2[i] = glhr::colored_vertex( V.T * glhr::gltopoint( v[offset+i-1] ), color);
|
||||
if(color) for(int i=0; i<cnt; i++) triangle_vertices.push_back(v2[0]), triangle_vertices.push_back(v2[i]), triangle_vertices.push_back(v2[i+1]);
|
||||
for(int i=1; i<cnt; i++) line_vertices.push_back(v2[i]), line_vertices.push_back(v2[i+1]);
|
||||
if(outline) {
|
||||
for(auto& v: v2) v.set_color(outline);
|
||||
for(int i=1; i<cnt; i++) line_vertices.push_back(v2[i]), line_vertices.push_back(v2[i+1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
vector<glvertex> v2(cnt);
|
||||
for(int i=0; i<cnt; i++) v2[i] = glhr::pointtogl( V.T * glhr::gltopoint( v[offset+i] ) );
|
||||
vector<glhr::colored_vertex> v2(cnt);
|
||||
for(int i=0; i<cnt; i++) v2[i] = glhr::colored_vertex( V.T * glhr::gltopoint( v[offset+i] ), color);
|
||||
if(color) for(int i=2; i<cnt-1; i++) triangle_vertices.push_back(v2[0]), triangle_vertices.push_back(v2[i-1]), triangle_vertices.push_back(v2[i]);
|
||||
for(int i=1; i<cnt; i++) line_vertices.push_back(v2[i-1]), line_vertices.push_back(v2[i]);
|
||||
if(outline) {
|
||||
for(auto& v: v2) v.set_color(outline);
|
||||
for(int i=1; i<cnt; i++) line_vertices.push_back(v2[i-1]), line_vertices.push_back(v2[i]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -679,6 +701,7 @@ void dqi_poly::gldraw() {
|
|||
else
|
||||
glhr::be_textured();
|
||||
if(flags & POLY_SHADE_TEXTURE) current_display->next_shader_flags |= GF_TEXTURE_SHADED;
|
||||
if(flags & POLY_NO_FOG) current_display->next_shader_flags |= GF_NO_FOG;
|
||||
glBindTexture(GL_TEXTURE_2D, tinf->texture_id);
|
||||
if(isize(tinf->colors))
|
||||
glhr::vertices_texture_color(v, tinf->tvertices, tinf->colors, offset, offset_texture);
|
||||
|
@ -688,12 +711,13 @@ void dqi_poly::gldraw() {
|
|||
}
|
||||
else {
|
||||
glhr::be_nontextured();
|
||||
if(flags & POLY_NO_FOG) current_display->next_shader_flags |= GF_NO_FOG;
|
||||
glhr::vertices(v);
|
||||
}
|
||||
|
||||
next_slr:
|
||||
|
||||
for(int ed = current_display->stereo_active() ? -1 : 0; ed<2; ed+=2) {
|
||||
for(int ed = current_display->separate_eyes() ? -1 : 0; ed<2; ed+=2) {
|
||||
if(global_projection && global_projection != ed) continue;
|
||||
|
||||
if(min_slr < max_slr) {
|
||||
|
@ -722,7 +746,7 @@ void dqi_poly::gldraw() {
|
|||
glhr::color2(color, (flags & POLY_INTENSE) ? 2 : 1);
|
||||
glhr::set_depthtest(model_needs_depth() && prio < PPR::SUPERLINE);
|
||||
glhr::set_depthwrite(model_needs_depth() && prio != PPR::TRANSPARENT_SHADOW && prio != PPR::EUCLIDEAN_SKY);
|
||||
glhr::set_fogbase(prio == PPR::SKY ? 1.0 + (euclid ? 20 : 5 / sightranges[geometry]) : 1.0);
|
||||
glhr::set_fogbase(prio == PPR::SKY ? 1.0 + ((abs(cgi.SKY - cgi.LOWSKY)) / sightranges[geometry]) : 1.0);
|
||||
glDrawArrays(GL_TRIANGLES, ioffset, cnt);
|
||||
}
|
||||
else {
|
||||
|
@ -733,7 +757,7 @@ void dqi_poly::gldraw() {
|
|||
glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT);
|
||||
glStencilFunc( GL_ALWAYS, 0x1, 0x1 );
|
||||
glhr::color2(0xFFFFFFFF);
|
||||
glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, offset, cnt);
|
||||
glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ioffset, cnt);
|
||||
|
||||
current_display->set_mask(ed);
|
||||
glhr::color2(color);
|
||||
|
@ -761,7 +785,7 @@ void dqi_poly::gldraw() {
|
|||
else {
|
||||
glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO);
|
||||
glStencilFunc( GL_EQUAL, 1, 1);
|
||||
glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, offset, cnt);
|
||||
glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ioffset, cnt);
|
||||
}
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
@ -804,7 +828,13 @@ void dqi_poly::gldraw() {
|
|||
#endif
|
||||
|
||||
EX ld scale_at(const shiftmatrix& T) {
|
||||
if(GDIM == 3 && pmodel == mdPerspective) return 1 / abs((tC0(unshift(T)))[2]);
|
||||
if(GDIM == 3 && pmodel == mdPerspective) {
|
||||
ld z = (tC0(unshift(T)))[2];
|
||||
if(z == 0) return 1;
|
||||
z = 1 / abs(z);
|
||||
if(z > 10) return 10;
|
||||
return z;
|
||||
}
|
||||
if(sol) return 1;
|
||||
hyperpoint h1, h2, h3;
|
||||
applymodel(tC0(T), h1);
|
||||
|
@ -836,6 +866,17 @@ EX ld linewidthat(const shiftpoint& h) {
|
|||
return dfc;
|
||||
}
|
||||
}
|
||||
else if(hyperbolic && pmodel == mdRelPerspective) {
|
||||
if(abs(h[3]) < 1e-6) return 1;
|
||||
return 1 / (1 + abs(h[3]));
|
||||
}
|
||||
else if(sl2 && pmodel == mdRelPerspective) {
|
||||
if(abs(h[2]) < 1e-6) return 1;
|
||||
return 1 / (1 + abs(h[2]));
|
||||
}
|
||||
else if(hyperbolic && GDIM == 3 && pmodel == mdPerspective && pconf.alpha == 0 && h[3] < 0.99) {
|
||||
return 1;
|
||||
}
|
||||
else if(perfect_linewidth >= (inHighQual ? 1 : 2)) {
|
||||
hyperpoint h0 = h.h / zlevel(h.h);
|
||||
shiftmatrix T = shiftless(rgpushxto0(h0), h.shift);
|
||||
|
@ -883,13 +924,30 @@ ld period_at(ld y) {
|
|||
}
|
||||
}
|
||||
|
||||
void ori_to_scr(glvertex& g) {
|
||||
auto& Ori = pconf.mori().v2;
|
||||
tie(g[0], g[1]) = make_pair(
|
||||
Ori[0][0] * g[0] + Ori[0][1] * g[1],
|
||||
Ori[1][0] * g[0] + Ori[1][1] * g[1]
|
||||
);
|
||||
}
|
||||
|
||||
void scr_to_ori(glvertex& g) {
|
||||
auto& Ori = pconf.mori().v2;
|
||||
/* we invert it, so transposition is applied in the formula */
|
||||
tie(g[0], g[1]) = make_pair(
|
||||
Ori[0][0] * g[0] + Ori[1][0] * g[1],
|
||||
Ori[0][1] * g[0] + Ori[1][1] * g[1]
|
||||
);
|
||||
}
|
||||
|
||||
void adjust(bool tinf) {
|
||||
|
||||
periods.resize(isize(glcoords));
|
||||
|
||||
if(!models::model_straight)
|
||||
for(auto& g: glcoords)
|
||||
models::apply_orientation(g[0], g[1]);
|
||||
scr_to_ori(g);
|
||||
|
||||
for(int i = 0; i<isize(glcoords); i++) periods[i] = period_at(glcoords[i][1]);
|
||||
|
||||
|
@ -947,7 +1005,7 @@ void adjust(bool tinf) {
|
|||
if(abs(first - last) < 1e-6) {
|
||||
if(!models::model_straight)
|
||||
for(auto& g: glcoords)
|
||||
models::apply_orientation(g[1], g[0]);
|
||||
ori_to_scr(g);
|
||||
}
|
||||
else {
|
||||
if(tinf) {
|
||||
|
@ -978,7 +1036,7 @@ void adjust(bool tinf) {
|
|||
}
|
||||
if(!models::model_straight)
|
||||
for(auto& g: glcoords)
|
||||
models::apply_orientation(g[1], g[0]);
|
||||
ori_to_scr(g);
|
||||
// we have already looped
|
||||
loop_min = loop_max = 0;
|
||||
}
|
||||
|
@ -1086,7 +1144,7 @@ EX namespace s2xe {
|
|||
}
|
||||
|
||||
void add2(pt h, int gen) {
|
||||
glcoords.push_back(glhr::pointtogl(point31(sin(h[0]) * (h[1] + 2 * M_PI * gen), cos(h[0]) * (h[1] + 2 * M_PI * gen), h[2])));
|
||||
glcoords.push_back(glhr::pointtogl(point31(sin(h[0]) * (h[1] + TAU * gen), cos(h[0]) * (h[1] + TAU * gen), h[2])));
|
||||
stinf.tvertices.push_back(glhr::makevertex(h[3], h[4], 0));
|
||||
}
|
||||
|
||||
|
@ -1103,13 +1161,13 @@ EX namespace s2xe {
|
|||
bool to_right(const pt& h2, const pt& h1) {
|
||||
ld x2 = h2[0];
|
||||
ld x1 = h1[0];
|
||||
if(x2 < x1) x2 += 2 * M_PI;
|
||||
if(x2 < x1) x2 += TAU;
|
||||
return x2 >= x2 && x2 <= x1 + M_PI;
|
||||
}
|
||||
|
||||
EX int qrings = 32;
|
||||
|
||||
ld seg() { return 2 * M_PI / qrings; }
|
||||
ld seg() { return TAU / qrings; }
|
||||
|
||||
void add_ortho_triangle(pt bl, pt tl, pt br, pt tr) {
|
||||
|
||||
|
@ -1142,12 +1200,12 @@ EX namespace s2xe {
|
|||
}
|
||||
|
||||
void add_ordered_triangle(array<pt, 3> v) {
|
||||
if(v[1][0] < v[0][0]) v[1][0] += 2 * M_PI;
|
||||
if(v[2][0] < v[1][0]) v[2][0] += 2 * M_PI;
|
||||
if(v[1][0] < v[0][0]) v[1][0] += TAU;
|
||||
if(v[2][0] < v[1][0]) v[2][0] += TAU;
|
||||
if(v[2][0] - v[0][0] < 1e-6) return;
|
||||
ld x = (v[1][0] - v[0][0]) / (v[2][0] - v[0][0]);
|
||||
|
||||
if(v[2][0] < v[0][0] + M_PI / 4 && maxy < M_PI - M_PI/4 && sightranges[geometry] <= 5) {
|
||||
if(v[2][0] < v[0][0] + 45._deg && maxy < 135._deg && sightranges[geometry] <= 5) {
|
||||
addall(v[0], v[1], v[2]);
|
||||
return;
|
||||
}
|
||||
|
@ -1173,16 +1231,16 @@ EX namespace s2xe {
|
|||
}
|
||||
|
||||
void add_triangle_around(array<pt, 3> v) {
|
||||
ld baseheight = (v[0][1] > M_PI/2) ? M_PI : 0;
|
||||
ld baseheight = (v[0][1] > 90._deg) ? M_PI : 0;
|
||||
ld tu = (v[0][3] + v[1][3] + v[2][3]) / 3;
|
||||
ld tv = (v[0][4] + v[1][4] + v[2][4]) / 3;
|
||||
array<pt, 3> vhigh;
|
||||
for(int i=0; i<3; i++) { vhigh[i] = v[i]; vhigh[i][1] = baseheight; vhigh[i][3] = tu; vhigh[i][4] = tv; }
|
||||
if(v[1][0] < v[0][0]) v[1][0] = v[1][0] + 2 * M_PI, vhigh[1][0] = vhigh[1][0] + 2 * M_PI;
|
||||
if(v[1][0] < v[0][0]) v[1][0] = v[1][0] + TAU, vhigh[1][0] = vhigh[1][0] + TAU;
|
||||
add_ortho_triangle(v[0], vhigh[0], v[1], vhigh[1]);
|
||||
if(v[2][0] < v[1][0]) v[2][0] = v[2][0] + 2 * M_PI, vhigh[2][0] = vhigh[2][0] + 2 * M_PI;
|
||||
if(v[2][0] < v[1][0]) v[2][0] = v[2][0] + TAU, vhigh[2][0] = vhigh[2][0] + TAU;
|
||||
add_ortho_triangle(v[1], vhigh[1], v[2], vhigh[2]);
|
||||
if(v[0][0] < v[2][0]) v[0][0] = v[0][0] + 2 * M_PI, vhigh[0][0] = vhigh[0][0] + 2 * M_PI;
|
||||
if(v[0][0] < v[2][0]) v[0][0] = v[0][0] + TAU, vhigh[0][0] = vhigh[0][0] + TAU;
|
||||
add_ortho_triangle(v[2], vhigh[2], v[0], vhigh[0]);
|
||||
}
|
||||
|
||||
|
@ -1193,12 +1251,12 @@ EX namespace s2xe {
|
|||
|
||||
minz = min(abs(v[0][2]), max(abs(v[1][2]), abs(v[2][2])));
|
||||
auto& s = sightranges[geometry];
|
||||
maxgen = sqrt(s * s - minz * minz) / (2 * M_PI) + 1;
|
||||
maxgen = sqrt(s * s - minz * minz) / TAU + 1;
|
||||
|
||||
maxy = max(v[0][1], max(v[1][1], v[2][1]));
|
||||
miny = min(v[0][1], min(v[1][1], v[2][1]));
|
||||
with_zero = true;
|
||||
if(maxy < M_PI / 4) {
|
||||
if(maxy < 45._deg) {
|
||||
add2(v[0], 0);
|
||||
add2(v[1], 0);
|
||||
add2(v[2], 0);
|
||||
|
@ -1288,7 +1346,7 @@ void draw_s2xe0(dqi_poly *p) {
|
|||
set_width(1);
|
||||
glcoords.clear();
|
||||
|
||||
int maxgen = sightranges[geometry] / (2 * M_PI) + 1;
|
||||
int maxgen = sightranges[geometry] / TAU + 1;
|
||||
|
||||
auto crossdot = [&] (const hyperpoint h1, const hyperpoint h2) { return make_pair(h1[0] * h2[1] - h1[1] * h2[0], h1[0] * h2[0] + h1[1] * h2[1]); };
|
||||
vector<point_data> pd;
|
||||
|
@ -1320,7 +1378,7 @@ void draw_s2xe0(dqi_poly *p) {
|
|||
for(int i=0; i<p->cnt; i++) {
|
||||
auto &c1 = pd[i];
|
||||
auto &c0 = pd[i==0?p->cnt-1 : i-1];
|
||||
if(c1.distance > M_PI/2 && c0.distance > M_PI/2 && crossdot(c0.direction, c1.direction).second < 0) return;
|
||||
if(c1.distance > 90._deg && c0.distance > 90._deg && crossdot(c0.direction, c1.direction).second < 0) return;
|
||||
if(c1.bad == 2) return;
|
||||
if(c1.bad == 1) no_gens = true;
|
||||
}
|
||||
|
@ -1332,12 +1390,12 @@ void draw_s2xe0(dqi_poly *p) {
|
|||
angles[i] = atan2(pd[i].direction[1], pd[i].direction[0]);
|
||||
}
|
||||
sort(angles.begin(), angles.end());
|
||||
angles.push_back(angles[0] + 2 * M_PI);
|
||||
angles.push_back(angles[0] + TAU);
|
||||
bool ok = false;
|
||||
for(int i=1; i<isize(angles); i++)
|
||||
if(angles[i] >= angles[i-1] + M_PI) ok = true;
|
||||
if(!ok) {
|
||||
for(auto &c: pd) if(c.distance > M_PI/2) return;
|
||||
for(auto &c: pd) if(c.distance > 90._deg) return;
|
||||
no_gens = true;
|
||||
}
|
||||
}
|
||||
|
@ -1347,7 +1405,7 @@ void draw_s2xe0(dqi_poly *p) {
|
|||
for(int gen=-g; gen<=g; gen++) {
|
||||
for(int i=0; i<p->cnt; i++) {
|
||||
auto& cur = pd[i];
|
||||
ld d = cur.distance + 2 * M_PI * gen;
|
||||
ld d = cur.distance + TAU * gen;
|
||||
hyperpoint h;
|
||||
h[0] = cur.direction[0] * d;
|
||||
h[1] = cur.direction[1] * d;
|
||||
|
@ -1414,8 +1472,6 @@ void draw_stretch(dqi_poly *p) {
|
|||
auto &lb = results[i+1];
|
||||
auto &lc = results[i+2];
|
||||
|
||||
int ia = 0, ib = 0, ic = 0;
|
||||
|
||||
for(auto& ha: la) for(auto& hb: lb) if(test(ha, hb))
|
||||
for(auto& hc: lc) if(test(ha, hc) && test(hb, hc)) {
|
||||
|
||||
|
@ -1425,7 +1481,6 @@ void draw_stretch(dqi_poly *p) {
|
|||
if(p->tinf)
|
||||
for(int j=0; j<3; j++)
|
||||
stinf.tvertices.push_back(p->tinf->tvertices[p->offset_texture+i+j]);
|
||||
ia++; ib++; ic++;
|
||||
}
|
||||
}
|
||||
npoly.cnt = isize(glcoords);
|
||||
|
@ -1511,21 +1566,21 @@ EX namespace ods {
|
|||
dqi_poly npoly = *p;
|
||||
npoly.offset = 0;
|
||||
npoly.tab = &glcoords;
|
||||
npoly.V = Id;
|
||||
npoly.V = shiftless(Id);
|
||||
npoly.tinf = p->tinf ? &stinf : NULL;
|
||||
if(npoly.tinf) {
|
||||
npoly.offset_texture = 0;
|
||||
stinf.texture_id = p->tinf->texture_id;
|
||||
stinf.tvertices.clear();
|
||||
}
|
||||
npoly.V = Id;
|
||||
npoly.V = shiftless(Id);
|
||||
glcoords.clear();
|
||||
|
||||
array<hyperpoint, 6> h;
|
||||
|
||||
if(0) for(int i=0; i<p->cnt; i+=3) {
|
||||
for(int j=0; j<3; j++)
|
||||
h[j] = p->V * glhr::gltopoint((*p->tab)[p->offset+i+j]);
|
||||
h[j] = unshift(p->V) * glhr::gltopoint((*p->tab)[p->offset+i+j]);
|
||||
|
||||
for(int j=0; j<3; j++) {
|
||||
glcoords.push_back(glhr::makevertex(h[j][0], h[j][1], h[j][2]));
|
||||
|
@ -1536,23 +1591,23 @@ EX namespace ods {
|
|||
if(1) for(int i=0; i<p->cnt; i+=3) {
|
||||
|
||||
for(int j=0; j<3; j++) {
|
||||
hyperpoint o = p->V * glhr::gltopoint((*p->tab)[p->offset+i+j]);
|
||||
if(nonisotropic || prod) {
|
||||
o = lp_apply(inverse_exp(o, iTable, false));
|
||||
o[3] = 1;
|
||||
shiftpoint o = p->V * glhr::gltopoint((*p->tab)[p->offset+i+j]);
|
||||
if(nonisotropic || gproduct) {
|
||||
auto o1 = lp_apply(inverse_exp(o, pNORMAL));
|
||||
o1[3] = 1;
|
||||
dynamicval<eGeometry> g(geometry, gEuclid);
|
||||
if(!project(o, h[j], h[j+3], global_projection == -1))
|
||||
if(!project(o1, h[j], h[j+3], global_projection == -1))
|
||||
goto next_i;
|
||||
}
|
||||
else if(!project(o, h[j], h[j+3], global_projection == -1))
|
||||
else if(!project(unshift(o), h[j], h[j+3], global_projection == -1))
|
||||
goto next_i;
|
||||
}
|
||||
|
||||
for(int j=0; j<6; j++) {
|
||||
// let Delta be from 0 to 2PI
|
||||
if(h[j][2]<0) h[j][2] += 2 * M_PI;
|
||||
if(h[j][2]<0) h[j][2] += TAU;
|
||||
// Theta is from -PI/2 to PI/2. Let it be from 0 to PI
|
||||
h[j][1] += global_projection * M_PI/2;
|
||||
h[j][1] += global_projection * 90._deg;
|
||||
h[j][3] = 1;
|
||||
}
|
||||
|
||||
|
@ -1569,8 +1624,8 @@ EX namespace ods {
|
|||
cyclefix(h[4][0], h[3][0]);
|
||||
cyclefix(h[5][0], h[3][0]);
|
||||
|
||||
if(abs(h[1][1] - h[0][1]) > M_PI/2) goto next_i;
|
||||
if(abs(h[2][1] - h[0][1]) > M_PI/2) goto next_i;
|
||||
if(abs(h[1][1] - h[0][1]) > 90._deg) goto next_i;
|
||||
if(abs(h[2][1] - h[0][1]) > 90._deg) goto next_i;
|
||||
|
||||
if(h[0][0] < -M_PI || h[0][0] > M_PI) println(hlog, h[0][0]);
|
||||
|
||||
|
@ -1579,7 +1634,7 @@ EX namespace ods {
|
|||
if(h[1][0] < -M_PI || h[2][0] < -M_PI) lst++;
|
||||
if(h[1][0] > +M_PI || h[2][0] > +M_PI) fst--;
|
||||
for(int x=fst; x<=lst; x++) for(int j=0; j<3; j++) {
|
||||
glcoords.push_back(glhr::makevertex(h[j][0] + 2 * M_PI * x, h[j][1], h[j][2]));
|
||||
glcoords.push_back(glhr::makevertex(h[j][0] + TAU * x, h[j][1], h[j][2]));
|
||||
if(npoly.tinf) stinf.tvertices.push_back(p->tinf->tvertices[p->offset_texture+i+j]);
|
||||
}
|
||||
}
|
||||
|
@ -1600,21 +1655,46 @@ EX namespace ods {
|
|||
bool broken_projection(dqi_poly& p0) {
|
||||
int broken_coord = models::get_broken_coord(pmodel);
|
||||
static bool in_broken = false;
|
||||
bool both_broken = pmodel == mdConformalSquare;
|
||||
|
||||
transmatrix T = p0.V.T, IT = Id, FT = Id;
|
||||
if(both_broken) FT = cspin(0, 1, 45._deg), T = FT * T, IT = cspin(0, 1, -45._deg);
|
||||
|
||||
ld zlow = 0;
|
||||
if(both_broken) {
|
||||
ld t = pconf.model_transition;
|
||||
zlow = (1-t*t) / (1+t*t);
|
||||
}
|
||||
// x * mt / (1-z) <= 1
|
||||
// sqrt(1-z*z) * mt / (1-z) <= 1
|
||||
// sqrt(1-z*z) <= (1-z) / mt
|
||||
|
||||
if(broken_coord && !in_broken) {
|
||||
|
||||
int zcoord = broken_coord;
|
||||
int ycoord = 3 - zcoord;
|
||||
int xcoord = 0;
|
||||
|
||||
zcoord = 2;
|
||||
|
||||
vector<hyperpoint> all;
|
||||
for(int i=0; i<p0.cnt; i++)
|
||||
all.push_back(p0.V.T * glhr::gltopoint((*p0.tab)[p0.offset+i]));
|
||||
all.push_back(T * glhr::gltopoint((*p0.tab)[p0.offset+i]));
|
||||
int fail = 0;
|
||||
int last_fail;
|
||||
|
||||
for(auto& h: all) models::apply_orientation(h[0], h[1]);
|
||||
|
||||
for(auto& h: all) models::scr_to_ori(h);
|
||||
|
||||
auto break_in_xz = [&] (hyperpoint a, hyperpoint b, int xcoord, int zcoord) {
|
||||
return a[xcoord] * b[xcoord] <= 0 && (a[xcoord] * (b[zcoord]+zlow) - b[xcoord] * (a[zcoord]+zlow)) * (a[xcoord] - b[xcoord]) < 0;
|
||||
};
|
||||
|
||||
auto break_in = [&] (hyperpoint a, hyperpoint b) {
|
||||
return a[0] * b[0] <= 0 && (a[0] * b[zcoord] - b[0] * a[zcoord]) * (a[0] - b[0]) < 0;
|
||||
if(both_broken) {
|
||||
for(int xc=0; xc<2; xc++) {if(break_in_xz(a, b, xc, zcoord)) { xcoord = xc; ycoord = 1-xc; return true; } }
|
||||
return false;
|
||||
}
|
||||
return break_in_xz(a, b, xcoord, zcoord);
|
||||
};
|
||||
|
||||
for(int i=0; i<p0.cnt-1; i++)
|
||||
|
@ -1624,16 +1704,21 @@ bool broken_projection(dqi_poly& p0) {
|
|||
dqi_poly p = p0;
|
||||
p.tab = &v;
|
||||
p.offset = 0;
|
||||
p.V.T = Id;
|
||||
p.V.T = IT;
|
||||
|
||||
/* we don't rotate h's back, just change p.V */
|
||||
for(int i=0; i<3; i++)
|
||||
models::apply_orientation(p.V.T[i][0], p.V.T[i][1]);
|
||||
models::scr_to_ori(p.V.T[i]);
|
||||
|
||||
if(fail) {
|
||||
if(p0.tinf) return true;
|
||||
dynamicval<bool> ib(in_broken, true);
|
||||
ld part = ilerp(all[last_fail][0], all[last_fail+1][0], 0);
|
||||
|
||||
ld part = ilerp(all[last_fail][xcoord], all[last_fail+1][xcoord], 0);
|
||||
if(both_broken && all[last_fail][ycoord] * all[last_fail+1][ycoord] < 0) {
|
||||
ld part2 = ilerp(all[last_fail][ycoord], all[last_fail+1][ycoord], 0);
|
||||
if(part2 > part) part = part2, swap(xcoord, ycoord);
|
||||
}
|
||||
hyperpoint initial = normalize(lerp(all[last_fail], all[last_fail+1], 1 - (1-part) * .99));
|
||||
bool have_initial = true;
|
||||
v.push_back(glhr::pointtogl(initial));
|
||||
|
@ -1641,19 +1726,48 @@ bool broken_projection(dqi_poly& p0) {
|
|||
int at = last_fail;
|
||||
do {
|
||||
v.push_back(glhr::pointtogl(all[at]));
|
||||
if(at == p0.cnt-1 && all[at] != all[0]) {
|
||||
if(at == p0.cnt-1 && sqhypot_d(2, all[at] - all[0]) > 1e-6) {
|
||||
p.cnt = isize(v); p.draw(); v.clear(); at = 0;
|
||||
have_initial = false;
|
||||
}
|
||||
int next = at+1;
|
||||
if(next == p0.cnt) next = 0;
|
||||
if(break_in(all[at], all[next])) {
|
||||
ld part = ilerp(all[at][0], all[next][0], 0);
|
||||
ld part = ilerp(all[at][xcoord], all[next][xcoord], 0);
|
||||
if(both_broken && all[at][ycoord] * all[next][ycoord] < 0) {
|
||||
ld part2 = ilerp(all[at][ycoord], all[next][ycoord], 0);
|
||||
if(part2 < part) part = part2, swap(xcoord, ycoord);
|
||||
}
|
||||
|
||||
hyperpoint final = normalize(lerp(all[at], all[next], part * .99));
|
||||
v.push_back(glhr::pointtogl(final));
|
||||
if(have_initial) {
|
||||
int max = 4 << vid.linequality;
|
||||
if(final[0] * initial[0] > 0) {
|
||||
if(both_broken) {
|
||||
auto square_close_corner = [&] (hyperpoint h) {
|
||||
hyperpoint end = -C0;
|
||||
end[0] = 0.01 * signum(h[0]);
|
||||
end[1] = 0.01 * signum(h[1]);
|
||||
/* if(abs(h1[0]) > abs(h1[1]))
|
||||
end[0] = 0.01 * signum(h1[0]), end[1] = 0.001 * signum(h1[1]);
|
||||
else
|
||||
end[1] = 0.01 * signum(h1[1]), end[0] = 0.001 * signum(h1[0]); */
|
||||
return normalize(end);
|
||||
};
|
||||
hyperpoint endf = square_close_corner(final);
|
||||
hyperpoint endi = square_close_corner(initial);
|
||||
if(endf != endi) {
|
||||
for(int i=1; i<=max; i++)
|
||||
v.push_back(glhr::pointtogl(lerp(final, endf, i * 1. / max)));
|
||||
for(int i=0; i<=max; i++)
|
||||
v.push_back(glhr::pointtogl(lerp(endi, initial, i * 1. / max)));
|
||||
}
|
||||
else {
|
||||
for(int i=1; i<=max; i++)
|
||||
v.push_back(glhr::pointtogl(lerp(final, initial, i * 1. / max)));
|
||||
}
|
||||
}
|
||||
else if(final[xcoord] * initial[xcoord] > 0) {
|
||||
for(int i=1; i<=max; i++)
|
||||
v.push_back(glhr::pointtogl(lerp(final, initial, i * 1. / max)));
|
||||
}
|
||||
|
@ -1777,8 +1891,8 @@ void dqi_poly::draw() {
|
|||
shiftpoint h2 = V * glhr::gltopoint((*tab)[offset+(i+1)%cnt]);
|
||||
|
||||
hyperpoint ah1 = h1.h, ah2 = h2.h;
|
||||
models::apply_orientation(ah1[0], ah1[1]);
|
||||
models::apply_orientation(ah2[0], ah2[1]);
|
||||
models::scr_to_ori(ah1);
|
||||
models::scr_to_ori(ah2);
|
||||
if(ah1[1] * ah2[1] > 0) continue;
|
||||
ld c1 = ah1[1], c2 = -ah2[1];
|
||||
if(c1 < 0) c1 = -c1, c2 = -c2;
|
||||
|
@ -1861,7 +1975,7 @@ void dqi_poly::draw() {
|
|||
if(isize(glcoords) <= 1) return;
|
||||
|
||||
cyl::loop_min = cyl::loop_max = 0;
|
||||
if(sphere && mdBandAny())
|
||||
if((sphere && mdBandAny()) || pmodel == mdPolar)
|
||||
cyl::adjust(tinf);
|
||||
|
||||
int poly_limit = max(vid.xres, vid.yres) * 2;
|
||||
|
@ -1932,8 +2046,8 @@ void dqi_poly::draw() {
|
|||
|
||||
if(l || lastl) {
|
||||
for(int i=0; i<isize(glcoords); i++) {
|
||||
glcoords[i][0] += models::ocos * cyl::periods[i] * (l - lastl);
|
||||
glcoords[i][1] += models::osin * cyl::periods[i] * (l - lastl);
|
||||
glcoords[i][0] += pconf.mori().get()[0][0] * cyl::periods[i] * (l - lastl);
|
||||
glcoords[i][1] += pconf.mori().get()[1][0] * cyl::periods[i] * (l - lastl);
|
||||
}
|
||||
lastl = l;
|
||||
}
|
||||
|
@ -2022,10 +2136,10 @@ void dqi_poly::draw() {
|
|||
else
|
||||
filledPolygonColorI(srend, polyx, polyy, polyi, color);
|
||||
|
||||
if(current_display->stereo_active()) filledPolygonColorI(auxrend, polyxr, polyy, polyi, color);
|
||||
if(current_display->separate_eyes()) filledPolygonColorI(auxrend, polyxr, polyy, polyi, color);
|
||||
|
||||
((vid.antialias & AA_NOGL) ?aapolylineColor:polylineColor)(srend, polyx, polyy, polyi, outline);
|
||||
if(current_display->stereo_active()) aapolylineColor(auxrend, polyxr, polyy, polyi, outline);
|
||||
if(current_display->separate_eyes()) aapolylineColor(auxrend, polyxr, polyy, polyi, outline);
|
||||
|
||||
if(vid.xres >= 2000 || fatborder) {
|
||||
int xmi = 3000, xma = -3000;
|
||||
|
@ -2162,7 +2276,7 @@ EX void quickqueue() {
|
|||
|
||||
/* todo */
|
||||
ld xintval(const shiftpoint& h) {
|
||||
if(sphereflipped()) return -h.h[2];
|
||||
if(sphere_flipped) return -h.h[2];
|
||||
if(hyperbolic) return -h.h[2];
|
||||
return -intval(h.h, C0);
|
||||
}
|
||||
|
@ -2176,7 +2290,7 @@ int qp[PMAX], qp0[PMAX];
|
|||
|
||||
color_t darken_color(color_t& color, bool outline) {
|
||||
int alpha = color & 255;
|
||||
if(sphere && pmodel == mdDisk && pconf.alpha <= 1)
|
||||
if(sphere && pmodel == mdDisk && pconf.alpha <= 0.99)
|
||||
return 0;
|
||||
else {
|
||||
if(outline && alpha < 255)
|
||||
|
@ -2257,7 +2371,7 @@ EX void draw_backside() {
|
|||
ptd->draw();
|
||||
}
|
||||
|
||||
spherespecial = sphereflipped() ? 1 : -1;
|
||||
spherespecial = sphere_flipped ? 1 : -1;
|
||||
reset_projection();
|
||||
|
||||
if(pmodel == mdRotatedHyperboles) {
|
||||
|
@ -2320,17 +2434,22 @@ EX void draw_main() {
|
|||
}
|
||||
|
||||
if(pmodel == mdHemisphere && sphere && hemi_side == 0 && !vrhr::rendering()) {
|
||||
hemi_side = models::sin_ball > 0 ? 1 : -1;
|
||||
hemi_side = (pconf.ball() * hyperpoint(0,1,0,1)) [2] < 0 ? 1 : -1;
|
||||
draw_main();
|
||||
|
||||
if(pconf.show_hyperboloid_flat) {
|
||||
dynamicval<eModel> dv (pmodel, mdHyperboloidFlat);
|
||||
dynamicval<int> ds (spherespecial, 1);
|
||||
for(auto& ptd: ptds)
|
||||
if(!among(ptd->prio, PPR::MOBILE_ARROW, PPR::OUTCIRCLE, PPR::CIRCLE))
|
||||
if(!among(ptd->prio, PPR::MOBILE_ARROW, PPR::OUTCIRCLE, PPR::CIRCLE))
|
||||
ptd->draw();
|
||||
}
|
||||
|
||||
for(auto& ptd: ptds) if(ptd->prio == PPR::OUTCIRCLE) {
|
||||
auto c = dynamic_cast<dqi_poly*> (&*ptd);
|
||||
if(c) { c->color = 0; c->outline = 0; }
|
||||
}
|
||||
|
||||
hemi_side *= -1;
|
||||
draw_main();
|
||||
hemi_side = 0;
|
||||
|
@ -2434,7 +2553,7 @@ EX void drawqueue() {
|
|||
#endif
|
||||
|
||||
#if MAXMDIM >= 4 && CAP_GL
|
||||
if(WDIM == 2 && GDIM == 3 && hyperbolic && !vrhr::rendering()) make_air();
|
||||
make_air();
|
||||
#endif
|
||||
|
||||
#if CAP_VR
|
||||
|
@ -2484,8 +2603,27 @@ EX void drawqueue() {
|
|||
});
|
||||
}
|
||||
|
||||
if(draw_plain_floors && (default_flooralpha < 255 || svg::in)) for(PPR p: {PPR::FLOOR}) {
|
||||
int pp = int(p);
|
||||
if(qp0[pp] == qp[pp]) continue;
|
||||
auto get_z = [&] (const unique_ptr<drawqueueitem>& p) -> ld {
|
||||
auto d = dynamic_cast<dqi_poly*> (&*p);
|
||||
if(!d) return 0;
|
||||
hyperpoint h = Hypc;
|
||||
|
||||
for(int i=0; i<d->cnt; i++) h += glhr::gltopoint( (*d->tab)[d->offset + i] );
|
||||
h /= d->cnt; normalize(h);
|
||||
h = unshift(d->V) * h;
|
||||
return h[2];
|
||||
};
|
||||
sort(&ptds[qp0[int(p)]], &ptds[qp[int(p)]],
|
||||
[&] (const unique_ptr<drawqueueitem>& p1, const unique_ptr<drawqueueitem>& p2) {
|
||||
return get_z(p1) > get_z(p2);
|
||||
});
|
||||
}
|
||||
|
||||
#if CAP_SDL
|
||||
if(current_display->stereo_active() && !vid.usingGL) {
|
||||
if(current_display->separate_eyes() && !vid.usingGL) {
|
||||
|
||||
if(aux && (aux->w != s->w || aux->h != s->h)) {
|
||||
SDL_FreeSurface(aux);
|
||||
|
@ -2513,7 +2651,7 @@ EX void drawqueue() {
|
|||
reset_projection();
|
||||
|
||||
#if CAP_GL
|
||||
if(model_needs_depth() && current_display->stereo_active()) {
|
||||
if(model_needs_depth() && current_display->separate_eyes()) {
|
||||
global_projection = -1;
|
||||
draw_main();
|
||||
#if CAP_GL
|
||||
|
@ -2624,9 +2762,18 @@ EX void curvepoint(const hyperpoint& H1) {
|
|||
curvedata.push_back(glhr::pointtogl(H1));
|
||||
}
|
||||
|
||||
EX dqi_poly& queuecurve(const shiftmatrix& V, color_t linecol, color_t fillcol, PPR prio) {
|
||||
EX void curvepoint_first() {
|
||||
curvedata.push_back(curvedata[curvestart]);
|
||||
}
|
||||
|
||||
EX dqi_poly& queuecurve_reuse(const shiftmatrix& V, color_t linecol, color_t fillcol, PPR prio) {
|
||||
auto &res = queuetable(V, curvedata, isize(curvedata)-curvestart, linecol, fillcol, prio);
|
||||
res.offset = curvestart;
|
||||
return res;
|
||||
}
|
||||
|
||||
EX dqi_poly& queuecurve(const shiftmatrix& V, color_t linecol, color_t fillcol, PPR prio) {
|
||||
auto &res = queuecurve_reuse(V, linecol, fillcol, prio);
|
||||
curvestart = isize(curvedata);
|
||||
return res;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
139
environment.cpp
139
environment.cpp
|
@ -54,20 +54,14 @@ EX vector<cell*> worms, ivies, ghosts, golems, hexsnakes;
|
|||
/** temporary changes during bfs */
|
||||
vector<pair<cell*, eMonster>> tempmonsters;
|
||||
|
||||
/** additional direction information for BFS algorithms.
|
||||
* It remembers from where we have got to this location
|
||||
* the opposite cell will be added to the queue first,
|
||||
* which helps the AI. Used by computePathdist and its callees.
|
||||
**/
|
||||
EX vector<int> path_reachedfrom;
|
||||
|
||||
/** The position of the first cell in dcal in distance 7. New wandering monsters can be generated in dcal[first7..]. */
|
||||
EX int first7;
|
||||
|
||||
/** the list of all nearby cells, according to cpdist */
|
||||
EX vector<cell*> dcal;
|
||||
|
||||
/** the list of all nearby cells, according to current pathdist */
|
||||
EX vector<cell*> pathq;
|
||||
EX vector<cellwalker> pathq;
|
||||
|
||||
/** the number of big statues -- they increase monster generation */
|
||||
EX int statuecount;
|
||||
|
@ -88,25 +82,61 @@ EX int gamerange() { return getDistLimit() + gamerange_bonus; }
|
|||
EX cell *pd_from;
|
||||
EX int pd_range;
|
||||
|
||||
EX void onpath(cell *c, int d) {
|
||||
if(!pathlock) { println(hlog, "onpath without pathlock"); }
|
||||
c->pathdist = d;
|
||||
pathq.push_back(c);
|
||||
#if HDR
|
||||
/** The pathdata is used to keep a list of visited cells. It is used as follows:
|
||||
* 1) create pathdata object: pathdata pd(identifier)
|
||||
* 2) use one of the following methods to mark cells as visited:
|
||||
* 2a) onpath_with_dir or onpath_random_dir, to mark a cell together with its distance and the direction we came from (used by computePathdist to make pathfinding not sensitive to direction indexing)
|
||||
* 2b) onpath, to mark a cell at its distance (used when ordering is irrelevant: compute_graphical_distance and in shmup)
|
||||
* 2c) onpatk_mark, to just mark a cell (used in groupmove2)
|
||||
* 3) All the visited cells are listed in pathq, and they have 'pathdist' set to their recorded distance (0 in case of onpath_mark).
|
||||
* 4) When the pathdata object is deleted, all the pathdist values are cleared back to PINFD.
|
||||
* The variable 'pathlock' ensures that we do not use two pathdata objects at once.
|
||||
**/
|
||||
|
||||
struct pathdata {
|
||||
void checklock();
|
||||
~pathdata();
|
||||
pathdata(eMonster m, bool include_allies IS(true));
|
||||
pathdata(int i);
|
||||
};
|
||||
#endif
|
||||
|
||||
/** using pathdata, record a cell (together with direction) as visited */
|
||||
EX void onpath_with_dir(cellwalker cw, int d) {
|
||||
if(!pathlock) {
|
||||
println(hlog, "onpath(", cw, ", ", d, ") without pathlock");
|
||||
}
|
||||
cw.at->pathdist = d;
|
||||
pathq.push_back(cw);
|
||||
}
|
||||
|
||||
void onpath_rf(cell *c, int d, int sp) {
|
||||
onpath(c, d);
|
||||
path_reachedfrom.push_back(sp);
|
||||
/** using pathdata, record a cell as visited, with random direction */
|
||||
EX void onpath_random_dir(cell *c, int d) {
|
||||
onpath_with_dir(cellwalker(c, hrand(c->type), hrand(2)), d);
|
||||
}
|
||||
|
||||
EX void onpath(cell *c, int d) {
|
||||
onpath_with_dir(cellwalker(c, 0, 0), d);
|
||||
}
|
||||
|
||||
EX void onpath_mark(cell *c) {
|
||||
onpath_with_dir(cellwalker(c, 0, 0), 0);
|
||||
}
|
||||
|
||||
EX void clear_pathdata() {
|
||||
for(auto c: pathq) c->pathdist = PINFD;
|
||||
for(auto c: pathq) c.at->pathdist = PINFD;
|
||||
pathq.clear();
|
||||
pathqm.clear();
|
||||
}
|
||||
|
||||
/** This ensures that we do not use two pathdata objects at once */
|
||||
EX int pathlock = 0;
|
||||
|
||||
/** compute_graphical_distance determines the distance of every cell
|
||||
* from the current FOV center. It uses the pathq structures but
|
||||
* does not lock them */
|
||||
|
||||
EX void compute_graphical_distance() {
|
||||
if(pathlock) { printf("path error: compute_graphical_distance\n"); }
|
||||
cell *c1 = centerover ? centerover : pd_from ? pd_from : cwt.at;
|
||||
|
@ -114,14 +144,13 @@ EX void compute_graphical_distance() {
|
|||
if(pd_from == c1 && pd_range == sr) return;
|
||||
clear_pathdata();
|
||||
|
||||
pathlock++;
|
||||
pd_from = c1;
|
||||
pd_range = sr;
|
||||
c1->pathdist = 0;
|
||||
pathq.push_back(pd_from);
|
||||
pathlock++;
|
||||
onpath(c1, 0);
|
||||
|
||||
for(int qb=0; qb<isize(pathq); qb++) {
|
||||
cell *c = pathq[qb];
|
||||
cell *c = pathq[qb].at;
|
||||
if(c->pathdist == pd_range) break;
|
||||
if(qb == 0) forCellCM(c1, c) ;
|
||||
forCellEx(c1, c)
|
||||
|
@ -153,7 +182,7 @@ struct princess_ai {
|
|||
void princess_ai::run() {
|
||||
int radius = toggle_radius(waOpenPlate);
|
||||
if(pathq.empty()) return;
|
||||
int d = pathq.back()->pathdist;
|
||||
int d = pathq.back().at->pathdist;
|
||||
if(d == PINFD - 1) return;
|
||||
d++;
|
||||
if(d < 5) d = 5; /* the Princess AI avoids plates when too close to the player */
|
||||
|
@ -168,17 +197,15 @@ void princess_ai::run() {
|
|||
info[0].visit(c1);
|
||||
}
|
||||
if(k == radius && c->wall == waOpenPlate && c->pathdist == PINFD)
|
||||
onpath_rf(c, d, hrand(c->type));
|
||||
onpath_random_dir(c, d);
|
||||
}
|
||||
}
|
||||
|
||||
EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
||||
|
||||
path_reachedfrom.clear();
|
||||
|
||||
for(cell *c: targets)
|
||||
if(include_allies || isPlayerOn(c))
|
||||
onpath_rf(c, isPlayerOn(c) ? 0 : 1, hrand(c->type));
|
||||
onpath_random_dir(c, isPlayerOn(c) ? 0 : 1);
|
||||
|
||||
int qtarg = isize(targets);
|
||||
|
||||
|
@ -191,8 +218,10 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
|||
princess_retry:
|
||||
|
||||
for(; qb < isize(pathq); qb++) {
|
||||
cell *c = pathq[qb];
|
||||
int fd = path_reachedfrom[qb] + c->type/2;
|
||||
cellwalker cw = pathq[qb];
|
||||
/* The opposite cell will be added to the queue first, which helps the AI. */
|
||||
cw += cw.at->type/2;
|
||||
cell*& c = cw.at;
|
||||
if(c->monst && !isBug(c) && !(isFriendly(c) && !c->stuntime)) {
|
||||
pathqm.push_back(c);
|
||||
continue; // no paths going through monsters
|
||||
|
@ -206,15 +235,19 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
|||
int d = c->pathdist;
|
||||
if(d == PINFD - 1) continue;
|
||||
for(int j=0; j<c->type; j++) {
|
||||
int i = (fd+j) % c->type;
|
||||
cellwalker cw1 = cw + j;
|
||||
// printf("i=%d cd=%d\n", i, c->move(i)->cpdist);
|
||||
cell *c2 = c->move(i);
|
||||
cell *c2 = cw1.peek();
|
||||
|
||||
flagtype f = P_MONSTER | P_REVDIR;
|
||||
if(param == moTameBomberbird) f |= P_FLYING;
|
||||
flagtype f = P_MONSTER;
|
||||
if(param == moTameBomberbird) f |= P_FLYING | P_ISFRIEND;
|
||||
if(isPrincess(param)) f |= P_ISFRIEND | P_USEBOAT | P_CHAIN;
|
||||
if(param == moGolem) f |= P_ISFRIEND;
|
||||
bool pass = c2 && c2->pathdist == PINFD;
|
||||
if(pass && qb < qtarg && !nonAdjacent(c, c2) && !thruVine(c,c2)) pass = passable(c2, NULL, f);
|
||||
else pass = pass && passable(c, c2, f);
|
||||
|
||||
if(c2 && c2->pathdist == PINFD &&
|
||||
passable(c2, (qb<qtarg) && !nonAdjacent(c,c2) && !thruVine(c,c2) ?NULL:c, f)) {
|
||||
if(pass) {
|
||||
|
||||
if(qb >= qtarg) {
|
||||
if(param == moTortoise && nogoSlow(c, c2)) continue;
|
||||
|
@ -224,7 +257,7 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
|||
continue;
|
||||
}
|
||||
|
||||
onpath_rf(c2, d+1, c->c.spin(i));
|
||||
onpath_with_dir(cw1 + wstep, d+1);
|
||||
}
|
||||
|
||||
else if(c2 && c2->wall == waClosedGate && princess)
|
||||
|
@ -238,15 +271,6 @@ EX void computePathdist(eMonster param, bool include_allies IS(true)) {
|
|||
}
|
||||
}
|
||||
|
||||
#if HDR
|
||||
struct pathdata {
|
||||
void checklock();
|
||||
~pathdata();
|
||||
pathdata(eMonster m, bool include_allies IS(true));
|
||||
pathdata(int i);
|
||||
};
|
||||
#endif
|
||||
|
||||
pathdata::~pathdata() {
|
||||
pathlock--;
|
||||
clear_pathdata();
|
||||
|
@ -280,8 +304,6 @@ EX vector<int> bfs_reachedfrom;
|
|||
/** calculate cpdist, 'have' flags, and do general fixings */
|
||||
EX void bfs() {
|
||||
|
||||
calcTidalPhase();
|
||||
|
||||
yendor::onpath();
|
||||
|
||||
int dcs = isize(dcal);
|
||||
|
@ -306,12 +328,9 @@ EX void bfs() {
|
|||
|
||||
dcal.clear(); bfs_reachedfrom.clear();
|
||||
|
||||
recalcTide = false;
|
||||
|
||||
for(cell *c: player_positions()) {
|
||||
if(c->cpdist == 0) continue;
|
||||
c->cpdist = 0;
|
||||
checkTide(c);
|
||||
dcal.push_back(c);
|
||||
bfs_reachedfrom.push_back(hrand(c->type));
|
||||
if(!invismove) targets.push_back(c);
|
||||
|
@ -349,7 +368,7 @@ EX void bfs() {
|
|||
c2->wall = waSea;
|
||||
|
||||
if(c2 && signed(c2->cpdist) > d+1) {
|
||||
if(WDIM == 3 && !gmatrix.count(c2)) {
|
||||
if(WDIM == 3 && (d > 2 && !gmatrix.count(c2))) {
|
||||
if(!first7) first7 = qb;
|
||||
continue;
|
||||
}
|
||||
|
@ -357,7 +376,7 @@ EX void bfs() {
|
|||
|
||||
// remove treasures
|
||||
if(!peace::on && c2->item && c2->cpdist == distlimit && itemclass(c2->item) == IC_TREASURE &&
|
||||
c2->item != itBabyTortoise && WDIM != 3 &&
|
||||
!among(c2->item, itBrownian, itBabyTortoise) && WDIM != 3 &&
|
||||
(items[c2->item] >= (ls::any_chaos()?10:20) + currentLocalTreasure || getGhostcount() >= 2)) {
|
||||
c2->item = itNone;
|
||||
if(c2->land == laMinefield) { c2->landparam &= ~3; }
|
||||
|
@ -412,8 +431,6 @@ EX void bfs() {
|
|||
dcal.push_back(c2);
|
||||
bfs_reachedfrom.push_back(c->c.spin(i));
|
||||
|
||||
checkTide(c2);
|
||||
|
||||
if(c2->wall == waBigStatue && c2->land != laTemple)
|
||||
statuecount++;
|
||||
|
||||
|
@ -524,11 +541,6 @@ EX void bfs() {
|
|||
if(c2->wall == waThumperOn) {
|
||||
targets.push_back(c2);
|
||||
}
|
||||
|
||||
while(recalcTide) {
|
||||
recalcTide = false;
|
||||
for(int i=0; i<isize(dcal); i++) checkTide(dcal[i]);
|
||||
}
|
||||
|
||||
for(auto& t: tempmonsters) t.first->monst = t.second;
|
||||
|
||||
|
@ -807,7 +819,16 @@ EX void findWormIvy(cell *c) {
|
|||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EX void advance_tides() {
|
||||
calcTidalPhase();
|
||||
recalcTide = true;
|
||||
while(recalcTide) {
|
||||
recalcTide = false;
|
||||
for(int i=0; i<isize(dcal); i++) checkTide(dcal[i]);
|
||||
}
|
||||
}
|
||||
|
||||
EX void monstersTurn() {
|
||||
reset_spill();
|
||||
checkSwitch();
|
||||
|
@ -845,6 +866,8 @@ EX void monstersTurn() {
|
|||
if(!phase1) livecaves();
|
||||
if(!phase1) ca::simulate();
|
||||
if(!phase1) heat::processfires();
|
||||
// this depends on turncount, so we do it always
|
||||
advance_tides();
|
||||
|
||||
for(cell *c: crush_now) {
|
||||
changes.ccell(c);
|
||||
|
|
43
euclid.cpp
43
euclid.cpp
|
@ -12,8 +12,8 @@ EX namespace euc {
|
|||
|
||||
#if HDR
|
||||
struct coord : array<int, 3> {
|
||||
coord() {}
|
||||
coord(int x, int y, int z) { self[0] = x; self[1] = y; self[2] = z; }
|
||||
explicit coord() = default;
|
||||
constexpr explicit coord(int x, int y, int z) : array<int,3> {{x,y,z}} {}
|
||||
coord& operator += (coord b) { for(int i: {0,1,2}) self[i] += b[i]; return self; }
|
||||
coord& operator -= (coord b) { for(int i: {0,1,2}) self[i] -= b[i]; return self; }
|
||||
coord operator + (coord b) const { coord a = self; return a += b; }
|
||||
|
@ -32,7 +32,7 @@ EX namespace euc {
|
|||
EX const coord eutester = coord(3,7,0);
|
||||
EX intmatrix euzeroall = make_array<coord>(euzero, euzero, euzero);
|
||||
|
||||
static const intmatrix main_axes = make_array<coord>(coord(1,0,0), coord(0,1,0), coord(0,0,1));
|
||||
static constexpr intmatrix main_axes = make_array<coord>(coord(1,0,0), coord(0,1,0), coord(0,0,1));
|
||||
|
||||
EX vector<coord> get_shifttable() {
|
||||
static const coord D0 = main_axes[0];
|
||||
|
@ -46,10 +46,12 @@ EX namespace euc {
|
|||
|
||||
switch(g) {
|
||||
case gCubeTiling:
|
||||
case gMengerSponge:
|
||||
shifttable = { +D0, +D1, +D2 };
|
||||
break;
|
||||
|
||||
case gRhombic3:
|
||||
case gSierpinskiTet:
|
||||
shifttable = { D0+D1, D0+D2, D1+D2, D1-D2, D0-D2, D0-D1 };
|
||||
break;
|
||||
|
||||
|
@ -58,16 +60,18 @@ EX namespace euc {
|
|||
break;
|
||||
|
||||
case gEuclid:
|
||||
case gSierpinski3:
|
||||
case gSixFlake:
|
||||
shifttable = { D0, D1, D1-D0, -D0, -D1, D0-D1 };
|
||||
break;
|
||||
|
||||
case gEuclidSquare:
|
||||
case gSierpinski4:
|
||||
shifttable = { D0, D1, -D0, -D1 };
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("euc::get_shifttable() called in geometry that is not euclid3");
|
||||
exit(1);
|
||||
throw hr_exception("euc::get_shifttable() called in geometry that is not euclid3");
|
||||
}
|
||||
|
||||
// reverse everything
|
||||
|
@ -137,10 +141,10 @@ EX namespace euc {
|
|||
map<gp::loc, struct cdata> eucdata;
|
||||
|
||||
void compute_tmatrix() {
|
||||
cgi.require_basics();
|
||||
shifttable = get_shifttable();
|
||||
tmatrix.resize(S7);
|
||||
for(int i=0; i<S7; i++)
|
||||
tmatrix[i] = eumove(shifttable[i]);
|
||||
for(int i=0; i<S7; i++) tmatrix[i] = eumove(shifttable[i]);
|
||||
}
|
||||
|
||||
void on_dim_change() override {
|
||||
|
@ -236,6 +240,7 @@ EX namespace euc {
|
|||
}
|
||||
|
||||
transmatrix adj(cell *c, int i) override {
|
||||
if(dont_inverse()) return adj(c->master, i);
|
||||
if(WDIM == 3) return adj(c->master, i);
|
||||
else return hrmap_standard::adj(c, i);
|
||||
}
|
||||
|
@ -255,8 +260,11 @@ EX namespace euc {
|
|||
bool draw = drawcell_subs(c, V * spin(master_to_c7_angle()));
|
||||
if(in_wallopt() && isWall3(c) && isize(dq::drawqueue) > 1000 && !hybrid::pmap) continue;
|
||||
|
||||
if(draw) for(int i=0; i<S7; i++)
|
||||
dq::enqueue_by_matrix(h->move(i), optimized_shift(V * adj(h, i)));
|
||||
if(draw) for(int i=0; i<S7; i++) {
|
||||
auto V1 = V * adj(h, i);
|
||||
if(geom3::apply_break_cylinder && cgi.emb->break_cylinder(V, V1)) continue;
|
||||
dq::enqueue_by_matrix(h->move(i), optimized_shift(V1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -954,7 +962,7 @@ EX namespace euc {
|
|||
dialog::addItem("special manifolds", 'S');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(quotient_size, 1, 12, 1, 2, "special manifold size", "");
|
||||
dialog::extra_options = [] {
|
||||
dialog::get_di().extra_options = [] {
|
||||
auto q = quotient_size;
|
||||
torus_config_option(XLAT("third-turn space"), 'A', make_third_turn(q,0,q));
|
||||
torus_config_option(XLAT("quarter-turn space"), 'B', make_quarter_turn(q,0,q));
|
||||
|
@ -1037,7 +1045,7 @@ EX namespace euc {
|
|||
"not implemented.)"
|
||||
)
|
||||
);
|
||||
dialog::extra_options = show_fundamental;
|
||||
dialog::get_di().extra_options = show_fundamental;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1200,13 +1208,14 @@ EX transmatrix eumove(coord co) {
|
|||
}
|
||||
transmatrix Mat = Id;
|
||||
if(a4) {
|
||||
Mat[0][LDIM] += co[0] * cgi.tessf;
|
||||
Mat[1][LDIM] += co[1] * cgi.tessf;
|
||||
Mat[0][2] += co[0] * cgi.tessf;
|
||||
Mat[1][2] += co[1] * cgi.tessf;
|
||||
}
|
||||
else {
|
||||
Mat[0][LDIM] += (co[0] + co[1] * .5) * cgi.tessf;
|
||||
Mat[1][LDIM] += co[1] * q3 /2 * cgi.tessf;
|
||||
Mat[0][2] += (co[0] + co[1] * .5) * cgi.tessf;
|
||||
Mat[1][2] += co[1] * q3 /2 * cgi.tessf;
|
||||
}
|
||||
if(embedded_plane) Mat = cgi.emb->base_to_actual(Mat);
|
||||
return Mat;
|
||||
}
|
||||
|
||||
|
@ -1356,7 +1365,9 @@ EX void generate() {
|
|||
*/
|
||||
EX bool in() {
|
||||
if(fake::in()) return FPIU(in());
|
||||
return euclid && standard_tiling();
|
||||
if(geometry == gCubeTiling && (reg3::cubes_reg3 || !PURE)) return false;
|
||||
if(cgflags & qEXPERIMENTAL) return false;
|
||||
return meuclid && standard_tiling();
|
||||
}
|
||||
|
||||
EX bool in(int dim) { return in() && WDIM == dim; }
|
||||
|
|
135
expansion.cpp
135
expansion.cpp
|
@ -113,22 +113,23 @@ void expansion_analyzer::preliminary_grouping() {
|
|||
for(int v: rulegen::treestates[i].rules)
|
||||
if(v >= 0) children[i].push_back(v);
|
||||
}
|
||||
else if(reg3::in_rule()) {
|
||||
#if MAXMDIM >= 4
|
||||
else if(reg3::exact_rules()) {
|
||||
rootid = reg3::rule_get_root(0);
|
||||
auto& chi = reg3::rule_get_children();
|
||||
N = isize(chi) / S7;
|
||||
auto& chpos = reg3::rule_get_childpos();
|
||||
N = isize(chpos) - 1;
|
||||
children.resize(N);
|
||||
int k = 0;
|
||||
for(int i=0; i<N; i++) for(int j=0; j<S7; j++) {
|
||||
for(int i=0; i<N; i++) for(int j=0; j<chpos[i+1]-chpos[i]; j++) {
|
||||
int ck = chi[k];
|
||||
if(ck < -1) ck += (1<<16);
|
||||
if(ck >= 0)
|
||||
children[i].push_back(ck);
|
||||
k++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
sample_id(currentmap->gamestart());
|
||||
// queue for, do not change to range-based for
|
||||
|
@ -144,7 +145,9 @@ void expansion_analyzer::preliminary_grouping() {
|
|||
}
|
||||
|
||||
void expansion_analyzer::reduce_grouping() {
|
||||
if(reg3::in_rule()) return;
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::exact_rules()) return;
|
||||
#endif
|
||||
if(currentmap->strict_tree_rules()) return;
|
||||
int old_N = N;
|
||||
vector<int> grouping;
|
||||
|
@ -238,7 +241,11 @@ bool expansion_analyzer::verify(int id) {
|
|||
|
||||
int expansion_analyzer::valid(int v, int step) {
|
||||
if(step < 0) return 0;
|
||||
int more = reg3::in_rule() ? 1 : 5;
|
||||
#if MAXMDIM >= 4
|
||||
int more = 5;
|
||||
#else
|
||||
int more = reg3::exact_rules() ? 1 : 5;
|
||||
#endif
|
||||
#if CAP_GMP == 0
|
||||
if(get_descendants(step+v+v+more).approx_int() >= bignum::BASE) return 0;
|
||||
typedef ld val;
|
||||
|
@ -391,16 +398,19 @@ int type_in_quick(expansion_analyzer& ea, cell *c, const cellfunction& f) {
|
|||
}
|
||||
|
||||
EX bool sizes_known() {
|
||||
if(reg3::in_rule()) return true;
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::exact_rules()) return true;
|
||||
#endif
|
||||
if(closed_manifold) return false;
|
||||
// Castle Anthrax is infinite
|
||||
if(bt::in()) return false;
|
||||
// not implemented
|
||||
if(arcm::in()) return false;
|
||||
if(kite::in()) return false;
|
||||
if(aperiodic) return false;
|
||||
if(currentmap->strict_tree_rules()) return true;
|
||||
if(arb::in()) return false;
|
||||
return true;
|
||||
if(INVERSE) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
EX bool trees_known() {
|
||||
|
@ -421,10 +431,12 @@ string expansion_analyzer::approximate_descendants(int d, int max_length) {
|
|||
return XLAT("about ") + fts(pow(10, log_10 - more_digits)) + "E" + its(more_digits);
|
||||
}
|
||||
|
||||
#if HDR
|
||||
enum eDistanceFrom { dfPlayer, dfStart, dfWorld };
|
||||
#endif
|
||||
EX string dfnames[3] = { "player", "start", "land" };
|
||||
|
||||
eDistanceFrom distance_from = dfPlayer;
|
||||
EX eDistanceFrom distance_from = dfPlayer;
|
||||
|
||||
#if HDR
|
||||
enum eNumberCoding { ncNone, ncDistance, ncType, ncDebug, ncError };
|
||||
|
@ -432,19 +444,31 @@ enum eNumberCoding { ncNone, ncDistance, ncType, ncDebug, ncError };
|
|||
EX string ncnames[5] = { "NO", "distance", "type", "debug", "error" };
|
||||
EX eNumberCoding number_coding = ncDistance;
|
||||
|
||||
bool mod_allowed() {
|
||||
return cheater || autocheat || arcm::in() || tour::on;
|
||||
EX bool mod_allowed() {
|
||||
return cheater || autocheat || arcm::in() || arb::in() || tour::on;
|
||||
}
|
||||
|
||||
EX bool distances_legal(cell *c) {
|
||||
if(mod_allowed()) return true;
|
||||
switch(distance_from) {
|
||||
case dfPlayer:
|
||||
return true;
|
||||
case dfStart:
|
||||
return bt::in();
|
||||
case dfWorld:
|
||||
return c && among(c->land, laOcean, laIvoryTower, laEndorian, laDungeon, laTemple, laWhirlpool, laCanvas);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EX int curr_dist(cell *c) {
|
||||
if(!distances_legal(c)) return 0;
|
||||
switch(distance_from) {
|
||||
case dfPlayer:
|
||||
return c->cpdist < INFD ? c->cpdist : celldistance(cwt.at, c);
|
||||
case dfStart:
|
||||
return celldist(c);
|
||||
case dfWorld:
|
||||
if(!mod_allowed() && !among(c->land, laOcean, laIvoryTower, laEndorian, laDungeon, laTemple, laWhirlpool, laCanvas))
|
||||
return 0;
|
||||
if((isCyclic(c->land) || among(c->land, laCanvas, laCaribbean, laStorms, laRlyeh))) {
|
||||
if(eubinary || c->master->alt) return celldistAlt(c);
|
||||
return UNKNOWN;
|
||||
|
@ -531,6 +555,15 @@ EX namespace ts {
|
|||
return c->cmodmove(pid + (valence() == 3 ? 2 : 1) + id);
|
||||
}
|
||||
|
||||
EX cell *get_child(cell *c, const cellfunction& cf, int v) {
|
||||
for(int i=0; i<c->type; i++) if(cf(c->cmodmove(i+v)) <= cf(c) && cf(c->cmodmove(i)) > cf(c))
|
||||
return c->cmodmove(i);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EX cell *right_child(cell *c, const cellfunction& cf) { return get_child(c, cf, -1); }
|
||||
EX cell *left_child(cell *c, const cellfunction& cf) { return get_child(c, cf, 1); }
|
||||
|
||||
#if HDR
|
||||
inline cell *left_parent(cell *c, const cellfunction& cf) { return verified_add(c, 1, 0, cf); }
|
||||
inline cell *right_parent(cell *c, const cellfunction& cf) { return verified_add(c, -1, 0, cf); }
|
||||
|
@ -543,7 +576,7 @@ EX bool use_color_codes = true;
|
|||
EX bool use_analyzer = true;
|
||||
EX bool show_distance_lists = true;
|
||||
|
||||
int first_distance = 0, scrolltime = 0;
|
||||
int last_distance = 16;
|
||||
bool scrolling_distances = false;
|
||||
|
||||
EX map<int, color_t> expcolors;
|
||||
|
@ -580,7 +613,7 @@ void celldrawer::do_viewdist() {
|
|||
}
|
||||
case ncType: {
|
||||
int t = -1;
|
||||
if(reg3::in_rule()) switch(distance_from) {
|
||||
if(reg3::exact_rules()) switch(distance_from) {
|
||||
case dfPlayer:
|
||||
t = -1;
|
||||
break;
|
||||
|
@ -621,11 +654,8 @@ void celldrawer::do_viewdist() {
|
|||
|
||||
if(!dist_label_colored) dc = dist_label_color;
|
||||
|
||||
// string label = its(fieldpattern::getriverdistleft(c)) + its(fieldpattern::getriverdistright(c));
|
||||
/* queuepolyat(V, shFloor[ct6], darkena(gradient(0, distcolors[cd&7], 0, .25, 1), fd, 0xC0),
|
||||
PPR::TEXT); */
|
||||
if(label != "")
|
||||
queuestr(V, (isize(label) > 1 ? .6 : 1), label, 0xFF000000 + dc, 1);
|
||||
queuestr(V, (isize(label) > 1 ? .6 : 1) * mapfontscale / 100, label, 0xFF000000 + dc, 1);
|
||||
}
|
||||
|
||||
EX void viewdist_configure_dialog() {
|
||||
|
@ -641,25 +671,11 @@ EX void viewdist_configure_dialog() {
|
|||
|
||||
dialog::addBoolItem_action(XLAT("color codes"), use_color_codes, 'u');
|
||||
|
||||
dialog::addSelItem(XLAT("display distances from"), its(first_distance), 'd');
|
||||
dialog::add_action([] () {
|
||||
scrolling_distances = false;
|
||||
dialog::editNumber(first_distance, 0, 3000, 1, 0, XLAT("display distances from"), "");
|
||||
dialog::bound_low(0);
|
||||
});
|
||||
|
||||
dialog::addBoolItem(XLAT("strict tree maps"), currentmap->strict_tree_rules(), 's');
|
||||
dialog::add_action_push(rulegen::show);
|
||||
|
||||
int id = 0;
|
||||
using namespace linepatterns;
|
||||
for(auto& lp: {&patTriTree, &patTriRings, &patTriOther}) {
|
||||
dialog::addColorItem(XLAT(lp->lpname), lp->color, '1'+(id++));
|
||||
dialog::add_action([&lp] () {
|
||||
dialog::openColorDialog(lp->color, NULL);
|
||||
dialog::dialogflags |= sm::MAYDARK | sm::SIDE | sm::EXPANSION;
|
||||
});
|
||||
}
|
||||
dialog::addItem(XLAT("line patterns"), 'L');
|
||||
dialog::add_action_push(linepatterns::showMenu);
|
||||
|
||||
if(!mod_allowed()) {
|
||||
dialog::addItem(XLAT("enable the cheat mode for additional options"), 'C');
|
||||
|
@ -715,21 +731,20 @@ string produce_coef_formula(vector<int> coef) {
|
|||
return fmt;
|
||||
}
|
||||
|
||||
EX bool auto_extend = true;
|
||||
|
||||
void expansion_analyzer::view_distances_dialog() {
|
||||
static int lastticks;
|
||||
if(scrolling_distances && !closed_manifold) {
|
||||
scrolltime += SDL_GetTicks() - lastticks;
|
||||
first_distance += scrolltime / scrollspeed;
|
||||
scrolltime %= scrollspeed;
|
||||
dialog::list_skip += (SDL_GetTicks() - lastticks) * dialog::dfspace / scrollspeed;
|
||||
}
|
||||
lastticks = SDL_GetTicks();
|
||||
if(first_distance < 0) first_distance = 0;
|
||||
|
||||
dynamicval<color_t> dv(distcolors[0], forecolor);
|
||||
dialog::init("");
|
||||
cmode |= sm::DIALOG_STRICT_X | sm::EXPANSION;
|
||||
cmode |= sm::DIALOG_STRICT_X | sm::EXPANSION | sm::AUTO_VALUES | sm::NARROW_LINES;
|
||||
|
||||
int maxlen = closed_manifold ? 128 : 16 + first_distance;
|
||||
int maxlen = last_distance;
|
||||
vector<bignum> qty(maxlen);
|
||||
auto& expansion = get_expansion();
|
||||
|
||||
|
@ -737,7 +752,7 @@ void expansion_analyzer::view_distances_dialog() {
|
|||
|
||||
if(really_use_analyzer) {
|
||||
int t;
|
||||
if(reg3::in_rule() || currentmap->strict_tree_rules()) {
|
||||
if(reg3::exact_rules() || currentmap->strict_tree_rules()) {
|
||||
if(!N) preliminary_grouping();
|
||||
t = rootid;
|
||||
}
|
||||
|
@ -768,13 +783,14 @@ void expansion_analyzer::view_distances_dialog() {
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
dialog::addBreak(100 - 100 * scrolltime / scrollspeed);
|
||||
|
||||
for(int i=first_distance; i<maxlen; i++) if(!qty[i].digits.empty())
|
||||
dialog::addInfo(its(i) + ": " + qty[i].get_str(100), distcolors[i]);
|
||||
|
||||
dialog::addBreak(100 * scrolltime / scrollspeed);
|
||||
dialog::start_list(1600, 1600, 'a');
|
||||
for(int i=0; i<maxlen; i++) if(!qty[i].digits.empty()) {
|
||||
dialog::addSelItem(qty[i].get_str(100), " " + its(i), dialog::list_fake_key);
|
||||
auto& last = dialog::lastItem();
|
||||
last.color = last.colorv = distcolors[i];
|
||||
}
|
||||
dialog::end_list();
|
||||
|
||||
if(sizes_known() || bt::in()) {
|
||||
if(euclid && !arb::in()) {
|
||||
|
@ -798,12 +814,24 @@ void expansion_analyzer::view_distances_dialog() {
|
|||
|
||||
dialog::addItem(XLAT("scroll"), 'S');
|
||||
dialog::addItem(XLAT("configure"), 'C');
|
||||
dialog::addSelItem(XLAT("display distances up to"), its(last_distance), 'D');
|
||||
dialog::add_action([] () {
|
||||
scrolling_distances = false;
|
||||
dialog::editNumber(last_distance, 0, 3000, 1, 0, XLAT("display distances up to"), "");
|
||||
dialog::bound_low(0);
|
||||
dialog::get_di().extra_options = [] {
|
||||
add_edit(auto_extend);
|
||||
};
|
||||
});
|
||||
|
||||
dialog::display();
|
||||
if(auto_extend && dialog::list_skip + dialog::list_actual_size == dialog::list_full_size) last_distance++;
|
||||
}
|
||||
|
||||
EX void enable_viewdists() {
|
||||
first_distance = 0;
|
||||
scrolltime = 0;
|
||||
last_distance = closed_manifold ? 128 : 16;
|
||||
dialog::list_skip = 0;
|
||||
scrolling_distances = false;
|
||||
viewdists = true;
|
||||
if(!mod_allowed()) {
|
||||
number_coding = ncDistance;
|
||||
|
@ -814,10 +842,11 @@ EX void enable_viewdists() {
|
|||
|
||||
bool expansion_handleKey(int sym, int uni) {
|
||||
if((cmode & sm::NORMAL) && viewdists) {
|
||||
dialog::handleNavigation(sym, uni);
|
||||
if(uni == 'S' && (cmode & sm::EXPANSION)) scrolling_distances = !scrolling_distances;
|
||||
else if(uni == 'C') pushScreen(viewdist_configure_dialog);
|
||||
else if(uni == 'A' && (cmode & sm::EXPANSION)) use_analyzer = !use_analyzer;
|
||||
else if(sym == SDLK_ESCAPE) first_distance = 0, viewdists = false;
|
||||
else if(sym == SDLK_ESCAPE) dialog::list_skip = 0, viewdists = false;
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -1060,7 +1089,7 @@ EX int hyperbolic_celldistance(cell *c1, cell *c2) {
|
|||
else {
|
||||
if(cl1 == cr2 || cr1 == cl2) found_distance = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(d >= found_distance) {
|
||||
if(sl_used == sibling_limit && IRREGULAR) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Hyperbolic Rogue -- fake mobile target
|
||||
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
|
||||
//
|
||||
// Compile with: g++ fake-mobile.cpp -o fake-mobile -I/usr/include/SDL -lSDL -lSDL_gfx -lGL -lSDL_ttf -lz -Wno-invalid-offsetof
|
||||
|
||||
#define ISFAKEMOBILE 1
|
||||
#define MOBPAR_FORMAL int
|
||||
|
@ -9,7 +11,7 @@
|
|||
#include <string>
|
||||
|
||||
namespace hr {
|
||||
const char *scorefile = "fakemobile_score.txt";
|
||||
std::string scorefile = "fakemobile_score.txt";
|
||||
}
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
@ -55,6 +57,17 @@ int gdpop() { return graphdata[gdpos++]; }
|
|||
|
||||
TTF_Font *font[256];
|
||||
|
||||
const char* fontname = "DejaVuSans-Bold.ttf";
|
||||
|
||||
void load_font() {
|
||||
if(!font[size])
|
||||
font[size] = TTF_OpenFont(fontname, size);
|
||||
if(!font[size]) {
|
||||
fprintf(stderr, "failed to open font: %s", fontname);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color, int align) {
|
||||
|
||||
if(strlen(str) == 0) return false;
|
||||
|
@ -69,8 +82,7 @@ bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color
|
|||
|
||||
col.r >>= darken; col.g >>= darken; col.b >>= darken;
|
||||
|
||||
if(!font[size])
|
||||
font[size] = TTF_OpenFont("VeraBd.ttf", size);
|
||||
load_font();
|
||||
|
||||
SDL_Surface *txt = TTF_RenderText_Solid(font[size], str, col);
|
||||
|
||||
|
@ -95,7 +107,7 @@ bool rawdisplaystr(int x, int y, int shift, int size, const char *str, int color
|
|||
int textwidth(int siz, const string &str) {
|
||||
if(isize(str) == 0) return 0;
|
||||
|
||||
if(!font[siz]) font[siz] = TTF_OpenFont("VeraBd.ttf", siz);
|
||||
load_font();
|
||||
|
||||
int w, h;
|
||||
TTF_SizeUTF8(font[siz], str.c_str(), &w, &h);
|
||||
|
|
68
fake.cpp
68
fake.cpp
|
@ -32,6 +32,7 @@ EX namespace fake {
|
|||
if(in()) return true;
|
||||
if(WDIM == 2 && standard_tiling() && (PURE || BITRUNCATED)) return true;
|
||||
if(arcm::in() && PURE) return true;
|
||||
if(hat::in()) return true;
|
||||
if(WDIM == 2) return false;
|
||||
if(among(geometry, gBitrunc3)) return false;
|
||||
#if MAXMDIM >= 4
|
||||
|
@ -53,6 +54,7 @@ EX namespace fake {
|
|||
dynamicval<hrmap*> gpm(pmap, this);
|
||||
dynamicval<eGeometry> gag(actual_geometry, geometry);
|
||||
dynamicval<eGeometry> g(geometry, underlying);
|
||||
dynamicval<int> uc(cgip->use_count, cgip->use_count+1);
|
||||
dynamicval<geometry_information*> gc(cgip, underlying_cgip);
|
||||
dynamicval<hrmap*> gu(currentmap, underlying_map);
|
||||
return t();
|
||||
|
@ -73,6 +75,7 @@ EX namespace fake {
|
|||
}
|
||||
|
||||
hrmap_fake() {
|
||||
underlying_map = nullptr;
|
||||
in_underlying([this] { initcells(); underlying_map = currentmap; });
|
||||
for(hrmap*& m: allmaps) if(m == underlying_map) m = NULL;
|
||||
}
|
||||
|
@ -89,7 +92,14 @@ EX namespace fake {
|
|||
|
||||
hyperpoint get_corner(cell *c, int cid, ld cf=3) override {
|
||||
|
||||
if(arcm::in()) {
|
||||
if(embedded_plane) {
|
||||
geom3::light_flip(true);
|
||||
hyperpoint h = get_corner(c, cid, cf);
|
||||
geom3::light_flip(false);
|
||||
return cgi.emb->base_to_actual(h);
|
||||
}
|
||||
|
||||
if(arcm::in() || hat::in()) {
|
||||
return underlying_map->get_corner(c, cid, cf);
|
||||
}
|
||||
|
||||
|
@ -99,6 +109,13 @@ EX namespace fake {
|
|||
}
|
||||
|
||||
transmatrix adj(cell *c, int d) override {
|
||||
if(embedded_plane) {
|
||||
geom3::light_flip(true);
|
||||
transmatrix T = adj(c, d);
|
||||
geom3::light_flip(false);
|
||||
return cgi.emb->base_to_actual(T);
|
||||
}
|
||||
if(hat::in()) return underlying_map->adj(c, d);
|
||||
if(variation == eVariation::coxeter) {
|
||||
array<int, 3> which;
|
||||
in_underlying([&which, c, d] {
|
||||
|
@ -237,19 +254,17 @@ EX namespace fake {
|
|||
auto h1 = V * befake(FPIU(get_corner_position(c, (i+1) % c->type)));
|
||||
ld b0 = atan2(unshift(h0));
|
||||
ld b1 = atan2(unshift(h1));
|
||||
while(b1 < b0) b1 += 2 * M_PI;
|
||||
while(b1 < b0) b1 += TAU;
|
||||
if(a0 == -1) {
|
||||
draw_recursive(c->move(i), optimized_shift(V * adj(c, i)), b0, b1, c, depth+1);
|
||||
}
|
||||
else {
|
||||
if(b1 - b0 > M_PI) continue;
|
||||
|
||||
if(b0 < a0 - M_PI) b0 += 2 * M_PI;
|
||||
if(b0 > a0 + M_PI) b0 -= 2 * M_PI;
|
||||
cyclefix(b0, a0);
|
||||
if(b0 < a0) b0 = a0;
|
||||
|
||||
if(b1 > a1 + M_PI) b1 -= 2 * M_PI;
|
||||
if(b1 < a1 - M_PI) b1 += 2 * M_PI;
|
||||
cyclefix(b1, a1);
|
||||
if(b1 > a1) b1 = a1;
|
||||
|
||||
if(b0 > b1) continue;
|
||||
|
@ -537,8 +552,10 @@ EX ld compute_euclidean() {
|
|||
#if CAP_ARCM
|
||||
if(arcm::in()) return arcm::current.N * 2 / arcm::current.euclidean_angle_sum;
|
||||
#endif
|
||||
if(underlying == gAperiodicHat) return 6;
|
||||
if(WDIM == 2) return 4 / (S7-2.) + 2;
|
||||
|
||||
|
||||
if(underlying == gRhombic3) return 3;
|
||||
if(underlying == gBitrunc3) return 2.55208;
|
||||
int middle = get_middle();
|
||||
|
@ -553,6 +570,7 @@ EX ld around_orig() {
|
|||
if(arcm::in())
|
||||
return arcm::current.N;
|
||||
#endif
|
||||
if(hat::in()) return 6;
|
||||
if(WDIM == 2)
|
||||
return S3;
|
||||
if(underlying == gRhombic3)
|
||||
|
@ -589,12 +607,16 @@ EX void compute_scale() {
|
|||
|
||||
ginf[gFake].g = geometry_of_curvature(good - around, WDIM);
|
||||
|
||||
geom3::apply_always3();
|
||||
ld around_ideal = 1/(1/2. - 1./get_middle());
|
||||
|
||||
bool have_ideal = abs(around_ideal - around) < 1e-6;
|
||||
if(underlying == gRhombic3 || underlying == gBitrunc3) have_ideal = false;
|
||||
|
||||
finalizer f([&] {if(vid.always3 && WDIM == 2) {
|
||||
geom3::ginf_backup[gFake] = ginf[gFake];
|
||||
geom3::apply_always3_to(ginf[gFake]);
|
||||
}});
|
||||
|
||||
if(arcm::in()) {
|
||||
ginf[gFake].tiling_name = "(" + ginf[gArchimedean].tiling_name + ")^" + fts(around / around_orig());
|
||||
return;
|
||||
|
@ -657,8 +679,9 @@ void set_gfake(ld _around) {
|
|||
compute_scale();
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
|
||||
|
||||
if(currentmap) new hrmap_fake(currentmap);
|
||||
if(hat::in()) hat::reshape();
|
||||
}
|
||||
|
||||
EX void change_around() {
|
||||
|
@ -682,7 +705,7 @@ EX void change_around() {
|
|||
|
||||
/* to compute scale */
|
||||
if(WDIM == 2)
|
||||
cgi.prepare_basics();
|
||||
cgi.require_basics();
|
||||
}
|
||||
|
||||
t = scale / t;
|
||||
|
@ -702,45 +725,46 @@ EX void configure() {
|
|||
underlying_cgip = cgip;
|
||||
around = around_orig();
|
||||
}
|
||||
dialog::editNumber(around, 2.01, 10, 1, around, "fake curvature",
|
||||
dialog::editNumber(around, 2.01, 10, 1, around, XLAT("fake curvature"),
|
||||
XLAT(
|
||||
"This feature lets you construct the same tiling, but "
|
||||
"from shapes of different curvature.\n\n"
|
||||
"The number you give here is (2D) vertex degree or (3D) "
|
||||
"the number of cells around an edge.\n\n"
|
||||
"the number of cells around an edge.\n\n")
|
||||
);
|
||||
if(fake::in())
|
||||
dialog::reaction = change_around;
|
||||
dialog::get_di().reaction = change_around;
|
||||
else
|
||||
dialog::reaction_final = change_around;
|
||||
dialog::extra_options = [] {
|
||||
dialog::get_di().reaction_final = change_around;
|
||||
dialog::get_di().extra_options = [] {
|
||||
ld e = compute_euclidean();
|
||||
dialog::addSelItem("Euclidean", fts(e), 'E');
|
||||
dialog::addSelItem(XLAT("Euclidean"), fts(e), 'E');
|
||||
dialog::add_action([e] {
|
||||
around = e;
|
||||
popScreen();
|
||||
change_around();
|
||||
});
|
||||
|
||||
dialog::addSelItem("original", fts(around_orig()), 'O');
|
||||
dialog::addSelItem(XLAT("original"), fts(around_orig()), 'O');
|
||||
dialog::add_action([] {
|
||||
around = around_orig();
|
||||
popScreen();
|
||||
change_around();
|
||||
});
|
||||
|
||||
dialog::addSelItem("double original", fts(2 * around_orig()), 'D');
|
||||
dialog::addSelItem(XLAT("double original"), fts(2 * around_orig()), 'D');
|
||||
dialog::add_action([] {
|
||||
around = 2 * around_orig();
|
||||
popScreen();
|
||||
change_around();
|
||||
});
|
||||
|
||||
dialog::addBoolItem_action("draw all if multiple of original", multiple_special_draw, 'M');
|
||||
dialog::addBoolItem_action("draw copies (2D only)", recursive_draw, 'C');
|
||||
dialog::addBoolItem_action(XLAT("draw all if multiple of original"), multiple_special_draw, 'M');
|
||||
dialog::addBoolItem_action(XLAT("draw copies (2D only)"), recursive_draw, 'C');
|
||||
|
||||
dialog::addBoolItem_choice("unordered", ordered_mode, 0, 'U');
|
||||
dialog::addBoolItem_choice("pre-ordered", ordered_mode, 1, 'P');
|
||||
dialog::addBoolItem_choice("post-ordered", ordered_mode, 2, 'Q');
|
||||
dialog::addBoolItem_choice(XLAT("unordered"), ordered_mode, 0, 'U');
|
||||
dialog::addBoolItem_choice(XLAT("pre-ordered"), ordered_mode, 1, 'P');
|
||||
dialog::addBoolItem_choice(XLAT("post-ordered"), ordered_mode, 2, 'Q');
|
||||
|
||||
};
|
||||
}
|
||||
|
|
134
fieldpattern.cpp
134
fieldpattern.cpp
|
@ -43,7 +43,7 @@ EX bool isprime(int n) {
|
|||
}
|
||||
|
||||
#if HDR
|
||||
#define MWDIM (prod ? 3 : WDIM+1)
|
||||
#define MWDIM (mproduct ? 3 : WDIM+1)
|
||||
|
||||
struct matrix : array<array<int, MAXMDIM>, MAXMDIM> {
|
||||
bool operator == (const matrix& B) const {
|
||||
|
@ -77,7 +77,7 @@ EX int btspin(int id, int d) {
|
|||
|
||||
#if HDR
|
||||
|
||||
static const int ERR = -99;
|
||||
static constexpr int ERR = -99;
|
||||
|
||||
struct triplet_info {
|
||||
int i, j, size;
|
||||
|
@ -142,14 +142,23 @@ struct fpattern {
|
|||
}
|
||||
|
||||
int sqr(int x) { return mul(x,x); }
|
||||
|
||||
|
||||
int err;
|
||||
|
||||
matrix mmul(const matrix& A, const matrix& B) {
|
||||
matrix res;
|
||||
for(int i=0; i<MWDIM; i++) for(int k=0; k<MWDIM; k++) {
|
||||
int t = 0;
|
||||
#ifdef EASY
|
||||
for(int j=0; j<MWDIM; j++) t += mul(A[i][j], B[j][k]);
|
||||
t %= Prime;
|
||||
int tp = 0, tn = 0;
|
||||
for(int j=0; j<MWDIM; j++) {
|
||||
int val = mul(A[i][j], B[j][k]);
|
||||
if(val > 0) tp += val;
|
||||
else tn += val;
|
||||
}
|
||||
tp %= Prime; tn %= Prime;
|
||||
if(tp && tn) err++;
|
||||
t = tp + tn;
|
||||
#else
|
||||
for(int j=0; j<MWDIM; j++) t = add(t, mul(A[i][j], B[j][k]));
|
||||
#endif
|
||||
|
@ -263,7 +272,7 @@ struct fpattern {
|
|||
|
||||
void build();
|
||||
|
||||
static const int MAXDIST = 120;
|
||||
static constexpr int MAXDIST = 120;
|
||||
|
||||
vector<char> disthep;
|
||||
vector<char> disthex;
|
||||
|
@ -362,12 +371,13 @@ struct discovery {
|
|||
#endif
|
||||
|
||||
bool fpattern::check_order(matrix M, int req) {
|
||||
int err = 0;
|
||||
matrix P = M;
|
||||
for(int i=1; i<req; i++) {
|
||||
if(P == Id) return false;
|
||||
P = mmul(P, M);
|
||||
}
|
||||
return P == Id;
|
||||
return P == Id && !err;
|
||||
}
|
||||
|
||||
vector<matrix> fpattern::generate_isometries() {
|
||||
|
@ -497,6 +507,7 @@ unsigned fpattern::compute_hash() {
|
|||
bool fpattern::generate_all3() {
|
||||
|
||||
reg3::generate_fulls();
|
||||
err = 0;
|
||||
|
||||
matrices.clear();
|
||||
matcode.clear();
|
||||
|
@ -505,19 +516,23 @@ bool fpattern::generate_all3() {
|
|||
for(int i=0; i<isize(matrices); i++) {
|
||||
add1(mmul(matrices[i], R), fullv[i] * cgi.full_R);
|
||||
add1(mmul(matrices[i], X), fullv[i] * cgi.full_X);
|
||||
if(err) return false;
|
||||
}
|
||||
local_group = isize(matrices);
|
||||
if(local_group != isize(cgi.cellrotations)) return false;
|
||||
|
||||
for(int i=0; i<(int)matrices.size(); i++) {
|
||||
matrix E = mmul(matrices[i], P);
|
||||
if(!matcode.count(E))
|
||||
for(int j=0; j<local_group; j++) add1(mmul(E, matrices[j]));
|
||||
if(err) return false;
|
||||
if(isize(matrices) >= limitv) { println(hlog, "limitv exceeded"); return false; }
|
||||
}
|
||||
hashv = compute_hash();
|
||||
DEBB(DF_FIELD, ("all = ", isize(matrices), "/", local_group, " = ", isize(matrices) / local_group, " hash = ", hashv, " count = ", ++hash_found[hashv]));
|
||||
|
||||
if(use_quotient_fp)
|
||||
generate_quotientgroup();
|
||||
generate_quotientgroup();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -585,8 +600,11 @@ void fpattern::generate_quotientgroup() {
|
|||
|
||||
}
|
||||
|
||||
EX purehookset hooks_solve3;
|
||||
|
||||
int fpattern::solve3() {
|
||||
reg3::construct_relations();
|
||||
|
||||
reg3::generate_fulls();
|
||||
|
||||
DEBB(DF_FIELD, ("generating isometries for ", Field));
|
||||
|
||||
|
@ -595,10 +613,6 @@ int fpattern::solve3() {
|
|||
|
||||
int cmb = 0;
|
||||
|
||||
int N = isize(cgi.rels);
|
||||
|
||||
vector<int> fails(N);
|
||||
|
||||
vector<matrix> possible_P, possible_X, possible_R;
|
||||
|
||||
for(auto& M: iso3) {
|
||||
|
@ -614,35 +628,32 @@ int fpattern::solve3() {
|
|||
DEBB(DF_FIELD, ("field = ", Field, " #P = ", isize(possible_P), " #X = ", isize(possible_X), " #R = ", isize(possible_R), " r_order = ", cgi.r_order, " xp_order = ", cgi.xp_order));
|
||||
|
||||
for(auto& xX: possible_X)
|
||||
for(auto& xP: possible_P) if(check_order(mmul(xP, xX), cgi.xp_order))
|
||||
for(auto& xR: possible_R) if(check_order(mmul(xR, xX), cgi.rx_order)) { // if(xR[0][0] == 1 && xR[0][1] == 0)
|
||||
#if CAP_THREAD && MAXMDIM >+ 4
|
||||
for(auto& xP: possible_P) if(check_order(mmul(xP, xX), cgi.xp_order))
|
||||
for(auto& xR: possible_R) if(check_order(mmul(xR, xX), cgi.rx_order)) {
|
||||
|
||||
err = 0;
|
||||
if(mmul(xX, xP) != mmul(xR, mmul(mmul(xP, xX), xR))) continue;
|
||||
if(err) continue;
|
||||
|
||||
#if CAP_THREAD && MAXMDIM >= 4
|
||||
if(dis) dis->check_suspend();
|
||||
if(dis && dis->stop_it) return 0;
|
||||
#endif
|
||||
auto by = [&] (char ch) -> matrix& { return ch == 'X' ? xX : ch == 'R' ? xR : xP; };
|
||||
for(int i=0; i<N; i++) {
|
||||
matrix ml = Id;
|
||||
for(char c: cgi.rels[i].first) { ml = mmul(ml, by(c)); if(ml == Id) { fails[i]++; goto bad; }}
|
||||
matrix mr = Id;
|
||||
for(char c: cgi.rels[i].second) { mr = mmul(mr, by(c)); if(mr == Id) { fails[i]++; goto bad; }}
|
||||
if(ml != mr) { fails[i]++; goto bad;}
|
||||
}
|
||||
|
||||
P = xP; R = xR; X = xX;
|
||||
if(!generate_all3()) continue;
|
||||
callhooks(hooks_solve3);
|
||||
#if CAP_THREAD && MAXMDIM >= 4
|
||||
if(dis) { dis->discovered(); continue; }
|
||||
#endif
|
||||
if(force_hash && hashv != force_hash) continue;
|
||||
cmb++;
|
||||
goto ok;
|
||||
bad: ;
|
||||
}
|
||||
|
||||
|
||||
ok:
|
||||
|
||||
DEBB(DF_FIELD, ("cmb = ", cmb, " for field = ", Field));
|
||||
for(int i=0; i<N; i++) if(fails[i]) DEBB(DF_FIELD, (cgi.rels[i], " fails = ", fails[i]));
|
||||
|
||||
return cmb;
|
||||
}
|
||||
|
@ -1270,7 +1281,13 @@ EX struct fpattern& getcurrfp() {
|
|||
return current_quotient_field;
|
||||
if(geometry == gSpace535) {
|
||||
// 120 cells, hash = 9EF7A9C4
|
||||
static fpattern fp(5);
|
||||
static fpattern fp(0);
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 5; fp.force_hash = 0xDCC3CACEu; fp.solve();
|
||||
}
|
||||
else {
|
||||
fp.Prime = 5; fp.force_hash = 0x9EF7A9C4u; fp.solve();
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
if(geometry == gSpace534) {
|
||||
|
@ -1280,7 +1297,7 @@ EX struct fpattern& getcurrfp() {
|
|||
// fp.Prime = 5; fp.force_hash = 0x72414D0C; fp.solve();
|
||||
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 11; fp.force_hash = 0x5FC4CFF0; fp.solve();
|
||||
fp.Prime = 11; fp.force_hash = 0x5FC4CFF0u; fp.solve();
|
||||
}
|
||||
else {
|
||||
shstream ins(STR("\x05\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\xfc\xff\xff\xff\x01\x00\x00\x00\x04\x00\x00\x00\xfc\xff\xff\xff\x04\x00\x00\x00\xfe\xff\xff\xff\x00\x00\x00\x00\x01\x00\x00\x00\xfe\xff\xff\xff\x04\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xfc\xff\xff\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xfc\xff\xff\xff\x02\x00\x00\x00\x00\x00\x00\x00\xfc\xff\xff\xff\x01\x00\x00\x00\xfd\xff\xff\xff\x00\x00\x00\x00\x02\x00\x00\x00\xfd\xff\xff\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"));
|
||||
|
@ -1296,7 +1313,7 @@ EX struct fpattern& getcurrfp() {
|
|||
// what is 0x72414D0C??
|
||||
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 11; fp.force_hash = 0x65CE0C00; fp.solve();
|
||||
fp.Prime = 11; fp.force_hash = 0x65CE0C00u; fp.solve();
|
||||
}
|
||||
else {
|
||||
shstream ins(STR("\x05\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xfc\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xfc\xff\xff\xff\x04\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\xff\xff\xff\xff\x02\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xfd\xff\xff\xff\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xfc\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\xfd\xff\xff\xff\x00\x00\x00\x00\xfd\xff\xff\xff\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\x03\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"));
|
||||
|
@ -1306,20 +1323,28 @@ EX struct fpattern& getcurrfp() {
|
|||
}
|
||||
if(geometry == gSpace436) {
|
||||
static fpattern fp(0);
|
||||
// FF82A214
|
||||
shstream ins(STR("\x05\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\xfd\xff\xff\xff\x00\x00\x00\x00\xfe\xff\xff\xff\xfd\xff\xff\xff\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\xfd\xff\xff\xff\x02\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\xfc\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\xfd\xff\xff\xff\x00\x00\x00\x00\xfd\xff\xff\xff\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\x03\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"));
|
||||
hread_fpattern(ins, fp);
|
||||
if(fp.Prime) return fp;
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 2; fp.force_hash = 0x235F7508u; fp.solve();
|
||||
}
|
||||
else {
|
||||
// FF82A214
|
||||
shstream ins(STR("\x05\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\xfd\xff\xff\xff\x00\x00\x00\x00\xfe\xff\xff\xff\xfd\xff\xff\xff\x01\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\xfd\xff\xff\xff\x02\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\xfc\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\xfd\xff\xff\xff\x00\x00\x00\x00\xfd\xff\xff\xff\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\x03\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"));
|
||||
hread_fpattern(ins, fp);
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
if(geometry == gSpace336) {
|
||||
// 672 cells in E3F6B7BC
|
||||
// 672 cells in 885F1184
|
||||
// 9408 cells in C4089F34
|
||||
static fpattern fp(0);
|
||||
if(fp.Prime) return fp;
|
||||
// fp.Prime = 7; fp.force_hash = 0xE3F6B7BCu; fp.solve();
|
||||
shstream ins(STR("\x07\x00\x00\x00\x03\x00\x00\x00\xfa\xff\xff\xff\x02\x00\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\xfe\xff\xff\xff\xfb\xff\xff\xff\xfc\xff\xff\xff\x03\x00\x00\x00\xfb\xff\xff\xff\xfd\xff\xff\xff\xfb\xff\xff\xff\x01\x00\x00\x00\xfd\xff\xff\xff\xfe\xff\xff\xff\xfd\xff\xff\xff\x03\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\xff\xff\xff\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xfa\xff\xff\xff\xfb\xff\xff\xff\x00\x00\x00\x00\xfa\xff\xff\xff\x02\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\xfb\xff\xff\xff\x06\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"));
|
||||
hread_fpattern(ins, fp);
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 3; fp.force_hash = 0xD29C2418u; fp.solve();
|
||||
}
|
||||
else {
|
||||
// fp.Prime = 7; fp.force_hash = 0xE3F6B7BCu; fp.solve();
|
||||
shstream ins(STR("\x07\x00\x00\x00\x03\x00\x00\x00\xfa\xff\xff\xff\x02\x00\x00\x00\x03\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\xfe\xff\xff\xff\xfb\xff\xff\xff\xfc\xff\xff\xff\x03\x00\x00\x00\xfb\xff\xff\xff\xfd\xff\xff\xff\xfb\xff\xff\xff\x01\x00\x00\x00\xfd\xff\xff\xff\xfe\xff\xff\xff\xfd\xff\xff\xff\x03\x00\x00\x00\x00\x00\x00\x00\xfd\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\xff\xff\xff\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xfa\xff\xff\xff\xfb\xff\xff\xff\x00\x00\x00\x00\xfa\xff\xff\xff\x02\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\xfb\xff\xff\xff\x06\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"));
|
||||
hread_fpattern(ins, fp);
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
if(geometry == gSpace344) {
|
||||
|
@ -1329,7 +1354,12 @@ EX struct fpattern& getcurrfp() {
|
|||
// 2600 cells in EC29DCEC
|
||||
static fpattern fp(0);
|
||||
if(fp.Prime) return fp;
|
||||
fp.Prime = 5; fp.force_hash = 0x558C8ED0u; fp.solve();
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 3; fp.force_hash = 0xB23AF1F4u; fp.solve();
|
||||
}
|
||||
else {
|
||||
fp.Prime = 5; fp.force_hash = 0x558C8ED0u; fp.solve();
|
||||
}
|
||||
return fp;
|
||||
// 4900 cells in CDCC7860 (7)
|
||||
}
|
||||
|
@ -1338,7 +1368,12 @@ EX struct fpattern& getcurrfp() {
|
|||
if(fp.Prime) return fp;
|
||||
// 130 cells in 3BA5C5A4
|
||||
// 260 cells in 9FDE7B38
|
||||
fp.Prime = 5; fp.force_hash = 0x9FDE7B38u; fp.solve();
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 5; fp.force_hash = 0x61385498u; fp.solve();
|
||||
}
|
||||
else {
|
||||
fp.Prime = 5; fp.force_hash = 0x9FDE7B38u; fp.solve();
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
if(geometry == gSpace345) {
|
||||
|
@ -1347,7 +1382,12 @@ EX struct fpattern& getcurrfp() {
|
|||
// 30 cells in 02ADCAA4 (3^2)
|
||||
// 650 cells in 7EFE8D98 (5^2)
|
||||
// 55 cells in F447F75C (11)
|
||||
fp.Prime = 11; fp.force_hash = 0xF447F75Cu; fp.solve();
|
||||
if(use_rule_fp) {
|
||||
fp.Prime = 3; fp.force_hash = 0xF978E264u; fp.solve();
|
||||
}
|
||||
else {
|
||||
fp.Prime = 11; fp.force_hash = 0xF447F75Cu; fp.solve();
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
if(geometry == gSpace353) {
|
||||
|
@ -1360,12 +1400,16 @@ EX struct fpattern& getcurrfp() {
|
|||
}
|
||||
if(geometry == gSpace354) {
|
||||
static fpattern fp(0);
|
||||
if(fp.Prime) return fp;
|
||||
fp.Prime = 11; fp.force_hash = 0x363D8DA4u; fp.solve();
|
||||
// fp.Prime = 11; fp.force_hash = 0x363D8DA4u; fp.solve();
|
||||
fp.Prime = 5; fp.force_hash = 0x58A8E850u; fp.solve();
|
||||
return fp;
|
||||
}
|
||||
if(geometry == gCubeTiling) {
|
||||
static fpattern fp(2);
|
||||
return fp;
|
||||
}
|
||||
if(!hyperbolic) return fp_invalid;
|
||||
if(WDIM == 3 && !quotient && !hybri && !bt::in()) {
|
||||
if(WDIM == 3 && !quotient && !mhybrid && !bt::in()) {
|
||||
static fpattern fp(0);
|
||||
if(fp.Prime) return fp;
|
||||
for(int p=2; p<20; p++) { fp.Prime = p; if(!fp.solve()) break; }
|
||||
|
|
|
@ -37,6 +37,7 @@ WALLFLAGCHECK(isAlch, flag & WF_ALCHEMY)
|
|||
WALLFLAGCHECK(isAlchAny, flag & WF_ALCHEMY)
|
||||
WALLFLAGCHECK(realred, flag & WF_RED)
|
||||
WALLFLAGCHECK(isWall, flag & WF_WALL)
|
||||
WALLFLAGCHECK(isNonblock, flag & WF_NONBLOCK)
|
||||
WALLFLAGCHECK(isPushable, flag & WF_PUSHABLE)
|
||||
WALLFLAGCHECK(conegraphtype, flag & WF_CONE)
|
||||
WALLFLAGCHECK(isStandardTree, flag & WF_STDTREE)
|
||||
|
|
321
floorshapes.cpp
321
floorshapes.cpp
|
@ -26,9 +26,16 @@ EX vector<basic_textureinfo> floor_texture_vertices;
|
|||
EX vector<glvertex> floor_texture_map;
|
||||
EX struct renderbuffer *floor_textures;
|
||||
|
||||
EX basic_textureinfo* get_floor_texture_vertices(int index) {
|
||||
if(noGUI || !vid.usingGL) return nullptr;
|
||||
return &floor_texture_vertices[index];
|
||||
}
|
||||
|
||||
/* 0: generate no floorshapes; 1: generate only plain floorshapes; 2: generate all */
|
||||
EX int floorshapes_level = 2;
|
||||
|
||||
EX ld global_boundary_ratio = 1;
|
||||
|
||||
void geometry_information::init_floorshapes() {
|
||||
if(floorshapes_level == 0) return;
|
||||
all_escher_floorshapes.clear();
|
||||
|
@ -104,17 +111,17 @@ mesher msh(eGeometry g, int sym, ld main, ld v0, ld v1, ld bspi, ld scale) {
|
|||
dynamicval<eGeometry> dg(geometry, g);
|
||||
|
||||
hyperpoint rot = xpush(v0) * xspinpush0(M_PI - M_PI/sym, main);
|
||||
hyperpoint bnlfar = xpush(v0) * spin(M_PI) * rspintox(rot) * rspintox(rot) * rspintox(rot) * xpush0(hdist0(rot));
|
||||
hyperpoint bnrfar = xpush(v0) * spin(M_PI) * spintox(rot) * spintox(rot) * spintox(rot) * xpush0(hdist0(rot));
|
||||
hyperpoint bnlfar = xpush(v0) * spin180() * rspintox(rot) * rspintox(rot) * rspintox(rot) * xpush0(hdist0(rot));
|
||||
hyperpoint bnrfar = xpush(v0) * spin180() * spintox(rot) * spintox(rot) * spintox(rot) * xpush0(hdist0(rot));
|
||||
|
||||
m.lcorner = xspinpush0 (bspi-M_PI/sym, main);
|
||||
m.rcorner = xspinpush0 (bspi+M_PI/sym, main);
|
||||
m.lcorner = xspinpush0 (bspi - M_PI/sym, main);
|
||||
m.rcorner = xspinpush0 (bspi + M_PI/sym, main);
|
||||
m.mfar[0] = xspinpush0 (bspi, v0);
|
||||
m.mfar[1] = xspinpush0 (bspi, v1);
|
||||
m.vfar[0] = spin(bspi) * bnlfar;
|
||||
m.vfar[2] = spin(bspi) * bnrfar;
|
||||
m.vfar[1] = spin(-2*M_PI/sym) * m.vfar[2];
|
||||
m.vfar[3] = spin(+2*M_PI/sym) * m.vfar[0];
|
||||
m.vfar[1] = spin(-TAU/sym) * m.vfar[2];
|
||||
m.vfar[3] = spin(+TAU/sym) * m.vfar[0];
|
||||
|
||||
return m;
|
||||
}
|
||||
|
@ -129,17 +136,12 @@ matrixitem genitem(const transmatrix& m1, const transmatrix& m2, int nsym) {
|
|||
mi.first = m1;
|
||||
mi.second.resize(nsym);
|
||||
for(int i=0; i<nsym; i++)
|
||||
mi.second[i] = spin(2*M_PI*i/nsym) * m2;
|
||||
mi.second[i] = spin(TAU*i/nsym) * m2;
|
||||
return mi;
|
||||
}
|
||||
|
||||
bool do_kleinize() { return S3 >= OINF || (cgflags & qIDEAL); }
|
||||
|
||||
EX hyperpoint kleinize(hyperpoint h) {
|
||||
if(GDIM == 2) return point3(h[0]/h[2], h[1]/h[2], 1);
|
||||
else return point31(h[0]/h[3], h[1]/h[3], h[2]/h[3]);
|
||||
}
|
||||
|
||||
EX hyperpoint may_kleinize(hyperpoint h) {
|
||||
if(do_kleinize()) return kleinize(h);
|
||||
else return h;
|
||||
|
@ -147,7 +149,7 @@ EX hyperpoint may_kleinize(hyperpoint h) {
|
|||
|
||||
void addmatrix(matrixlist& matrices, hyperpoint o0, hyperpoint o1, hyperpoint o2, hyperpoint n0, hyperpoint n1, hyperpoint n2, int d, int osym, int nsym) {
|
||||
if(do_kleinize()) o0 = kleinize(o0), o1 = kleinize(o1), o2 = kleinize(o2), n0 = kleinize(n0), n1 = kleinize(n1), n2 = kleinize(n2);
|
||||
matrices.v.push_back(genitem(inverse(spin(2*M_PI*d/osym)*build_matrix(o0, o1, o2,C02)), spin(2*M_PI*d/nsym)*build_matrix(n0, n1, n2,C02), nsym));
|
||||
matrices.v.push_back(genitem(inverse(spin(TAU*d/osym)*build_matrix(o0, o1, o2,C02)), spin(TAU*d/nsym)*build_matrix(n0, n1, n2,C02), nsym));
|
||||
}
|
||||
|
||||
matrixlist hex_matrices, hept_matrices;
|
||||
|
@ -223,20 +225,20 @@ void geometry_information::bshape2(hpcshape& sh, PPR prio, int shapeid, matrixli
|
|||
hyperpoint lstmid = hpxyz(0,0,0);
|
||||
for(auto pp: lst) lstmid += pp;
|
||||
transmatrix T = spin(-m.o.bspi);
|
||||
while((spin(2*M_PI / rots) * T* lstmid)[0] < (T*lstmid)[0])
|
||||
T = spin(2*M_PI / rots) * T;
|
||||
while((spin(-2*M_PI / rots) * T* lstmid)[0] < (T*lstmid)[0])
|
||||
T = spin(-2*M_PI / rots) * T;
|
||||
while((spin(TAU / rots) * T* lstmid)[0] < (T*lstmid)[0])
|
||||
T = spin(TAU / rots) * T;
|
||||
while((spin(-TAU / rots) * T* lstmid)[0] < (T*lstmid)[0])
|
||||
T = spin(-TAU / rots) * T;
|
||||
T = spin(m.o.bspi) * T;
|
||||
for(auto &pp: lst) pp = T * pp;
|
||||
|
||||
if(osym % rots && rots % osym) printf("warning: rotation oddity (shapeid %d, osym=%d rots=%d)\n", shapeid, osym, rots);
|
||||
if(osym % rots && rots % osym && (debugflags & DF_GEOM)) printf("warning: rotation oddity (shapeid %d, osym=%d rots=%d)\n", shapeid, osym, rots);
|
||||
|
||||
if(rots > osym && rots % osym == 0) {
|
||||
int rep = rots / osym;
|
||||
int s = lst.size();
|
||||
for(int i=0; i<s*(rep-1); i++)
|
||||
lst.push_back(spin(2*M_PI/rots) * lst[i]);
|
||||
lst.push_back(spin(TAU/rots) * lst[i]);
|
||||
rots /= rep;
|
||||
}
|
||||
|
||||
|
@ -258,7 +260,7 @@ void geometry_information::bshape2(hpcshape& sh, PPR prio, int shapeid, matrixli
|
|||
nh = m.second[r] * z, mapped++;
|
||||
}
|
||||
}
|
||||
if(mapped == 0) printf("warning: not mapped (shapeid %d)\n", shapeid);
|
||||
if(mapped == 0 && (debugflags & DF_GEOM)) printf("warning: not mapped (shapeid %d)\n", shapeid);
|
||||
if(invalid) {
|
||||
apeirogonal = true;
|
||||
for(auto h: head) tail.push_back(h);
|
||||
|
@ -277,6 +279,10 @@ template<class T> void sizeto(T& t, int n) {
|
|||
if(isize(t) <= n) t.resize(n+1);
|
||||
}
|
||||
|
||||
template<class T, class U> void sizeto(T& t, int n, const U& val) {
|
||||
if(isize(t) <= n) t.resize(n+1, val);
|
||||
}
|
||||
|
||||
void geometry_information::bshape_regular(floorshape &fsh, int id, int sides, ld shift, ld size, cell *c) {
|
||||
|
||||
sizeto(fsh.b, id);
|
||||
|
@ -286,20 +292,23 @@ void geometry_information::bshape_regular(floorshape &fsh, int id, int sides, ld
|
|||
if(bt::in()) {
|
||||
|
||||
const int STEP = vid.texture_step;
|
||||
|
||||
|
||||
for(int t=0; t<2; t++) {
|
||||
|
||||
if(t == 0)
|
||||
bshape(fsh.b[id], fsh.prio);
|
||||
if(t == 1)
|
||||
bshape(fsh.shadow[id], fsh.prio);
|
||||
|
||||
int STEP1 = STEP;
|
||||
if((embedded_plane || geom3::flipped) && t == 0) STEP1 = 1;
|
||||
|
||||
for(int i=0; i<sides; i++) {
|
||||
hyperpoint h0 = bt::get_corner_horo_coordinates(c, i) * size;
|
||||
hyperpoint h1 = bt::get_corner_horo_coordinates(c, i+1) * size;
|
||||
if(t) h0 *= SHADMUL, h1 *= SHADMUL;
|
||||
hyperpoint hd = (h1 - h0) / STEP;
|
||||
for(int j=0; j<STEP; j++) {
|
||||
hyperpoint hd = (h1 - h0) / STEP1;
|
||||
for(int j=0; j<STEP1; j++) {
|
||||
hpcpush(bt::get_horopoint(h0 + hd * j));
|
||||
if(geometry == gBinary4 && among(i, 2, 4)) break;
|
||||
if(geometry == gBinaryTiling && among(i, 0, 4)) break;
|
||||
|
@ -331,11 +340,11 @@ void geometry_information::bshape_regular(floorshape &fsh, int id, int sides, ld
|
|||
|
||||
bshape(fsh.b[id], fsh.prio);
|
||||
for(int t=0; t<=sides; t++)
|
||||
hpcpush(xspinpush0(t*2 * M_PI / sides + shift * M_PI / S42, size));
|
||||
hpcpush(xspinpush0(t * TAU / sides + shift * S_step, size));
|
||||
|
||||
bshape(fsh.shadow[id], fsh.prio);
|
||||
for(int t=0; t<=sides; t++)
|
||||
hpcpush(xspinpush0(t*2 * M_PI / sides + shift * M_PI / S42, size * SHADMUL));
|
||||
hpcpush(xspinpush0(t * TAU / sides + shift * S_step, size * SHADMUL));
|
||||
|
||||
for(int k=0; k<SIDEPARS; k++) {
|
||||
fsh.side[k].resize(2);
|
||||
|
@ -343,6 +352,17 @@ void geometry_information::bshape_regular(floorshape &fsh, int id, int sides, ld
|
|||
hpcpush(xspinpush0(+M_PI/sides, size));
|
||||
hpcpush(xspinpush0(-M_PI/sides, size));
|
||||
chasmifyPoly(dlow_table[k], dhi_table[k], k);
|
||||
|
||||
if(cgi.emb->is_euc_in_noniso()) {
|
||||
fsh.gpside[k].resize(c->type);
|
||||
for(int i=0; i<c->type; i++) {
|
||||
sizeto(fsh.gpside[k][i], id);
|
||||
bshape(fsh.gpside[k][i][id], PPR::LAKEWALL);
|
||||
hpcpush(xspinpush0(M_PI - i * TAU / sides + shift * S_step, size));
|
||||
hpcpush(xspinpush0(M_PI - (i + 1) * TAU / sides + shift * S_step, size));
|
||||
chasmifyPoly(dlow_table[k], dhi_table[k], k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,6 +386,24 @@ void geometry_information::finish_apeirogon(hyperpoint center) {
|
|||
}
|
||||
}
|
||||
|
||||
hyperpoint get_circumscribed_corner(cell *c, int t, hyperpoint h) {
|
||||
|
||||
hyperpoint h0 = currentmap->adjmod(c, t) * h;
|
||||
hyperpoint h1 = currentmap->adjmod(c, t-1) * h;
|
||||
transmatrix T;
|
||||
array<hyperpoint, 3> hs = {h, h0, h1};
|
||||
set_column(T, 3, C03);
|
||||
hyperpoint res = C03;
|
||||
for(int i=0; i<3; i++) {
|
||||
hyperpoint ahs = hs[i];
|
||||
if(hyperbolic) ahs[3] *= -1;
|
||||
set_column(T, i, ahs);
|
||||
res[i] = dot_d(4, hs[i], ahs);
|
||||
}
|
||||
T = transpose(T);
|
||||
return inverse(T) * res;
|
||||
}
|
||||
|
||||
// !siid equals pseudohept(c)
|
||||
|
||||
void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, int sidir) {
|
||||
|
@ -421,26 +459,28 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
if(&fsh == &shTriheptaFloor) {
|
||||
if(!siid) {
|
||||
for(int i=0; i<cor; i++)
|
||||
cornerlist.push_back(midcorner(c, i, .49));
|
||||
cornerlist.push_back(midcorner(c, i, .5 - .01 * global_boundary_ratio));
|
||||
}
|
||||
else {
|
||||
for(int i=0; i<cor; i++) {
|
||||
int ri = i;
|
||||
if((i&1) == ((sidir+siid)&1)) ri--;
|
||||
ri = c->c.fix(ri);
|
||||
cornerlist.push_back(mid(get_corner_position(c, ri, 3.1), get_corner_position(c, c->c.fix(ri+1), 3.1)));
|
||||
ld val = 3 + 0.1 * global_boundary_ratio;
|
||||
cornerlist.push_back(mid(get_corner_position(c, ri, val), get_corner_position(c, c->c.fix(ri+1), val)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(&fsh == &shBigTriangle) {
|
||||
ld val = 1 - 0.06 * global_boundary_ratio;
|
||||
if(!siid) {
|
||||
for(int i=0; i<cor; i++) cornerlist.push_back(hpxy(0,0));
|
||||
}
|
||||
else if(geosupport_chessboard()) {
|
||||
for(int i=0; i<cor; i++) {
|
||||
hyperpoint nc = nearcorner(c, i);
|
||||
cornerlist.push_back(mid_at(hpxy(0,0), nc, .94));
|
||||
cornerlist.push_back(mid_at(hpxy(0,0), nc, val));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -449,16 +489,17 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
if((i&1) != ((sidir+siid)&1)) ri--;
|
||||
ri = c->c.fix(ri);
|
||||
hyperpoint nc = nearcorner(c, ri);
|
||||
cornerlist.push_back(mid_at(hpxy(0,0), nc, .94));
|
||||
cornerlist.push_back(mid_at(hpxy(0,0), nc, val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(&fsh == &shBigHepta) {
|
||||
ld val = 1 - 0.06 * global_boundary_ratio;
|
||||
if(!siid) {
|
||||
for(int i=0; i<cor; i++) {
|
||||
hyperpoint nc = nearcorner(c, i);
|
||||
cornerlist.push_back(mid_at(hpxy(0,0), nc, .94));
|
||||
cornerlist.push_back(mid_at(hpxy(0,0), nc, val));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -466,7 +507,7 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
}
|
||||
}
|
||||
|
||||
else if(arb::in()) {
|
||||
else if(arb::in() || aperiodic || arcm::in() || IRREGULAR) {
|
||||
vector<hyperpoint> actual;
|
||||
for(int j=0; j<cor; j++)
|
||||
actual.push_back(get_corner_position(c, j));
|
||||
|
@ -480,29 +521,34 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
}
|
||||
|
||||
auto &ac = arb::current_or_slided();
|
||||
ld dist = min_dist * (1 - 3 / sca) * ac.boundary_ratio;
|
||||
|
||||
|
||||
ld dist = min_dist * (1 - 3 / sca) * (arb::in() ? ac.boundary_ratio : 1);
|
||||
ld area = 0;
|
||||
for(int j=0; j<cor; j++) {
|
||||
hyperpoint current = kleinize(actual[j]);
|
||||
hyperpoint last = kleinize(actual[j?j-1:cor-1]);
|
||||
hyperpoint last = kleinize(atmod(actual, j-1));
|
||||
area += current[0] * last[1] - last[0] * current[1];
|
||||
}
|
||||
if(area < 0) dist = -dist;
|
||||
|
||||
int id = arb::id_of(c->master);
|
||||
auto& sh = ac.shapes[id];
|
||||
apeirogonal = sh.apeirogonal;
|
||||
|
||||
apeirogonal = false;
|
||||
int id = 0;
|
||||
arb::shape *sh = nullptr;
|
||||
if(arb::in()) {
|
||||
id = arb::id_of(c->master);
|
||||
sh = &ac.shapes[id];
|
||||
apeirogonal = sh->apeirogonal;
|
||||
}
|
||||
|
||||
for(int j=0; j<cor; j++) {
|
||||
hyperpoint last = actual[j?j-1:cor-1];
|
||||
hyperpoint current = ypush(1e-6 * randd()) * xpush(1e-6) * actual[j];
|
||||
hyperpoint next = actual[j<cor-1?j+1:0];
|
||||
hyperpoint last = atmod(actual, j-1);
|
||||
hyperpoint current = ypush(1e-7) * xpush(1e-6) * actual[j];
|
||||
hyperpoint next = atmod(actual, j+1);
|
||||
|
||||
if(apeirogonal) {
|
||||
if(j == 0) last = arb::get_adj(arb::current_or_slided(), id, cor-1, id, cor-2) * actual[cor-3];
|
||||
if(j == cor-2) next = arb::get_adj(arb::current_or_slided(), id, cor-2, id, cor-1) * actual[1];
|
||||
if(j == cor-1) { cornerlist.push_back(sh.vertices.back()); continue; }
|
||||
if(j == 0) last = arb::get_adj(ac, id, cor-1, id, cor-2, false) * actual[cor-3];
|
||||
if(j == cor-2) next = arb::get_adj(ac, id, cor-2, id, cor-1, false) * actual[1];
|
||||
if(j == cor-1) { cornerlist.push_back(sh->vertices.back()); continue; }
|
||||
}
|
||||
|
||||
auto T = gpushxto0(current);
|
||||
|
@ -640,7 +686,7 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
int id = arb::id_of(c->master);
|
||||
auto &ac = arb::current_or_slided();
|
||||
auto& sh = ac.shapes[id];
|
||||
hpcpush(arb::get_adj(arb::current_or_slided(), id, cor-2, id, cor-1) * starting_point);
|
||||
hpcpush(arb::get_adj(arb::current_or_slided(), id, cor-2, id, cor-1, false) * starting_point);
|
||||
finish_apeirogon(sh.vertices.back());
|
||||
}
|
||||
}
|
||||
|
@ -648,7 +694,7 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(WDIM == 2 && GDIM == 3) {
|
||||
if(embedded_plane) {
|
||||
finishshape();
|
||||
for(auto pfsh: all_plain_floorshapes) {
|
||||
auto& fsh = *pfsh;
|
||||
|
@ -660,42 +706,57 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
sizeto(fsh.levels[k], id);
|
||||
bshape(fsh.levels[k][id], fsh.prio);
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
last->tinf = &floor_texture_vertices[fsh.id];
|
||||
last->tinf = get_floor_texture_vertices(fsh.id);
|
||||
last->texture_offset = 0;
|
||||
|
||||
#if CAP_BT
|
||||
if(bt::in())
|
||||
for(int t=0; t<c->type; t++)
|
||||
texture_order([&] (ld x, ld y) {
|
||||
hyperpoint left = bt::get_corner_horo_coordinates(c, t);
|
||||
hyperpoint right = bt::get_corner_horo_coordinates(c, t+1);
|
||||
hpcpush(orthogonal_move(bt::get_horopoint(left * x + right * y), dfloor_table[k]));
|
||||
});
|
||||
else
|
||||
#endif
|
||||
if(1) {
|
||||
int s = fsh.b[id].s;
|
||||
int e = fsh.b[id].e-1;
|
||||
hyperpoint ctr = Hypc;
|
||||
for(int t=0; t<e-s; t++)
|
||||
ctr += orthogonal_move(may_kleinize(hpc[s+t]), dfloor_table[k]);
|
||||
ctr = normalize(ctr);
|
||||
if(vid.pseudohedral) for(int t=0; t<e-s; t++) {
|
||||
hyperpoint v1 = orthogonal_move(may_kleinize(hpc[s+t]), dfloor_table[k]) - ctr;
|
||||
hyperpoint v2 = orthogonal_move(may_kleinize(hpc[s+t+1]), dfloor_table[k]) - ctr;
|
||||
texture_order([&] (ld x, ld y) {
|
||||
hpcpush(normalize(ctr + v1 * x + v2 * y));
|
||||
});
|
||||
|
||||
if(vid.pseudohedral == phInscribed) {
|
||||
hyperpoint ctr = Hypc;
|
||||
for(int t=0; t<e-s; t++)
|
||||
ctr += kleinize(cgi.emb->orthogonal_move(hpc[s+t], dfloor_table[k]));
|
||||
ctr = normalize(ctr);
|
||||
|
||||
for(int t=0; t<e-s; t++) {
|
||||
hyperpoint v1 = kleinize(cgi.emb->orthogonal_move(hpc[s+t], dfloor_table[k])) - ctr;
|
||||
hyperpoint v2 = kleinize(cgi.emb->orthogonal_move(hpc[s+t+1], dfloor_table[k])) - ctr;
|
||||
texture_order([&] (ld x, ld y) {
|
||||
hpcpush(normalize(ctr + v1 * x + v2 * y));
|
||||
});
|
||||
}
|
||||
}
|
||||
if(!vid.pseudohedral) for(int t=0; t<e-s; t++) {
|
||||
hyperpoint v1 = may_kleinize(hpc[s+t]) - C0;
|
||||
hyperpoint v2 = may_kleinize(hpc[s+t+1]) - C0;
|
||||
if(vid.pseudohedral == phCircumscribed) {
|
||||
|
||||
vector<hyperpoint> hs(c->type);
|
||||
hyperpoint z = Hypc; z[2] = dfloor_table[k];
|
||||
hyperpoint ctr = cgi.emb->logical_to_actual(z);
|
||||
for(int t=0; t<c->type; t++) hs[t] = get_circumscribed_corner(c, t, ctr);
|
||||
// for(int t=0; t<c->type; t++) hs[t] = xspinpush0(t * TAU / c->type, 0.2); // kleinize(get_circumscribed_corner(c, t, ctr));
|
||||
|
||||
for(int t=0; t<c->type; t++) {
|
||||
hyperpoint v1 = hs[t] - ctr;
|
||||
hyperpoint v2 = atmod(hs, t+1) - ctr;
|
||||
texture_order([&] (ld x, ld y) {
|
||||
hpcpush(normalize(ctr + v1 * x + v2 * y));
|
||||
});
|
||||
}
|
||||
/* also affect the plain floor */
|
||||
bshape(fsh.b[id], PPR::FLOOR);
|
||||
for(hyperpoint& h: hs) hpcpush(h);
|
||||
hpcpush(hs[0]);
|
||||
}
|
||||
if(vid.pseudohedral == phOFF) for(int t=0; t<e-s; t++) {
|
||||
|
||||
hyperpoint v1 = cgi.emb->actual_to_logical(hpc[s+t]);
|
||||
hyperpoint v2 = cgi.emb->actual_to_logical(hpc[s+t+1]);
|
||||
|
||||
texture_order([&] (ld x, ld y) {
|
||||
hpcpush(
|
||||
orthogonal_move(
|
||||
normalize(C0 + v1 * x + v2 * y)
|
||||
, dfloor_table[k])
|
||||
);
|
||||
hyperpoint a = v1 * x + v2 * y;
|
||||
a[2] = dfloor_table[k];
|
||||
auto c = cgi.emb->logical_to_actual(a);
|
||||
cgi.hpcpush(c);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -708,27 +769,20 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
sizeto(fsh.cone[co], id);
|
||||
bshape(fsh.cone[co][id], fsh.prio);
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
last->tinf = &floor_texture_vertices[fsh.id];
|
||||
last->tinf = get_floor_texture_vertices(fsh.id);
|
||||
last->texture_offset = 0;
|
||||
ld h = (FLOOR - WALL) / (co+1);
|
||||
ld top = co ? (FLOOR + WALL) / 2 : WALL;
|
||||
#if CAP_BT
|
||||
if(bt::in())
|
||||
for(int t=0; t<c->type; t++)
|
||||
texture_order([&] (ld x, ld y) {
|
||||
hyperpoint left = bt::get_corner_horo_coordinates(c, t);
|
||||
hyperpoint right = bt::get_corner_horo_coordinates(c, t+1);
|
||||
hpcpush(orthogonal_move(bt::get_horopoint(left * x + right * y), top + h * (x+y)));
|
||||
});
|
||||
else
|
||||
#endif
|
||||
if(1) {
|
||||
int s = fsh.b[id].s;
|
||||
int e = fsh.b[id].e-1;
|
||||
for(int t=0; t<e-s; t++) {
|
||||
hyperpoint v1 = may_kleinize(hpc[s+t]) - C0;
|
||||
hyperpoint v2 = may_kleinize(hpc[s+t+1]) - C0;
|
||||
texture_order([&] (ld x, ld y) { hpcpush(orthogonal_move(normalize(C0 + v1 * x + v2 * y), top + h * (x+y))); });
|
||||
hyperpoint v1 = cgi.emb->actual_to_logical(hpc[s+t]);
|
||||
hyperpoint v2 = cgi.emb->actual_to_logical(hpc[s+t+1]);
|
||||
texture_order([&] (ld x, ld y) {
|
||||
hyperpoint a = v1 * x + v2 * y; a[2] = top + h * (x+y);
|
||||
hpcpush(cgi.emb->logical_to_actual(a));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -776,6 +830,8 @@ void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, i
|
|||
#endif
|
||||
}
|
||||
|
||||
EX hookset<bool(cell*)> hooks_floorshapes;
|
||||
|
||||
void geometry_information::generate_floorshapes() {
|
||||
|
||||
DEBBI(DF_POLY, ("generate_floorshapes"));
|
||||
|
@ -784,19 +840,23 @@ void geometry_information::generate_floorshapes() {
|
|||
cell model;
|
||||
model.master = &modelh;
|
||||
modelh.c7 = &model;
|
||||
model.type = modelh.type = S7;
|
||||
model.type = modelh.type = FULL_EDGE;
|
||||
|
||||
auto mmerge1 = [&] (int i, int j) { model.c.setspin(i, j, false); modelh.c.setspin(i, j, false); };
|
||||
auto mmerge = [&] (int i, int j) { mmerge1(i, j); mmerge1(j, i); };
|
||||
|
||||
for(int i=0; i<S7; i++) {
|
||||
for(int i=0; i<FULL_EDGE; i++) {
|
||||
model.move(i) = &model;
|
||||
modelh.move(i) = &modelh;
|
||||
model.c.setspin(i, i, false);
|
||||
modelh.c.setspin(i, i, false);
|
||||
}
|
||||
|
||||
if(WDIM == 3) ;
|
||||
model.type = modelh.type = S7;
|
||||
|
||||
if(callhandlers(false, hooks_floorshapes, &model)) ;
|
||||
|
||||
else if(WDIM == 3) ;
|
||||
|
||||
#if CAP_IRR
|
||||
else if(IRREGULAR) {
|
||||
|
@ -822,6 +882,14 @@ void geometry_information::generate_floorshapes() {
|
|||
|
||||
else if(inforder::mixed()) { /* will be generated on the fly */ }
|
||||
|
||||
else if(hat::in()) {
|
||||
dynamicval<bool> ncor(approx_nearcorner, true);
|
||||
for(int i=0; i<2; i++) {
|
||||
modelh.c7 = i == 1 ? &model : nullptr;
|
||||
generate_floorshapes_for(i, &model, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if CAP_BT
|
||||
else if(kite::in()) {
|
||||
dynamicval<bool> ncor(approx_nearcorner, true);
|
||||
|
@ -836,21 +904,7 @@ void geometry_information::generate_floorshapes() {
|
|||
|
||||
#if CAP_ARCM
|
||||
else if(arcm::in()) {
|
||||
arcm::parent_index_of(&modelh) = 0;
|
||||
auto &ac = arcm::current;
|
||||
for(int i=0; i<2*ac.N + 2; i++) {
|
||||
if(ac.regular && i>=2 && i < 2*ac.N) continue;
|
||||
arcm::id_of(&modelh) = i;
|
||||
model.type = isize(ac.triangles[i]);
|
||||
if(DUAL) model.type /= 2, arcm::parent_index_of(&modelh) = !(i&1);
|
||||
|
||||
if(BITRUNCATED)
|
||||
generate_floorshapes_for(i, &model, !arcm::pseudohept(&model), arcm::pseudohept(&model) ? 0 : 1^(i&1));
|
||||
else if(geosupport_football() == 2)
|
||||
generate_floorshapes_for(i, &model, !arcm::pseudohept(&model), i >= 4 ? 1 : 0);
|
||||
else
|
||||
generate_floorshapes_for(i, &model, 0, 0);
|
||||
}
|
||||
/* will be generated on the fly */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -885,7 +939,7 @@ void geometry_information::generate_floorshapes() {
|
|||
ms.c.connect(j, &models[co.sid], co.eid, co.mirror);
|
||||
}
|
||||
}
|
||||
for(int i=0; i<n; i++) generate_floorshapes_for(i, &models[i], 0, 0);
|
||||
for(int i=0; i<n; i++) generate_floorshapes_for(i, &models[i], c.shapes[i].football_type < 2, c.shapes[i].football_type == 0);
|
||||
}
|
||||
|
||||
else if(geometry == gBinary4) {
|
||||
|
@ -946,7 +1000,7 @@ EX namespace gp {
|
|||
bool master = !(li.relative.first||li.relative.second);
|
||||
int cor = master ? S7 : SG6;
|
||||
if(master) li.last_dir = -1;
|
||||
DEBB(DF_GP, (format("last=%d at=%d,%d tot=%d siid=%d sidir=%d cor=%d id=%d\n", li.last_dir, li.relative.first, li.relative.second, li.total_dir, siid, sidir, cor, id)));
|
||||
DEBB(DF_GP, (hr::format("last=%d at=%d,%d tot=%d siid=%d sidir=%d cor=%d id=%d\n", li.last_dir, li.relative.first, li.relative.second, li.total_dir, siid, sidir, cor, id)));
|
||||
|
||||
cgi.generate_floorshapes_for(id, c0, siid, sidir);
|
||||
|
||||
|
@ -1033,6 +1087,23 @@ EX void set_floor(const transmatrix& spin, hpcshape& sh) {
|
|||
qfi.usershape = -1;
|
||||
}
|
||||
|
||||
/** currently only for arcm */
|
||||
EX void ensure_floorshape_generated(int id, cell *c) {
|
||||
hpcshape nul; nul.s = -1;
|
||||
sizeto(cgi.shFloor.b, id, nul);
|
||||
if(cgi.shFloor.b[id].s == -1) {
|
||||
cgi.require_shapes();
|
||||
if(BITRUNCATED)
|
||||
cgi.generate_floorshapes_for(id, c, !arcm::pseudohept(c), arcm::pseudohept(c) ? 0 : 1^(id&1));
|
||||
else if(geosupport_football() == 2)
|
||||
cgi.generate_floorshapes_for(id, c, !arcm::pseudohept(c), id >= 4 ? 1 : 0);
|
||||
else
|
||||
cgi.generate_floorshapes_for(id, c, 0, 0);
|
||||
cgi.finishshape();
|
||||
cgi.extra_vertices();
|
||||
}
|
||||
}
|
||||
|
||||
EX int shvid(cell *c) {
|
||||
return currentmap->shvid(c);
|
||||
}
|
||||
|
@ -1068,7 +1139,6 @@ int hrmap_standard::shvid(cell *c) {
|
|||
cgi.crossf = cgi.tessf;
|
||||
|
||||
cgi.require_shapes();
|
||||
println(hlog, "generating floorshapes for ", t);
|
||||
cgi.generate_floorshapes_for(t, &model, 0, 0);
|
||||
cgi.finishshape();
|
||||
cgi.extra_vertices();
|
||||
|
@ -1105,12 +1175,14 @@ EX struct dqi_poly *draw_shapevec(cell *c, const shiftmatrix& V, const vector<hp
|
|||
#endif
|
||||
#if CAP_ARCM
|
||||
else if(arcm::in()) {
|
||||
return &queuepolyat(V, shv[shvid(c)], col, prio);
|
||||
int id = shvid(c);
|
||||
ensure_floorshape_generated(id, c);
|
||||
return &queuepolyat(V, shv[id], col, prio);
|
||||
}
|
||||
#endif
|
||||
else if(GOLDBERG && ishex1(c))
|
||||
return &queuepolyat(V * pispin, shv[0], col, prio);
|
||||
else if(!(S7&1) && PURE && !kite::in() && !a4) {
|
||||
else if(!(S7&1) && PURE && !aperiodic && !a4) {
|
||||
auto si = patterns::getpatterninfo(c, patterns::PAT_COLORING, 0);
|
||||
if(si.id == 8) si.dir++;
|
||||
transmatrix D = applyPatterndir(c, si);
|
||||
|
@ -1213,7 +1285,7 @@ void draw_shape_for_texture(floorshape* sh) {
|
|||
queuepoly(shiftless(eupush(gx+a, gy+b)), sh->b[0], 0xFFFFFFFF);
|
||||
|
||||
if(sh == &cgi.shCrossFloor) {
|
||||
queuepoly(shiftless(eupush(gx, gy) * spin(M_PI/4)), cgi.shCross, 0x808080FF);
|
||||
queuepoly(shiftless(eupush(gx, gy) * spin(45._deg)), cgi.shCross, 0x808080FF);
|
||||
}
|
||||
|
||||
if(1) {
|
||||
|
@ -1232,15 +1304,17 @@ void draw_shape_for_texture(floorshape* sh) {
|
|||
ld d = hdist(h1, h2);
|
||||
hyperpoint h3 = h1 + (h2-h1) /d * min(d, .1);
|
||||
for(int a=0; a<4; a++) {
|
||||
curvepoint(eupush(gx,gy) * eupush(spin(90*degree*a) * h1) * C0);
|
||||
curvepoint(eupush(gx,gy) * eupush(spin(90*degree*a) * h3) * C0);
|
||||
curvepoint(eupush(gx,gy) * eupush(spin(90._deg*a) * h1) * C0);
|
||||
curvepoint(eupush(gx,gy) * eupush(spin(90._deg*a) * h3) * C0);
|
||||
queuecurve(shiftless(Id), 0x10101010, 0, PPR::LINE);
|
||||
}
|
||||
}
|
||||
|
||||
auto& ftv = floor_texture_vertices[sh->id];
|
||||
ftv.tvertices.clear();
|
||||
ftv.texture_id = floor_textures->renderedTexture;
|
||||
auto ftv = get_floor_texture_vertices(sh->id);
|
||||
if(ftv) {
|
||||
ftv->tvertices.clear();
|
||||
ftv->texture_id = floor_textures->renderedTexture;
|
||||
}
|
||||
|
||||
hyperpoint center = eupush(gx, gy) * C0;
|
||||
hyperpoint v1 = hpxyz3(sd, sd, 0, 0);
|
||||
|
@ -1268,9 +1342,9 @@ void draw_shape_for_texture(floorshape* sh) {
|
|||
};
|
||||
|
||||
// SL2 needs 6 times more
|
||||
texture_order([&] (ld x, ld y) {
|
||||
if(ftv) texture_order([&] (ld x, ld y) {
|
||||
auto v = tvec_at(x, y);
|
||||
ftv.tvertices.push_back(glhr::makevertex(v[0], v[1], 0));
|
||||
ftv->tvertices.push_back(glhr::makevertex(v[0], v[1], 0));
|
||||
});
|
||||
|
||||
floor_texture_square_size = 2 * (tvec_at(1, 0)[0] - tvec_at(0, 0)[0]);
|
||||
|
@ -1287,11 +1361,12 @@ EX void ensure_vertex_number(basic_textureinfo& bti, int qty) {
|
|||
|
||||
/** ensure_vertex_number for a hpcshape */
|
||||
EX void ensure_vertex_number(hpcshape& sh) {
|
||||
if(!sh.tinf) return;
|
||||
ensure_vertex_number(*sh.tinf, sh.e - sh.s);
|
||||
}
|
||||
|
||||
EX void bind_floor_texture(hpcshape& li, int id) {
|
||||
li.tinf = &floor_texture_vertices[id];
|
||||
li.tinf = get_floor_texture_vertices(id);
|
||||
ensure_vertex_number(li);
|
||||
}
|
||||
|
||||
|
@ -1306,7 +1381,7 @@ void geometry_information::make_floor_textures_here() {
|
|||
vid.xres = FLOORTEXTURESIZE;
|
||||
vid.yres = FLOORTEXTURESIZE;
|
||||
pconf.scale = 0.125;
|
||||
pconf.camera_angle = 0;
|
||||
dynamicval<transmatrix> vm(pconf.cam(), Id);
|
||||
pconf.alpha = 1;
|
||||
dynamicval<ld> lw(vid.linewidth, 2);
|
||||
|
||||
|
@ -1391,7 +1466,9 @@ EX void make_floor_textures() {
|
|||
dynamicval<eModel> gm(pmodel, mdDisk);
|
||||
dynamicval<eVariation> va(variation, eVariation::pure);
|
||||
dynamicval<geometryinfo1> gie(ginf[geometry].g, giEuclid2);
|
||||
dynamicval<flagtype> gief(ginf[geometry].flags, qOPTQ);
|
||||
dynamicval<geometryinfo1> gih(ginf[gNormal].g, giHyperb2);
|
||||
dynamicval<flagtype> gihf(ginf[gNormal].flags, 0);
|
||||
dynamicval<bool> a3(vid.always3, false);
|
||||
dynamicval<bool> hq(inHighQual, true);
|
||||
dynamicval<int> hd(darken, 0);
|
||||
|
|
6
game.cpp
6
game.cpp
|
@ -266,6 +266,10 @@ EX void activateSafety(eLand l) {
|
|||
save_turns = turncount;
|
||||
}
|
||||
#endif
|
||||
if(items[itOrbChoice]) {
|
||||
items[itOrbChoice] = 0;
|
||||
cwt.at->item = itOrbSafety;
|
||||
}
|
||||
}
|
||||
|
||||
EX void placeGolem(cell *on, cell *moveto, eMonster m) {
|
||||
|
@ -343,6 +347,8 @@ EX void pushThumper(const movei& mi) {
|
|||
if(w == waThumperOn)
|
||||
explode = 2;
|
||||
}
|
||||
if(w == waExplosiveBarrel && cto->wall == waMineMine)
|
||||
explode = 2;
|
||||
destroyTrapsOn(cto);
|
||||
if(cto->wall == waOpenPlate || cto->wall == waClosePlate) {
|
||||
toggleGates(cto, cto->wall);
|
||||
|
|
188
geom-exp.cpp
188
geom-exp.cpp
|
@ -152,11 +152,8 @@ void validity_info() {
|
|||
EX bool showquotients;
|
||||
|
||||
string validclasses[4] = {" (X)", " (½)", "", " (!)"};
|
||||
|
||||
EX void ge_land_selection() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen();
|
||||
|
||||
EX void gen_landvisited() {
|
||||
if(cheater) for(int i=0; i<landtypes; i++) landvisited[i] = true;
|
||||
|
||||
for(int i=0; i<landtypes; i++)
|
||||
|
@ -177,6 +174,13 @@ EX void ge_land_selection() {
|
|||
landvisited[laCamelot] |= hiitemsMax(treasureType(laCamelot)) >= 1;
|
||||
landvisited[laCA] = true;
|
||||
landvisited[laAsteroids] = true;
|
||||
}
|
||||
|
||||
EX void ge_land_selection() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen();
|
||||
|
||||
gen_landvisited();
|
||||
|
||||
dialog::init(XLAT("select the starting land"));
|
||||
if(dialog::infix != "") mouseovers = dialog::infix;
|
||||
|
@ -187,17 +191,17 @@ EX void ge_land_selection() {
|
|||
});
|
||||
stable_sort(landlist.begin(), landlist.end(), [] (eLand l1, eLand l2) { return land_validity(l1).quality_level > land_validity(l2).quality_level; });
|
||||
|
||||
for(int i=0; i<euperpage; i++) {
|
||||
if(euperpage * eupage + i >= isize(landlist)) { dialog::addBreak(100); break; }
|
||||
eLand l = landlist[euperpage * eupage + i];
|
||||
char ch = '1'+i;
|
||||
dialog::start_list(900, 900, '1');
|
||||
|
||||
for(auto& l: landlist) {
|
||||
|
||||
string s = XLAT1(linf[l].name);
|
||||
|
||||
if(landvisited[l]) {
|
||||
dialog::addBoolItem(s, l == specialland, ch);
|
||||
dialog::addBoolItem(s, l == specialland, dialog::list_fake_key++);
|
||||
}
|
||||
else {
|
||||
dialog::addSelItem(s, XLAT("(locked)"), ch);
|
||||
dialog::addSelItem(s, XLAT("(locked)"), dialog::list_fake_key++);
|
||||
}
|
||||
|
||||
dialog::lastItem().color = linf[l].color;
|
||||
|
@ -217,13 +221,13 @@ EX void ge_land_selection() {
|
|||
}));
|
||||
});
|
||||
}
|
||||
dialog::addItem(XLAT("next page"), '-');
|
||||
dialog::addInfo(XLAT("press letters to search"));
|
||||
dialog::end_list();
|
||||
|
||||
dialog::addBreak(25);
|
||||
validity_info();
|
||||
dialog::addBreak(25);
|
||||
|
||||
dialog::addInfo(XLAT("press letters to search"));
|
||||
dual::add_choice();
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
|
@ -231,11 +235,7 @@ EX void ge_land_selection() {
|
|||
keyhandler = [] (int sym, int uni) {
|
||||
dialog::handleNavigation(sym, uni);
|
||||
|
||||
if(uni == '-' || uni == PSEUDOKEY_WHEELUP || uni == PSEUDOKEY_WHEELDOWN) {
|
||||
eupage++;
|
||||
if(eupage * euperpage >= isize(landlist)) eupage = 0;
|
||||
}
|
||||
else if(dialog::editInfix(uni)) eupage = 0;
|
||||
if(dialog::editInfix(uni)) dialog::list_skip = 0;
|
||||
else if(doexiton(sym, uni)) popScreen();
|
||||
};
|
||||
}
|
||||
|
@ -249,6 +249,7 @@ EX void activate_ge_land_selection() {
|
|||
#if HDR
|
||||
struct geometry_filter {
|
||||
string name;
|
||||
int hotkey;
|
||||
/** test if the current geometry matches the filter */
|
||||
function<bool()> test;
|
||||
};
|
||||
|
@ -258,22 +259,24 @@ EX geometry_filter *current_filter;
|
|||
|
||||
bool forced_quotient() { return quotient && !(cgflags & qOPTQ); }
|
||||
|
||||
EX geometry_filter gf_hyperbolic = {"hyperbolic", [] { return (arcm::in() || arb::in() || hyperbolic) && !forced_quotient(); }};
|
||||
EX geometry_filter gf_spherical = {"spherical", [] { return (arcm::in() || arb::in() || sphere) && !forced_quotient(); }};
|
||||
EX geometry_filter gf_euclidean = {"Euclidean", [] { return (arcm::in() || arb::in() || euclid) && !forced_quotient(); }};
|
||||
EX geometry_filter gf_other = {"non-isotropic", [] { return prod || nonisotropic; }};
|
||||
EX geometry_filter gf_regular_2d = {"regular 2D tesselations", [] {
|
||||
EX geometry_filter gf_hyperbolic = {"hyperbolic", 'h', [] { return (arcm::in() || arb::in() || hyperbolic) && !forced_quotient(); }};
|
||||
EX geometry_filter gf_spherical = {"spherical", 's', [] { return (arcm::in() || arb::in() || sphere) && !forced_quotient(); }};
|
||||
EX geometry_filter gf_euclidean = {"Euclidean", 'e', [] { return (arcm::in() || arb::in() || euclid) && !forced_quotient(); }};
|
||||
EX geometry_filter gf_other = {"non-isotropic", 'n', [] { return mproduct || nonisotropic; }};
|
||||
EX geometry_filter gf_regular_2d = {"regular 2D tesselations", 'r', [] {
|
||||
return standard_tiling() && WDIM == 2 && !forced_quotient();
|
||||
}};
|
||||
EX geometry_filter gf_regular_3d = {"regular 3D honeycombs", [] {
|
||||
EX geometry_filter gf_regular_3d = {"regular 3D honeycombs", '3', [] {
|
||||
if(euclid) return geometry == gCubeTiling;
|
||||
return !bt::in() && !kite::in() && WDIM == 3 && !forced_quotient() && !nonisotropic && !prod;
|
||||
return !bt::in() && !kite::in() && WDIM == 3 && !forced_quotient() && !nonisotropic && !mproduct;
|
||||
}};
|
||||
EX geometry_filter gf_quotient = {"interesting quotient spaces", [] {
|
||||
EX geometry_filter gf_quotient = {"interesting quotient spaces", 'q', [] {
|
||||
return forced_quotient() && !elliptic;
|
||||
}};
|
||||
EX geometry_filter gf_tes_file = {"load from file", 'f', [] { return arb::in(); }};
|
||||
EX geometry_filter gf_no_filters = {"no filters", '-', [] { return true; }};
|
||||
|
||||
EX vector<geometry_filter*> available_filters = { &gf_hyperbolic, &gf_spherical, &gf_euclidean, &gf_other, &gf_regular_2d, &gf_regular_3d, &gf_quotient };
|
||||
EX vector<geometry_filter*> available_filters = { &gf_hyperbolic, &gf_spherical, &gf_euclidean, &gf_other, &gf_regular_2d, &gf_regular_3d, &gf_quotient, &gf_tes_file, &gf_no_filters };
|
||||
|
||||
void ge_select_filter() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
|
@ -281,12 +284,11 @@ void ge_select_filter() {
|
|||
|
||||
dialog::init(XLAT("geometries"));
|
||||
|
||||
char x = 'a';
|
||||
for(auto f: available_filters) {
|
||||
if(current_filter)
|
||||
dialog::addBoolItem(XLAT(f->name), f == current_filter, x++);
|
||||
dialog::addBoolItem(XLAT(f->name), f == current_filter, f->hotkey);
|
||||
else
|
||||
dialog::addItem(XLAT(f->name), x++);
|
||||
dialog::addItem(XLAT(f->name), f->hotkey);
|
||||
dialog::add_action([f] { current_filter = f; popScreen(); });
|
||||
}
|
||||
|
||||
|
@ -324,7 +326,7 @@ void set_or_configure_geometry(eGeometry g) {
|
|||
if(g == gRotSpace) {
|
||||
bool ok = true;
|
||||
if(arcm::in()) ok = PURE;
|
||||
else if(bt::in() || kite::in()) ok = false;
|
||||
else if(bt::in() || aperiodic) ok = false;
|
||||
else ok = PURE || BITRUNCATED;
|
||||
if(!ok) {
|
||||
addMessage(XLAT("Only works with (semi-)regular tilings"));
|
||||
|
@ -348,9 +350,11 @@ void set_or_configure_geometry(eGeometry g) {
|
|||
|
||||
/** is g2 the same tiling as the current geometry (geometry)? */
|
||||
bool same_tiling(eGeometry g2) {
|
||||
/* no quotients for fractals */
|
||||
if(cgflags & qFRACTAL) return g2 == geometry;
|
||||
if(g2 == gCrystal)
|
||||
return S3 == 4;
|
||||
if(g2 == gFieldQuotient && hyperbolic && standard_tiling())
|
||||
if(g2 == gFieldQuotient && (hyperbolic || (geometry == gCubeTiling && reg3::cubes_reg3)) && standard_tiling())
|
||||
return true;
|
||||
if(g2 == gFieldQuotient && geometry != gFieldQuotient) {
|
||||
int ce = 0;
|
||||
|
@ -366,6 +370,7 @@ bool same_tiling(eGeometry g2) {
|
|||
}
|
||||
|
||||
void ge_select_tiling() {
|
||||
if(current_filter == &gf_tes_file) { popScreen(); set_or_configure_geometry(gArbitrary); }
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen();
|
||||
|
||||
|
@ -378,7 +383,8 @@ void ge_select_tiling() {
|
|||
|
||||
dialog::addBreak(100);
|
||||
|
||||
char letter = 'a';
|
||||
dialog::start_list(500, 1500, 'a');
|
||||
|
||||
for(int i=0; i<isize(ginf); i++) {
|
||||
eGeometry g = eGeometry(i);
|
||||
if(among(g, gProduct, gRotSpace)) hybrid::configure(g);
|
||||
|
@ -406,11 +412,12 @@ void ge_select_tiling() {
|
|||
dialog::addBoolItem(
|
||||
is_product ? XLAT("current geometry x E") :
|
||||
is_rotspace ? XLAT("space of rotations in current geometry") :
|
||||
XLAT(ginf[g].menu_displayed_name), on, letter++);
|
||||
XLAT(ginf[g].menu_displayed_name), on, dialog::list_fake_key++);
|
||||
dialog::lastItem().value += validclasses[land_validity(specialland).quality_level];
|
||||
dialog::add_action([g] { set_or_configure_geometry(g); });
|
||||
}
|
||||
|
||||
dialog::end_list();
|
||||
dialog::addBreak(100);
|
||||
dual::add_choice();
|
||||
dialog::addBack();
|
||||
|
@ -506,34 +513,27 @@ EX void showQuotientConfig3() {
|
|||
}
|
||||
#endif
|
||||
|
||||
EX string geometry_name() {
|
||||
switch(ginf[geometry].cclass) {
|
||||
EX string geometry_name(eGeometryClass gc) {
|
||||
switch(gc) {
|
||||
case gcHyperbolic:
|
||||
return XLAT("hyperbolic") + dim_name();
|
||||
return XLAT("hyperbolic");
|
||||
|
||||
case gcEuclid:
|
||||
if(cgflags & qAFFINE)
|
||||
return XLAT("affine") + dim_name();
|
||||
return XLAT("flat") + dim_name();
|
||||
return XLAT("affine");
|
||||
return XLAT("flat");
|
||||
|
||||
case gcSphere:
|
||||
return XLAT("spherical") + dim_name();
|
||||
return XLAT("spherical");
|
||||
|
||||
case gcSolNIH:
|
||||
#if CAP_SOLV
|
||||
switch(sn::geom()) {
|
||||
case gSol:
|
||||
return XLAT("Sol");
|
||||
case gNIH:
|
||||
return XLAT("hyperbolic (3:2)");
|
||||
case gSolN:
|
||||
return XLAT("Sol (3:2)");
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
#else
|
||||
case gcSol:
|
||||
return XLAT("Sol");
|
||||
#endif
|
||||
|
||||
case gcNIH:
|
||||
return XLAT("hyperbolic (3:2)");
|
||||
|
||||
case gcSolN:
|
||||
return XLAT("Sol (3:2)");
|
||||
|
||||
case gcNil:
|
||||
return XLAT("Nil");
|
||||
|
@ -547,6 +547,19 @@ EX string geometry_name() {
|
|||
return "?";
|
||||
}
|
||||
|
||||
EX string geometry_name() {
|
||||
if(cgi.emb && cgi.emb->is_same_in_same())
|
||||
return geometry_name(geom3::mgclass());
|
||||
else if(embedded_plane && gproduct)
|
||||
return geometry_name(geom3::mgclass()) + " (x E)";
|
||||
else if(embedded_plane)
|
||||
return geometry_name(geom3::mgclass()) + " @ " + geometry_name(geom3::ggclass());
|
||||
else if(among(ginf[geometry].cclass, gcHyperbolic, gcEuclid, gcSphere))
|
||||
return geometry_name(ginf[geometry].cclass) + dim_name();
|
||||
else
|
||||
return geometry_name(ginf[geometry].cclass);
|
||||
}
|
||||
|
||||
EX void select_quotient_screen() {
|
||||
cmode = sm::SIDE | sm::MAYDARK;
|
||||
gamescreen();
|
||||
|
@ -595,7 +608,7 @@ EX void select_quotient_screen() {
|
|||
}
|
||||
|
||||
EX void select_quotient() {
|
||||
if(euclid && !kite::in() && !arcm::in()) {
|
||||
if(meuclid && !aperiodic && !arcm::in() && !reg3::cubes_reg3 && !(cgflags & qFRACTAL)) {
|
||||
euc::prepare_torus3();
|
||||
pushScreen(euc::show_torus3);
|
||||
}
|
||||
|
@ -609,7 +622,7 @@ EX void select_quotient() {
|
|||
pushScreen(asonov::show_config);
|
||||
}
|
||||
#endif
|
||||
else if(prod)
|
||||
else if(mproduct)
|
||||
pushScreen(product::show_config);
|
||||
else if(rotspace)
|
||||
hybrid::configure_period();
|
||||
|
@ -633,7 +646,7 @@ EX void select_quotient() {
|
|||
EX string full_geometry_name() {
|
||||
string qstring = ginf[geometry].quotient_name;
|
||||
bool variable =
|
||||
!(prod || hybri || bt::in() || (WDIM == 3 && !reg3::in()) || kite::in() || arb::in());
|
||||
!(mproduct || mhybrid || bt::in() || (WDIM == 3 && !reg3::in()) || aperiodic || arb::in());
|
||||
|
||||
string fgname = XLAT(ginf[geometry].tiling_name);
|
||||
if(qstring != "none") fgname += " " + XLAT(qstring);
|
||||
|
@ -650,7 +663,7 @@ void action_change_variation() {
|
|||
else if(arcm::in()) arcm::next_variation();
|
||||
#endif
|
||||
#if MAXMDIM >= 4
|
||||
else if(reg3::in()) reg3::configure_variation();
|
||||
else if(reg3::in() || geometry == gCubeTiling) reg3::configure_variation();
|
||||
#endif
|
||||
else if(euc::in(2,4) || !CAP_GP) dialog::do_if_confirmed([] {
|
||||
set_variation(PURE ? eVariation::bitruncated : eVariation::pure);
|
||||
|
@ -681,7 +694,7 @@ EX void menuitem_binary_width(char key) {
|
|||
dialog::addSelItem(XLAT("binary tiling width"), fts(vid.binary_width), key);
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(vid.binary_width, 0, 2, 0.1, 1, XLAT("binary tiling width"), "");
|
||||
dialog::reaction = [] () {
|
||||
dialog::get_ne().reaction = [] () {
|
||||
#if CAP_TEXTURE
|
||||
texture::config.remap();
|
||||
#endif
|
||||
|
@ -696,7 +709,7 @@ EX void menuitem_nilwidth(char key) {
|
|||
dialog::addSelItem(XLAT("Nil width"), fts(nilv::nilwidth), key);
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(nilv::nilwidth, 0.01, 2, 0.1, 1, XLAT("Nil width"), "");
|
||||
dialog::reaction = ray::reset_raycaster;
|
||||
dialog::get_ne().reaction = ray::reset_raycaster;
|
||||
dialog::bound_low(0.01);
|
||||
});
|
||||
}
|
||||
|
@ -710,7 +723,7 @@ EX void edit_stretch() {
|
|||
"Value of 0 means not stretched, -1 means S2xE or H2xE (works only in the limit). (Must be > -1)"
|
||||
)
|
||||
);
|
||||
dialog::reaction = [] { if(abs(stretch::factor+1) < 1e-3) stretch::factor = -.9; ray::reset_raycaster(); };
|
||||
dialog::get_ne().reaction = [] { if(abs(stretch::factor+1) < 1e-3) stretch::factor = -.9; ray::reset_raycaster(); };
|
||||
}
|
||||
|
||||
#if HDR
|
||||
|
@ -760,9 +773,9 @@ EX geometry_data compute_geometry_data() {
|
|||
gd.area = PURE ? 1 : 3;
|
||||
|
||||
gd.euler = 0;
|
||||
if(euclid) gd.euler = 0;
|
||||
else if(sphere && nonorientable) gd.euler = 1;
|
||||
else if(sphere) gd.euler = 2;
|
||||
if(meuclid) gd.euler = 0;
|
||||
else if(msphere && nonorientable) gd.euler = 1;
|
||||
else if(msphere) gd.euler = 2;
|
||||
else if(!closed_manifold) gd.euler = -2;
|
||||
else if(WDIM == 3) gd.euler = 0;
|
||||
else switch(geometry) {
|
||||
|
@ -805,7 +818,7 @@ EX geometry_data compute_geometry_data() {
|
|||
gd.nom *= gd.euler;
|
||||
gd.denom *= 2;
|
||||
|
||||
if(hybri) gd.nom *= hybrid::csteps, gd.denom *= cgi.single_step;
|
||||
if(mhybrid) gd.nom *= hybrid::csteps, gd.denom *= cgi.single_step;
|
||||
|
||||
int g = gcd(gd.nom, gd.denom);
|
||||
if(g) {
|
||||
|
@ -900,7 +913,7 @@ EX geometry_data compute_geometry_data() {
|
|||
gd.size_str =
|
||||
disksize ? its(isize(currentmap->allcells())) :
|
||||
#if CAP_BT
|
||||
bt::in() ? fts(8 * M_PI * sqrt(2) * log(2) / pow(vid.binary_width, WDIM-1), 4) + " exp(∞)" :
|
||||
bt::in() ? fts(1440._deg * sqrt(2) * log(2) / pow(vid.binary_width, WDIM-1), 4) + " exp(∞)" :
|
||||
#endif
|
||||
#if CAP_ARCM
|
||||
arcm::in() && (WDIM == 2) ? arcm::current.world_size() :
|
||||
|
@ -931,6 +944,13 @@ EX geometry_data compute_geometry_data() {
|
|||
return gd;
|
||||
}
|
||||
|
||||
EX void add_size_action() {
|
||||
if(WDIM == 2 || reg3::exact_rules()) dialog::add_action([] {
|
||||
if(!viewdists) { enable_viewdists(); pushScreen(viewdist_configure_dialog); }
|
||||
else if(viewdists) viewdists = false;
|
||||
});
|
||||
}
|
||||
|
||||
EX void showEuclideanMenu() {
|
||||
// for(int i=2; i<lt; i++) landvisited[i] = true;
|
||||
|
||||
|
@ -949,6 +969,7 @@ EX void showEuclideanMenu() {
|
|||
});
|
||||
|
||||
string qstring = ginf[geometry].quotient_name;
|
||||
if(meuclid && quotient) qstring = ONOFF(true);
|
||||
|
||||
if(qstring == "none")
|
||||
dialog::addBoolItem(XLAT("quotient space"), false, 'q');
|
||||
|
@ -987,6 +1008,7 @@ EX void showEuclideanMenu() {
|
|||
dialog::add_action_push(arb::set_sliders);
|
||||
}
|
||||
if(arb::is_apeirogonal()) add_edit(arb::apeirogon_simplified_display);
|
||||
if(arb::in()) add_edit(debug_tiles);
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(cgflags & qULTRA) {
|
||||
|
@ -998,13 +1020,14 @@ EX void showEuclideanMenu() {
|
|||
}
|
||||
#endif
|
||||
|
||||
if(prod) {
|
||||
if(mproduct) {
|
||||
dialog::addSelItem(XLAT("Z-level height factor"), fts(vid.plevel_factor), 'Z');
|
||||
dialog::add_action([] {
|
||||
dialog::editNumber(vid.plevel_factor, 0, 2, 0.1, 0.7, XLAT("Z-level height factor"), "");
|
||||
dialog::get_ne().reaction = ray::reset_raycaster;
|
||||
});
|
||||
}
|
||||
else if(hybri) {
|
||||
else if(mhybrid) {
|
||||
dialog::addSelItem(XLAT("number of levels"), its(hybrid::csteps / cgi.single_step), 'L');
|
||||
dialog::add_action(hybrid::configure_period);
|
||||
}
|
||||
|
@ -1012,10 +1035,16 @@ EX void showEuclideanMenu() {
|
|||
menuitem_binary_width('v');
|
||||
add_edit_wall_quality('W');
|
||||
}
|
||||
else if(hat::in()) {
|
||||
add_edit(hat::hat_param);
|
||||
add_edit(hat::hat_param_imag);
|
||||
}
|
||||
else if(nil) {
|
||||
menuitem_nilwidth('v');
|
||||
}
|
||||
else if((WDIM == 3 || kite::in() || arb::in()) && !reg3::in()) dialog::addBreak(100);
|
||||
else if((WDIM == 3 || aperiodic || arb::in()) && !reg3::in() && geometry != gCubeTiling) dialog::addBreak(100);
|
||||
else if(cgclass & qFRACTAL)
|
||||
dialog::addBreak(100);
|
||||
else
|
||||
menuitem_change_variation('v');
|
||||
|
||||
|
@ -1034,7 +1063,7 @@ EX void showEuclideanMenu() {
|
|||
}
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
if(hybri) {
|
||||
if(mhybrid) {
|
||||
auto r = rots::underlying_scale;
|
||||
dialog::addSelItem(XLAT("view the underlying geometry"), r > 0 ? fts(r)+"x" : ONOFF(false), '6');
|
||||
dialog::add_action([] {
|
||||
|
@ -1049,7 +1078,7 @@ EX void showEuclideanMenu() {
|
|||
);
|
||||
dialog::bound_low(0);
|
||||
dialog::bound_up(1);
|
||||
dialog::extra_options = [] () { rots::draw_underlying(true); };
|
||||
dialog::get_di().extra_options = [] () { rots::draw_underlying(true); };
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
@ -1068,11 +1097,11 @@ EX void showEuclideanMenu() {
|
|||
dialog::add_action([] {
|
||||
dialog::editNumber(bounded_mine_quantity, 0, bounded_mine_max, 1, (bounded_mine_max+5)/10,
|
||||
XLAT("number of mines"), "");
|
||||
dialog::reaction = [] {
|
||||
dialog::get_ne().reaction = [] {
|
||||
if(bounded_mine_quantity < 0) bounded_mine_quantity = 0;
|
||||
if(bounded_mine_quantity > bounded_mine_max) bounded_mine_quantity = bounded_mine_max;
|
||||
};
|
||||
dialog::reaction_final = [] {
|
||||
dialog::get_ne().reaction_final = [] {
|
||||
bounded_mine_percentage = bounded_mine_quantity * 1. / bounded_mine_max;
|
||||
stop_game();
|
||||
start_game();
|
||||
|
@ -1091,7 +1120,7 @@ EX void showEuclideanMenu() {
|
|||
}
|
||||
|
||||
dialog::addBoolItem(XLAT("pattern"), specialland == laCanvas, 'p');
|
||||
if(specialland == laCanvas) dialog::lastItem().value = patterns::whichCanvas;
|
||||
if(specialland == laCanvas) dialog::lastItem().value = ccolor::which->name;
|
||||
dialog::add_action_push(patterns::showPrePattern);
|
||||
validity_info();
|
||||
if(WDIM == 3) {
|
||||
|
@ -1099,8 +1128,9 @@ EX void showEuclideanMenu() {
|
|||
dialog::add_action_push(show3D);
|
||||
}
|
||||
menuitem_projection('1');
|
||||
if(nonisotropic && !sl2)
|
||||
dialog::addBoolItem_action(XLAT("geodesic movement in Sol/Nil"), nisot::geodesic_movement, 'G');
|
||||
if(lie_movement_available()) {
|
||||
add_edit(nisot::geodesic_movement);
|
||||
}
|
||||
#if CAP_CRYSTAL && MAXMDIM >= 4
|
||||
crystal::add_crystal_transform('x');
|
||||
#endif
|
||||
|
@ -1120,7 +1150,7 @@ EX void showEuclideanMenu() {
|
|||
dialog::addTitle(XLAT("info about: %1", full_geometry_name()), 0xFFFFFF, 150);
|
||||
|
||||
auto gd = compute_geometry_data();
|
||||
if(WDIM == 2 && !arb::in() && !kite::in()) dialog::addSelItem(XLAT("faces per vertex"), gd.spf, 0);
|
||||
if(WDIM == 2 && !arb::in() && !aperiodic) dialog::addSelItem(XLAT("faces per vertex"), gd.spf, 0);
|
||||
|
||||
if(arb::in() && arb::current.comment != "") {
|
||||
dialog::addBreak(100);
|
||||
|
@ -1128,11 +1158,7 @@ EX void showEuclideanMenu() {
|
|||
}
|
||||
|
||||
dialog::addSelItem(XLAT("size of the world"), gd.size_str, '3');
|
||||
|
||||
if(WDIM == 2 || reg3::in_rule()) dialog::add_action([] {
|
||||
if(!viewdists) { enable_viewdists(); pushScreen(viewdist_configure_dialog); }
|
||||
else if(viewdists) viewdists = false;
|
||||
});
|
||||
add_size_action();
|
||||
|
||||
if(closed_manifold) {
|
||||
dialog::addSelItem(XLAT("Euler characteristics"), its(gd.euler), 0);
|
||||
|
|
445
geometry.cpp
445
geometry.cpp
|
@ -22,7 +22,7 @@ struct usershapelayer {
|
|||
|
||||
extern int usershape_changes;
|
||||
|
||||
static const int USERLAYERS = 32;
|
||||
static constexpr int USERLAYERS = 32;
|
||||
|
||||
struct usershape { usershapelayer d[USERLAYERS]; };
|
||||
|
||||
|
@ -35,6 +35,7 @@ struct hpcshape {
|
|||
int texture_offset;
|
||||
int shs, she;
|
||||
void clear() { s = e = shs = she = texture_offset = 0; prio = PPR::ZERO; tinf = NULL; flags = 0; }
|
||||
hpcshape() { clear(); }
|
||||
};
|
||||
|
||||
#define SIDE_SLEV 0
|
||||
|
@ -56,15 +57,15 @@ struct hpcshape {
|
|||
#define GOLDBERG_BITS 5
|
||||
#endif
|
||||
|
||||
static const int GOLDBERG_LIMIT = (1<<GOLDBERG_BITS);
|
||||
static const int GOLDBERG_MASK = (GOLDBERG_LIMIT-1);
|
||||
static constexpr int GOLDBERG_LIMIT = (1<<GOLDBERG_BITS);
|
||||
static constexpr int GOLDBERG_MASK = (GOLDBERG_LIMIT-1);
|
||||
|
||||
#ifndef BADMODEL
|
||||
#define BADMODEL 0
|
||||
#endif
|
||||
|
||||
#ifndef WINGS
|
||||
static const int WINGS = (BADMODEL ? 1 : 4);
|
||||
static constexpr int WINGS = (BADMODEL ? 1 : 4);
|
||||
#endif
|
||||
|
||||
typedef array<hpcshape, WINGS+1> hpcshape_animated;
|
||||
|
@ -142,6 +143,10 @@ struct subcellshape {
|
|||
void compute_common();
|
||||
};
|
||||
|
||||
enum class ePipeEnd {sharp, ball};
|
||||
|
||||
struct embedding_method;
|
||||
|
||||
/** basic geometry parameters */
|
||||
struct geometry_information {
|
||||
|
||||
|
@ -189,7 +194,6 @@ struct geometry_information {
|
|||
|
||||
vector<transmatrix> ultra_mirrors;
|
||||
|
||||
vector<pair<string, string> > rels;
|
||||
int xp_order, r_order, rx_order;
|
||||
|
||||
transmatrix full_X, full_R, full_P;
|
||||
|
@ -198,6 +202,8 @@ struct geometry_information {
|
|||
vector<transmatrix> heptmove, hexmove, invhexmove;
|
||||
|
||||
int base_distlimit;
|
||||
|
||||
unique_ptr<embedding_method> emb;
|
||||
|
||||
/** size of the Sword (from Orb of the Sword), used in the shmup mode */
|
||||
ld sword_size;
|
||||
|
@ -230,7 +236,7 @@ struct geometry_information {
|
|||
BODY, BODY1, BODY2, BODY3,
|
||||
NECK1, NECK, NECK3, HEAD, HEAD1, HEAD2, HEAD3,
|
||||
ALEG0, ALEG, ABODY, AHEAD, BIRD, LOWSKY, SKY, HIGH, HIGH2,
|
||||
SHALLOW;
|
||||
HELL, STAR, SHALLOW;
|
||||
ld human_height, slev;
|
||||
|
||||
ld eyelevel_familiar, eyelevel_human, eyelevel_dog;
|
||||
|
@ -253,16 +259,17 @@ hpcshape
|
|||
shTriheptaSpecial[14],
|
||||
shCross, shGiantStar[2], shLake, shMirror,
|
||||
shHalfFloor[6], shHalfMirror[3],
|
||||
shGem[2], shStar, shDisk, shDiskT, shDiskS, shDiskM, shDiskSq, shRing,
|
||||
shGem[2], shStar, shFlash, shDisk, shHalfDisk, shDiskT, shDiskS, shDiskM, shDiskSq, shEccentricDisk, shDiskSegment,
|
||||
shHeptagon, shHeptagram,
|
||||
shTinyBird, shTinyShark,
|
||||
shEgg,
|
||||
shSpikedRing, shTargetRing, shSawRing, shGearRing, shPeaceRing, shHeptaRing,
|
||||
shSpearRing, shLoveRing,
|
||||
shFrogRing,
|
||||
shPowerGearRing, shProtectiveRing, shTerraRing, shMoveRing, shReserved4, shMoonDisk,
|
||||
shDaisy, shTriangle, shNecro, shStatue, shKey, shWindArrow,
|
||||
shEgg, shSmallEgg,
|
||||
shRing, shSpikedRing, shTargetRing, shSawRing, shGearRing, shPeaceRing,
|
||||
shHeptaRing, shSpearRing, shLoveRing, shFrogRing,
|
||||
shPowerGearRing, shProtectiveRing, shTerraRing, shMoveRing,
|
||||
shReserved4, shMoonDisk,
|
||||
shDaisy, shSnowflake, shTriangle, shNecro, shStatue, shKey, shWindArrow,
|
||||
shGun,
|
||||
shFigurine, shTreat,
|
||||
shFigurine, shTreat, shSmallTreat,
|
||||
shElementalShard,
|
||||
// shBranch,
|
||||
shIBranch, shTentacle, shTentacleX, shILeaf[3],
|
||||
|
@ -276,43 +283,43 @@ hpcshape
|
|||
shWolf1, shWolf2, shWolf3,
|
||||
shRatEye1, shRatEye2, shRatEye3,
|
||||
shDogStripes,
|
||||
shPBody, shPSword, shPKnife,
|
||||
shPBody, shSmallPBody, shPSword, shSmallPSword, shPKnife,
|
||||
shFerocityM, shFerocityF,
|
||||
shHumanFoot, shHumanLeg, shHumanGroin, shHumanNeck, shSkeletalFoot, shYetiFoot,
|
||||
shMagicSword, shMagicShovel, shSeaTentacle, shKrakenHead, shKrakenEye, shKrakenEye2,
|
||||
shMagicSword, shSmallSword, shMagicShovel, shSeaTentacle, shKrakenHead, shKrakenEye, shKrakenEye2,
|
||||
shArrow,
|
||||
shPHead, shPFace, shGolemhead, shHood, shArmor,
|
||||
shAztecHead, shAztecCap,
|
||||
shSabre, shTurban1, shTurban2, shVikingHelmet, shRaiderHelmet, shRaiderArmor, shRaiderBody, shRaiderShirt,
|
||||
shWestHat1, shWestHat2, shGunInHand,
|
||||
shKnightArmor, shKnightCloak, shWightCloak,
|
||||
shGhost, shEyes, shSlime, shJelly, shJoint, shWormHead, shTentHead, shShark, shWormSegment, shSmallWormSegment, shWormTail, shSmallWormTail,
|
||||
shSlimeEyes, shDragonEyes, shWormEyes, shGhostEyes,
|
||||
shMiniGhost, shMiniEyes,
|
||||
shHedgehogBlade, shHedgehogBladePlayer,
|
||||
shGhost, shEyes, shSlime, shJelly, shJoint, shWormHead, shSmallWormHead, shTentHead, shShark, shWormSegment, shSmallWormSegment, shWormTail, shSmallWormTail,
|
||||
shSlimeEyes, shDragonEyes, shSmallDragonEyes, shWormEyes, shSmallWormEyes, shGhostEyes,
|
||||
shMiniGhost, shSmallEyes, shMiniEyes,
|
||||
shHedgehogBlade, shSmallHedgehogBlade, shHedgehogBladePlayer,
|
||||
shWolfBody, shWolfHead, shWolfLegs, shWolfEyes,
|
||||
shWolfFrontLeg, shWolfRearLeg, shWolfFrontPaw, shWolfRearPaw,
|
||||
shFemaleBody, shFemaleHair, shFemaleDress, shWitchDress,
|
||||
shWitchHair, shBeautyHair, shFlowerHair, shFlowerHand, shSuspenders, shTrophy,
|
||||
shBugBody, shBugArmor, shBugLeg, shBugAntenna,
|
||||
shPickAxe, shPike, shFlailBall, shFlailTrunk, shFlailChain, shHammerHead,
|
||||
shPickAxe, shSmallPickAxe, shPike, shFlailBall, shSmallFlailBall, shFlailTrunk, shSmallFlailTrunk, shFlailChain, shHammerHead, shSmallHammerHead,
|
||||
shBook, shBookCover, shGrail,
|
||||
shBoatOuter, shBoatInner, shCompass1, shCompass2, shCompass3,
|
||||
shKnife, shTongue, shFlailMissile, shTrapArrow,
|
||||
shPirateHook, shPirateHood, shEyepatch, shPirateX,
|
||||
shPirateHook, shSmallPirateHook, shPirateHood, shEyepatch, shPirateX,
|
||||
// shScratch,
|
||||
shHeptaMarker, shSnowball, shHugeDisk, shSun, shNightStar, shEuclideanSky,
|
||||
shHeptaMarker, shSnowball, shHugeDisk, shSkyboxSun, shSun, shNightStar, shEuclideanSky,
|
||||
shSkeletonBody, shSkull, shSkullEyes, shFatBody, shWaterElemental,
|
||||
shPalaceGate, shFishTail,
|
||||
shMouse, shMouseLegs, shMouseEyes,
|
||||
shPrincessDress, shPrinceDress,
|
||||
shWizardCape1, shWizardCape2,
|
||||
shBigCarpet1, shBigCarpet2, shBigCarpet3,
|
||||
shGoatHead, shRose, shRoseItem, shThorns,
|
||||
shGoatHead, shRose, shRoseItem, shSmallRose, shThorns,
|
||||
shRatHead, shRatTail, shRatEyes, shRatCape1, shRatCape2,
|
||||
shWizardHat1, shWizardHat2,
|
||||
shTortoise[13][6],
|
||||
shDragonLegs, shDragonTail, shDragonHead, shDragonSegment, shDragonNostril,
|
||||
shDragonLegs, shDragonTail, shDragonHead, shSmallDragonHead, shDragonSegment, shDragonNostril, shSmallDragonNostril,
|
||||
shDragonWings,
|
||||
shSolidBranch, shWeakBranch, shBead0, shBead1,
|
||||
shBatWings, shBatBody, shBatMouth, shBatFang, shBatEye,
|
||||
|
@ -325,6 +332,8 @@ hpcshape
|
|||
shTrylobiteFrontLeg, shTrylobiteRearLeg, shTrylobiteFrontClaw, shTrylobiteRearClaw,
|
||||
|
||||
shBullBody, shBullHead, shBullHorn, shBullRearHoof, shBullFrontHoof,
|
||||
shSmallBullHead, shSmallBullHorn,
|
||||
shTinyBullHead, shTinyBullHorn, shTinyBullBody,
|
||||
|
||||
shButterflyBody, shButterflyWing, shGadflyBody, shGadflyWing, shGadflyEye,
|
||||
|
||||
|
@ -337,9 +346,12 @@ hpcshape
|
|||
|
||||
shPBodyOnly, shPBodyArm, shPBodyHand, shPHeadOnly,
|
||||
|
||||
shDodeca;
|
||||
shDodeca, shSmallerDodeca,
|
||||
|
||||
shLightningBolt, shHumanoid, shHalfHumanoid, shHourglass,
|
||||
shShield, shSmallFan, shTreeIcon, shLeafIcon;
|
||||
|
||||
hpcshape shFrogRearFoot, shFrogFrontFoot, shFrogRearLeg, shFrogFrontLeg, shFrogRearLeg2, shFrogBody, shFrogEye, shFrogStripe, shFrogJumpFoot, shFrogJumpLeg;
|
||||
hpcshape shFrogRearFoot, shFrogFrontFoot, shFrogRearLeg, shFrogFrontLeg, shFrogRearLeg2, shFrogBody, shFrogEye, shFrogStripe, shFrogJumpFoot, shFrogJumpLeg, shSmallFrogRearFoot, shSmallFrogFrontFoot, shSmallFrogRearLeg, shSmallFrogFrontLeg, shSmallFrogRearLeg2, shSmallFrogBody;
|
||||
|
||||
hpcshape_animated
|
||||
shAnimatedEagle, shAnimatedTinyEagle, shAnimatedGadfly, shAnimatedHawk, shAnimatedButterfly,
|
||||
|
@ -347,6 +359,8 @@ hpcshape
|
|||
|
||||
hpcshape shTinyArrow;
|
||||
|
||||
hpcshape shCrossbow, shCrossbowBolt, shCrossbowstringLoaded, shCrossbowstringUnloaded, shCrossbowstringSemiloaded, shCrossbowIcon, shCrossbowstringIcon;
|
||||
|
||||
hpcshape shReserved[16];
|
||||
|
||||
int orb_inner_ring; //< for shDisk* shapes, the number of vertices in the inner ring
|
||||
|
@ -403,6 +417,7 @@ hpcshape
|
|||
hpcshape shFullCross[2];
|
||||
|
||||
int SD3, SD6, SD7, S12, S14, S21, S28, S42, S36, S84;
|
||||
ld S_step;
|
||||
|
||||
vector<pair<int, cell*>> walloffsets;
|
||||
|
||||
|
@ -522,17 +537,22 @@ hpcshape
|
|||
|
||||
/** contains the texture point coordinates for 3D models */
|
||||
basic_textureinfo models_texture;
|
||||
|
||||
geometry_information() { last = NULL; }
|
||||
|
||||
geometry_information() { last = NULL; use_count = 0; }
|
||||
|
||||
void require_basics() { if(state & 1) return; state |= 1; prepare_basics(); }
|
||||
void require_shapes() { if(state & 2) return; state |= 2; prepare_shapes(); }
|
||||
void require_usershapes() { if(usershape_state == usershape_changes) return; usershape_state = usershape_changes; prepare_usershapes(); }
|
||||
int timestamp;
|
||||
|
||||
hpcshape& generate_pipe(ld length, ld width);
|
||||
hpcshape& gen_pipe(hpcshape& pipe, ePipeEnd endtype, ld ratio, const hr::function<hyperpoint(ld,ld,ld)>& f);
|
||||
hpcshape& get_pipe_iso(ld length, ld width, ePipeEnd endtype = ePipeEnd::sharp);
|
||||
hpcshape& get_pipe_noniso(hyperpoint target, ld width, ePipeEnd endtype = ePipeEnd::sharp);
|
||||
|
||||
map<string, unique_ptr<gi_extension>> ext;
|
||||
|
||||
/** prevent from being destroyed */
|
||||
int use_count;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -553,11 +573,9 @@ EX void add_wall(int i, const vector<hyperpoint>& h) {
|
|||
*/
|
||||
|
||||
#if HDR
|
||||
static const ld hcrossf7 = 0.620672, hexf7 = 0.378077, tessf7 = 1.090550, hexhexdist7 = 0.566256;
|
||||
static constexpr ld hcrossf7 = 0.620672, hexf7 = 0.378077, tessf7 = 1.090550, hexhexdist7 = 0.566256;
|
||||
#endif
|
||||
|
||||
EX bool scale_used() { return (shmup::on && geometry == gNormal && BITRUNCATED) ? (cheater || autocheat) : true; }
|
||||
|
||||
EX bool is_subcube_based(eVariation var) {
|
||||
return among(var, eVariation::subcubes, eVariation::dual_subcubes, eVariation::bch, eVariation::bch_oct);
|
||||
}
|
||||
|
@ -572,7 +590,7 @@ void geometry_information::prepare_basics() {
|
|||
|
||||
hexshift = 0;
|
||||
|
||||
ld ALPHA = 2 * M_PI / S7;
|
||||
ld ALPHA = TAU / S7;
|
||||
|
||||
ld fmin, fmax;
|
||||
|
||||
|
@ -580,7 +598,13 @@ void geometry_information::prepare_basics() {
|
|||
|
||||
heptshape = nullptr;
|
||||
|
||||
if(arcm::in() && !prod)
|
||||
xp_order = 0;
|
||||
|
||||
emb = make_embed();
|
||||
bool geuclid = euclid;
|
||||
bool ghyperbolic = hyperbolic;
|
||||
|
||||
if(arcm::in() && !mproduct)
|
||||
ginf[gArchimedean].cclass = gcHyperbolic;
|
||||
|
||||
dynamicval<eVariation> gv(variation, variation);
|
||||
|
@ -590,9 +614,9 @@ void geometry_information::prepare_basics() {
|
|||
println(hlog, "bitruncated = ", BITRUNCATED);
|
||||
}
|
||||
|
||||
if(hybri) {
|
||||
if(mhybrid) {
|
||||
auto t = this;
|
||||
ld d = prod ? 1 : 2;
|
||||
ld d = mproduct ? 1 : 2;
|
||||
hybrid::in_underlying_geometry([&] {
|
||||
t->rhexf = cgi.rhexf / d;
|
||||
t->hexf = cgi.hexf / d;
|
||||
|
@ -600,12 +624,14 @@ void geometry_information::prepare_basics() {
|
|||
t->hcrossf = cgi.crossf / d;
|
||||
t->tessf = cgi.tessf / d;
|
||||
t->hexvdist = cgi.hexvdist / d;
|
||||
t->hexhexdist = hdist(xpush0(cgi.hcrossf), xspinpush0(M_PI*2/S7, cgi.hcrossf)) / d;
|
||||
t->hexhexdist = hdist(xpush0(cgi.hcrossf), xspinpush0(TAU/S7, cgi.hcrossf)) / d;
|
||||
t->base_distlimit = cgi.base_distlimit-1;
|
||||
});
|
||||
goto hybrid_finish;
|
||||
}
|
||||
|
||||
if(embedded_plane) geom3::light_flip(true);
|
||||
|
||||
if((sphere || hyperbolic) && WDIM == 3 && !bt::in()) {
|
||||
rhexf = hexf = 0.378077;
|
||||
crossf = hcrossf = 0.620672;
|
||||
|
@ -617,13 +643,13 @@ void geometry_information::prepare_basics() {
|
|||
s3 = S3;
|
||||
if(fake::in() && !arcm::in()) s3 = fake::around;
|
||||
|
||||
beta = (S3 >= OINF && !fake::in()) ? 0 : 2*M_PI/s3;
|
||||
beta = (S3 >= OINF && !fake::in()) ? 0 : TAU/s3;
|
||||
|
||||
tessf = euclid ? 1 : edge_of_triangle_with_angles(beta, M_PI/S7, M_PI/S7);
|
||||
|
||||
if(elliptic && S7 == 4 && !fake::in()) tessf = M_PI/2;
|
||||
if(elliptic && S7 == 4 && !fake::in()) tessf = 90._deg;
|
||||
|
||||
hcrossf = euclid ? tessf / 2 / sin(M_PI/s3) : edge_of_triangle_with_angles(M_PI/2, M_PI/S7, beta/2);
|
||||
hcrossf = euclid ? tessf / 2 / sin(M_PI/s3) : edge_of_triangle_with_angles(90._deg, M_PI/S7, beta/2);
|
||||
|
||||
if(S3 >= OINF) hcrossf = 10;
|
||||
|
||||
|
@ -633,15 +659,15 @@ void geometry_information::prepare_basics() {
|
|||
for(int p=0; p<100; p++) {
|
||||
ld f = (fmin+fmax) / 2;
|
||||
hyperpoint H = xpush0(f);
|
||||
hyperpoint H1 = spin(2*M_PI/S7) * H;
|
||||
hyperpoint H1 = spin(TAU/S7) * H;
|
||||
hyperpoint H2 = xpush0(tessf-f);
|
||||
ld v1 = intval(H, H1), v2 = intval(H, H2);
|
||||
|
||||
if(fake::in() && WDIM == 2) {
|
||||
hexvdist = hdist(xpush0(f), xspinpush0(ALPHA/2, hcrossf));
|
||||
v2 = hdist(
|
||||
spin(M_PI/2/S3) * xpush0(hexvdist),
|
||||
spin(-M_PI/2/S3) * xpush0(hexvdist)
|
||||
spin(90._deg/S3) * xpush0(hexvdist),
|
||||
spin(-90._deg/S3) * xpush0(hexvdist)
|
||||
);
|
||||
|
||||
v1 = hdist(
|
||||
|
@ -655,37 +681,27 @@ void geometry_information::prepare_basics() {
|
|||
hexf = fmin;
|
||||
|
||||
rhexf = BITRUNCATED ? hexf : hcrossf;
|
||||
edgelen = hdist(xpush0(rhexf), xspinpush0(M_PI*2/S7, rhexf));
|
||||
edgelen = hdist(xpush0(rhexf), xspinpush0(TAU/S7, rhexf));
|
||||
|
||||
if(BITRUNCATED && !(S7&1))
|
||||
hexshift = ALPHA/2 + ALPHA * ((S7-1)/2) + M_PI;
|
||||
|
||||
finish:
|
||||
|
||||
heptmove.resize(S7);
|
||||
hexmove.resize(S7);
|
||||
invhexmove.resize(S7);
|
||||
|
||||
for(int d=0; d<S7; d++)
|
||||
heptmove[d] = spin(-d * ALPHA) * xpush(tessf) * spin(M_PI);
|
||||
|
||||
for(int d=0; d<S7; d++)
|
||||
hexmove[d] = spin(hexshift-d * ALPHA) * xpush(-crossf)* spin(M_PI);
|
||||
|
||||
for(int d=0; d<S7; d++) invhexmove[d] = iso_inverse(hexmove[d]);
|
||||
|
||||
hexvdist = hdist(xpush0(hexf), xspinpush0(ALPHA/2, hcrossf));
|
||||
|
||||
hexhexdist = fake::in() ?
|
||||
2 * hdist0(mid(xspinpush0(M_PI/S6, hexvdist), xspinpush0(-M_PI/S6, hexvdist)))
|
||||
: hdist(xpush0(crossf), xspinpush0(M_PI*2/S7, crossf));
|
||||
: hdist(xpush0(crossf), xspinpush0(TAU/S7, crossf));
|
||||
|
||||
DEBB(DF_GEOM | DF_POLY,
|
||||
(format("S7=%d S6=%d hexf = " LDF" hcross = " LDF" tessf = " LDF" hexshift = " LDF " hexhex = " LDF " hexv = " LDF "\n", S7, S6, hexf, hcrossf, tessf, hexshift,
|
||||
(hr::format("S7=%d S6=%d hexf = " LDF" hcross = " LDF" tessf = " LDF" hexshift = " LDF " hexhex = " LDF " hexv = " LDF "\n", S7, S6, hexf, hcrossf, tessf, hexshift,
|
||||
hexhexdist, hexvdist)));
|
||||
|
||||
base_distlimit = ginf[geometry].distlimit[!BITRUNCATED];
|
||||
|
||||
hybrid_finish:
|
||||
|
||||
#if CAP_GP
|
||||
gp::compute_geometry(inv);
|
||||
#endif
|
||||
|
@ -708,9 +724,6 @@ void geometry_information::prepare_basics() {
|
|||
if(geometry == gHoroRec || kite::in() || sol || nil || nih) hexvdist = rhexf = .5, tessf = .5, scalefactor = .5, crossf = hcrossf7/2;
|
||||
if(bt::in()) scalefactor *= min<ld>(vid.binary_width, 1), crossf *= min<ld>(vid.binary_width, 1);
|
||||
#endif
|
||||
#if CAP_BT && MAXMDIM >= 4
|
||||
if(bt::in()) bt::build_tmatrix();
|
||||
#endif
|
||||
#if MAXMDIM >= 4
|
||||
if(reg3::in()) reg3::generate();
|
||||
if(euc::in(3)) euc::generate();
|
||||
|
@ -723,8 +736,6 @@ void geometry_information::prepare_basics() {
|
|||
else if(nil) nilv::create_faces();
|
||||
#endif
|
||||
|
||||
hybrid_finish:
|
||||
|
||||
scalefactor = crossf / hcrossf7;
|
||||
orbsize = crossf;
|
||||
|
||||
|
@ -764,17 +775,29 @@ void geometry_information::prepare_basics() {
|
|||
}
|
||||
#endif
|
||||
|
||||
if(scale_used()) {
|
||||
if(meuclid && ghyperbolic) {
|
||||
scalefactor *= exp(-vid.depth);
|
||||
}
|
||||
|
||||
if(msphere && geuclid) scalefactor *= (1 + vid.depth);
|
||||
if(msphere && ghyperbolic) scalefactor *= sinh(1 + vid.depth);
|
||||
|
||||
if(true) {
|
||||
scalefactor *= vid.creature_scale;
|
||||
orbsize *= vid.creature_scale;
|
||||
}
|
||||
|
||||
zhexf = BITRUNCATED ? hexf : crossf* .55;
|
||||
if(scale_used()) zhexf *= vid.creature_scale;
|
||||
zhexf *= vid.creature_scale;
|
||||
if(WDIM == 2 && GDIM == 3) zhexf *= 1.5, orbsize *= 1.2;
|
||||
|
||||
floorrad0 = hexvdist* (GDIM == 3 ? 1 : 0.92);
|
||||
floorrad1 = rhexf * (GDIM == 3 ? 1 : 0.94);
|
||||
if(cgi.emb->is_euc_in_hyp()) {
|
||||
zhexf *= exp(-vid.depth);
|
||||
orbsize *= exp(-vid.depth);
|
||||
}
|
||||
|
||||
floorrad0 = hexvdist* (GDIM == 3 ? 1 : 1 - 0.08 * global_boundary_ratio);
|
||||
floorrad1 = rhexf * (GDIM == 3 ? 1 : 1 - 0.06 * global_boundary_ratio);
|
||||
|
||||
if(euc::in(2,4)) {
|
||||
if(!BITRUNCATED)
|
||||
|
@ -786,7 +809,7 @@ void geometry_information::prepare_basics() {
|
|||
|
||||
plevel = vid.plevel_factor * scalefactor;
|
||||
single_step = 1;
|
||||
if(hybri && !prod) {
|
||||
if(mhybrid && !mproduct) {
|
||||
#if CAP_ARCM
|
||||
if(hybrid::underlying == gArchimedean)
|
||||
arcm::current.get_step_values(psl_steps, single_step);
|
||||
|
@ -804,17 +827,32 @@ void geometry_information::prepare_basics() {
|
|||
plevel = M_PI * single_step / psl_steps;
|
||||
}
|
||||
|
||||
if(hybri) {
|
||||
/* we do not want too short creatures, better make the scale factor smaller */
|
||||
scalefactor = min(scalefactor, cgi.plevel * 1.8 / vid.height_width);
|
||||
}
|
||||
|
||||
set_sibling_limit();
|
||||
|
||||
geom3::light_flip(false);
|
||||
|
||||
#if CAP_BT && MAXMDIM >= 4
|
||||
if(bt::in()) bt::build_tmatrix();
|
||||
#endif
|
||||
|
||||
prepare_compute3();
|
||||
if(hyperbolic && &currfp != &fieldpattern::fp_invalid)
|
||||
currfp.analyze();
|
||||
|
||||
|
||||
heptmove.resize(S7);
|
||||
hexmove.resize(S7);
|
||||
invhexmove.resize(S7);
|
||||
|
||||
for(int d=0; d<S7; d++)
|
||||
heptmove[d] = spin(-d * ALPHA) * lxpush(tessf) * spin(M_PI);
|
||||
|
||||
for(int d=0; d<S7; d++)
|
||||
hexmove[d] = spin(hexshift-d * ALPHA) * lxpush(-crossf)* spin(M_PI);
|
||||
|
||||
for(int d=0; d<S7; d++) invhexmove[d] = iso_inverse(hexmove[d]);
|
||||
|
||||
gp::prepare_matrices(inv);
|
||||
|
||||
#if CAP_SOLV
|
||||
if(asonov::in()) {
|
||||
asonov::prepare();
|
||||
|
@ -823,13 +861,6 @@ void geometry_information::prepare_basics() {
|
|||
#endif
|
||||
}
|
||||
|
||||
EX transmatrix xspinpush(ld dir, ld dist) {
|
||||
if(euclid)
|
||||
return eupush(cos(dir) * dist, -sin(dir) * dist);
|
||||
else
|
||||
return spin(dir) * xpush(dist) * spin(-dir);
|
||||
}
|
||||
|
||||
EX purehookset hooks_swapdim;
|
||||
|
||||
EX namespace geom3 {
|
||||
|
@ -865,16 +896,21 @@ EX namespace geom3 {
|
|||
}
|
||||
|
||||
EX ld lev_to_factor(ld lev) {
|
||||
if(prod) return -lev;
|
||||
if(mproduct) return -lev;
|
||||
if(WDIM == 3) return lev;
|
||||
if(GDIM == 3) return vid.depth - lev;
|
||||
return projection_to_factor(lev_to_projection(lev));
|
||||
}
|
||||
EX ld factor_to_lev(ld fac) {
|
||||
if(prod) return -fac;
|
||||
if(GDIM == 3) return fac;
|
||||
if(mproduct) return -fac;
|
||||
if(WDIM == 3) return fac;
|
||||
if(GDIM == 3) return vid.depth - fac;
|
||||
return vid.depth - projection_to_abslev(factor_to_projection(fac));
|
||||
}
|
||||
|
||||
EX ld to_wh(ld val) {
|
||||
return factor_to_lev(val / actual_wall_height());
|
||||
}
|
||||
|
||||
EX void do_auto_eye() {
|
||||
if(!vid.auto_eye) return;
|
||||
|
@ -894,9 +930,10 @@ EX namespace geom3 {
|
|||
}
|
||||
|
||||
EX string invalid;
|
||||
EX bool changing_embedded_settings;
|
||||
|
||||
EX ld actual_wall_height() {
|
||||
if(hybri) return cgi.plevel;
|
||||
if(mhybrid) return cgi.plevel;
|
||||
#if CAP_GP
|
||||
if(GOLDBERG && vid.gp_autoscale_heights)
|
||||
return vid.wall_height * min<ld>(4 / hypot_d(2, gp::next), 1);
|
||||
|
@ -911,7 +948,7 @@ EX namespace geom3 {
|
|||
// tanh(depth) / tanh(camera) == pconf.alpha
|
||||
invalid = "";
|
||||
|
||||
if(GDIM == 3) ;
|
||||
if(GDIM == 3 || flipped || changing_embedded_settings);
|
||||
else if(vid.tc_alpha < vid.tc_depth && vid.tc_alpha < vid.tc_camera)
|
||||
pconf.alpha = tan_auto(vid.depth) / tan_auto(vid.camera);
|
||||
else if(vid.tc_depth < vid.tc_alpha && vid.tc_depth < vid.tc_camera) {
|
||||
|
@ -959,16 +996,18 @@ EX namespace geom3 {
|
|||
ABODY = 1.08;
|
||||
AHEAD = 1.12;
|
||||
BIRD = 1.20;
|
||||
SHALLOW = .95;
|
||||
STUFF = 1;
|
||||
LOWSKY = SKY = HIGH = HIGH2 = STAR = 1;
|
||||
}
|
||||
else {
|
||||
INFDEEP = GDIM == 3 ? (sphere ? M_PI/2 : +5) : (euclid || sphere) ? 0.01 : lev_to_projection(0) * tanh(vid.camera);
|
||||
ld wh = actual_wall_height();
|
||||
WALL = lev_to_factor(wh);
|
||||
FLOOR = lev_to_factor(0);
|
||||
|
||||
human_height = vid.human_wall_ratio * wh;
|
||||
if(WDIM == 3) human_height = scalefactor * vid.height_width / 2;
|
||||
if(hybri) human_height = min(human_height, cgi.plevel * .9);
|
||||
if(mhybrid) human_height = min(human_height, cgi.plevel * .9);
|
||||
|
||||
ld reduce = (WDIM == 3 ? human_height / 2 : 0);
|
||||
|
||||
|
@ -992,7 +1031,10 @@ EX namespace geom3 {
|
|||
|
||||
reduce = (GDIM == 3 ? human_height * .3 : 0);
|
||||
|
||||
STUFF = lev_to_factor(0) - max(orbsize * 0.3, zhexf * .6);
|
||||
int sgn = vid.wall_height > 0 ? 1 : -1;
|
||||
ld ees = cgi.emb->is_euc_in_noniso() ? geom3::euclid_embed_scale_mean() : 1;
|
||||
|
||||
STUFF = lev_to_factor(0) - sgn * max(orbsize * ees * 0.3, zhexf * ees * .6);
|
||||
|
||||
ABODY = lev_to_factor(human_height * .4 - reduce);
|
||||
ALEG0 = lev_to_factor(human_height * .0 - reduce);
|
||||
|
@ -1005,55 +1047,78 @@ EX namespace geom3 {
|
|||
slev = vid.rock_wall_ratio * wh / 3;
|
||||
for(int s=0; s<=3; s++)
|
||||
SLEV[s] = lev_to_factor(vid.rock_wall_ratio * wh * s/3);
|
||||
LAKE = lev_to_factor(-vid.lake_top);
|
||||
SHALLOW = lev_to_factor(-.4);
|
||||
HELLSPIKE = lev_to_factor(-(vid.lake_top+vid.lake_bottom)/2);
|
||||
BOTTOM = lev_to_factor(-vid.lake_bottom);
|
||||
LOWSKY = lev_to_factor(2 * wh);
|
||||
HIGH = LOWSKY;
|
||||
HIGH2 = lev_to_factor(3 * wh);
|
||||
SKY = LOWSKY - 5;
|
||||
LAKE = lev_to_factor(wh * -vid.lake_top);
|
||||
SHALLOW = lev_to_factor(wh * -vid.lake_shallow);
|
||||
HELLSPIKE = lev_to_factor(wh * -(vid.lake_top+vid.lake_bottom)/2);
|
||||
BOTTOM = lev_to_factor(wh * -vid.lake_bottom);
|
||||
LOWSKY = lev_to_factor(vid.lowsky_height * wh);
|
||||
HIGH = lev_to_factor(vid.wall_height2 * wh);
|
||||
HIGH2 = lev_to_factor(vid.wall_height3 * wh);
|
||||
SKY = vid.sky_height == use_the_default_value ? cgi.emb->height_limit(-sgn) : lev_to_factor(vid.sky_height * wh);
|
||||
STAR = vid.star_height == use_the_default_value ? lerp(FLOOR, SKY, 0.95) : lev_to_factor(vid.star_height * wh);
|
||||
HELL = -SKY;
|
||||
if(embedded_plane)
|
||||
INFDEEP = vid.infdeep_height == use_the_default_value ? cgi.emb->height_limit(sgn) : lev_to_factor(vid.infdeep_height * wh);
|
||||
else
|
||||
INFDEEP = (euclid || sphere) ? 0.01 : lev_to_projection(0) * tanh(vid.camera);
|
||||
|
||||
/* in spherical/cylindrical case, make sure that the high stuff does not go through the center */
|
||||
|
||||
if(vid.height_limits) {
|
||||
auto hp = cgi.emb->height_limit(1);
|
||||
auto hn = cgi.emb->height_limit(-1);
|
||||
auto adjust = [&] (ld& val, ld& guide, ld lerpval) {
|
||||
if(val > hp)
|
||||
val = lerp(guide, hp, lerpval);
|
||||
else if(val < hn)
|
||||
val = lerp(guide, hn, lerpval);
|
||||
};
|
||||
adjust(HIGH, FLOOR, 0.8);
|
||||
adjust(HIGH2, HIGH, 0.5);
|
||||
adjust(SKY, FLOOR, 1);
|
||||
adjust(STAR, FLOOR, 0.9);
|
||||
adjust(LAKE, FLOOR, 0.8);
|
||||
adjust(SHALLOW, LAKE, 0.9);
|
||||
adjust(BOTTOM, SHALLOW, 0.5);
|
||||
adjust(INFDEEP, FLOOR, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EX namespace geom3 {
|
||||
|
||||
EX void apply_always3() {
|
||||
for(geometryinfo& gi: ginf) {
|
||||
auto &g = gi.g;
|
||||
if(vid.always3 && g.gameplay_dimension == 2 && g.graphical_dimension == 2) {
|
||||
g.graphical_dimension++;
|
||||
g.homogeneous_dimension++;
|
||||
g.sig[3] = g.sig[2];
|
||||
g.sig[2] = g.sig[1];
|
||||
}
|
||||
if(!vid.always3 && g.gameplay_dimension == 2 && g.graphical_dimension == 3) {
|
||||
g.graphical_dimension--;
|
||||
g.homogeneous_dimension--;
|
||||
g.sig[1] = g.sig[2];
|
||||
g.sig[2] = g.sig[3];
|
||||
}
|
||||
}
|
||||
|
||||
/** direction of swapping: +1 => from 2D to 3D; -1 => from 3D to 2D; 0 => make everything right */
|
||||
EX int swap_direction;
|
||||
|
||||
EX void swapdim(int dir) {
|
||||
swap_direction = dir;
|
||||
decide_lpu();
|
||||
swapmatrix_view(NLP, View);
|
||||
swapmatrix_view(NLP, current_display->which_copy);
|
||||
callhooks(hooks_swapdim);
|
||||
for(auto m: allmaps) m->on_dim_change();
|
||||
}
|
||||
|
||||
|
||||
#if MAXMDIM >= 4
|
||||
EX void switch_always3() {
|
||||
EX void switch_always3() {
|
||||
if(dual::split(switch_always3)) return;
|
||||
#if CAP_GL && CAP_RUG
|
||||
if(rug::rugged) rug::close();
|
||||
#endif
|
||||
if(vid.always3) swapdim(-1);
|
||||
vid.always3 = !vid.always3;
|
||||
apply_always3();
|
||||
swapmatrix(View);
|
||||
callhooks(hooks_swapdim);
|
||||
check_cgi(); cgi.require_basics();
|
||||
if(vid.always3) swapdim(+1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EX void switch_tpp() {
|
||||
if(dual::split(switch_fpp)) return;
|
||||
if(pmodel == mdDisk && pconf.camera_angle) {
|
||||
if(rug::rugged) rug::close();
|
||||
if(pmodel == mdDisk && !models::camera_straight) {
|
||||
vid.yshift = 0;
|
||||
pconf.camera_angle = 0;
|
||||
pconf.cam() = Id;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = 0;
|
||||
pconf.scale = 1;
|
||||
|
@ -1061,7 +1126,7 @@ EX void switch_always3() {
|
|||
}
|
||||
else {
|
||||
vid.yshift = -0.3;
|
||||
pconf.camera_angle = -45;
|
||||
pconf.cam() = cspin(1, 2, -45._deg);
|
||||
pconf.scale = 18/16. * vid.xres / vid.yres / multi::players;
|
||||
pconf.xposition = 0;
|
||||
pconf.yposition = -0.9;
|
||||
|
@ -1069,58 +1134,73 @@ EX void switch_always3() {
|
|||
vid.fixed_facing_dir = 90;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EX void switch_fpp() {
|
||||
#if MAXMDIM >= 4
|
||||
#if CAP_GL && CAP_RUG
|
||||
if(rug::rugged) rug::close();
|
||||
#endif
|
||||
if(dual::split(switch_fpp)) return;
|
||||
check_cgi(); cgi.require_basics();
|
||||
View = iso_inverse(models::rotmatrix()) * View;
|
||||
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
|
||||
if(!changing_embedded_settings)
|
||||
View = inverse(models::rotmatrix()) * View;
|
||||
|
||||
if(!vid.always3) {
|
||||
vid.always3 = true;
|
||||
apply_always3();
|
||||
ld ms = min<ld>(cgi.scalefactor, 1);
|
||||
vid.wall_height = 1.5 * ms;
|
||||
if(sphere) {
|
||||
vid.depth = M_PI / 6;
|
||||
vid.wall_height = M_PI / 3;
|
||||
}
|
||||
vid.human_wall_ratio = 0.8;
|
||||
if(euclid && allowIncreasedSight() && vid.use_smart_range == 0) {
|
||||
genrange_bonus = gamerange_bonus = sightrange_bonus = cgi.base_distlimit * 3/2;
|
||||
}
|
||||
vid.camera = 0;
|
||||
vid.depth = ms;
|
||||
if(pmodel == mdDisk) pmodel = mdPerspective;
|
||||
swapmatrix(View);
|
||||
swapmatrix(current_display->which_copy);
|
||||
callhooks(hooks_swapdim);
|
||||
for(auto m: allmaps) m->on_dim_change();
|
||||
if(cgflags & qIDEAL && vid.texture_step < 32)
|
||||
vid.texture_step = 32;
|
||||
#if CAP_RACING
|
||||
racing::player_relative = true;
|
||||
#endif
|
||||
auto emb = make_embed();
|
||||
emb->auto_configure();
|
||||
check_cgi();
|
||||
cgi.require_basics();
|
||||
swapdim(+1);
|
||||
}
|
||||
else {
|
||||
swapdim(-1);
|
||||
vid.always3 = false;
|
||||
apply_always3();
|
||||
vid.wall_height = .3;
|
||||
vid.human_wall_ratio = .7;
|
||||
vid.camera = 1;
|
||||
vid.depth = 1;
|
||||
if(pmodel == mdPerspective) pmodel = mdDisk;
|
||||
swapmatrix(View);
|
||||
swapmatrix(current_display->which_copy);
|
||||
callhooks(hooks_swapdim);
|
||||
for(auto m: allmaps) m->on_dim_change();
|
||||
if(!changing_embedded_settings) {
|
||||
vid.wall_height = .3;
|
||||
vid.human_wall_ratio = .7;
|
||||
vid.camera = 1;
|
||||
vid.depth = 1;
|
||||
}
|
||||
if(among(pmodel, mdPerspective, mdGeodesic)) pmodel = mdDisk;
|
||||
swapdim(0);
|
||||
}
|
||||
View = models::rotmatrix() * View;
|
||||
|
||||
if(!changing_embedded_settings)
|
||||
View = models::rotmatrix() * View;
|
||||
#endif
|
||||
}
|
||||
|
||||
EX void apply_settings_full() {
|
||||
if(cgip && vid.always3) {
|
||||
changing_embedded_settings = true;
|
||||
geom3::switch_fpp();
|
||||
#if MAXMDIM >= 4
|
||||
delete_sky();
|
||||
#endif
|
||||
// not sure why this is needed...
|
||||
resetGL();
|
||||
geom3::switch_fpp();
|
||||
changing_embedded_settings = false;
|
||||
}
|
||||
}
|
||||
|
||||
EX void apply_settings_light() {
|
||||
#if MAXMDIM >= 4
|
||||
if(cgip && vid.always3) {
|
||||
changing_embedded_settings = true;
|
||||
geom3::switch_always3();
|
||||
geom3::switch_always3();
|
||||
changing_embedded_settings = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
EX }
|
||||
|
||||
EX geometry_information *cgip;
|
||||
|
@ -1172,21 +1252,26 @@ EX string cgi_string() {
|
|||
|
||||
if(arb::in()) V("AP", its(arb::apeirogon_simplified_display));
|
||||
|
||||
if(arb::in()) V("F", its(arb::extended_football));
|
||||
|
||||
V("BR", fts(global_boundary_ratio));
|
||||
|
||||
if(cryst) V("CRYSTAL", its(ginf[gCrystal].sides) + its(ginf[gCrystal].vertex));
|
||||
|
||||
if(bt::in() || GDIM == 3) V("WQ", its(vid.texture_step));
|
||||
|
||||
if(hybri) {
|
||||
if(mhybrid) {
|
||||
V("U", PIU(cgi_string()));
|
||||
// its(int(hybrid::underlying)));
|
||||
}
|
||||
|
||||
if(prod) V("PL", fts(vid.plevel_factor));
|
||||
if(mproduct) V("PL", fts(vid.plevel_factor));
|
||||
|
||||
if(geometry == gFieldQuotient) { V("S3=", its(S3)); V("S7=", its(S7)); }
|
||||
if(nil) V("NIL", its(S7));
|
||||
|
||||
if(bt::in()) V("BT", fts(vid.binary_width));
|
||||
if(hat::in()) V("H", fts(hat::hat_param));
|
||||
if(hat::in() && hat::hat_param_imag) V("HI", fts(hat::hat_param_imag));
|
||||
|
||||
if(nil) V("NILW", fts(nilv::nilwidth));
|
||||
|
||||
|
@ -1202,13 +1287,32 @@ EX string cgi_string() {
|
|||
V("ASH", ONOFF(vid.gp_autoscale_heights));
|
||||
V("LT", fts(vid.lake_top));
|
||||
V("LB", fts(vid.lake_bottom));
|
||||
if(GDIM == 3 && vid.pseudohedral)
|
||||
V("PS", fts(vid.depth_bonus));
|
||||
if(GDIM == 3 && vid.pseudohedral) {
|
||||
V("PSH", fts(vid.pseudohedral));
|
||||
V("PSD", fts(vid.depth_bonus));
|
||||
}
|
||||
V("LS", fts(vid.lake_shallow));
|
||||
V("SSu", fts(vid.sun_size));
|
||||
V("SSt", fts(vid.star_size));
|
||||
V("WH2", fts(vid.wall_height2));
|
||||
V("WH3", fts(vid.wall_height3));
|
||||
V("WHL", fts(vid.lowsky_height));
|
||||
if(vid.sky_height != use_the_default_value) V("SHe", fts(vid.sky_height));
|
||||
if(vid.star_height != use_the_default_value) V("StH", fts(vid.star_height));
|
||||
if(vid.infdeep_height != use_the_default_value) V("ID", fts(vid.infdeep_height));
|
||||
}
|
||||
|
||||
V("3D", ONOFF(vid.always3));
|
||||
|
||||
if(scale_used()) V("CS", fts(vid.creature_scale));
|
||||
if(embedded_plane) V("X:", its(geom3::ggclass()));
|
||||
|
||||
if(embedded_plane && meuclid) {
|
||||
V("XS:", fts(geom3::euclid_embed_scale));
|
||||
V("YS:", fts(geom3::euclid_embed_scale_y));
|
||||
V("RS:", fts(geom3::euclid_embed_rotate));
|
||||
}
|
||||
|
||||
if(vid.creature_scale != 1) V("CS", fts(vid.creature_scale));
|
||||
|
||||
if(WDIM == 3) V("HTW", fts(vid.height_width));
|
||||
|
||||
|
@ -1219,7 +1323,7 @@ EX string cgi_string() {
|
|||
return s;
|
||||
}
|
||||
|
||||
#if MAXMDIM >= 4 && CAP_RAY
|
||||
#if CAP_PORTALS
|
||||
#define IFINTRA(x,y) x
|
||||
#else
|
||||
#define IFINTRA(x,y) y
|
||||
|
@ -1230,15 +1334,18 @@ EX void check_cgi() {
|
|||
|
||||
cgip = &cgis[s];
|
||||
cgi.timestamp = ++ntimestamp;
|
||||
if(hybri) hybrid::underlying_cgip->timestamp = ntimestamp;
|
||||
if(mhybrid) hybrid::underlying_cgip->timestamp = ntimestamp;
|
||||
if(fake::in()) fake::underlying_cgip->timestamp = ntimestamp;
|
||||
#if CAP_ARCM
|
||||
if(arcm::alt_cgip) arcm::alt_cgip->timestamp = ntimestamp;
|
||||
if(arcm::alt_cgip[0]) arcm::alt_cgip[0]->timestamp = ntimestamp;
|
||||
if(arcm::alt_cgip[1]) arcm::alt_cgip[1]->timestamp = ntimestamp;
|
||||
#endif
|
||||
|
||||
if(isize(cgis) > 4 && IFINTRA(intra::data.empty(), true)) {
|
||||
int limit = 4;
|
||||
for(auto& t: cgis) if(t.second.use_count) limit++;
|
||||
if(isize(cgis) > limit) {
|
||||
vector<pair<int, string>> timestamps;
|
||||
for(auto& t: cgis) timestamps.emplace_back(-t.second.timestamp, t.first);
|
||||
for(auto& t: cgis) if(!t.second.use_count) timestamps.emplace_back(-t.second.timestamp, t.first);
|
||||
sort(timestamps.begin(), timestamps.end());
|
||||
while(isize(timestamps) > 4) {
|
||||
DEBB(DF_GEOM, ("erasing geometry ", timestamps.back().second));
|
||||
|
|
152
geometry2.cpp
152
geometry2.cpp
|
@ -42,7 +42,7 @@ EX transmatrix relative_matrix_recursive(heptagon *h2, heptagon *h1) {
|
|||
}
|
||||
else {
|
||||
for(int i=0; i<h2->type; i++) if(h2->move(i) && h2->move(i)->distance < h2->distance) {
|
||||
where = currentmap->iadj(h2, 0) * where;
|
||||
where = currentmap->iadj(h2, i) * where;
|
||||
h2 = h2->move(i);
|
||||
goto again;
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ transmatrix hrmap_standard::master_relative(cell *c, bool get_inverse) {
|
|||
#if CAP_IRR
|
||||
else if(IRREGULAR) {
|
||||
int id = irr::cellindex[c];
|
||||
ld alpha = 2 * M_PI / S7 * irr::periodmap[c->master].base.spin;
|
||||
ld alpha = TAU / S7 * irr::periodmap[c->master].base.spin;
|
||||
return get_inverse ? irr::cells[id].rpusher * spin(-alpha-master_to_c7_angle()): spin(alpha + master_to_c7_angle()) * irr::cells[id].pusher;
|
||||
}
|
||||
#endif
|
||||
|
@ -81,6 +81,8 @@ transmatrix hrmap_standard::master_relative(cell *c, bool get_inverse) {
|
|||
}
|
||||
else if(WDIM == 3)
|
||||
return Id;
|
||||
else if(dont_inverse())
|
||||
return Id;
|
||||
else
|
||||
return pispin * Id;
|
||||
}
|
||||
|
@ -100,12 +102,12 @@ transmatrix hrmap_standard::adj(heptagon *h, int d) {
|
|||
int t0 = h->type;
|
||||
int t1 = h->cmove(d)->type;
|
||||
int sp = h->c.spin(d);
|
||||
return spin(-d * 2 * M_PI / t0) * xpush(spacedist(h->c7, d)) * spin(M_PI + 2*M_PI*sp/t1);
|
||||
return spin(-d * TAU / t0) * lxpush(spacedist(h->c7, d)) * spin(M_PI + TAU * sp / t1);
|
||||
}
|
||||
transmatrix T = cgi.heptmove[d];
|
||||
if(h->c.mirror(d)) T = T * Mirror;
|
||||
int sp = h->c.spin(d);
|
||||
if(sp) T = T * spin(2*M_PI*sp/S7);
|
||||
if(sp) T = T * spin(TAU*sp/S7);
|
||||
return T;
|
||||
}
|
||||
|
||||
|
@ -235,10 +237,14 @@ void horo_distance::become(hyperpoint h1) {
|
|||
a = abs(bt::horo_level(h1));
|
||||
}
|
||||
#endif
|
||||
else if(hybri)
|
||||
else if(mhybrid || sl2)
|
||||
a = 0, b = hdist(h1, C0);
|
||||
else if(cgi.emb->is_euc_in_product())
|
||||
a = 0, b = hdist(h1, C0);
|
||||
else if(cgi.emb->is_cylinder())
|
||||
a = 0, b = hdist(h1, tile_center());
|
||||
else
|
||||
a = 0, b = intval(h1, C0);
|
||||
a = 0, b = intval(h1, tile_center());
|
||||
}
|
||||
|
||||
horo_distance::horo_distance(shiftpoint h1, const shiftmatrix& T) {
|
||||
|
@ -246,9 +252,13 @@ horo_distance::horo_distance(shiftpoint h1, const shiftmatrix& T) {
|
|||
if(bt::in()) become(inverse_shift(T, h1));
|
||||
else
|
||||
#endif
|
||||
if(sn::in() || hybri || nil) become(inverse_shift(T, h1));
|
||||
if(sn::in() || mhybrid || nil || sl2) become(inverse_shift(T, h1));
|
||||
else if(cgi.emb->is_euc_in_product())
|
||||
a = 0, b = hdist(h1.h, unshift(T * tile_center(), h1.shift));
|
||||
else if(cgi.emb->is_cylinder())
|
||||
a = 0, b = hdist(h1.h, unshift(T * tile_center(), h1.shift));
|
||||
else
|
||||
a = 0, b = intval(h1.h, unshift(tC0(T), h1.shift));
|
||||
a = 0, b = intval(h1.h, unshift(T * tile_center(), h1.shift));
|
||||
}
|
||||
|
||||
bool horo_distance::operator < (const horo_distance z) const {
|
||||
|
@ -268,6 +278,7 @@ void virtualRebase_cell(cell*& base, T& at, const U& check) {
|
|||
while(true) {
|
||||
cell *newbase = NULL;
|
||||
forCellIdCM(c2, i, base) {
|
||||
if(c2 == &out_of_bounds) continue;
|
||||
transmatrix V2 = currentmap->iadj(base, i);
|
||||
T cand_at = V2 * at;
|
||||
horo_distance newz(check(cand_at));
|
||||
|
@ -310,7 +321,7 @@ void virtualRebase_cell(cell*& base, T& at, const U& check) {
|
|||
template<class T, class U>
|
||||
void virtualRebase(cell*& base, T& at, const U& check) {
|
||||
|
||||
if(nil) {
|
||||
if(nil && WDIM == 3) {
|
||||
hyperpoint h = check(at);
|
||||
auto step = [&] (int i) {
|
||||
at = currentmap->adj(base, (i+S7/2) % S7) * at;
|
||||
|
@ -331,7 +342,44 @@ void virtualRebase(cell*& base, T& at, const U& check) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(prod) {
|
||||
if(geometry == gSol) {
|
||||
/** the general algorithm sometimes makes much more iterations than needed... try to approximate the geodesic */
|
||||
hyperpoint h = check(at);
|
||||
auto step = [&] (int i) {
|
||||
at = currentmap->iadj(base, i) * at;
|
||||
base = base->cmove(i);
|
||||
h = check(at);
|
||||
};
|
||||
|
||||
auto nw = vid.binary_width * log(2);
|
||||
while(abs(h[0]) > 2) step(6);
|
||||
while(h[0] < -0.5 * nw) step(4);
|
||||
while(h[0] > +0.5 * nw) step(0);
|
||||
while(abs(h[1]) > 2) {
|
||||
step(2);
|
||||
while(h[0] < -0.5 * nw) step(4);
|
||||
while(h[0] > +0.5 * nw) step(0);
|
||||
}
|
||||
while(h[1] < -0.5 * nw) step(5);
|
||||
while(h[1] > +0.5 * nw) step(1);
|
||||
while(h[2] > 1) {
|
||||
step(2);
|
||||
while(h[0] < -0.5 * nw) step(4);
|
||||
while(h[0] > +0.5 * nw) step(0);
|
||||
while(h[1] < -0.5 * nw) step(5);
|
||||
while(h[1] > +0.5 * nw) step(1);
|
||||
}
|
||||
while(h[2] < -1) {
|
||||
step(6);
|
||||
while(h[0] < -0.5 * nw) step(4);
|
||||
while(h[0] > +0.5 * nw) step(0);
|
||||
while(h[1] < -0.5 * nw) step(5);
|
||||
while(h[1] > +0.5 * nw) step(1);
|
||||
}
|
||||
}
|
||||
/* todo variants of sol */
|
||||
|
||||
if(mproduct) {
|
||||
auto d = product_decompose(check(at)).first;
|
||||
while(d > cgi.plevel / 2) {
|
||||
at = currentmap->iadj(base, base->type-1) * at;
|
||||
|
@ -342,9 +390,9 @@ void virtualRebase(cell*& base, T& at, const U& check) {
|
|||
base = base->cmove(base->type-2); d += cgi.plevel;
|
||||
}
|
||||
auto w = hybrid::get_where(base);
|
||||
at = mscale(at, -d);
|
||||
at = orthogonal_move(at, -d);
|
||||
PIU( virtualRebase(w.first, at, check) );
|
||||
at = mscale(at, +d);
|
||||
at = orthogonal_move(at, +d);
|
||||
base = hybrid::get_at(w.first, w.second);
|
||||
return;
|
||||
}
|
||||
|
@ -400,13 +448,17 @@ void hrmap_hyperbolic::virtualRebase(heptagon*& base, transmatrix& at) {
|
|||
}
|
||||
|
||||
EX bool no_easy_spin() {
|
||||
return NONSTDVAR || arcm::in() || WDIM == 3 || bt::in() || kite::in();
|
||||
return NONSTDVAR || arcm::in() || WDIM == 3 || bt::in() || aperiodic;
|
||||
}
|
||||
|
||||
EX bool never_invert;
|
||||
|
||||
EX bool dont_inverse() { return never_invert || (PURE && cgi.emb->is_euc_in_noniso()); }
|
||||
|
||||
ld hrmap_standard::spin_angle(cell *c, int d) {
|
||||
if(WDIM == 3) return SPIN_NOT_AVAILABLE;
|
||||
ld hexshift = 0;
|
||||
if(c == c->master->c7 && (S7 % 2 == 0) && BITRUNCATED) hexshift = cgi.hexshift + 2*M_PI/c->type;
|
||||
if(c == c->master->c7 && (S7 % 2 == 0) && BITRUNCATED) hexshift = cgi.hexshift + TAU/c->type;
|
||||
else if(cgi.hexshift && c == c->master->c7) hexshift = cgi.hexshift;
|
||||
#if CAP_IRR
|
||||
if(IRREGULAR) {
|
||||
|
@ -417,7 +469,8 @@ ld hrmap_standard::spin_angle(cell *c, int d) {
|
|||
return -atan2(p[1], p[0]) - hexshift;
|
||||
}
|
||||
#endif
|
||||
return M_PI - d * 2 * M_PI / c->type - hexshift;
|
||||
if(dont_inverse()) return - d * TAU / c->type;
|
||||
return M_PI - d * TAU / c->type - hexshift;
|
||||
}
|
||||
|
||||
EX transmatrix ddspin(cell *c, int d, ld bonus IS(0)) { return currentmap->spin_to(c, d, bonus); }
|
||||
|
@ -425,7 +478,10 @@ EX transmatrix iddspin(cell *c, int d, ld bonus IS(0)) { return currentmap->spin
|
|||
EX ld cellgfxdist(cell *c, int d) { return currentmap->spacedist(c, d); }
|
||||
|
||||
EX transmatrix ddspin_side(cell *c, int d, ld bonus IS(0)) {
|
||||
if(kite::in()) {
|
||||
if(cgi.emb->is_in_noniso())
|
||||
return spin(bonus);
|
||||
if(aperiodic) {
|
||||
if(embedded_plane) return spin(bonus);
|
||||
hyperpoint h1 = get_corner_position(c, gmod(d, c->type), 3);
|
||||
hyperpoint h2 = get_corner_position(c, gmod(d+1, c->type) , 3);
|
||||
hyperpoint hm = mid(h1, h2);
|
||||
|
@ -435,7 +491,10 @@ EX transmatrix ddspin_side(cell *c, int d, ld bonus IS(0)) {
|
|||
}
|
||||
|
||||
EX transmatrix iddspin_side(cell *c, int d, ld bonus IS(0)) {
|
||||
if(kite::in()) {
|
||||
if(cgi.emb->is_in_noniso())
|
||||
return spin(bonus);
|
||||
if(aperiodic) {
|
||||
if(embedded_plane) return spin(bonus);
|
||||
hyperpoint h1 = get_corner_position(c, gmod(d, c->type), 3);
|
||||
hyperpoint h2 = get_corner_position(c, gmod(d+1, c->type) , 3);
|
||||
hyperpoint hm = mid(h1, h2);
|
||||
|
@ -493,7 +552,7 @@ transmatrix hrmap_standard::adj(cell *c, int i) {
|
|||
return calc_relative_matrix(c->cmove(i), c, C0);
|
||||
}
|
||||
double d = cellgfxdist(c, i);
|
||||
transmatrix T = ddspin(c, i) * xpush(d);
|
||||
transmatrix T = ddspin(c, i) * lxpush(d);
|
||||
if(c->c.mirror(i)) T = T * Mirror;
|
||||
cell *c1 = c->cmove(i);
|
||||
T = T * iddspin(c1, c->c.spin(i), M_PI);
|
||||
|
@ -503,17 +562,17 @@ transmatrix hrmap_standard::adj(cell *c, int i) {
|
|||
EX double randd() { return (rand() + .5) / (RAND_MAX + 1.); }
|
||||
|
||||
EX hyperpoint randomPointIn(int t) {
|
||||
if(NONSTDVAR || arcm::in() || kite::in()) {
|
||||
if(NONSTDVAR || arcm::in() || aperiodic) {
|
||||
// Let these geometries be less confusing.
|
||||
// Also easier to implement ;)
|
||||
return xspinpush0(2 * M_PI * randd(), asinh(randd() / 20));
|
||||
return xspinpush0(TAU * randd(), asinh(randd() / 20));
|
||||
}
|
||||
while(true) {
|
||||
hyperpoint h = xspinpush0(2*M_PI*(randd()-.5)/t, asinh(randd()));
|
||||
hyperpoint h = xspinpush0(TAU * (randd()-.5)/t, asinh(randd()));
|
||||
double d =
|
||||
PURE ? cgi.tessf : t == 6 ? cgi.hexhexdist : cgi.crossf;
|
||||
if(hdist0(h) < hdist0(xpush(-d) * h))
|
||||
return spin(2*M_PI/t * (rand() % t)) * h;
|
||||
return spin(TAU / t * (rand() % t)) * h;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,15 +596,18 @@ hyperpoint hrmap_standard::get_corner(cell *c, int cid, ld cf) {
|
|||
}
|
||||
#endif
|
||||
if(PURE) {
|
||||
return ddspin(c,cid,M_PI/S7) * xpush0(cgi.hcrossf * 3 / cf);
|
||||
if(cgi.emb->is_euc_in_noniso()) {
|
||||
return lspinpush0(spin_angle(c, cid) + M_PI/S7, cgi.hcrossf * 3 / cf);
|
||||
}
|
||||
return ddspin(c,cid,M_PI/S7) * lxpush0(cgi.hcrossf * 3 / cf);
|
||||
}
|
||||
if(BITRUNCATED) {
|
||||
if(!ishept(c))
|
||||
return ddspin(c,cid,M_PI/S6) * xpush0(cgi.hexvdist * 3 / cf);
|
||||
return ddspin(c,cid,M_PI/S6) * lxpush0(cgi.hexvdist * 3 / cf);
|
||||
else
|
||||
return ddspin(c,cid,M_PI/S7) * xpush0(cgi.rhexf * 3 / cf);
|
||||
return ddspin(c,cid,M_PI/S7) * lxpush0(cgi.rhexf * 3 / cf);
|
||||
}
|
||||
return C0;
|
||||
return tile_center();
|
||||
}
|
||||
|
||||
EX bool approx_nearcorner = false;
|
||||
|
@ -575,7 +637,7 @@ EX hyperpoint nearcorner(cell *c, int i) {
|
|||
auto& t = ac.get_triangle(c->master, i-1);
|
||||
int id = arcm::id_of(c->master);
|
||||
int id1 = ac.get_adj(ac.get_adj(c->master, i-1), -2).first;
|
||||
return xspinpush0(-t.first - M_PI / c->type, ac.inradius[id/2] + ac.inradius[id1/2] + (ac.real_faces == 0 ? 2 * M_PI / (ac.N == 2 ? 2.1 : ac.N) : 0));
|
||||
return xspinpush0(-t.first - M_PI / c->type, ac.inradius[id/2] + ac.inradius[id1/2] + (ac.real_faces == 0 ? TAU / (ac.N == 2 ? 2.1 : ac.N) : 0));
|
||||
}
|
||||
if(BITRUNCATED) {
|
||||
auto &ac = arcm::current;
|
||||
|
@ -594,10 +656,10 @@ EX hyperpoint nearcorner(cell *c, int i) {
|
|||
ld yx = log(2) / 2;
|
||||
ld yy = yx;
|
||||
hyperpoint neis[5];
|
||||
neis[0] = bt::get_horopoint(2*yy, -0.5);
|
||||
neis[1] = bt::get_horopoint(2*yy, +0.5);
|
||||
neis[0] = bt::get_horopoint(2*yy, -0.25);
|
||||
neis[1] = bt::get_horopoint(2*yy, +0.25);
|
||||
neis[2] = bt::get_horopoint(0, 1);
|
||||
neis[3] = bt::get_horopoint(-2*yy, c->master->zebraval ? -0.25 : +0.25);
|
||||
neis[3] = bt::get_horopoint(-2*yy, c->master->zebraval ? -0.5 : +0.5);
|
||||
neis[4] = bt::get_horopoint(0, -1);
|
||||
return neis[i];
|
||||
}
|
||||
|
@ -605,15 +667,15 @@ EX hyperpoint nearcorner(cell *c, int i) {
|
|||
ld yx = log(3) / 2;
|
||||
ld yy = yx;
|
||||
hyperpoint neis[6];
|
||||
neis[0] = bt::get_horopoint(2*yy, -1);
|
||||
neis[0] = bt::get_horopoint(2*yy, -1/3.);
|
||||
neis[1] = bt::get_horopoint(2*yy, +0);
|
||||
neis[2] = bt::get_horopoint(2*yy, +1);
|
||||
neis[2] = bt::get_horopoint(2*yy, +1/3.);
|
||||
neis[3] = bt::get_horopoint(0, 1);
|
||||
neis[4] = bt::get_horopoint(-2*yy, c->master->zebraval / 3.);
|
||||
neis[4] = bt::get_horopoint(-2*yy, c->master->zebraval);
|
||||
neis[5] = bt::get_horopoint(0, -1);
|
||||
return neis[i];
|
||||
}
|
||||
if(kite::in()) {
|
||||
if(aperiodic) {
|
||||
if(approx_nearcorner)
|
||||
return currentmap->get_corner(c, i, 3) + currentmap->get_corner(c, i+1, 3) - C0;
|
||||
else
|
||||
|
@ -629,20 +691,20 @@ EX hyperpoint nearcorner(cell *c, int i) {
|
|||
// ld xx = 1 / sqrt(2)/2;
|
||||
hyperpoint neis[7];
|
||||
neis[0] = bt::get_horopoint(0, 1);
|
||||
neis[1] = bt::get_horopoint(yy*2, 1);
|
||||
neis[1] = bt::get_horopoint(yy*2, 0.5);
|
||||
neis[2] = bt::get_horopoint(yy*2, 0);
|
||||
neis[3] = bt::get_horopoint(yy*2, -1);
|
||||
neis[3] = bt::get_horopoint(yy*2, -0.5);
|
||||
neis[4] = bt::get_horopoint(0, -1);
|
||||
if(c->type == 7)
|
||||
neis[5] = bt::get_horopoint(-yy*2, -.5),
|
||||
neis[6] = bt::get_horopoint(-yy*2, +.5);
|
||||
neis[5] = bt::get_horopoint(-yy*2, -1),
|
||||
neis[6] = bt::get_horopoint(-yy*2, +1);
|
||||
else
|
||||
neis[5] = bt::get_horopoint(-yy*2, 0);
|
||||
return neis[i];
|
||||
}
|
||||
#endif
|
||||
double d = cellgfxdist(c, i);
|
||||
return ddspin(c, i) * xpush0(d);
|
||||
return ddspin(c, i) * lxpush0(d);
|
||||
}
|
||||
|
||||
/** /brief get the coordinates of the another vertex of c->move(i)
|
||||
|
@ -680,7 +742,7 @@ EX hyperpoint farcorner(cell *c, int i, int which) {
|
|||
}
|
||||
#endif
|
||||
#if CAP_BT
|
||||
if(bt::in() || kite::in())
|
||||
if(bt::in() || aperiodic)
|
||||
return nearcorner(c, (i+which) % c->type); // lazy
|
||||
#endif
|
||||
#if CAP_ARCM
|
||||
|
@ -691,7 +753,7 @@ EX hyperpoint farcorner(cell *c, int i, int which) {
|
|||
int id = arcm::id_of(c->master);
|
||||
auto id1 = ac.get_adj(ac.get_adj(c->master, i-1), -2).first;
|
||||
int n1 = isize(ac.adjacent[id1]);
|
||||
return spin(-t.first - M_PI / c->type) * xpush(ac.inradius[id/2] + ac.inradius[id1/2]) * xspinpush0(M_PI + M_PI/n1*(which?3:-3), ac.circumradius[id1/2]);
|
||||
return spin(-t.first - M_PI / c->type) * lxpush(ac.inradius[id/2] + ac.inradius[id1/2]) * xspinpush0(M_PI + M_PI/n1*(which?3:-3), ac.circumradius[id1/2]);
|
||||
}
|
||||
if(BITRUNCATED || DUAL) {
|
||||
int mul = DUALMUL;
|
||||
|
@ -705,7 +767,7 @@ EX hyperpoint farcorner(cell *c, int i, int which) {
|
|||
|
||||
auto& t2 = arcm::current.get_triangle(adj);
|
||||
|
||||
return spin(-t1.first) * xpush(t1.second) * spin(M_PI + t2.first) * get_corner_position(&cx, which ? -mul : 2*mul);
|
||||
return spin(-t1.first) * lxpush(t1.second) * spin(M_PI + t2.first) * get_corner_position(&cx, which ? -mul : 2*mul);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -731,7 +793,7 @@ EX hyperpoint get_warp_corner(cell *c, int cid) {
|
|||
#if CAP_IRR || CAP_ARCM
|
||||
if(IRREGULAR || arcm::in()) return midcorner(c, cid, .5);
|
||||
#endif
|
||||
return ddspin(c,cid,M_PI/S7) * xpush0(cgi.tessf/2);
|
||||
return ddspin(c,cid,M_PI/S7) * lxpush0(cgi.tessf/2);
|
||||
}
|
||||
|
||||
EX map<cell*, map<cell*, vector<transmatrix>>> brm_structure;
|
||||
|
@ -809,7 +871,7 @@ int brm_hook = addHook(hooks_clearmemory, 0, []() {
|
|||
});
|
||||
|
||||
EX bool exhaustive_distance_appropriate() {
|
||||
if(euclid && (kite::in() || arcm::in() || arb::in() || quotient)) return true;
|
||||
if(euclid && (aperiodic || arcm::in() || arb::in() || quotient)) return true;
|
||||
#if MAXMDIM >= 4
|
||||
if(nil && quotient) return true;
|
||||
#endif
|
||||
|
@ -862,7 +924,7 @@ EX pathgen generate_random_path(cellwalker start, int length, bool for_yendor, b
|
|||
p.last = p.path.back();
|
||||
}
|
||||
|
||||
else if(hybri) {
|
||||
else if(mhybrid) {
|
||||
/* I am lazy */
|
||||
for(int i=1; i<=length; i++) p.path[i] = p.path[i-1]->cmove(p.path[i-1]->type-1);
|
||||
p.last = p.path.back();
|
||||
|
|
34
glhr.cpp
34
glhr.cpp
|
@ -57,7 +57,7 @@ EX }
|
|||
EX void glError(const char* GLcall, const char* file, const int line) {
|
||||
GLenum errCode = glGetError();
|
||||
if(errCode!=GL_NO_ERROR) {
|
||||
println(hlog, format("OPENGL ERROR #%i: in file %s on line %i :: %s",errCode,file, line, GLcall));
|
||||
println(hlog, hr::format("OPENGL ERROR #%i: in file %s on line %i :: %s",errCode,file, line, GLcall));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ struct glwrap {
|
|||
void glwrap::act(const char *when) {
|
||||
GLenum errCode = glGetError();
|
||||
if(errCode!=GL_NO_ERROR) {
|
||||
println(hlog, format("GL error %i %s: %s:%i", errCode, when, msg, line));
|
||||
println(hlog, hr::format("GL error %i %s: %s:%i", errCode, when, msg, line));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,11 +124,14 @@ struct glmatrix {
|
|||
color[2] = b;
|
||||
color[3] = 1;
|
||||
}
|
||||
colored_vertex(hyperpoint h, color_t col) {
|
||||
coords = pointtogl(h);
|
||||
void set_color(color_t col) {
|
||||
for(int i=0; i<4; i++)
|
||||
color[i] = part(col, 3-i) / 255.0;
|
||||
}
|
||||
colored_vertex(hyperpoint h, color_t col) {
|
||||
coords = pointtogl(h);
|
||||
set_color(col);
|
||||
}
|
||||
};
|
||||
|
||||
struct textured_vertex {
|
||||
|
@ -208,6 +211,14 @@ EX glmatrix tmtogl(const transmatrix& T) {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
EX transmatrix gltotm(const glmatrix& T) {
|
||||
transmatrix tmp;
|
||||
for(int i=0; i<4; i++)
|
||||
for(int j=0; j<4; j++)
|
||||
tmp[i][j] = T[i][j];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
EX glmatrix tmtogl_transpose(const transmatrix& T) {
|
||||
glmatrix tmp;
|
||||
for(int i=0; i<4; i++)
|
||||
|
@ -237,10 +248,8 @@ EX glmatrix& as_glmatrix(GLfloat o[16]) {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
#if HDR
|
||||
constexpr ld vnear_default = 1e-3;
|
||||
constexpr ld vfar_default = 1e9;
|
||||
#endif
|
||||
EX ld vnear_default = 1e-3;
|
||||
EX ld vfar_default = 1e9;
|
||||
|
||||
EX glmatrix frustum(ld x, ld y, ld vnear IS(vnear_default), ld vfar IS(vfar_default)) {
|
||||
GLfloat frustum[16] = {
|
||||
|
@ -266,7 +275,7 @@ EX glmatrix translate(ld x, ld y, ld z) {
|
|||
|
||||
// /* shaders */
|
||||
|
||||
glmatrix projection;
|
||||
EX glmatrix projection;
|
||||
|
||||
EX void new_projection() {
|
||||
WITHSHADER({
|
||||
|
@ -319,11 +328,11 @@ EX int compileShader(int type, const string& s) {
|
|||
GLint status;
|
||||
|
||||
if(debug_gl) {
|
||||
println(hlog, "===\n");
|
||||
println(hlog, "=== ", full_geometry_name(), " @ ", models::get_model_name(pmodel));
|
||||
int lineno = 1;
|
||||
string cline = "";
|
||||
for(char c: s+"\n") {
|
||||
if(c == '\n') println(hlog, format("%4d : ", lineno), cline), lineno++, cline = "";
|
||||
if(c == '\n') println(hlog, hr::format("%4d : ", lineno), cline), lineno++, cline = "";
|
||||
else cline += c;
|
||||
}
|
||||
println(hlog, "===");
|
||||
|
@ -655,7 +664,10 @@ EX void full_enable(shared_ptr<GLprogram> p) {
|
|||
current_projection[0][0] = -1e8;
|
||||
}, {})
|
||||
id_modelview();
|
||||
#if MINIMIZE_GL_CALLS
|
||||
#else
|
||||
current_linewidth = -1;
|
||||
#endif
|
||||
/* if(current_depthwrite) glDepthMask(GL_TRUE);
|
||||
else glDepthMask(GL_FALSE);
|
||||
if(current_depthtest) glEnable(GL_DEPTH_TEST);
|
||||
|
|
72
goldberg.cpp
72
goldberg.cpp
|
@ -234,7 +234,7 @@ EX namespace gp {
|
|||
auto& wc = get_mapping(at);
|
||||
auto wcw = get_localwalk(wc, dir);
|
||||
auto& wc1 = get_mapping(at + eudir(dir));
|
||||
DEBB0(DF_GP, (format(" md:%02d s:%d", wc.mindir, wc.cw.spin)); )
|
||||
DEBB0(DF_GP, (hr::format(" md:%02d s:%d", wc.mindir, wc.cw.spin)); )
|
||||
DEBB0(DF_GP, (" connection ", at, "/", dir, " ", wc.cw+dir, "=", wcw, " ~ ", at+eudir(dir), "/", dir1, " "); )
|
||||
if(!wc1.cw.at) {
|
||||
wc1.start = wc.start;
|
||||
|
@ -274,6 +274,8 @@ EX namespace gp {
|
|||
if(do_adjm) {
|
||||
get_adj(wcw.at, wcw.spin) = inverse(wc.adjm) * wc1.adjm;
|
||||
get_adj(wcw1.at, wcw1.spin) = inverse(wc1.adjm) * wc.adjm;
|
||||
if(geom3::flipped) gp_swapped.emplace(wcw.at, wcw.spin);
|
||||
if(geom3::flipped) gp_swapped.emplace(wcw1.at, wcw1.spin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,6 +285,7 @@ EX namespace gp {
|
|||
}
|
||||
|
||||
EX map<pair<cell*, int>, transmatrix> gp_adj;
|
||||
EX set<pair<cell*, int>> gp_swapped;
|
||||
|
||||
EX transmatrix& get_adj(cell *c, int i) { return gp_adj[make_pair(c,i)]; }
|
||||
|
||||
|
@ -646,22 +649,24 @@ EX namespace gp {
|
|||
}
|
||||
if(sp>SG3) sp -= SG6;
|
||||
|
||||
return normalize(spin(2*M_PI*sp/S7) * cornmul(T, corner));
|
||||
return normalize(spin(TAU*sp/S7) * cornmul(T, corner));
|
||||
}
|
||||
|
||||
transmatrix dir_matrix(int i) {
|
||||
auto ddspin = [] (int d) -> transmatrix {
|
||||
return spin(M_PI - d * 2 * M_PI / S7 - cgi.hexshift);
|
||||
return spin(M_PI - d * TAU / S7 - cgi.hexshift);
|
||||
};
|
||||
return spin(-cgi.gpdata->alpha) * build_matrix(
|
||||
C0,
|
||||
ddspin(i) * xpush0(cgi.tessf),
|
||||
ddspin(i+1) * xpush0(cgi.tessf),
|
||||
geom3::flipped ? C02 : tile_center(),
|
||||
geom3::flipped ? ddspin(i) * xpush0(cgi.tessf) : ddspin(i) * lxpush0(cgi.tessf),
|
||||
geom3::flipped ? ddspin(i+1) * xpush0(cgi.tessf) : ddspin(i+1) * lxpush0(cgi.tessf),
|
||||
C03
|
||||
);
|
||||
}
|
||||
|
||||
void prepare_matrices() {
|
||||
EX void prepare_matrices(bool inv) {
|
||||
if(!(GOLDBERG_INV || inv)) return;
|
||||
if(embedded_plane) geom3::light_flip(true);
|
||||
cgi.gpdata->corners = inverse(build_matrix(
|
||||
loctoh_ort(loc(0,0)),
|
||||
loctoh_ort(param),
|
||||
|
@ -669,6 +674,9 @@ EX namespace gp {
|
|||
C03
|
||||
));
|
||||
cgi.gpdata->Tf.resize(S7);
|
||||
|
||||
/* should work directly without flipping but it does not... flipping for now */
|
||||
|
||||
for(int i=0; i<S7; i++) {
|
||||
transmatrix T = dir_matrix(i);
|
||||
for(int x=-GOLDBERG_LIMIT_HALF; x<GOLDBERG_LIMIT_HALF; x++)
|
||||
|
@ -678,9 +686,21 @@ EX namespace gp {
|
|||
|
||||
hyperpoint h = atz(T, cgi.gpdata->corners, at, 6);
|
||||
hyperpoint hl = atz(T, cgi.gpdata->corners, at + eudir(d), 6);
|
||||
cgi.gpdata->Tf[i][x&GOLDBERG_MASK][y&GOLDBERG_MASK][d] = rgpushxto0(h) * rspintox(gpushxto0(h) * hl) * spin(M_PI);
|
||||
auto& res = cgi.gpdata->Tf[i][x&GOLDBERG_MASK][y&GOLDBERG_MASK][d];
|
||||
res = rgpushxto0(h) * rspintox(gpushxto0(h) * hl) * spin180();
|
||||
}
|
||||
}
|
||||
|
||||
if(geom3::flipped) {
|
||||
geom3::light_flip(false);
|
||||
for(int i=0; i<S7; i++) {
|
||||
for(int x=-GOLDBERG_LIMIT_HALF; x<GOLDBERG_LIMIT_HALF; x++)
|
||||
for(int y=-GOLDBERG_LIMIT_HALF; y<GOLDBERG_LIMIT_HALF; y++)
|
||||
for(int d=0; d<(S3==3?6:4); d++) {
|
||||
auto& T = cgi.gpdata->Tf[i][x&GOLDBERG_MASK][y&GOLDBERG_MASK][d];
|
||||
T = cgi.emb->base_to_actual(T);
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
EX hyperpoint get_corner_position(const local_info& li, int cid, ld cf IS(3)) {
|
||||
|
@ -729,7 +749,6 @@ EX namespace gp {
|
|||
cgi.base_distlimit = 2 * param.first + 2 * param.second + 1;
|
||||
if(cgi.base_distlimit > SEE_ALL)
|
||||
cgi.base_distlimit = SEE_ALL;
|
||||
prepare_matrices();
|
||||
DEBB(DF_GEOM | DF_POLY, ("scale = ", scale));
|
||||
}
|
||||
}
|
||||
|
@ -794,6 +813,15 @@ EX namespace gp {
|
|||
screens = g;
|
||||
}
|
||||
|
||||
EX bool check_whirl_set(loc xy) {
|
||||
if(!check_limits(xy)) {
|
||||
addMessage(XLAT("Outside of the supported limits"));
|
||||
return false;
|
||||
}
|
||||
whirl_set(xy);
|
||||
return true;
|
||||
}
|
||||
|
||||
string helptext() {
|
||||
return XLAT(
|
||||
"Goldberg polyhedra are obtained by adding extra hexagons to a dodecahedron. "
|
||||
|
@ -868,10 +896,11 @@ EX namespace gp {
|
|||
}
|
||||
|
||||
dialog::addBreak(100);
|
||||
int max_goldberg = (1<<GOLDBERG_BITS)/2 - 1;
|
||||
dialog::addSelItem("x", its(config.first), 'x');
|
||||
dialog::add_action([] { dialog::editNumber(config.first, 0, 8, 1, 1, "x", helptext()); });
|
||||
dialog::add_action([max_goldberg] { dialog::editNumber(config.first, 0, max_goldberg, 1, 1, "x", helptext()); });
|
||||
dialog::addSelItem("y", its(config.second), 'y');
|
||||
dialog::add_action([] { dialog::editNumber(config.second, 0, 8, 1, 1, "y", helptext()); });
|
||||
dialog::add_action([max_goldberg] { dialog::editNumber(config.second, 0, max_goldberg, 1, 1, "y", helptext()); });
|
||||
|
||||
if(!check_limits(config))
|
||||
dialog::addInfo(XLAT("Outside of the supported limits"));
|
||||
|
@ -954,24 +983,24 @@ EX namespace gp {
|
|||
auto p = univ_param();
|
||||
if(S3 == 3 && !UNTRUNCATED) {
|
||||
println(hlog, "set param to ", p * loc(1,1));
|
||||
whirl_set(p * loc(1, 1));
|
||||
if(!check_whirl_set(p * loc(1, 1))) return;
|
||||
set_variation(eVariation::untruncated);
|
||||
start_game();
|
||||
config = human_representation(univ_param());
|
||||
}
|
||||
else if(S3 == 4 && !UNRECTIFIED) {
|
||||
whirl_set(p * loc(1, 1));
|
||||
if(!check_whirl_set(p * loc(1, 1))) return;
|
||||
set_variation(eVariation::unrectified);
|
||||
start_game();
|
||||
config = human_representation(univ_param());
|
||||
}
|
||||
else if(S3 == 3 && UNTRUNCATED) {
|
||||
println(hlog, "whirl_set to ", (p * loc(1,1)) / 3);
|
||||
whirl_set((p * loc(1,1)) / 3);
|
||||
if(!check_whirl_set((p * loc(1,1)) / 3)) return;
|
||||
config = human_representation(univ_param());
|
||||
}
|
||||
else if(S3 == 4 && UNRECTIFIED) {
|
||||
whirl_set((p * loc(1,1)) / 2);
|
||||
if(!check_whirl_set((p * loc(1,1)) / 2)) return;
|
||||
config = human_representation(univ_param());
|
||||
}
|
||||
});
|
||||
|
@ -1240,6 +1269,7 @@ EX namespace gp {
|
|||
}
|
||||
|
||||
hrmap_inverse() {
|
||||
underlying_map = nullptr;
|
||||
if(0) {
|
||||
println(hlog, "making ucgi");
|
||||
dynamicval<eVariation> gva(variation, variation_for(param));
|
||||
|
@ -1412,11 +1442,17 @@ EX namespace gp {
|
|||
return C0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
EX hrmap* new_inverse() { return new hrmap_inverse; }
|
||||
|
||||
hrmap_inverse* inv_map() { return (hrmap_inverse*)currentmap; }
|
||||
|
||||
EX bool inverse_pseudohept(cell *c) {
|
||||
cell *c1 = inv_map()->mapping[c];
|
||||
if(!c1) return false;
|
||||
return UIU(pseudohept(c1));
|
||||
}
|
||||
|
||||
EX hrmap* get_underlying_map() { return inv_map()->underlying_map; }
|
||||
EX cell* get_mapped(cell *c) { return inv_map()->get_mapped(c, 0); }
|
||||
EX int untruncated_shift(cell *c) { return inv_map()->shift[c]; }
|
||||
|
@ -1444,5 +1480,9 @@ EX namespace gp {
|
|||
#endif
|
||||
|
||||
|
||||
auto hooksw = addHook(hooks_swapdim, 100, [] {
|
||||
for(auto& p: gp_adj) swapmatrix(p.second);
|
||||
});
|
||||
|
||||
|
||||
}}
|
||||
|
|
157
help.cpp
157
help.cpp
|
@ -14,7 +14,7 @@ EX function<void()> help_delegate;
|
|||
|
||||
#if HDR
|
||||
struct help_extension {
|
||||
char key;
|
||||
int key;
|
||||
string text;
|
||||
string subtext;
|
||||
color_t color;
|
||||
|
@ -97,23 +97,23 @@ EX void buildHelpText() {
|
|||
#endif
|
||||
help += XLAT("! (version %1)\n\n", VER);
|
||||
|
||||
help += XLAT(
|
||||
if(!game_keys_scroll) help += XLAT(
|
||||
"You have been trapped in a strange, non-Euclidean world. Collect as much treasure as possible "
|
||||
"before being caught by monsters. The more treasure you collect, the more "
|
||||
"monsters come to hunt you, as long as you are in the same land type. The "
|
||||
"Orbs of Yendor are the ultimate treasure; get at least one of them to win the game!"
|
||||
);
|
||||
help += XLAT(" (press ESC for some hints about it).");
|
||||
help += "\n\n";
|
||||
if(!game_keys_scroll) help += XLAT(" (press ESC for some hints about it).");
|
||||
if(!game_keys_scroll) help += "\n\n";
|
||||
|
||||
if(!shmup::on && !hardcore)
|
||||
if(!shmup::on && !hardcore && !game_keys_scroll)
|
||||
help += XLAT(
|
||||
"You can fight most monsters by moving into their location. "
|
||||
"The monster could also kill you by moving into your location, but the game "
|
||||
"automatically cancels all moves which result in that.\n\n"
|
||||
);
|
||||
|
||||
if(shmup::on) {
|
||||
if(shmup::on && !game_keys_scroll) {
|
||||
help += XLAT(
|
||||
"Shmup (shoot'em up) mode: You can play a hyperbolic shoot'em up game. The game is based "
|
||||
"on the usual turn-based grid-based HyperRogue, but there are some changes. You fight by "
|
||||
|
@ -122,14 +122,14 @@ EX void buildHelpText() {
|
|||
"adapted too.\n\n");
|
||||
}
|
||||
|
||||
if(shmup::on && multi::players > 1) {
|
||||
if(shmup::on && multi::players > 1 && !game_keys_scroll) {
|
||||
help += XLAT(
|
||||
"Multiplayer: Play cooperatively (locally); treasures, kills, and deaths are calculated "
|
||||
"for each player too, for more competitive play. Orbs and treasures are shared, orbs drain "
|
||||
"faster, knives recharge slower, and player characters are not allowed to separate.\n\n");
|
||||
}
|
||||
|
||||
if(multi::players > 1 && !shmup::on) {
|
||||
if(multi::players > 1 && !shmup::on && !game_keys_scroll) {
|
||||
help += XLAT(
|
||||
"Turn-based multiplayer: Turns are executed in parallel. A player can leave the game "
|
||||
"by pressing a designated key (useful when about to get killed or lost). The following "
|
||||
|
@ -143,11 +143,11 @@ EX void buildHelpText() {
|
|||
}
|
||||
|
||||
#if CAP_INV
|
||||
if(inv::on)
|
||||
if(inv::on && !game_keys_scroll)
|
||||
help += XLAT(
|
||||
inv::helptext
|
||||
);
|
||||
else
|
||||
else if(!game_keys_scroll)
|
||||
#endif
|
||||
help += XLAT(
|
||||
"There are many lands in HyperRogue. Collect 10 treasure "
|
||||
|
@ -156,7 +156,7 @@ EX void buildHelpText() {
|
|||
"get access to new lands. At 25 treasures "
|
||||
"this type of Orbs starts appearing in other lands as well. Press 'o' to "
|
||||
"get the details of all the Lands.\n\n");
|
||||
help += "\n\n";
|
||||
if(!game_keys_scroll) help += "\n\n";
|
||||
|
||||
#if ISMOBILE
|
||||
help += XLAT(
|
||||
|
@ -166,11 +166,17 @@ EX void buildHelpText() {
|
|||
"numbers displayed to get their meanings.\n"
|
||||
);
|
||||
#else
|
||||
if(DEFAULTCONTROL)
|
||||
if(DEFAULTCONTROL && !game_keys_scroll)
|
||||
help += XLAT(
|
||||
"Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Space. "
|
||||
"To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n"
|
||||
);
|
||||
else if(DEFAULTCONTROL && WDIM == 2)
|
||||
help += XLAT(
|
||||
"You are currently in a visualization. Press wasd to scroll, qe to rotate. You can also use the arrow keys. ESC for menu.\n\n");
|
||||
else if(DEFAULTCONTROL && WDIM == 3)
|
||||
help += XLAT(
|
||||
"You are currently in a visualization. Press wasdqe to rotate the camera, ijklyh to move. You can also use the arrow keys and Home/End and PgUp/PgDn. ESC for menu.\n\n");
|
||||
help += XLAT(
|
||||
"You can right click any element to get more information about it.\n\n"
|
||||
);
|
||||
|
@ -179,9 +185,10 @@ EX void buildHelpText() {
|
|||
#endif
|
||||
#endif
|
||||
help += XLAT("See more on the website: ")
|
||||
+ "http//roguetemple.com/z/hyper/\n\n";
|
||||
+ "https://roguetemple.com/z/hyper/\n\n";
|
||||
|
||||
#if CAP_TOUR
|
||||
if(!tour::on)
|
||||
help += XLAT("Try the Guided Tour to help with understanding the "
|
||||
"geometry of HyperRogue (menu -> special modes).\n\n");
|
||||
#endif
|
||||
|
@ -211,6 +218,7 @@ EX void buildHelpText() {
|
|||
}
|
||||
|
||||
EX string standard_help() {
|
||||
if(nohelp == 2) return "";
|
||||
return XLAT("Press F1 or right click for help");
|
||||
}
|
||||
|
||||
|
@ -228,11 +236,12 @@ EX void buildCredits() {
|
|||
help += XLAT(
|
||||
"special thanks to the following people for their bug reports, feature requests, porting, and other help:\n\n%1\n\n",
|
||||
"Konstantin Stupnik, ortoslon, chrysn, Adam Borowski, Damyan Ivanov, Ryan Farnsley, mcobit, Darren Grey, tricosahedron, Maciej Chojecki, Marek Čtrnáct, "
|
||||
"wonderfullizardofoz, Piotr Migdał, tehora, Michael Heerdegen, Sprite Guard, zelda0x181e, Vipul, snowyowl0, Patashu, phenomist, Alan Malloy, Tom Fryers, Sinquetica, _monad, CtrlAltDestroy, jruderman, "
|
||||
"wonderfullizardofoz, Piotr Migdał, Tehora Rogue, Michael Heerdegen, Sprite Guard, zelda0x181e, Vipul, snowyowl0, Patashu, phenomist, Alan Malloy, Tom Fryers, Sinquetica, _monad, CtrlAltDestroy, jruderman, "
|
||||
"Kojiguchi Kazuki, baconcow, Alan, SurelyYouJest, hotdogPi, DivisionByZero, xXxWeedGokuxXx, jpystynen, Dmitry Marakasov, Alexandre Moine, Arthur O'Dwyer, "
|
||||
"Triple_Agent_AAA, bluetailedgnat, Allalinor, Shitford, KittyTac, Christopher King, KosGD, TravelDemon, Bubbles, rdococ, frozenlake, MagmaMcFry, "
|
||||
"Snakebird Priestess, roaringdragon2, Stopping Dog, bengineer8, Sir Light IJIJ, ShadeBlade, Saplou, shnourok, Ralith, madasa, 6% remaining, Chimera245, Remik Pi, alien foxcat thing, "
|
||||
"Piotr Grochowski, Ann, still-flow, tyzone, Paradoxica, LottieRatWorld, aismallard"
|
||||
"Piotr Grochowski, Ann, still-flow, tyzone, Paradoxica, LottieRatWorld, aismallard, albatross, EncodedSpirit, Jacob Mandelson, CrashTuvai, cvoight, jennlbw, Kali Ranya, spiritbackup, Dylan, L_Lord, AntiRogue, "
|
||||
"masonlgreen, A human, Pasu4"
|
||||
);
|
||||
#ifdef EXTRALICENSE
|
||||
help += EXTRALICENSE;
|
||||
|
@ -402,7 +411,7 @@ EX string generateHelpForItem(eItem it) {
|
|||
help += XLAT("You can press 'g' or click them in the list to drop a Dead Orb.");
|
||||
#endif
|
||||
if(it == itOrbLightning || it == itOrbFlash)
|
||||
help += XLAT("\n\nThis Orb is triggered on your first attack or illegal move.");
|
||||
help += XLAT("\n\nThis Orb is triggered on your first direct melee attack or illegal move.");
|
||||
if(it == itOrbShield)
|
||||
help += XLAT("\n\nThis Orb protects you from attacks, scents, and insulates you "
|
||||
"from electricity. It does not let you go through deadly terrain, but "
|
||||
|
@ -518,6 +527,33 @@ EX string generateHelpForItem(eItem it) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
int oc = orbcharges(it); if(oc) {
|
||||
|
||||
if(items[itOrbIntensity]) {
|
||||
int oc2 = intensify(oc);
|
||||
help += XLAT("\n\nOrb charges gained on pickup: %1 (increased to %2 by %the3)", its(oc), its(oc2), itOrbIntensity);
|
||||
}
|
||||
else
|
||||
help += XLAT("\n\nOrb charges gained on pickup: %1", its(oc));
|
||||
}
|
||||
|
||||
int ac = 0;
|
||||
if(among(it, itOrbFrog, itOrbPhasing, itOrbDash)) ac = 5;
|
||||
if(among(it, itOrbSummon)) ac = 20;
|
||||
if(among(it, itOrbPsi)) ac = 30;
|
||||
if(among(it, itOrbStunning)) ac = 10;
|
||||
if(among(it, itOrbMorph)) ac = 3;
|
||||
if(among(it, itOrbIllusion)) ac = 5;
|
||||
if(among(it, itOrbDragon)) ac = 5;
|
||||
if(among(it, itOrbAir)) ac = 1;
|
||||
|
||||
if(ac) {
|
||||
if(items[itOrbEnergy])
|
||||
help += XLAT("\n\nActivation cost: %1 charges (reduced to %2 by %the3)\n", its(ac), its((1+ac)/2), itOrbEnergy);
|
||||
else
|
||||
help += XLAT("\n\nActivation cost: %1 charges\n", its(ac));
|
||||
}
|
||||
|
||||
if(it == itOrb37 && (S7 != 7 || !BITRUNCATED))
|
||||
help += "\n\n" + other_geometry() + forbidden_unmarked();
|
||||
|
@ -544,6 +580,20 @@ EX string generateHelpForItem(eItem it) {
|
|||
return help;
|
||||
}
|
||||
|
||||
void mine_dialog() {
|
||||
cmode = sm::SIDE;
|
||||
gamescreen();
|
||||
dialog::init("Minefield graphics");
|
||||
add_edit(numerical_minefield);
|
||||
add_edit(mine_zero_display);
|
||||
add_edit(mine_opacity);
|
||||
add_edit(mine_hollow);
|
||||
add_edit(mine_markers);
|
||||
dialog::addItem(XLAT("minefield colors"), 'c');
|
||||
dialog::add_action_push([] { edit_color_table(minecolors); });
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
void addMinefieldExplanation(string& s) {
|
||||
|
||||
s += XLAT(
|
||||
|
@ -559,7 +609,7 @@ void addMinefieldExplanation(string& s) {
|
|||
s += XLAT("Known mines may be marked by touching while in drag mode. Your allies won't step on marked mines.");
|
||||
#endif
|
||||
|
||||
help_extensions.push_back(help_extension{'n', XLAT("toggle numerical display"), [] () { numerical_minefield = !numerical_minefield; }});
|
||||
help_extensions.push_back(help_extension{'c', XLAT("configure"), [] () { pushScreen(mine_dialog); } });
|
||||
}
|
||||
|
||||
EX string generateHelpForWall(eWall w) {
|
||||
|
@ -578,8 +628,7 @@ EX string generateHelpForWall(eWall w) {
|
|||
void buteol(string& s, int current, int req) {
|
||||
int siz = isize(s);
|
||||
if(s[siz-1] == '\n') s.resize(siz-1);
|
||||
char buf[100]; sprintf(buf, " (%d/%d)", current, req);
|
||||
s += buf; s += "\n";
|
||||
s += hr::format(" (%d/%d)\n", current, req);
|
||||
}
|
||||
|
||||
EX string generateHelpForMonster(eMonster m) {
|
||||
|
@ -692,10 +741,12 @@ void add_reqs(eLand l, string& s) {
|
|||
#define COND(x,y) s += (y);
|
||||
#define ITEMS_TOTAL(list, z) \
|
||||
{ int now = 0; string t = "("; for(eItem i: list) { if(t!="(") t += " | "; t += XLATN(iinf[i].name); now += items[i]; } t += ")"; s += XLAT("Treasure required: %1 x %2.\n", its(z), t); buteol(s, now, z); }
|
||||
#define INMODE(x) ;
|
||||
#define ACCONLY(z) s += XLAT("Accessible only from %the1.\n", z);
|
||||
#define ACCONLY2(z,x) s += XLAT("Accessible only from %the1 or %the2.\n", z, x);
|
||||
#define ACCONLY3(z,y,x) s += XLAT("Accessible only from %the1 or %the2.\n", z, y, x);
|
||||
#define ACCONLY3(z,y,x) s += XLAT("Accessible only from %the1, %2, or %3.\n", z, y, x);
|
||||
#define ACCONLYF(z) s += XLAT("Accessible only from %the1 (until finished).\n", z);
|
||||
#define IFINGAME(land, ok, fallback) if(isLandIngame(land)) { ok } else { s += XLAT("Alternative rule when %the1 is not in the game:\n", land); fallback }
|
||||
#include "content.cpp"
|
||||
|
||||
case landtypes: return;
|
||||
|
@ -838,7 +889,10 @@ int windtotal;
|
|||
EX hookset<void(cell*)> hooks_mouseover;
|
||||
|
||||
template<class T> void set_help_to(T t) {
|
||||
help = bygen([t] { gotoHelpFor(t); });
|
||||
help = bygen([t] {
|
||||
gotoHelpFor(t);
|
||||
help_extensions.push_back(help_extension{'h', XLAT("HyperRogue help"), [] () { buildHelpText(); }});
|
||||
});
|
||||
}
|
||||
|
||||
EX void describeMouseover() {
|
||||
|
@ -870,9 +924,9 @@ EX void describeMouseover() {
|
|||
if(shmup::on)
|
||||
out += " (" + its(c->landparam)+")";
|
||||
else {
|
||||
bool b = c->landparam >= tide[(turncount-1) % tidalsize];
|
||||
bool b = c->landparam >= tide[turncount % tidalsize];
|
||||
int t = 1;
|
||||
for(; t < 1000 && b == (c->landparam >= tide[(turncount+t-1) % tidalsize]); t++) ;
|
||||
for(; t < 1000 && b == (c->landparam >= tide[(turncount+t) % tidalsize]); t++) ;
|
||||
if(b)
|
||||
out += " (" + turnstring(t) + XLAT(" to surface") + ")";
|
||||
else
|
||||
|
@ -881,7 +935,7 @@ EX void describeMouseover() {
|
|||
}
|
||||
#if CAP_FIELD
|
||||
else if(c->land == laVolcano) {
|
||||
int id = lavatide(c, -1)/4;
|
||||
int id = lavatide(c, 0)/4;
|
||||
if(id < 96/4)
|
||||
out += " (" + turnstring(96/4-id) + XLAT(" to go cold") + ")";
|
||||
else
|
||||
|
@ -919,7 +973,7 @@ EX void describeMouseover() {
|
|||
}
|
||||
|
||||
if(buggyGeneration) {
|
||||
char buf[80]; sprintf(buf, " %p H=%d M=%d", hr::voidp(c), c->landparam, c->mpdist); out += buf;
|
||||
out += hr::format(" %p H=%d M=%d", hr::voidp(c), c->landparam, c->mpdist);
|
||||
}
|
||||
|
||||
if(randomPatternsMode)
|
||||
|
@ -954,7 +1008,12 @@ EX void describeMouseover() {
|
|||
if(c->wall && !(c->wall == waChasm && c->land == laDual && ctof(c)) &&
|
||||
!(c->land == laMemory) &&
|
||||
!((c->wall == waFloorA || c->wall == waFloorB) && c->item)) {
|
||||
out += ", "; out += XLAT1(winf[c->wall].name);
|
||||
|
||||
eWall w = c->wall;
|
||||
if(isAlch(w))
|
||||
w = conditional_flip_slime(mousing ? det(mouseoverV.T) < 0 : det(View) < 0, w);
|
||||
|
||||
out += ", "; out += XLAT1(winf[w].name);
|
||||
|
||||
if(c->wall == waRose) out += " (" + its(7-rosephase) + ")";
|
||||
if(c->wall == waTerraWarrior) out += " (" + its(c->wparam) + ")";
|
||||
|
@ -1071,16 +1130,7 @@ EX void describeMouseover() {
|
|||
#endif
|
||||
}
|
||||
|
||||
EX void showHelp() {
|
||||
cmode = sm::HELP | sm::DOTOUR | sm::DARKEN;
|
||||
getcstat = SDLK_ESCAPE;
|
||||
if(help == "HELPFUN") {
|
||||
help_delegate();
|
||||
return;
|
||||
}
|
||||
|
||||
gamescreen();
|
||||
string help2;
|
||||
EX void addHelpWithTitle() {
|
||||
if(help[0] == '@') {
|
||||
int iv = help.find("\t");
|
||||
int id = help.find("\n");
|
||||
|
@ -1091,29 +1141,46 @@ EX void showHelp() {
|
|||
dialog::init("help", forecolor, 120, 100);
|
||||
dialog::addHelp(help);
|
||||
}
|
||||
}
|
||||
|
||||
EX void showHelp() {
|
||||
cmode = sm::HELP | sm::DOTOUR | sm::DARKEN;
|
||||
getcstat = SDLK_ESCAPE;
|
||||
if(help == "HELPFUN") {
|
||||
help_delegate();
|
||||
return;
|
||||
}
|
||||
|
||||
gamescreen();
|
||||
string help2;
|
||||
addHelpWithTitle();
|
||||
|
||||
bool in_list = false;
|
||||
|
||||
for(auto& he: help_extensions) {
|
||||
if(!in_list && he.key == dialog::first_list_fake_key) {
|
||||
dialog::start_list(1000, 1000, 'a');
|
||||
in_list = true;
|
||||
}
|
||||
if(in_list && (he.key < dialog::first_list_fake_key || he.key > dialog::first_list_fake_key + 1000)) {
|
||||
in_list = false;
|
||||
dialog::end_list();
|
||||
}
|
||||
|
||||
if(he.subtext != "")
|
||||
dialog::addSelItem(he.text, he.subtext, he.key);
|
||||
else
|
||||
dialog::addItem(he.text, he.key);
|
||||
dialog::add_action(he.action);
|
||||
dialog::lastItem().color = he.color;
|
||||
}
|
||||
if(in_list) dialog::end_list();
|
||||
|
||||
dialog::display();
|
||||
|
||||
keyhandler = [] (int sym, int uni) {
|
||||
dialog::handleNavigation(sym, uni);
|
||||
|
||||
for(auto& he: help_extensions)
|
||||
if(uni == he.key) {
|
||||
// we need to copy he.action
|
||||
// as otherwise it could clear the extensions,
|
||||
// leading to errors
|
||||
auto act = he.action;
|
||||
act();
|
||||
return;
|
||||
}
|
||||
if(sym == SDLK_F1) {
|
||||
auto i = help;
|
||||
buildHelpText();
|
||||
|
|
|
@ -25,6 +25,7 @@ cell *newCell(int type, heptagon *master);
|
|||
*/
|
||||
|
||||
EX hstate transition(hstate s, int dir) {
|
||||
if(embedded_plane) return IPF(transition(s, dir));
|
||||
if(sphere) {
|
||||
if(S7 == 4) {
|
||||
if(s == hsOrigin) return dir == 0 ? hsB0 : hsB1;
|
||||
|
@ -136,8 +137,8 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0, int fix
|
|||
int d1 = (d+S7-1)%S7;
|
||||
bool missing0 = !h->move(0)->move(d1);
|
||||
if(missing0) {
|
||||
if(s == 1)
|
||||
h->distance = h->move(0)->distance + 1;
|
||||
if(s == 1 && h->move(0)->s != hsOrigin)
|
||||
h->distance = h->move(0)->distance + 1;
|
||||
}
|
||||
else {
|
||||
heptagon* h1 = createStep(h->move(0), d1);
|
||||
|
|
51
history.cpp
51
history.cpp
|
@ -40,12 +40,12 @@ namespace spiral {
|
|||
CY = band[0]->h;
|
||||
SX = out->w;
|
||||
SY = out->h;
|
||||
|
||||
ld prec = 2*M_PI*M_PI;
|
||||
|
||||
ld k = -2*M_PI*M_PI / log(2.6180339);
|
||||
ld k = -prec / log(2.6180339);
|
||||
|
||||
// cxld mnoznik = cxld(0, M_PI) / cxld(k, M_PI);
|
||||
|
||||
cxld factor = cxld(0, -CY/2/M_PI/M_PI) * cxld(k, M_PI);
|
||||
cxld factor = cxld(0, -CY/prec) * cxld(k, M_PI);
|
||||
|
||||
Yshift = CY * k / M_PI;
|
||||
|
||||
|
@ -372,7 +372,7 @@ EX namespace history {
|
|||
v[ph+1]->at * C0;
|
||||
|
||||
View = xpush(-(phase-ph) * hdist(now, next)) * View;
|
||||
if(WDIM == 2 || prod) {
|
||||
if(WDIM == 2 || mproduct) {
|
||||
View = models::rotmatrix() * View;
|
||||
}
|
||||
else {
|
||||
|
@ -453,10 +453,15 @@ EX namespace history {
|
|||
if(1) {
|
||||
// block for RAII
|
||||
dynamicval<videopar> dv(vid, vid);
|
||||
dynamicval<ld> dr(models::rotation, 0);
|
||||
dynamicval<trans23> dr(models::rotation, Id);
|
||||
dynamicval<bool> di(inHighQual, true);
|
||||
|
||||
renderbuffer glbuf(bandfull, bandfull, vid.usingGL);
|
||||
glbuf.make_surface(); if(!glbuf.srf) {
|
||||
addMessage(XLAT("Could not create an image of that size."));
|
||||
return;
|
||||
}
|
||||
|
||||
vid.xres = vid.yres = bandfull;
|
||||
glbuf.enable(); current_display->radius = bandhalf;
|
||||
calcparam();
|
||||
|
@ -470,7 +475,7 @@ EX namespace history {
|
|||
auto save_band_segment = [&] {
|
||||
string fname = name_format;
|
||||
replace_str(fname, "$DATE", timebuf);
|
||||
replace_str(fname, "$ID", format("%03d", segid++));
|
||||
replace_str(fname, "$ID", hr::format("%03d", segid++));
|
||||
IMAGESAVE(band, fname.c_str());
|
||||
|
||||
if(dospiral)
|
||||
|
@ -480,7 +485,8 @@ EX namespace history {
|
|||
};
|
||||
|
||||
if(!band) {
|
||||
addMessage("Could not create an image of that size.");
|
||||
addMessage(XLAT("Could not create an image of that size."));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
|
@ -498,10 +504,7 @@ EX namespace history {
|
|||
|
||||
pushScreen(progress_screen);
|
||||
|
||||
char buf[128];
|
||||
sprintf(buf, "#%03d", segid);
|
||||
|
||||
progress(s0 + buf + " ("+its(j+bonus)+"/"+its(siz+bonus+bonus-1)+")"); */
|
||||
progress(s0 + hr::format("#%03d (%d/%d)", segid, j+bonus, siz+bonus+bonus-1)); */
|
||||
|
||||
// calcparam(); current_display->radius = bandhalf;
|
||||
phase = j; movetophase();
|
||||
|
@ -531,6 +534,10 @@ EX namespace history {
|
|||
len -= bandsegment; xpos -= bandsegment;
|
||||
seglen = min(int(len), bandsegment);
|
||||
band = SDL_CreateRGBSurface(SDL_SWSURFACE, seglen, bandfull,32,0,0,0,0);
|
||||
if(!band) {
|
||||
addMessage(XLAT("Could not create an image of that size."));
|
||||
return;
|
||||
}
|
||||
goto drawsegment;
|
||||
}
|
||||
xpos += bwidth;
|
||||
|
@ -749,19 +756,19 @@ EX namespace history {
|
|||
history::includeHistory = false;
|
||||
}) + addHook(hooks_configfile, 0, [] {
|
||||
|
||||
addsaver(autobandhistory, "include history"); // check!
|
||||
param_f(lvspeed, "lvspeed", "lineview speed");
|
||||
addsaver(extra_line_steps, "lineview extension");
|
||||
param_b(autobandhistory, "include history"); // check!
|
||||
param_f(lvspeed, parameter_names("lvspeed", "lineview speed"));
|
||||
param_f(extra_line_steps, "lineview extension");
|
||||
|
||||
addsaver(bandhalf, "band width");
|
||||
addsaver(bandsegment, "band segment");
|
||||
addsaver(autoband, "automatic band");
|
||||
addsaver(autobandhistory, "automatic band history");
|
||||
addsaver(dospiral, "do spiral");
|
||||
param_i(bandhalf, "band width");
|
||||
param_i(bandsegment, "band segment");
|
||||
param_b(autoband, "automatic band");
|
||||
param_b(autobandhistory, "automatic band history");
|
||||
param_b(dospiral, "do spiral");
|
||||
|
||||
#if CAP_SHOT && CAP_SDL
|
||||
addsaver(band_format_auto, "band_format_auto");
|
||||
addsaver(band_format_now, "band_format_now");
|
||||
param_str(band_format_auto, "band_format_auto");
|
||||
param_str(band_format_now, "band_format_now");
|
||||
#endif
|
||||
});
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
xзМ■Иmц0┘╘:n▌╕q t.А╚М:|▄жя╡┘C┼┼" :@M─фШ(И▐s░R║╧V┴V│сл*яэY2┤dгёRxоv(x^*|>aИ╔≈Ч╞ЩK=┘zВЙ4Цs$Ф▐└└оp┌rw╟├ш\xг└В4/С_j 8/Ш┘7p┬°ШyXя|ВШ1©▒>D~УСcЮлГвЯ╝≥оoФЭ6АЖРrч'yyЁДЪ~иъчоЫK┴зhтNci5╨ч║┼[▓╚и╣╫E;Xrк░eв▄м`П╬│щ*ЗVQ╠W▒╙Ц╝К╗ь╚I5ЯЭ⌡╗ьkH╣ьУv#Уп╣3БY;#·╣D_Ь█?xhLХН
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
xΪ<EFBFBD>•ωRΤ@Ζ›K`ρDΕ[ΔµEEAE±*{°ψI6wΟGσ<47>µ{<7B>LΟ&T±UI6Ώώ<CE8F>έσMgwόΟΒ%ΎCΗ3Λt,™ƒ?+ζΊf®‹†^π|Wώή%Ω‚Ι<E2809A>έ<1C>θf&>ίΰ+Βk<CE92>2?4dζωΌ›SKή¥·ω7`,ΧΧ]`½δΊ®ζWα…§GΨ…»s\χoωNKΏ5Η<0F>~‹Όaς~Συ³βZ#Ή\οΆ:o«σ<C2AB>πGrιΫ’α<E28099>ηΰώ±α³™δ²Ι¥ΟΛp<13>ƒ®ϋ¥ΙβsYwn5ό‡π_rι?(®uR/ΉάΗσύ>μΓϊΞ>σ½δrήΦa@[oω=βoΝ>ςy•ψK“λ}³Ώ·Ar9'λ†ΛΊ’s~™ηJ³οϋ ύ—\Ξ³ζO¥ϊ—zΝεΊzp<7A>®Οηϋ=£—\ζΡ|Ϋθ?Α^—}φΰΨ9a½<61>ΙεΌυΰ†Ϊχ¶ήq9?–Ο½ύ’Λ9μ‘Οα1ό4λuzΗεώjήε<CEAE>γΎ<CEB3>›Tχόjυγψ‡f>ο€ε]ύXξζΑκ»όw\ώ<>X~άΩ<CEAC>ζς=ZSΌύ~I.ϋ—\φ)Ήχ»χ—ώy<02>£ƒ΄Β 1<><31>WO0<>b<EFBFBD>ΒC (’NsLσ£43
|
||||
~Φ*ΆJGΊ<47>·QW3lΥd<12>ZI‘`’'<27>^ΠΩE Ίf}2<>}ΰΕετ5²vϋΤ'χW•φ©Η*µkκ«υ¤ρϋDΛ"Γ~Y©¨‘.ιHΤ<48>WuθQWΥFό^"ΡΧ9Α"¥3U:΅JeTΚω|buά‘&¶Ώ$<24>q„#ς…5#γµ£rxΟ8¨¬Λλ0Ζ9β(ϋ3lbΓΌ »a]`>%‰kµαΜ<CEB1>ΨZCρ<43>ΞΞ>ΒTω IάTζz6>π¨ν<C2A8>έ7ΊqMG)jΩ9<CEA9>Sf³<C2AD>Κ·we–“†ηµ§γσ3<#ί™ϊΪ<CF8A>΄Υu:ή<>"<22>’†½¥§γσS<Ν
|
||||
¥γΈL•+™Ρρ:&<26>Ώ“¬4λ”qλΔS‹spl®Φ'”§ Zν:YSgάzΞu<CE9E>uvΟυ<%bΚ|:Ά<>ο¦<<0F>Ψ ω23WΚ
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
xз∙∙=t
A├©╫!"!┌$"n┬ ┤ёп┬÷ёJ╔Rы≥²╜T*∙J╔R╔R╘hT*∙J╔R╘T*∙JЕ°xФчмэoЪНIЖ°gФЩч}Г⌡ы{▀≥Ш ╡ "┴└!I:L²╒ч╝<╫▄РeHN©╞ФvzЛ╪╚>:╚В╛ЖуЩ╙К7Юv╒о7пШHТуs╖пгe©▄длhT'Е─ЙрФ▐)=У╛▄zN∙~╜╫²g╪q/щSОuZ╔■>я╒Г∙>╣_Вт{-*}FИ╝рK-╨ш╡╤ъsE9╒·░▀┘>б|╘пGЕ╟Л5©*W╘нЖ°кr█ЫL╤ЗFжd]√e Й┼\G÷≈c2%ш[#"н╔yn°Ё▄В▄кп>т5╥Лт2√й⌡
folT%/т6У╔fе-;X█и│÷вэ╕$)▌бwь╢Т∙U/т6~_╛hze.U╩╤{╝╘╨kR e▄ЮщБыба
|
||||
c·∙э░ёaТь`╗;ХиРф╝зО╖╠о0П}мmЙ^⌠вЭ╤NЕЁ{gwЕ╧aNф²2:фШ&СХ<mrкN=cяЛ^ЙRУBМБЗXy2ж<0>╥М╒сSммБ┼┘ ≤├YX└eX┘5╦w`а&<├'ПrxоА╪└WПчю╪┘wП>б'Ь_Ю+|┐ОП~б/Ь
Ю/ЭW1ввLблCVююzр©БЧ÷⌠Tq
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue