Compare commits
693 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b4ce68606 | |||
| 164e9dbe36 | |||
| 2a21eb4392 | |||
| 97061f7a32 | |||
| 7f84f3daef | |||
| 9f3e09498d | |||
| 55bcd92860 | |||
| 1030a2a4f3 | |||
| bc407187e1 | |||
| 62c7b6b7bb | |||
| 35ac115e8b | |||
| f99f8c271e | |||
| 21dabc9cfc | |||
| 77d9bfc772 | |||
| 29617451d8 | |||
| e530695f54 | |||
| 1f4de65356 | |||
| 9dc186abf4 | |||
| 086d9f6af6 | |||
| 7e658d74b5 | |||
| 2bb242e6fb | |||
| d85441867e | |||
| 38aa80d60a | |||
| 5e35e53eb3 | |||
| f41effd44f | |||
| 17fad8b33c | |||
| 1c96c88082 | |||
| 2b884d0aea | |||
| 89345d4fbc | |||
| cf8de05d1b | |||
| f9432c7c05 | |||
| d6f30d6519 | |||
| eb864338b4 | |||
| bf13491987 | |||
| 0dd26de905 | |||
| 795bdcd427 | |||
| 6f57d2366e | |||
| 8b86bb1b31 | |||
| 0db343c959 | |||
| f5cd740497 | |||
| b6c67ddf34 | |||
| c51b08c827 | |||
| 970894ea21 | |||
| d5d933b4e6 | |||
| 7e32263946 | |||
| 543cc22c44 | |||
| c86cd88a57 | |||
| ac5b3466e7 | |||
| 3cdd564228 | |||
| a5fb3c6ac5 | |||
| 3f36f933ff | |||
| 22b284063b | |||
| f32bcae8d3 | |||
| c05f4001fd | |||
| a72ac33768 | |||
| c53c9b1793 | |||
| c56128a7e2 | |||
| b4e9d86d1d | |||
| aac931f6b2 | |||
| ed9e9110e5 | |||
| c4194e2b76 | |||
| 84236093c8 | |||
| 77f698397a | |||
| b7329299f9 | |||
| 127723a1e7 | |||
| 4a7b8a2bb9 | |||
| 2f91573284 | |||
| f49ef7594d | |||
| 0022de499d | |||
| 359da9a688 | |||
| 1a636c8c40 | |||
| 2c95793293 | |||
| 93d2100546 | |||
| eeb408c68c | |||
| d5ed705f22 | |||
| adf07a7c98 | |||
| ea4e07b2c9 | |||
| ac7e2fda94 | |||
| 8690d406f3 | |||
| ebcfd3963d | |||
| ea9c9edff1 | |||
| 2e49f1d06b | |||
| 0981768c72 | |||
| 70a55d1175 | |||
| 7ae041595a | |||
| ac14c8f931 | |||
| e147ce5d37 | |||
| 472727552e | |||
| 373ab0c3dc | |||
| 5bca261582 | |||
| 99f71874c0 | |||
| 1c8011ff74 | |||
| f9cd90bd49 | |||
| 988596075c | |||
| 2b27729062 | |||
| dac40ecf98 | |||
| c48b4ea0fe | |||
| 7380da7b5e | |||
| 815bcf176c | |||
| ba487bea41 | |||
| 6cdff07180 | |||
| 87705f7e4b | |||
| c90ec248cd | |||
| 0c046e8c29 | |||
| b7a503e5c4 | |||
| aaf5f1ff71 | |||
| a5dd5ce9df | |||
| b08e5e1d96 | |||
| b6bda04a7a | |||
| 1cf5808f4f | |||
| 7401a8e3b4 | |||
| c3ca12edb9 | |||
| 9d8b0b3a90 | |||
| 0a75e34f3f | |||
| 2f0fd9fd7b | |||
| 0d7d36c0b5 | |||
| a321e4ef66 | |||
| 041f54352c | |||
| 09cc0a5c34 | |||
| 1e4117fcab | |||
| cfb537dc0f | |||
| e5e01dca88 | |||
| eba219bcce | |||
| 8632d71ed6 | |||
| 5e0d096ec0 | |||
| 7c463c9eb9 | |||
| cd83bbb67d | |||
| 476b7a6a45 | |||
| e4290598d5 | |||
| 3343385a7c | |||
| a831c2ada3 | |||
| a945201cec | |||
| 2e3df272ec | |||
| ded4caca2f | |||
| a12fc6e344 | |||
| fa0875e63b | |||
| 05d33ec58e | |||
| 7013cffeaa | |||
| a1a5af034d | |||
| 9aac386ec9 | |||
| 651eb8834b | |||
| 48221582c3 | |||
| e04e1e70af | |||
| a78a4147db | |||
| 657a014cae | |||
| de7226f792 | |||
| 22a125d720 | |||
| 8ae6bc9102 | |||
| 3f19e89b91 | |||
| 399c3017ad | |||
| 183d5a2416 | |||
| ddd67c6034 | |||
| 202552a967 | |||
| 9d3439b25c | |||
| b6ccee010b | |||
| 02ab4a9014 | |||
| 429f74393e | |||
| a547b3a384 | |||
| 8e2b367e94 | |||
| ea6d338d71 | |||
| c2396bcd5e | |||
| 4e0b63f06b | |||
| 323b1e1799 | |||
| 148f527504 | |||
| 6a8951ab39 | |||
| b76374fb58 | |||
| c435ca5fa7 | |||
| c9735e9a98 | |||
| 0400e9276d | |||
| 632790fabd | |||
| b61bbda668 | |||
| c2e99e2ce6 | |||
| cfca8f1fdd | |||
| b0d44738c7 | |||
| 8088e21ba4 | |||
| 68dad2a148 | |||
| a25b642164 | |||
| b37fa47211 | |||
| aea65b3753 | |||
| 3a68ba8927 | |||
| 97c21b5057 | |||
| 5be939a39f | |||
| 080022127c | |||
| eb017c01a9 | |||
| 1ea6355a9e | |||
| f6f766c5b6 | |||
| d8bf437214 | |||
| 5dc3ebed4f | |||
| 43690ace29 | |||
| e6696a1758 | |||
| 93b0aa948f | |||
| 439faf425f | |||
| 33c5f79ed7 | |||
| 0ca86eb01b | |||
| d69b736a72 | |||
| ac4bb8bc11 | |||
| fbf8e7155c | |||
| f2de40e096 | |||
| c6a3f090cd | |||
| 46a467de46 | |||
| 62b06f8fc6 | |||
| f18f1d20f3 | |||
| a88aa57ef0 | |||
| ba1ed773af | |||
| 76f2145072 | |||
| ba856346a9 | |||
| 39e33848aa | |||
| dfe6ecadac | |||
| e9093b9360 | |||
| cbc778bff7 | |||
| b65709fca4 | |||
| d45bdbc3d0 | |||
| 50f0072c7a | |||
| c443e0d39c | |||
| 14483629e5 | |||
| 3a5a97c6b9 | |||
| 9936388600 | |||
| 6aacebcc74 | |||
| c842fef2f7 | |||
| a87eca3bd8 | |||
| daf174ec3f | |||
| 7afcdce21e | |||
| 3bc2ff2853 | |||
| f7f9190227 | |||
| bfd7f6e5a5 | |||
| 8e8e249426 | |||
| 99d0d115c7 | |||
| 798c015944 | |||
| 732621f37c | |||
| 238b9d04bb | |||
| 57e96458d5 | |||
| 9dbdd2b830 | |||
| d60238a400 | |||
| 7319651ac4 | |||
| 36a228489b | |||
| 27e9b1d6f2 | |||
| 4bf8aff2e6 | |||
| 1c0e046236 | |||
| a65c56eb41 | |||
| 00f958a71e | |||
| 8aadf5a446 | |||
| a344011486 | |||
| a17a20fe8b | |||
| ee56aa50be | |||
| b4b32d52e3 | |||
| 526dbaf396 | |||
| 737f896070 | |||
| fb56190f6f | |||
| c4ac1d7e6c | |||
| 7d650ebbc3 | |||
| 72971b5f16 | |||
| 937c791196 | |||
| 3348938d46 | |||
| f95819cf37 | |||
| 9563d730bd | |||
| 5be8c8ed36 | |||
| 38b6643d1d | |||
| 038ead0d55 | |||
| a4d342caa1 | |||
| c00c04acd2 | |||
| 7772f2e97f | |||
| 99a9524ee7 | |||
| 840ef3b3a5 | |||
| 009321d905 | |||
| 1a094e1970 | |||
| 6df0d2dc6e | |||
| 5011246e79 | |||
| c8e07cf857 | |||
| a54f00875f | |||
| ce92d564f4 | |||
| afabcbde49 | |||
| 88d0780d69 | |||
| 33d4652758 | |||
| 09967ac256 | |||
| aa84b2b8cd | |||
| a8f1ac38fa | |||
| d11c3fcc2f | |||
| 92b54edb4a | |||
| e54453e6c6 | |||
| c7e7bb5c25 | |||
| 596a17453d | |||
| 70a3dee588 | |||
| b4fc50ad71 | |||
| 930ad77db5 | |||
| 20de12792f | |||
| 6eaccb9976 | |||
| a877275916 | |||
| e4e8e0a444 | |||
| ef222e66f2 | |||
| 31eed1cb48 | |||
| 0cd61b758e | |||
| 4ef54cf8cb | |||
| 5066439fef | |||
| dd12d2ebcb | |||
| cfdda5716d | |||
| a33715ad51 | |||
| 05aac02966 | |||
| 1af0186886 | |||
| 3e0dbb9755 | |||
| d9f7d94115 | |||
| 94f4e680af | |||
| e17b5d2300 | |||
| 601f8a97fa | |||
| e6b7f25932 | |||
| 6c08b21f7f | |||
| d22c530f79 | |||
| ddcaffc1b1 | |||
| 6696be59a4 | |||
| e1df468d93 | |||
| 5a57e8341a | |||
| dd137c68f6 | |||
| 1275f1d31f | |||
| 27d53b4e93 | |||
| 46691e9934 | |||
| 30f2a99a2c | |||
| 650344a0c8 | |||
| ebde514c98 | |||
| 4739d9f9fc | |||
| ef39757229 | |||
| e09f9313f9 | |||
| 94a17a63c1 | |||
| 594c546f11 | |||
| cda9947e17 | |||
| 48a350b63a | |||
| 28da6810d7 | |||
| f5ce186a7d | |||
| 04bebe5910 | |||
| fe5060a2c0 | |||
| 8de990fdde | |||
| 8a92773a17 | |||
| 9f8b2fee1e | |||
| 9205f082f1 | |||
| ff4c17d1c1 | |||
| 34a4609af2 | |||
| 25475632d9 | |||
| bfc23ce6f7 | |||
| a97abd26d0 | |||
| 11821ff14d | |||
| 5c34b379d1 | |||
| c4d4c67302 | |||
| c04ee35fc3 | |||
| 09b52a4586 | |||
| 1f9f5a1cc5 | |||
| be250e218e | |||
| cf38a16f49 | |||
| a31b1c79e3 | |||
| ad520eff77 | |||
| 0354f99bd2 | |||
| 301ec86c27 | |||
| ee96ff3ddd | |||
| 53f545caad | |||
| 755933486c | |||
| 5d8a90167c | |||
| f89c71f314 | |||
| 5ad4cc0610 | |||
| f0752317e6 | |||
| ed63704184 | |||
| 3316c8e5cb | |||
| 0a2368650a | |||
| b9958ce16f | |||
| 8cbe5dd602 | |||
| f1cb7dbbbe | |||
| 5f8477a4ad | |||
| d4c2397a68 | |||
| a7b608a06e | |||
| 50ad3655c9 | |||
| abc598a722 | |||
| b23136d568 | |||
| 8291373427 | |||
| 618df1c668 | |||
| cdc326e36c | |||
| 4c024f9e46 | |||
| d93b9a6765 | |||
| 7b1283c418 | |||
| 6882fb4519 | |||
| 57f4704e18 | |||
| 50ca70b0db | |||
| 821361f9bf | |||
| 2c05e52912 | |||
| 8301a24afe | |||
| 945c789482 | |||
| 13ba19c1ff | |||
| 9bc920073b | |||
| df526dc76f | |||
| 702398dd34 | |||
| 1e5add914e | |||
| 4980beea87 | |||
| 91b2ee1a13 | |||
| 937617d7af | |||
| 94751a6fd5 | |||
| 01ab50cb27 | |||
| d0bcbc8ed8 | |||
| b660b02e0e | |||
| 153ea74966 | |||
| c81830efec | |||
| 6ec2e716cb | |||
| 96e7c5885b | |||
| 41d575c9c9 | |||
| 7f31fc6259 | |||
| 817fd26dcf | |||
| aecc8b0889 | |||
| b45c202ac5 | |||
| 16ad8543d8 | |||
| e985bc6f69 | |||
| 8682fcbe91 | |||
| e8ca773557 | |||
| c622158818 | |||
| 7237840a2a | |||
| 6254020024 | |||
| 1d161e613c | |||
| e8c1b4d581 | |||
| b5f61205eb | |||
| 6f0636da9f | |||
| b3fd39c42c | |||
| 40ed431ee2 | |||
| 15d3d9e70b | |||
| 8ad6b5590b | |||
| 1c2c267e1a | |||
| e45bfb9248 | |||
| 5df98d5b95 | |||
| a4fd88f21d | |||
| 793ba0eb05 | |||
| 531700378f | |||
| 4875d5a970 | |||
| 3ff6be4cb0 | |||
| c418757042 | |||
| e272d4f999 | |||
| c50b344041 | |||
| bd11c9c759 | |||
| f7b678e291 | |||
| 6cabe7ffd4 | |||
| f973099fd3 | |||
| 1833ed9c56 | |||
| d56cf37f2b | |||
| c5b5172481 | |||
| 938d0df95c | |||
| 525b7e13dd | |||
| a67eb2381d | |||
| 0d48606b51 | |||
| 3c0b65c485 | |||
| 771118afde | |||
| 29b9e0de8b | |||
| f26f537f50 | |||
| 91c9a5392b | |||
| 6ae9df1204 | |||
| d46600ac86 | |||
| 004782a1e4 | |||
| b2b48cd8a1 | |||
| 2277f6b278 | |||
| ba59d9786f | |||
| bdf5aa5b64 | |||
| a384a57622 | |||
| 586840aa53 | |||
| 1ab674136b | |||
| 71302b3219 | |||
| c161a74d73 | |||
| df1f737539 | |||
| 64e7e3844e | |||
| 51a3d2a63e | |||
| 53a053bfff | |||
| 220bf15cfb | |||
| 885e58c85c | |||
| 7c2e786d0b | |||
| a7ee0ad847 | |||
| 033d90ed3e | |||
| 849066de8a | |||
| eb65b7d7b7 | |||
| 97499eb523 | |||
| 02480db158 | |||
| e35ee9d126 | |||
| 004c4c09e3 | |||
| 52214f81cf | |||
| 516d7948ee | |||
| a490168fa2 | |||
| 306137a026 | |||
| 0a5527f3d4 | |||
| 4dbe24c8ea | |||
| 5477725b7e | |||
| 81bba5e7e0 | |||
| 9c29142e6a | |||
| 3dc3a3a378 | |||
| 3151d7d626 | |||
| d68f968632 | |||
| 74d9198522 | |||
| 0b56d47022 | |||
| 587ab1338e | |||
| 4816c48aa6 | |||
| 2456589fa7 | |||
| d7849a94b1 | |||
| cfb9f4fe25 | |||
| a269cf339b | |||
| 1c8e4f86ee | |||
| f2835c245f | |||
| 462512ad30 | |||
| db5a7dcfde | |||
| 17bba5dea8 | |||
| fbdb5cd844 | |||
| 393fb1c1b0 | |||
| 08e89b1aef | |||
| 1f25d95b1b | |||
| 1f3a71797e | |||
| a821ef2aef | |||
| 6845279c49 | |||
| 79b745e005 | |||
| 6fff0e31d1 | |||
| 11efe56437 | |||
| 7f5786c28c | |||
| 85b49b330a | |||
| d797e72445 | |||
| 5f21b565cd | |||
| 9ed06c9a34 | |||
| 50f315666f | |||
| 62bdbc81e4 | |||
| d9c3d15b9b | |||
| bb6bb78163 | |||
| 3f80c56163 | |||
| 3a571fd239 | |||
| 4fb5452dc4 | |||
| 652f1d2620 | |||
| 275f514810 | |||
| 7cf09e76f8 | |||
| 61080134fd | |||
| 563bed3b25 | |||
| 75740c388f | |||
| 5d96f4d700 | |||
| df8fd21c0b | |||
| 046ecb1e41 | |||
| f3dd7bccd8 | |||
| d6b64b3576 | |||
| 22c00c47ff | |||
| 6d0e65c2b0 | |||
| 0a6fd452c1 | |||
| 28a8a4ff2a | |||
| 71c09cf16d | |||
| 794085660e | |||
| 3d89186308 | |||
| a0bd7b64d7 | |||
| 4c633c98ff | |||
| 45ff70c207 | |||
| 0328f41564 | |||
| 9ab4684aef | |||
| e64cf9a6af | |||
| f13f220564 | |||
| 311b5750df | |||
| e54aee332d | |||
| e4bf09f15a | |||
| aa166814ea | |||
| d37ab6072f | |||
| ba83cb7985 | |||
| 3052e56d03 | |||
| b682740751 | |||
| 38429cb697 | |||
| dc7b6790b8 | |||
| 7a247df3e1 | |||
| de2087c0e8 | |||
| f5da195605 | |||
| 6cd6411c25 | |||
| 40e77728ad | |||
| d50ff5729f | |||
| 76b4f2f72f | |||
| a608375433 | |||
| c3f8ba245d | |||
| 34b3fe93bb | |||
| 996ec9a7f7 | |||
| 2b38ca9a89 | |||
| 67788a2bd8 | |||
| 58fcaa8af2 | |||
| 24e89c8b8a | |||
| 1293b89905 | |||
| 807fc61541 | |||
| 9741c751b3 | |||
| d3003ae473 | |||
| 9fde24f341 | |||
| 452eb17b5f | |||
| 36963aac30 | |||
| f161cdfe7c | |||
| 455c5a5e07 | |||
| 9852f61d0f | |||
| a2c8cde4c4 | |||
| 497d28eafd | |||
| f3f3377c4d | |||
| 4c81c61644 | |||
| 31a6ab6db0 | |||
| 69f2aedef7 | |||
| e8818a4db5 | |||
| 470a7e82bc | |||
| 6439c233f1 | |||
| c931d42d62 | |||
| 5b497e107a | |||
| 324094f418 | |||
| 9ade6442b2 | |||
| ffea49bc40 | |||
| 2b89a890d0 | |||
| 3a67388ff3 | |||
| 3468bbb073 | |||
| 963178c609 | |||
| cfdb049368 | |||
| 058d83fd00 | |||
| c7ccc37dca | |||
| 74345d0c3b | |||
| 907b94c74f | |||
| 2c6b397be6 | |||
| eddcb2402d | |||
| 0301f3c300 | |||
| 7a8cfb73cd | |||
| c7c6f964bf | |||
| 91df7cfd72 | |||
| 0ed9ee64c4 | |||
| f82d2871d5 | |||
| 01cea3df06 | |||
| 591cfb5857 | |||
| bc2037f74e | |||
| 6aa3b21190 | |||
| b262b6edc0 | |||
| b7be05669b | |||
| 071e299d48 | |||
| 1e885d70c3 | |||
| e04a43e56d | |||
| 378796cdda | |||
| 48c37d1c17 | |||
| fe8f9fc5cd | |||
| ced6ab7e8d | |||
| 378e02eb6c | |||
| 4677d9ff30 | |||
| 0541b2171b | |||
| dc59a14e82 | |||
| 1a13afb6e3 | |||
| 03dd76c18a | |||
| 9426a96df3 | |||
| 382faf59c9 | |||
| cab68e23ac | |||
| 60a6c5124e | |||
| 028b753be6 | |||
| d020668e0c | |||
| 656a78962e | |||
| 5a2f5aa295 | |||
| 5e37a2322c | |||
| 3ca9f200fd | |||
| 37e3a842f5 | |||
| 4e8e2c951b | |||
| 43b66df22a | |||
| b192a431d7 | |||
| 3be98ab612 | |||
| ed950322ff | |||
| 4cde8c60bc | |||
| 9924e10f13 | |||
| eeb0640525 | |||
| 693c11ada0 | |||
| 038fd7225f | |||
| 999e32f37c | |||
| 8c2ac5adbb | |||
| 9c1e2e08c3 | |||
| e7f7960540 | |||
| a46bad4497 | |||
| 06d02ad45d | |||
| c39a213e62 | |||
| 2caca39a22 | |||
| 8d46191ff8 | |||
| fb7af9328d | |||
| 0991baf964 | |||
| bdefecbe9b | |||
| eef48f319a | |||
| 3a788c867c | |||
| 1ba723ade1 | |||
| c06105cd00 | |||
| 97c72685bb | |||
| 23fccaac9c | |||
| 74b6bdba0f | |||
| d69e3a253d | |||
| 744c7a2331 | |||
| c355cb034c | |||
| 5e321cc4cf | |||
| fbecce0543 | |||
| a6c24e9cb6 | |||
| 14a624db3f | |||
| 16a4c8231f | |||
| 931c99617c | |||
| 037f340a03 | |||
| b6cc417641 | |||
| 6565a0734a | |||
| 0aac70c5fb | |||
| 8551dc407b | |||
| 1eec7921ce | |||
| 18920a24c5 | |||
| e0c6f0f00f | |||
| a4f6391fac | |||
| a570bd57d0 | |||
| f1ff179b98 | |||
| 6d09acc78e | |||
| 960d97de49 | |||
| ebe64b06e3 | |||
| 99887f95e2 | |||
| 2e5a9fce3e |
@@ -7,10 +7,10 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
||||
|
||||
Minecraft version: 1.12.2 [change as necessary]
|
||||
Wizardry version: 4.1.4 [change as necessary]
|
||||
Wizardry version: 4.3 [change as necessary]
|
||||
Environment: Singleplayer/LAN game/Server [delete as necessary]
|
||||
|
||||
Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.]
|
||||
|
||||
@@ -7,7 +7,7 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
||||
|
||||
Minecraft versions: [if this suggestion only applies to some versions, list them here]
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question about the mod or the code
|
||||
title: "[Give a brief, relevant title here]"
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
||||
|
||||
Minecraft version: 1.12.2 [change as necessary]
|
||||
Wizardry version: 4.3 [change as necessary]
|
||||
|
||||
Question details: [explain your question here]
|
||||
|
||||
Other mods involved: [if this question involves other mods, list them here]
|
||||
@@ -23,6 +23,7 @@ run
|
||||
logs
|
||||
/misc
|
||||
/libs
|
||||
libs_src
|
||||
libsfordeobf
|
||||
generated
|
||||
Thumbs.db
|
||||
@@ -8,6 +8,8 @@ When submitting an issue, I would be grateful if you could follow these few guid
|
||||
|
||||
- Please stick to the issue template, it's there to help you provide the right information so I can fix the problem more easily. If you're not sure what to put for anything, that's ok, just leave it as it is.
|
||||
|
||||
- One issue per issue please! Make a separate issue for each bug/suggestion. If you think multiple different issues may be related, reference between them using # followed by the issue number, and github will automagically link them.
|
||||
|
||||
- Please give me as much information about the issue as you can, but keep it relevant. "This is really annoying me and my friend" does not help me fix the problem!
|
||||
|
||||
- Make sure your wizardry and Forge versions are both up-to-date for the game version you are using.
|
||||
@@ -16,6 +18,8 @@ When submitting an issue, I would be grateful if you could follow these few guid
|
||||
|
||||
- Don't close an issue unless it has actually been fixed or is no longer relevant - otherwise I might not end up fixing it at all! Usually I'll take care of closing issues anyway, so you don't have to worry about it.
|
||||
|
||||
- Please don't revive old issues, _especially_ if they have been fixed, because I don't routinely check them. Make a new issue and link the old one to it if you think it's related.
|
||||
|
||||
- Most importantly, use gist or pastebin to post crash reports. Do not paste the entire crash report inline, not even in a code block!
|
||||
> If you've got a git account (which you do, if you're posting an issue) you can access gist, and pastebin doesn't require an account at all, so there's no excuse!
|
||||
|
||||
@@ -41,4 +45,13 @@ Pull requests aren't just for code - if you would like to help translate Wizardr
|
||||
|
||||
- Firstly, the .lang file: if you're familiar with translating mods, this is all pretty standard - it holds the names of blocks, items, mobs and so on. Ignore the %X$s bits, they're placeholders for stuff that gets put in by Wizardry when the game is running.
|
||||
|
||||
- Secondly, the handbook text file: the US english version is named handbook_en_US.txt, and (rather obviously) other languages' text files replace 'en_US' with the name of their corresponding .lang file. Anything wirtten in BLOCK CAPITALS should be left alone, because Wizardry replaces it with the appropriate text when the game is running.
|
||||
- Secondly, the handbook JSON file: the US english version is named handbook_en_us.json, and (rather obviously) other languages' text files replace 'en_us' with the name of their corresponding .lang file. Make sure you only change the _values_ (after each `:`), not the identifiers - for a summary of JSON syntax, see the [JSON webpage](https://www.json.org/json-en.html). If you're familiar with advancements, loot tables and similar files, this won't be new to you. The handbook file also applies its own form of markup to the main text, with the following features:
|
||||
|
||||
- `#image tag` adds an image to the text with the given tag. Image tags are defined in the `"images": {...}` block at the start of the file. Each named entry in this block defines a single image with that name as its tag. Each entry is a JSON object containing a file location and optional caption/dimensions.
|
||||
- `#recipe tag` adds a crafting recipe to the text with the given tag. Similar to image tags, recipe tags are defined in the `"recipes": {...}` block at the start of the file. Each named entry in this block defines a recipe with that name as its tag. Each entry contains a list of one or more locations or recipes to display (if more than one is specified, the display will cycle through the different recipes).
|
||||
- Anything else with a `#` directly before it (with no space) will be treated as a format argument if possible. This means everything between the `#` and the next space will be replaced with something else at runtime, similar to the `%X$s` bits in a normal .lang file. The current available format arguments can be found [here](https://github.com/Electroblob77/Wizardry/blob/1.12.2/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java#L177-L203).
|
||||
- `@section@` adds a hyperlink to the given section, which will display as the name of that section. `@section alt text@` is the same, except alt text is displayed instead of the section name (alt text may contain spaces). It is also possible to hyperlink to a webpage, simply replace the section name with the url (e.g. `@https://example.com/@` or `@https://example.com/ alt text@`).
|
||||
|
||||
If all of that confused you, the simple rule is: _Don't translate anything directly after an `@` symbol, directly after a `#`, or the first word after `#image` or `#recipe`_. However, you should translate the `"caption"` entries in the `images` block.
|
||||
|
||||
**Please ensure all translation files are encoded in UTF-8 format, otherwise they might crash the game!**
|
||||
+27
-5
@@ -1,7 +1,7 @@
|
||||
# Credits
|
||||
|
||||
Electroblob's Wizardry
|
||||
Version 4.1.4
|
||||
Version 4.3
|
||||
For Minecraft 1.12.2
|
||||
|
||||
Designed, coded and textured by Electroblob
|
||||
@@ -18,11 +18,33 @@ In addition, I'd like to thank the following individuals for their contributions
|
||||
- 12foo
|
||||
- Shadows-of-Fire
|
||||
- HellFirePvP
|
||||
- Tora-B
|
||||
- Avatair
|
||||
- Aeronica
|
||||
- UltraHex
|
||||
- Azim-Palmer
|
||||
- raoulvdberge
|
||||
- rafasoares
|
||||
|
||||
#### Translations
|
||||
|
||||
- Russian: VilagVil
|
||||
- Spanish and Mexican Spanish: MadWrist
|
||||
- Chinese: ZHENGLOC and dragon-evol
|
||||
- Spanish: MadWrist, Alsentar
|
||||
- Mexican Spanish: MadWrist
|
||||
- Russian: VilagVil, kellixon, bigenergy, MugGod2
|
||||
- French: Hahdrim
|
||||
- Brazilian Portuguese: lorrampi
|
||||
- Chinese (Simplified): ZHENGLOC, dragon-evol, Hokorizero, TUsama, Determancer
|
||||
- Korean: shejery, rewi_wire
|
||||
- Polish: Trozuu
|
||||
- German: BirdyDragon
|
||||
- Chinese (Traditional): chesterccj305
|
||||
- Hungarian: Bombadil
|
||||
|
||||
Lightning ray sound effect from OhhWowProductions
|
||||
#### Sound Effects
|
||||
- OhhWowProductions
|
||||
- fredzed
|
||||
- deleted_user_3277771
|
||||
- DiscoveryME
|
||||
- OGSoundFX
|
||||
- leosalom
|
||||
- juskiddink
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
|
||||
|
||||
Minecraft version: 1.12.2 [change as necessary]
|
||||
Wizardry version: 4.1.4 [change as necessary]
|
||||
Wizardry version: 4.3 [change as necessary]
|
||||
Environment: Singleplayer/LAN game/Server [delete as necessary]
|
||||
|
||||
Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/relations/dependents) [](https://discord.gg/MTmMzMv)
|
||||
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [](https://discord.gg/hs8yJP2)
|
||||
|
||||

|
||||

|
||||
|
||||
Source code for Electroblob's Wizardry, a Minecraft mod currently for versions 1.7.10, 1.10.2, 1.11.2, and 1.12.2. Wizardry adds an RPG-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!
|
||||
|
||||
Please read the [guide for contributing](guide_for_contributing.md) before submitting an issue or a PR.
|
||||
Please read the [guide for contributing](CONTRIBUTING.md) before submitting an issue or a PR.
|
||||
|
||||
<b>Links</b>
|
||||
|
||||
|
||||
+9
-37
@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
|
||||
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||
|
||||
|
||||
version = "4.2.1" // There, it matches semver, happy now?
|
||||
version = "4.3" // There, it matches semver, happy now?
|
||||
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
archivesBaseName = "ElectroblobsWizardry"
|
||||
|
||||
@@ -31,19 +31,14 @@ repositories {
|
||||
name = "ModMaven"
|
||||
url = "modmaven.k-4u.nl"
|
||||
}
|
||||
flatDir {
|
||||
// evErYthINg hAS tO Be a mAVeN rEPoSiTOrY... (to use deobfProvided, for some reason)
|
||||
// The lack of documentation is actually quite impressive, see the following threads:
|
||||
// http://www.minecraftforge.net/forum/topic/44262-solved-how-to-build-mod-with-dependencies/
|
||||
// https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2866817-setting-up-dependencies-in-minecraft-forge-with
|
||||
// http://www.minecraftforge.net/forum/topic/44534-adding-dependencies-to-a-forge-project/
|
||||
dirs "libsfordeobf" // Don't put src jars in libs or forge will think you have duplicate mods
|
||||
maven {
|
||||
name = "Curseforge Maven"
|
||||
url = "https://minecraft.curseforge.com/api/maven/"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
minecraft {
|
||||
version = "1.12.2-14.23.5.2814"
|
||||
version = "1.12.2-14.23.5.2847"
|
||||
runDir = "run"
|
||||
|
||||
// the mappings can be changed at any time, and must be in the following format.
|
||||
@@ -56,37 +51,14 @@ minecraft {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// you may put jars on which you depend on in ./libs
|
||||
// or you may define them like so..
|
||||
//compile "some.group:artifact:version:classifier"
|
||||
//compile "some.group:artifact:version"
|
||||
|
||||
// compile against the JEI API but do not include it at runtime
|
||||
// Compile against the JEI API but do not include it at runtime
|
||||
deobfProvided "mezz.jei:jei_${mc_version}:${jei_version}:api"
|
||||
// at runtime, use the full JEI jar
|
||||
// At runtime, use the full JEI jar
|
||||
runtime "mezz.jei:jei_${mc_version}:${jei_version}"
|
||||
|
||||
//deobfProvided "baubles:baubles-1.12:1.5.2:api" // #ihavenoideawhatimdoing #itjustworks
|
||||
//runtime "baubles:baubles-1.12:1.5.2" // If in doubt, copy what already works
|
||||
|
||||
//deobfProvided "antiqueatlas:antiqueatlas-1.12.2:4.5.1:src"
|
||||
//runtime "antiqueatlas:antiqueatlas-1.12.2:4.5.1"
|
||||
|
||||
// real examples
|
||||
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
|
||||
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
|
||||
|
||||
// the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
|
||||
//provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
|
||||
// the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
|
||||
// except that these dependencies get remapped to your current MCP mappings
|
||||
//deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
//deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
|
||||
// for more info...
|
||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
||||
// http://www.gradle.org/docs/current/userguide/dependency_management.html
|
||||
deobfCompile "baubles:Baubles:${mc_version_short}:${baubles_version}"
|
||||
deobfCompile "antique-atlas:antiqueatlas:${mc_version}:${antique_atlas_version}"
|
||||
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -2,4 +2,7 @@
|
||||
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||
org.gradle.jvmargs=-Xmx3G
|
||||
mc_version=1.12.2
|
||||
jei_version=4.13.1.225
|
||||
mc_version_short=1.12
|
||||
jei_version=4.15.0.291
|
||||
baubles_version=1.5.2
|
||||
antique_atlas_version=4.6.3
|
||||
@@ -1,5 +1,7 @@
|
||||
package electroblob.wizardry;
|
||||
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
|
||||
import electroblob.wizardry.item.ItemSpectralBow;
|
||||
import electroblob.wizardry.packet.*;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
@@ -7,6 +9,7 @@ import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
@@ -18,6 +21,7 @@ import net.minecraft.util.text.translation.I18n;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -40,6 +44,8 @@ public class CommonProxy {
|
||||
|
||||
public void initialiseLayers(){}
|
||||
|
||||
public void initialiseAnimations(){}
|
||||
|
||||
public void registerKeyBindings(){}
|
||||
|
||||
public net.minecraft.client.model.ModelBiped getWizardArmourModel(){
|
||||
@@ -73,7 +79,7 @@ public class CommonProxy {
|
||||
// SECTION Items
|
||||
// ===============================================================================================================
|
||||
|
||||
public boolean shouldDisplayDiscovered(Spell spell, ItemStack stack){
|
||||
public boolean shouldDisplayDiscovered(Spell spell, @Nullable ItemStack stack){
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -99,9 +105,32 @@ public class CommonProxy {
|
||||
return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack);
|
||||
}
|
||||
|
||||
/** Like {@link CommonProxy#addMultiLineDescription(List, String, Style)}, but style defaults to light grey. */
|
||||
public void addMultiLineDescription(List<String> tooltip, String key){
|
||||
this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY));
|
||||
/**
|
||||
* Translates the given key with no specified style. Client-side only; on the server this simply returns
|
||||
* the given translation key. Useful whenever translation from common classes is required, e.g. item tooltips.
|
||||
* @param key The unlocalised name to be translated.
|
||||
* @param args The format arguments to pass into the translation, if any.
|
||||
* @return The resulting translated text.
|
||||
*/
|
||||
public String translate(String key, Object... args){
|
||||
return translate(key, new Style(), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the given key and formats it with the given style. Client-side only; on the server this simply returns
|
||||
* the given translation key. Useful whenever translation from common classes is required, e.g. item tooltips.
|
||||
* @param key The unlocalised name to be translated.
|
||||
* @param style The {@link Style} to use for the displayed text.
|
||||
* @param args The format arguments to pass into the translation, if any.
|
||||
* @return The resulting translated text.
|
||||
*/
|
||||
public String translate(String key, Style style, Object... args){
|
||||
return key;
|
||||
}
|
||||
|
||||
/** Like {@link CommonProxy#addMultiLineDescription(List, String, Style, Object...)}, but style defaults to light grey. */
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Object... args){
|
||||
this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY), args);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +141,7 @@ public class CommonProxy {
|
||||
* @param key The translation key for the description
|
||||
* @param style A style to apply
|
||||
*/
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style){}
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style, Object... args){}
|
||||
|
||||
// SECTION Packet Handlers
|
||||
// ===============================================================================================================
|
||||
@@ -139,8 +168,6 @@ public class CommonProxy {
|
||||
|
||||
public void handleAdvancementSyncPacket(PacketSyncAdvancements.Message message){}
|
||||
|
||||
public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){}
|
||||
|
||||
public void handleResurrectionPacket(PacketResurrection.Message message){}
|
||||
|
||||
public void handlePossessionPacket(PacketPossession.Message message){}
|
||||
@@ -170,6 +197,12 @@ public class CommonProxy {
|
||||
*/
|
||||
public void playMovingSound(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){}
|
||||
|
||||
/**
|
||||
* Plays the spell charge-up sound at the given entity.
|
||||
* @param entity The source of the sound
|
||||
*/
|
||||
public void playChargeupSound(EntityLivingBase entity){}
|
||||
|
||||
/**
|
||||
* Plays a continuous spell sound which moves with the given entity.
|
||||
*
|
||||
@@ -238,17 +271,63 @@ public class CommonProxy {
|
||||
+ "of sound events, but the given array contained less than 3 sound events!");
|
||||
playSpellSoundLoop(world, x, y, z, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch, duration);
|
||||
}
|
||||
|
||||
/** Starts the first-person blink overlay effect for the specified player. */
|
||||
public void playBlinkEffect(EntityPlayer player){}
|
||||
|
||||
/**
|
||||
* Starts the client-side screen shake effect for the specified player.
|
||||
* @param player The player whose screen is to be shaken
|
||||
* @param intensity The amplitude of the shaking (around 10 looks about right)
|
||||
*/
|
||||
public void shakeScreen(EntityPlayer player, float intensity){}
|
||||
|
||||
/**
|
||||
* Loads the given shader for the given player, if they have shaders enabled.
|
||||
* @param player The player to load the shader for
|
||||
* @param shader The location of the shader to load
|
||||
*/
|
||||
public void loadShader(EntityPlayer player, ResourceLocation shader){}
|
||||
|
||||
/**
|
||||
* Gets the client side world using Minecraft.getMinecraft().world. <b>Only to be called client side!</b> Returns
|
||||
* null on the server side.
|
||||
* Gets the client-side world using {@code Minecraft.getMinecraft().world}. <b>Only to be called client side!</b>
|
||||
* Returns null on the server side.
|
||||
*/
|
||||
public World getTheWorld(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client-side player using Minecraft.getMinecraft().player. <b>Only to be called client side!</b> Returns
|
||||
* null on the server side.
|
||||
*/
|
||||
public EntityPlayer getThePlayer(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the game is being viewed from the perspective of the given entity and is set to first-person
|
||||
* view. Always returns false on the server side.
|
||||
*/
|
||||
public boolean isFirstPerson(Entity entity){
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns an unmodifiable set of the string keys for all of the loaded spell HUD skins. */
|
||||
public Set<String> getSpellHUDSkins(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Notifies nearby players of a bookshelf change, causing any lectern or arcane workbench GUI (client-side) or
|
||||
* container (both sides) to refresh its linked bookshelves (does not send packets). */
|
||||
public void notifyBookshelfChange(World world, BlockPos pos){
|
||||
for(EntityPlayer player : world.playerEntities){
|
||||
if(player.getDistanceSq(pos) < BlockBookshelf.PLAYER_NOTIFY_RANGE * BlockBookshelf.PLAYER_NOTIFY_RANGE){
|
||||
if(player.openContainer instanceof ContainerArcaneWorkbench){
|
||||
((ContainerArcaneWorkbench)player.openContainer).refreshBookshelfSlots();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry;
|
||||
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.command.CommandCastSpell;
|
||||
import electroblob.wizardry.command.CommandDiscoverSpell;
|
||||
import electroblob.wizardry.command.CommandSetAlly;
|
||||
@@ -8,14 +9,17 @@ import electroblob.wizardry.data.DispenserCastingData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration;
|
||||
import electroblob.wizardry.integration.baubles.WizardryBaublesIntegration;
|
||||
import electroblob.wizardry.inventory.ContainerBookshelf;
|
||||
import electroblob.wizardry.misc.DonationPerksHandler;
|
||||
import electroblob.wizardry.misc.Forfeit;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.*;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.CustomSoundCategory;
|
||||
import electroblob.wizardry.util.SpellProperties;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
import electroblob.wizardry.worldgen.*;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@@ -31,6 +35,9 @@ import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* <i>"Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as
|
||||
* possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master
|
||||
@@ -41,7 +48,11 @@ import org.apache.logging.log4j.Logger;
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob.wizardry.WizardryGuiFactory")
|
||||
|
||||
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, acceptedMinecraftVersions = "[1.12.2]",
|
||||
guiFactory = "electroblob.wizardry.WizardryGuiFactory",
|
||||
dependencies = "required-after:forge@[14.23.5.2847,);after:jei@[4.15.0,);after:baubles@[1.5.2,);after:antiqueatlas@[4.6,)")
|
||||
|
||||
public class Wizardry {
|
||||
|
||||
/** Wizardry's mod ID. */
|
||||
@@ -51,14 +62,14 @@ public class Wizardry {
|
||||
/**
|
||||
* The version number for this version of wizardry. The following system is used for version numbers:
|
||||
* <p></p>
|
||||
* <center><b>[major Minecraft version].[major mod version].[minor mod version/patch]
|
||||
* <center><b>[major Minecraft version].[major mod version].[minor mod version/patch]</b>
|
||||
* <p></p>
|
||||
* </center></b> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same
|
||||
* </center> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same
|
||||
* features as Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning.
|
||||
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
|
||||
* 1.11.x versions, and so on.
|
||||
*/
|
||||
public static final String VERSION = "4.2.1";
|
||||
public static final String VERSION = "4.3";
|
||||
|
||||
// IDEA: Triggering of inbuilt Forge events in relevant places?
|
||||
// IDEA: Abstract the vanilla particles behind the particle builder
|
||||
@@ -79,6 +90,12 @@ public class Wizardry {
|
||||
* - <b>INFO</b>: Anything that might happen during normal mod operation that the user needs to know about. */
|
||||
public static Logger logger;
|
||||
|
||||
/** A {@link File} object representing wizardry's config folder, {@code config/ebwizardry}). As of wizardry 4.2.4,
|
||||
* this folder contains the main config file and the global spell properties folder, if used. */
|
||||
public static File configDirectory;
|
||||
|
||||
public static boolean tisTheSeason;
|
||||
|
||||
// The instance of wizardry that Forge uses.
|
||||
@Instance(Wizardry.MODID)
|
||||
public static Wizardry instance;
|
||||
@@ -94,8 +111,13 @@ public class Wizardry {
|
||||
|
||||
proxy.registerResourceReloadListeners();
|
||||
|
||||
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
|
||||
settings.initConfig(event);
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
tisTheSeason = calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DAY_OF_MONTH) >= 24
|
||||
&& calendar.get(Calendar.DAY_OF_MONTH) <= 26;
|
||||
|
||||
// Capabilities
|
||||
WizardData.register();
|
||||
DispenserCastingData.register();
|
||||
@@ -105,11 +127,15 @@ public class Wizardry {
|
||||
WizardryLoot.register();
|
||||
WizardryAdvancementTriggers.register();
|
||||
Forfeit.register();
|
||||
BlockBookshelf.registerStandardBookModelTextures();
|
||||
|
||||
// Client-side stuff (via proxies)
|
||||
proxy.registerRenderers();
|
||||
proxy.registerKeyBindings();
|
||||
|
||||
// Commented out for 4.2.3 to get rid of the sound bug, reinstate once a fix is found.
|
||||
WizardrySounds.SPELLS = SoundCategory.PLAYERS;//CustomSoundCategory.add(Wizardry.MODID + "_spells");
|
||||
|
||||
WizardryBaublesIntegration.init();
|
||||
WizardryAntiqueAtlasIntegration.init();
|
||||
|
||||
@@ -130,6 +156,8 @@ public class Wizardry {
|
||||
GameRegistry.registerWorldGenerator(new WorldGenWizardTower(), 20);
|
||||
GameRegistry.registerWorldGenerator(new WorldGenObelisk(), 20);
|
||||
GameRegistry.registerWorldGenerator(new WorldGenShrine(), 20);
|
||||
GameRegistry.registerWorldGenerator(new WorldGenLibraryRuins(), 20);
|
||||
GameRegistry.registerWorldGenerator(new WorldGenUndergroundLibraryRuins(), 20);
|
||||
|
||||
// This is for the config change and missing mappings events
|
||||
MinecraftForge.EVENT_BUS.register(instance); // Since there's already an instance we might as well use it
|
||||
@@ -138,9 +166,13 @@ public class Wizardry {
|
||||
WizardryPacketHandler.initPackets();
|
||||
|
||||
// Post-registry extras
|
||||
BlockBookshelf.compileBookModelTextures();
|
||||
ContainerBookshelf.initDefaultBookItems();
|
||||
WizardryItems.populateWandMap();
|
||||
WizardryItems.populateArmourMap();
|
||||
WizardryItems.registerDispenseBehaviours();
|
||||
WizardryItems.registerBannerPatterns();
|
||||
WandHelper.populateUpgradeMap();
|
||||
Spell.registry.forEach(Spell::init);
|
||||
SpellProperties.init();
|
||||
|
||||
@@ -148,13 +180,12 @@ public class Wizardry {
|
||||
proxy.initGuiBits();
|
||||
proxy.registerParticles();
|
||||
proxy.registerSoundEventListener();
|
||||
|
||||
WizardrySounds.SPELLS = CustomSoundCategory.add(Wizardry.MODID + ":spells");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void postInit(FMLPostInitializationEvent event){
|
||||
proxy.initialiseLayers();
|
||||
proxy.initialiseAnimations();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -169,7 +200,12 @@ public class Wizardry {
|
||||
public void onConfigChanged(net.minecraftforge.fml.client.event.ConfigChangedEvent.OnConfigChangedEvent event){
|
||||
if(event.getModID().equals(Wizardry.MODID)){
|
||||
settings.saveConfigChanges();
|
||||
// All of the synchronised settings require a world restart anyway so this doesn't need syncing.
|
||||
// All of the synchronised settings require a world restart anyway so don't need syncing, except for the
|
||||
// donor perks which have special behaviour (since we have to update everyone when a donor logs in anyway,
|
||||
// we might as well reuse the packet and let them change the setting mid-game)
|
||||
if(event.isWorldRunning() && DonationPerksHandler.isDonor(proxy.getThePlayer())){
|
||||
DonationPerksHandler.sendToServer(proxy.getThePlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.entity.projectile.EntityArrow;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumHand;
|
||||
@@ -33,6 +34,9 @@ import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.storage.loot.LootContext;
|
||||
import net.minecraft.world.storage.loot.LootTable;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.event.entity.PlaySoundAtEntityEvent;
|
||||
@@ -46,6 +50,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* General-purpose event handler for things that don't fit anywhere else or groups of related behaviours that are better
|
||||
@@ -79,6 +84,7 @@ public final class WizardryEventHandler {
|
||||
Wizardry.settings.sync((EntityPlayerMP)event.player);
|
||||
syncAdvancements((EntityPlayerMP)event.player, false);
|
||||
}
|
||||
|
||||
Spell.syncProperties(event.player);
|
||||
}
|
||||
|
||||
@@ -169,7 +175,7 @@ public final class WizardryEventHandler {
|
||||
&& Wizardry.settings.discoveryMode){
|
||||
// Sound and text only happen server-side, in survival, with discovery mode on, and only when
|
||||
// the spell wasn't cast using commands.
|
||||
WizardryUtilities.playSoundAtPlayer(player, WizardrySounds.MISC_DISCOVER_SPELL, 1.25f, 1);
|
||||
EntityUtils.playSoundAtPlayer(player, WizardrySounds.MISC_DISCOVER_SPELL, 1.25f, 1);
|
||||
player.sendMessage(new TextComponentTranslation("spell.discover",
|
||||
event.getSpell().getNameForTranslationFormatted()));
|
||||
}
|
||||
@@ -188,16 +194,33 @@ public final class WizardryEventHandler {
|
||||
@SubscribeEvent
|
||||
public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){
|
||||
|
||||
if(event.getTarget() != null && event.getEntityLiving() instanceof EntityLiving
|
||||
&& event.getTarget().isPotionActive(WizardryPotions.muffle)){
|
||||
if(event.getEntityLiving() instanceof EntityLiving && event.getTarget() != null){
|
||||
|
||||
Vec3d vec = event.getTarget().getPositionEyes(1).subtract(event.getEntity().getPositionEyes(1));
|
||||
// Find the angle between the direction the mob is looking and the direction the player is in
|
||||
// Angle between a and b = acos((a.b) / (|a|*|b|))
|
||||
double angle = Math.acos(vec.dotProduct(event.getEntity().getLookVec()) / vec.length());
|
||||
System.out.println(angle);
|
||||
// If the player is not within the 144-degree arc in front of the mob, it won't detect them
|
||||
if(angle > 0.4 * Math.PI){
|
||||
// Muffle
|
||||
if(event.getTarget().isPotionActive(WizardryPotions.muffle)){
|
||||
|
||||
Vec3d vec = event.getTarget().getPositionEyes(1).subtract(event.getEntity().getPositionEyes(1));
|
||||
// Find the angle between the direction the mob is looking and the direction the player is in
|
||||
// Angle between a and b = acos((a.b) / (|a|*|b|))
|
||||
double angle = Math.acos(vec.dotProduct(event.getEntity().getLookVec()) / vec.length());
|
||||
System.out.println(angle);
|
||||
// If the player is not within the 144-degree arc in front of the mob, it won't detect them
|
||||
if(angle > 0.4 * Math.PI){
|
||||
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Mirage
|
||||
if(event.getTarget().isPotionActive(WizardryPotions.mirage)){
|
||||
// Can't find players under mirage at all! (Pretty sure this excludes revenge-targeting)
|
||||
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
||||
}
|
||||
|
||||
// Blindness tweak
|
||||
// I'm not going as far as potion core's implementation, this is just so it does *something* to mobs
|
||||
if(event.getEntityLiving().isPotionActive(MobEffects.BLINDNESS) && !Loader.isModLoaded("potioncore")
|
||||
&& Wizardry.settings.blindnessTweak && event.getTarget().getDistanceSq(event.getEntity()) > 3.5 * 3.5){
|
||||
// Can't detect anything more than 3.5 blocks away (roughly the player's view distance when blinded)
|
||||
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
||||
}
|
||||
}
|
||||
@@ -265,7 +288,7 @@ public final class WizardryEventHandler {
|
||||
.target(attacker).spawn(world);
|
||||
|
||||
ParticleBuilder.spawnShockParticles(world, attacker.posX,
|
||||
attacker.getEntityBoundingBox().minY + attacker.height / 2, attacker.posZ);
|
||||
attacker.posY + attacker.height / 2, attacker.posZ);
|
||||
}
|
||||
|
||||
DamageSafetyChecker.attackEntitySafely(attacker, MagicDamage.causeDirectMagicDamage(event.getEntityLiving(),
|
||||
@@ -280,13 +303,20 @@ public final class WizardryEventHandler {
|
||||
@SubscribeEvent(priority = EventPriority.LOW) // Again, we don't want these effects if the event is cancelled
|
||||
public static void onLivingHurtEvent(LivingHurtEvent event){
|
||||
|
||||
// Ward
|
||||
PotionEffect effect = event.getEntityLiving().getActivePotionEffect(WizardryPotions.ward);
|
||||
|
||||
if(effect != null && event.getSource().isMagicDamage()){
|
||||
event.setAmount(event.getAmount() * Math.max(0, 1 - 0.4f * effect.getAmplifier())); // Resistance is 20%
|
||||
}
|
||||
|
||||
// Flaming and freezing swords
|
||||
if(event.getSource().getTrueSource() instanceof EntityLivingBase){
|
||||
|
||||
EntityLivingBase attacker = (EntityLivingBase)event.getSource().getTrueSource();
|
||||
|
||||
// Players can only ever attack with their main hand, so this is the right method to use here.
|
||||
if(!attacker.getHeldItemMainhand().isEmpty() && ImbueWeapon.isSword(attacker.getHeldItemMainhand().getItem())){
|
||||
if(!attacker.getHeldItemMainhand().isEmpty() && ImbueWeapon.isSword(attacker.getHeldItemMainhand())){
|
||||
|
||||
int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon,
|
||||
attacker.getHeldItemMainhand());
|
||||
@@ -327,14 +357,6 @@ public final class WizardryEventHandler {
|
||||
@SubscribeEvent
|
||||
public static void onLivingUpdateEvent(LivingUpdateEvent event){
|
||||
|
||||
// Experimental animation feature
|
||||
// if(event.getEntityLiving().isHandActive() && event.getEntityLiving().getActiveItemStack().getItemUseAction() == WizardryUtilities.POINT){
|
||||
// event.getEntityLiving().isSwingInProgress = true;
|
||||
// event.getEntityLiving().swingProgress = 1f;
|
||||
// event.getEntityLiving().prevSwingProgress = 1;
|
||||
// event.getEntityLiving().swingingHand = event.getEntityLiving().getActiveHand();
|
||||
// }
|
||||
|
||||
if(event.getEntityLiving().world.isRemote){
|
||||
|
||||
// Client-side continuous spell casting for NPCs
|
||||
@@ -343,16 +365,19 @@ public final class WizardryEventHandler {
|
||||
|
||||
Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell();
|
||||
SpellModifiers modifiers = ((ISpellCaster)event.getEntity()).getModifiers();
|
||||
int count = ((ISpellCaster)event.getEntity()).getSpellCounter();
|
||||
|
||||
if(spell != null && spell != Spells.none){ // IntelliJ is wrong, do NOT remove the null check!
|
||||
|
||||
if(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(SpellCastEvent.Source.NPC, spell, event.getEntityLiving(),
|
||||
modifiers, 0))){
|
||||
modifiers, count))){
|
||||
|
||||
spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0,
|
||||
spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, count,
|
||||
// TODO: This implementation of modifiers relies on them being accessible client-side.
|
||||
// Right now that doesn't matter because NPCs don't use modifiers, but they might in future
|
||||
((EntityLiving)event.getEntity()).getAttackTarget(), modifiers);
|
||||
|
||||
((ISpellCaster)event.getEntity()).setSpellCounter(count + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,7 +391,23 @@ public final class WizardryEventHandler {
|
||||
|
||||
EntityPlayer player = (EntityPlayer)event.getSource().getTrueSource();
|
||||
|
||||
for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){
|
||||
// Compatibility with "Lycanites Mobs" -it uses custom loot drop logic which can't be hooked, given the
|
||||
// number of mobs that spawn as Lycanites when this mod is active it would massively nerf the wizard drops
|
||||
// if we didn't handle this
|
||||
if(event.getEntity().getClass().getCanonicalName().contains("lycanitesmobs"))
|
||||
{
|
||||
WorldServer world = (WorldServer)event.getEntity().getEntityWorld();
|
||||
LootTable table = world.getLootTableManager().getLootTableFromLocation(new ResourceLocation(Wizardry.MODID, "entities/mob_additions"));
|
||||
|
||||
LootContext ctx = new LootContext.Builder(world).withPlayer(player).build();
|
||||
List<ItemStack> stacks = table.generateLootForPools(world.rand, ctx);
|
||||
|
||||
for(ItemStack stack : stacks) {
|
||||
event.getEntity().entityDropItem(stack, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
for(ItemStack stack : InventoryUtils.getPrioritisedHotbarAndOffhand(player)){
|
||||
|
||||
if(stack.getItem() instanceof IManaStoringItem && !((IManaStoringItem)stack.getItem()).isManaFull(stack)
|
||||
&& WandHelper.getUpgradeLevel(stack, WizardryItems.siphon_upgrade) > 0){
|
||||
@@ -397,7 +438,7 @@ public final class WizardryEventHandler {
|
||||
@SubscribeEvent // Priority doesn't matter here, we're only setting event fields so if it's cancelled it won't matter
|
||||
public static void onLivingFallEvent(LivingFallEvent event){
|
||||
// Why is fall damage based on distance fallen? Why? Who on earth came up with that? It makes no sense whatsoever!
|
||||
if(Wizardry.settings.replaceVanillaFallDamage && !Loader.isModLoaded("speedbasedfalldamage")){
|
||||
if(!event.getEntity().world.isRemote && Wizardry.settings.replaceVanillaFallDamage && !Loader.isModLoaded("speedbasedfalldamage")){
|
||||
// We want to keep the fall damage EXACTLY THE SAME for free, uninterrupted falls, but fix the weirdness
|
||||
// caused when something else changes the entity's velocity
|
||||
// All living entities have a gravity of 0.08b/t^2
|
||||
@@ -444,7 +485,8 @@ public final class WizardryEventHandler {
|
||||
// Wizardry.logger.info("Replaced fall distance {} with effective distance {} based on entity velocity", event.getDistance(), y);
|
||||
// }
|
||||
|
||||
event.setDistance((float)y);
|
||||
// Don't let it increase fall damage beyond vanilla values
|
||||
if(y < event.getDistance()) event.setDistance((float)y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package electroblob.wizardry;
|
||||
|
||||
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
|
||||
import electroblob.wizardry.inventory.ContainerBookshelf;
|
||||
import electroblob.wizardry.inventory.ContainerPortableWorkbench;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.item.ItemWizardHandbook;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
|
||||
import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -21,40 +23,82 @@ public class WizardryGuiHandler implements IGuiHandler {
|
||||
public static final int ARCANE_WORKBENCH = nextGuiId++;
|
||||
public static final int WIZARD_HANDBOOK = nextGuiId++;
|
||||
public static final int PORTABLE_CRAFTING = nextGuiId++;
|
||||
public static final int BOOKSHELF = nextGuiId++;
|
||||
public static final int LECTERN = nextGuiId++;
|
||||
|
||||
@Override
|
||||
public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z){
|
||||
|
||||
if(id == ARCANE_WORKBENCH){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
|
||||
|
||||
if(tileEntity instanceof TileEntityArcaneWorkbench){
|
||||
return new ContainerArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench)tileEntity);
|
||||
}
|
||||
|
||||
}else if(id == PORTABLE_CRAFTING){
|
||||
return new ContainerPortableWorkbench(player.inventory, world, new BlockPos(x, y, z));
|
||||
|
||||
}else if(id == BOOKSHELF){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
|
||||
|
||||
if(tileEntity instanceof TileEntityBookshelf){
|
||||
return new ContainerBookshelf(player.inventory, (TileEntityBookshelf)tileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z){
|
||||
|
||||
if(id == ARCANE_WORKBENCH){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
|
||||
|
||||
if(tileEntity instanceof TileEntityArcaneWorkbench){
|
||||
return new electroblob.wizardry.client.gui.GuiArcaneWorkbench(player.inventory,
|
||||
(TileEntityArcaneWorkbench)tileEntity);
|
||||
}
|
||||
|
||||
}else if(id == WIZARD_HANDBOOK && (player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook
|
||||
|| player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook)){
|
||||
|
||||
return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook();
|
||||
|
||||
}else if(id == SPELL_BOOK){
|
||||
|
||||
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemMainhand().getItemDamage()));
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemMainhand());
|
||||
}else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemOffhand().getItemDamage()));
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemOffhand());
|
||||
}
|
||||
|
||||
}else if(id == PORTABLE_CRAFTING){
|
||||
return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
|
||||
|
||||
}else if(id == BOOKSHELF){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
|
||||
|
||||
if(tileEntity instanceof TileEntityBookshelf){
|
||||
return new electroblob.wizardry.client.gui.GuiBookshelf(player.inventory,
|
||||
(TileEntityBookshelf)tileEntity);
|
||||
}
|
||||
|
||||
}else if(id == LECTERN){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
|
||||
|
||||
if(tileEntity instanceof TileEntityLectern){
|
||||
return new electroblob.wizardry.client.gui.GuiLectern((TileEntityLectern)tileEntity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import electroblob.wizardry.worldgen.WorldGenSurfaceStructure;
|
||||
import electroblob.wizardry.worldgen.WorldGenWizardryStructure;
|
||||
import net.minecraft.advancements.ICriterionTrigger;
|
||||
import net.minecraft.advancements.PlayerAdvancements;
|
||||
import net.minecraft.advancements.critereon.AbstractCriterionInstance;
|
||||
@@ -77,11 +77,11 @@ public class StructureTrigger implements ICriterionTrigger<StructureTrigger.Inst
|
||||
|
||||
public static class Instance extends AbstractCriterionInstance {
|
||||
|
||||
private final WorldGenSurfaceStructure structureType;
|
||||
private final WorldGenWizardryStructure structureType;
|
||||
|
||||
public Instance(ResourceLocation criterionIn, String name){
|
||||
super(criterionIn);
|
||||
this.structureType = WorldGenSurfaceStructure.byName(name);
|
||||
this.structureType = WorldGenWizardryStructure.byName(name);
|
||||
}
|
||||
|
||||
public boolean test(WorldServer world, double x, double y, double z){
|
||||
|
||||
+18
-18
@@ -17,14 +17,14 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** Advancement trigger for things done in the arcane workbench. The majority of any
|
||||
/** Advancement trigger for things done in the arcane workbench or imbuement altar. The majority of any
|
||||
* ICriterionTrigger class is just boilerplate, and this is no exception. */
|
||||
public class ArcaneWorkbenchTrigger implements ICriterionTrigger<ArcaneWorkbenchTrigger.Instance> {
|
||||
public class WizardryContainerTrigger implements ICriterionTrigger<WizardryContainerTrigger.Instance> {
|
||||
|
||||
private final ResourceLocation id;
|
||||
private final Map<PlayerAdvancements, ArcaneWorkbenchTrigger.Listeners> listeners = Maps.newHashMap();
|
||||
private final Map<PlayerAdvancements, WizardryContainerTrigger.Listeners> listeners = Maps.newHashMap();
|
||||
|
||||
public ArcaneWorkbenchTrigger(ResourceLocation id){
|
||||
public WizardryContainerTrigger(ResourceLocation id){
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@@ -32,21 +32,21 @@ public class ArcaneWorkbenchTrigger implements ICriterionTrigger<ArcaneWorkbench
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void addListener(PlayerAdvancements advancements, Listener<ArcaneWorkbenchTrigger.Instance> listener){
|
||||
public void addListener(PlayerAdvancements advancements, Listener<WizardryContainerTrigger.Instance> listener){
|
||||
|
||||
ArcaneWorkbenchTrigger.Listeners listeners = this.listeners.get(advancements);
|
||||
WizardryContainerTrigger.Listeners listeners = this.listeners.get(advancements);
|
||||
|
||||
if(listeners == null){
|
||||
listeners = new ArcaneWorkbenchTrigger.Listeners(advancements);
|
||||
listeners = new WizardryContainerTrigger.Listeners(advancements);
|
||||
this.listeners.put(advancements, listeners);
|
||||
}
|
||||
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeListener(PlayerAdvancements advancements, Listener<ArcaneWorkbenchTrigger.Instance> listener){
|
||||
public void removeListener(PlayerAdvancements advancements, Listener<WizardryContainerTrigger.Instance> listener){
|
||||
|
||||
ArcaneWorkbenchTrigger.Listeners listeners = this.listeners.get(advancements);
|
||||
WizardryContainerTrigger.Listeners listeners = this.listeners.get(advancements);
|
||||
|
||||
if(listeners != null){
|
||||
listeners.remove(listener);
|
||||
@@ -61,13 +61,13 @@ public class ArcaneWorkbenchTrigger implements ICriterionTrigger<ArcaneWorkbench
|
||||
this.listeners.remove(advancements);
|
||||
}
|
||||
|
||||
public ArcaneWorkbenchTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){
|
||||
return new ArcaneWorkbenchTrigger.Instance(this.id, ItemPredicate.deserialize(json.get("item")));
|
||||
public WizardryContainerTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){
|
||||
return new WizardryContainerTrigger.Instance(this.id, ItemPredicate.deserialize(json.get("item")));
|
||||
}
|
||||
|
||||
public void trigger(EntityPlayerMP player, ItemStack stack){
|
||||
|
||||
ArcaneWorkbenchTrigger.Listeners listeners = this.listeners.get(player.getAdvancements());
|
||||
WizardryContainerTrigger.Listeners listeners = this.listeners.get(player.getAdvancements());
|
||||
|
||||
if(listeners != null){
|
||||
listeners.trigger(stack);
|
||||
@@ -91,7 +91,7 @@ public class ArcaneWorkbenchTrigger implements ICriterionTrigger<ArcaneWorkbench
|
||||
static class Listeners {
|
||||
|
||||
private final PlayerAdvancements playerAdvancements;
|
||||
private final Set<Listener<ArcaneWorkbenchTrigger.Instance>> listeners = Sets.newHashSet();
|
||||
private final Set<Listener<WizardryContainerTrigger.Instance>> listeners = Sets.newHashSet();
|
||||
|
||||
public Listeners(PlayerAdvancements advancements){
|
||||
this.playerAdvancements = advancements;
|
||||
@@ -101,19 +101,19 @@ public class ArcaneWorkbenchTrigger implements ICriterionTrigger<ArcaneWorkbench
|
||||
return this.listeners.isEmpty();
|
||||
}
|
||||
|
||||
public void add(Listener<ArcaneWorkbenchTrigger.Instance> listener){
|
||||
public void add(Listener<WizardryContainerTrigger.Instance> listener){
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void remove(Listener<ArcaneWorkbenchTrigger.Instance> listener){
|
||||
public void remove(Listener<WizardryContainerTrigger.Instance> listener){
|
||||
this.listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void trigger(ItemStack stack){
|
||||
|
||||
List<Listener<ArcaneWorkbenchTrigger.Instance>> list = null;
|
||||
List<Listener<WizardryContainerTrigger.Instance>> list = null;
|
||||
|
||||
for(Listener<ArcaneWorkbenchTrigger.Instance> listener : this.listeners){
|
||||
for(Listener<WizardryContainerTrigger.Instance> listener : this.listeners){
|
||||
|
||||
if(listener.getCriterionInstance().test(stack)){
|
||||
|
||||
@@ -126,7 +126,7 @@ public class ArcaneWorkbenchTrigger implements ICriterionTrigger<ArcaneWorkbench
|
||||
}
|
||||
|
||||
if(list != null){
|
||||
for(Listener<ArcaneWorkbenchTrigger.Instance> listener : list){
|
||||
for(Listener<WizardryContainerTrigger.Instance> listener : list){
|
||||
listener.grantCriterion(this.playerAdvancements);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import electroblob.wizardry.Settings;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.WizardryGuiHandler;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
||||
import net.minecraft.block.BlockHorizontal;
|
||||
import net.minecraft.block.ITileEntityProvider;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.properties.PropertyInteger;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.InventoryHelper;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.IWorldEventListener;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
import net.minecraftforge.common.property.Properties;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvider {
|
||||
|
||||
/** When a bookshelf block (of any kind specified in the config) is added or removed, players within this range will
|
||||
* be notified of the change. */
|
||||
public static final double PLAYER_NOTIFY_RANGE = 32;
|
||||
public static final int SLOT_COUNT = 12;
|
||||
|
||||
public static final UnlistedPropertyInt[] BOOKS = new UnlistedPropertyInt[SLOT_COUNT];
|
||||
|
||||
private static final Map<Supplier<Item>, ResourceLocation> BOOK_TEXTURE_MAP = new HashMap<>();
|
||||
private static ImmutableList<Item> bookItems;
|
||||
private static ImmutableList<ResourceLocation> bookTextures;
|
||||
|
||||
public BlockBookshelf(){
|
||||
super(Material.WOOD);
|
||||
this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH));
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
this.setHardness(2.0F);
|
||||
this.setResistance(5.0F);
|
||||
this.setSoundType(SoundType.WOOD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockStateContainer createBlockState(){
|
||||
// IProperty<?>[] properties = { FACING };
|
||||
// return new BlockStateContainer(this, ArrayUtils.addAll(properties, BOOKS));
|
||||
return new BlockStateContainer.Builder(this).add(FACING).add(BOOKS).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
|
||||
return state.getValue(FACING).getAxis() == face.getAxis() ? BlockFaceShape.UNDEFINED : BlockFaceShape.SOLID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer){
|
||||
return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());
|
||||
}
|
||||
|
||||
// Why on earth are these two not in BlockHorizontal?
|
||||
|
||||
@Override
|
||||
public IBlockState withRotation(IBlockState state, Rotation rotation){
|
||||
return state.withProperty(FACING, rotation.rotate(state.getValue(FACING)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState withMirror(IBlockState state, Mirror mirror){
|
||||
return state.withRotation(mirror.toRotation(state.getValue(FACING)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state){
|
||||
super.onBlockAdded(worldIn, pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void breakBlock(World world, BlockPos pos, IBlockState block){
|
||||
|
||||
TileEntity tileentity = world.getTileEntity(pos);
|
||||
|
||||
if(tileentity instanceof TileEntityBookshelf){
|
||||
InventoryHelper.dropInventoryItems(world, pos, (TileEntityBookshelf)tileentity);
|
||||
}
|
||||
|
||||
super.breakBlock(world, pos, block); // For blocks that don't extend BlockContainer, this removes the TE
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int meta){
|
||||
EnumFacing enumfacing = EnumFacing.byIndex(meta);
|
||||
if(enumfacing.getAxis() == EnumFacing.Axis.Y) enumfacing = EnumFacing.NORTH;
|
||||
return this.getDefaultState().withProperty(FACING, enumfacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetaFromState(IBlockState state){
|
||||
return state.getValue(FACING).getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
|
||||
IExtendedBlockState s = (IExtendedBlockState)super.getExtendedState(state, world, pos);
|
||||
|
||||
if(world.getTileEntity(pos) instanceof TileEntityBookshelf){
|
||||
|
||||
TileEntityBookshelf tileentity = ((TileEntityBookshelf)world.getTileEntity(pos));
|
||||
|
||||
for(int i = 0; i < tileentity.getSizeInventory(); i++){
|
||||
|
||||
if(tileentity.getStackInSlot(i).isEmpty()){
|
||||
s = s.withProperty(BOOKS[i], bookItems.size());
|
||||
|
||||
}else{
|
||||
Item item = tileentity.getStackInSlot(i).getItem();
|
||||
// Default to the standard spell book texture, which will always be the first item in the list
|
||||
s = s.withProperty(BOOKS[i], bookItems.contains(item) ? bookItems.indexOf(item) : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int meta){
|
||||
return new TileEntityBookshelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
|
||||
EnumFacing side, float hitX, float hitY, float hitZ){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity == null || player.isSneaking()){
|
||||
return false;
|
||||
}
|
||||
|
||||
player.openGui(Wizardry.instance, WizardryGuiHandler.BOOKSHELF, world, pos.getX(), pos.getY(), pos.getZ());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasComparatorInputOverride(IBlockState state){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getComparatorInputOverride(IBlockState state, World world, BlockPos pos){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity instanceof TileEntityBookshelf){
|
||||
|
||||
int slotsOccupied = 0;
|
||||
|
||||
for(int i = 0; i < ((TileEntityBookshelf)tileEntity).getSizeInventory(); i++){
|
||||
if(!((TileEntityBookshelf)tileEntity).getStackInSlot(i).isEmpty()) slotsOccupied++;
|
||||
}
|
||||
|
||||
return slotsOccupied;
|
||||
|
||||
}
|
||||
|
||||
return super.getComparatorInputOverride(state, world, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eventReceived(IBlockState state, World world, BlockPos pos, int id, int param){
|
||||
super.eventReceived(state, world, pos, id, param);
|
||||
TileEntity tileentity = world.getTileEntity(pos);
|
||||
return tileentity != null && tileentity.receiveClientEvent(id, param);
|
||||
}
|
||||
|
||||
/** Returns the list of book textures, in ID order. */
|
||||
public static ImmutableList<ResourceLocation> getBookTextures(){
|
||||
// ModelBookshelf calls this before init() so we need to return the map values as a fallback
|
||||
return bookTextures == null ? ImmutableList.copyOf(BOOK_TEXTURE_MAP.values()) : bookTextures;
|
||||
}
|
||||
|
||||
/** Returns the list of registered book items, in ID order. */
|
||||
public static ImmutableList<Item> getBookItems(){
|
||||
return bookItems;
|
||||
}
|
||||
|
||||
/** Called during block registration to initialise the block properties for each book. */
|
||||
public static void initBookProperties(){
|
||||
for(int i=0; i<SLOT_COUNT; i++){
|
||||
BOOKS[i] = new UnlistedPropertyInt("book" + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Based on BlockFluid's UnlistedPropertyBool; this is only needed because of Java's weird restrictions on generics
|
||||
private static final class UnlistedPropertyInt extends Properties.PropertyAdapter<Integer> {
|
||||
|
||||
public UnlistedPropertyInt(String name){
|
||||
// Max is inclusive here, but we're using the largest value for no book so there's an extra one (can't use -1)
|
||||
super(PropertyInteger.create(name, 0, BOOK_TEXTURE_MAP.size()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Called from {@link Wizardry#init(FMLInitializationEvent)} to retrieve the actual book items and compile them
|
||||
* and their textures into immutable lists. */
|
||||
public static void compileBookModelTextures(){
|
||||
|
||||
ImmutableList.Builder<Item> itemListBuider = ImmutableList.builder();
|
||||
ImmutableList.Builder<ResourceLocation> textureListBuilder = ImmutableList.builder();
|
||||
|
||||
for(Map.Entry<Supplier<Item>, ResourceLocation> entry : BOOK_TEXTURE_MAP.entrySet()){
|
||||
itemListBuider.add(entry.getKey().get());
|
||||
textureListBuilder.add(entry.getValue());
|
||||
}
|
||||
|
||||
bookItems = itemListBuider.build();
|
||||
bookTextures = textureListBuilder.build();
|
||||
}
|
||||
|
||||
/** Called from {@link Wizardry#preInit(FMLPreInitializationEvent)} to register the default set of book textures. */
|
||||
public static void registerStandardBookModelTextures(){
|
||||
// Vanilla Minecraft books
|
||||
// Regular brown books are the default so they're registered first
|
||||
registerBookModelTexture(() -> Items.BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
|
||||
registerBookModelTexture(() -> Items.WRITABLE_BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
|
||||
registerBookModelTexture(() -> Items.WRITTEN_BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
|
||||
registerBookModelTexture(() -> Items.ENCHANTED_BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_enchanted"));
|
||||
// Wizardry books
|
||||
registerBookModelTexture(() -> WizardryItems.spell_book, new ResourceLocation(Wizardry.MODID, "blocks/books_red"));
|
||||
registerBookModelTexture(() -> WizardryItems.wizard_handbook, new ResourceLocation(Wizardry.MODID, "blocks/books_blue"));
|
||||
registerBookModelTexture(() -> WizardryItems.arcane_tome, new ResourceLocation(Wizardry.MODID, "blocks/books_purple"));
|
||||
registerBookModelTexture(() -> WizardryItems.ruined_spell_book, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
|
||||
registerBookModelTexture(() -> WizardryItems.scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
|
||||
registerBookModelTexture(() -> WizardryItems.blank_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
|
||||
registerBookModelTexture(() -> WizardryItems.identification_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_purple"));
|
||||
registerBookModelTexture(() -> WizardryItems.armour_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_red"));
|
||||
// Can't use the map in WandHelper because this is called from preInit (addons will have to add theirs manually)
|
||||
registerBookModelTexture(() -> WizardryItems.storage_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.siphon_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.condenser_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.range_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.duration_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.cooldown_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.blast_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.attunement_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
registerBookModelTexture(() -> WizardryItems.melee_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a book texture to be used for the book model when the given item is placed in a bookshelf. This method
|
||||
* <b>must</b> be called from {@code preInit} as the registered item count is required during block registration.
|
||||
* This also necessitates the use of a supplier to fetch the item, since the items will not yet be registered.
|
||||
* @param itemFactory A {@link Supplier} that returns the book item to link the texture to. This item need not
|
||||
* be an instance of {@link electroblob.wizardry.item.ItemSpellBook ItemSpellBook}. Duplicate
|
||||
* items will result in an {@link IllegalArgumentException} being thrown later.
|
||||
* @param texture The texture to apply to the book model.
|
||||
*/
|
||||
public static void registerBookModelTexture(Supplier<Item> itemFactory, ResourceLocation texture){
|
||||
BOOK_TEXTURE_MAP.put(itemFactory, texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of nearby bookshelves' inventories, where 'bookshelves' are any tile entities with inventories
|
||||
* whose blocks are specified in the config file under the {@code bookshelfBlocks} option.
|
||||
* @param world The world to search in
|
||||
* @param centre The position to search around
|
||||
* @param exclude Any tile entities that should be excluded from the returned list
|
||||
* @return A list of nearby {@link IInventory} objects that count as valid bookshelves
|
||||
*/
|
||||
public static List<IInventory> findNearbyBookshelves(World world, BlockPos centre, TileEntity... exclude){
|
||||
|
||||
List<IInventory> bookshelves = new ArrayList<>();
|
||||
|
||||
int searchRadius = Wizardry.settings.bookshelfSearchRadius;
|
||||
|
||||
for(int x = -searchRadius; x <= searchRadius; x++){
|
||||
for(int y = -searchRadius; y <= searchRadius; y++){
|
||||
for(int z = -searchRadius; z <= searchRadius; z++){
|
||||
|
||||
BlockPos pos = centre.add(x, y, z);
|
||||
|
||||
if(Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, world.getBlockState(pos))){
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if(te instanceof IInventory && !ArrayUtils.contains(exclude, te)) bookshelves.add((IInventory)te);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bookshelves;
|
||||
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onWorldLoadEvent(WorldEvent.Load event){
|
||||
event.getWorld().addEventListener(Listener.instance);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onWorldUnloadEvent(WorldEvent.Unload event){
|
||||
event.getWorld().removeEventListener(Listener.instance);
|
||||
}
|
||||
|
||||
public static class Listener implements IWorldEventListener {
|
||||
|
||||
public static final Listener instance = new Listener();
|
||||
|
||||
private Listener(){}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(World world, BlockPos pos, IBlockState oldState, IBlockState newState, int flags){
|
||||
|
||||
if(oldState == newState) return; // Probably won't happen but just in case
|
||||
|
||||
if(Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, oldState) // Bookshelf removed
|
||||
|| Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, newState)){ // Bookshelf placed
|
||||
// It is also possible (with commands) for a bookshelf to be replaced with another bookshelf, in which
|
||||
// case this should still just be called once
|
||||
Wizardry.proxy.notifyBookshelfChange(world, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Dummy implementations
|
||||
@Override public void notifyLightSet(BlockPos pos){}
|
||||
@Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2){}
|
||||
@Override public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch){}
|
||||
@Override public void playRecord(SoundEvent soundIn, BlockPos pos){}
|
||||
@Override public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord, double xSpeed, double ySpeed, double zSpeed, int... parameters){}
|
||||
@Override public void spawnParticle(int id, boolean ignoreRange, boolean minimiseParticleLevel, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed, int... parameters){}
|
||||
@Override public void onEntityAdded(Entity entityIn){}
|
||||
@Override public void onEntityRemoved(Entity entityIn){}
|
||||
@Override public void broadcastSound(int soundID, BlockPos pos, int data){}
|
||||
@Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data){}
|
||||
@Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress){}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
@@ -56,7 +57,7 @@ public class BlockCrystalFlower extends BlockBush {
|
||||
@SubscribeEvent
|
||||
public static void onBonemealEvent(BonemealEvent event){
|
||||
// Grows crystal flowers when bonemeal is used on grass
|
||||
if(event.getBlock().getBlock() == Blocks.GRASS){
|
||||
if(Wizardry.settings.bonemealGrowsCrystalFlowers && event.getBlock().getBlock() == Blocks.GRASS){
|
||||
|
||||
BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8),
|
||||
event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityFlowerPot;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
|
||||
public class BlockCrystalFlowerPot extends Block {
|
||||
|
||||
protected static final AxisAlignedBB BOUNDING_BOX = new AxisAlignedBB(0.3125D, 0.0D, 0.3125D, 0.6875D, 0.375D, 0.6875D);
|
||||
|
||||
public BlockCrystalFlowerPot(){
|
||||
super(Material.CIRCUITS);
|
||||
this.setLightLevel(0.4f);
|
||||
this.setTickRandomly(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
|
||||
if(world.isRemote && random.nextBoolean()){
|
||||
ParticleBuilder.create(Type.SPARKLE)
|
||||
.pos(pos.getX() + 0.3 + random.nextDouble() * 0.4, pos.getY() + 0.6 + random.nextDouble() * 0.3, pos.getZ() + 0.3 + random.nextDouble() * 0.4)
|
||||
.vel(0, 0.01, 0)
|
||||
.time(20 + random.nextInt(10))
|
||||
.clr(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2))
|
||||
.spawn(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TileEntity createTileEntity(World world, IBlockState state){
|
||||
return new TileEntityFlowerPot(Item.getItemFromBlock(WizardryBlocks.crystal_flower), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(IBlockState state){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||
|
||||
ItemStack stack = new ItemStack(WizardryBlocks.crystal_flower);
|
||||
|
||||
if(player.getHeldItem(hand).isEmpty()){
|
||||
player.setHeldItem(hand, stack);
|
||||
}else if(!player.addItemStackToInventory(stack)){
|
||||
player.dropItem(stack, false);
|
||||
}
|
||||
|
||||
world.setBlockState(pos, Blocks.FLOWER_POT.getDefaultState());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getPickBlock(IBlockState state, RayTraceResult target, World world, BlockPos pos, EntityPlayer player){
|
||||
return new ItemStack(WizardryBlocks.crystal_flower);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDrops(net.minecraft.util.NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, IBlockState state, int fortune){
|
||||
super.getDrops(drops, world, pos, state, fortune);
|
||||
drops.add(new ItemStack(WizardryBlocks.crystal_flower));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getItemDropped(IBlockState state, Random rand, int fortune){
|
||||
return Items.FLOWER_POT;
|
||||
}
|
||||
|
||||
// The rest are identical behaviour to BlockFlowerPot
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
return BOUNDING_BOX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceBlockAt(World world, BlockPos pos){
|
||||
IBlockState downState = world.getBlockState(pos.down());
|
||||
return super.canPlaceBlockAt(world, pos) && (downState.isTopSolid() || downState.getBlockFaceShape(world, pos.down(), EnumFacing.UP) == BlockFaceShape.SOLID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour){
|
||||
IBlockState downState = world.getBlockState(pos.down());
|
||||
if(!downState.isTopSolid() && downState.getBlockFaceShape(world, pos.down(), EnumFacing.UP) != BlockFaceShape.SOLID){
|
||||
this.dropBlockAsItem(world, pos, state, 0);
|
||||
world.setBlockToAir(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockRenderLayer getRenderLayer(){
|
||||
return BlockRenderLayer.CUTOUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFaceShape getBlockFaceShape(IBlockAccess worldIn, IBlockState state, BlockPos pos, EnumFacing face){
|
||||
return BlockFaceShape.UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest){
|
||||
if(willHarvest) return true; // If it will harvest, delay deletion of the block until after getDrops
|
||||
return super.removedByPlayer(state, world, pos, player, willHarvest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, @Nullable TileEntity te, ItemStack tool){
|
||||
super.harvestBlock(world, player, pos, state, te, tool);
|
||||
world.setBlockToAir(pos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import net.minecraft.block.BlockFrostedIce;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
@@ -12,6 +14,17 @@ import java.util.Random;
|
||||
* disappears instead of turning to water. */
|
||||
public class BlockDryFrostedIce extends BlockFrostedIce {
|
||||
|
||||
public BlockDryFrostedIce(){
|
||||
super();
|
||||
setDefaultSlipperiness(0.98f); // For some strange reason BlockFrostedIce overrides BlockIce's icy-ness...
|
||||
setSoundType(SoundType.GLASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material getMaterial(IBlockState state){
|
||||
return Material.ICE; // For goodness sake
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void turnIntoWater(World world, BlockPos pos){
|
||||
world.destroyBlock(pos, false);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import net.minecraft.block.BlockPlanks;
|
||||
import net.minecraft.block.SoundType;
|
||||
|
||||
public class BlockGildedWood extends BlockPlanks {
|
||||
|
||||
public BlockGildedWood(){
|
||||
super();
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
this.setHardness(2.0F);
|
||||
this.setResistance(5.0F);
|
||||
this.setSoundType(SoundType.WOOD); // Why is this protected?!
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.tileentity.TileEntityImbuementAltar;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.ITileEntityProvider;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.properties.PropertyBool;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.InventoryHelper;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class BlockImbuementAltar extends Block implements ITileEntityProvider {
|
||||
|
||||
public static final PropertyBool ACTIVE = PropertyBool.create("active");
|
||||
|
||||
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.75, 1.0);
|
||||
|
||||
public BlockImbuementAltar(){
|
||||
super(Material.ROCK);
|
||||
this.setBlockUnbreakable();
|
||||
this.setResistance(6000000);
|
||||
this.setLightLevel(0.4f);
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
this.setDefaultState(this.blockState.getBaseState().withProperty(ACTIVE, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockStateContainer createBlockState(){
|
||||
return new BlockStateContainer(this, ACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int meta){
|
||||
return this.getDefaultState().withProperty(ACTIVE, meta == 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetaFromState(IBlockState state){
|
||||
return state.getValue(ACTIVE) ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
return AABB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int metadata){
|
||||
return new TileEntityImbuementAltar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumBlockRenderType getRenderType(IBlockState state){
|
||||
return EnumBlockRenderType.MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockRenderLayer getRenderLayer(){
|
||||
return BlockRenderLayer.CUTOUT; // Required to shade parts of the block faces differently to others
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
|
||||
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return state.getValue(ACTIVE) ? super.getLightValue(state, world, pos) : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour){
|
||||
|
||||
boolean shouldBeActive = Arrays.stream(EnumFacing.HORIZONTALS)
|
||||
.allMatch(s -> world.getBlockState(pos.offset(s)).getBlock() == WizardryBlocks.receptacle
|
||||
&& world.getBlockState(pos.offset(s)).getValue(BlockReceptacle.FACING) == s);
|
||||
|
||||
if(world.getBlockState(pos).getValue(ACTIVE) != shouldBeActive){ // Only set when it actually needs changing
|
||||
world.setBlockState(pos, world.getBlockState(pos).withProperty(ACTIVE, shouldBeActive));
|
||||
world.checkLight(pos);
|
||||
}
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
if(tileEntity instanceof TileEntityImbuementAltar){
|
||||
((TileEntityImbuementAltar)tileEntity).checkRecipe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
|
||||
EnumFacing side, float hitX, float hitY, float hitZ){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(!(tileEntity instanceof TileEntityImbuementAltar) || player.isSneaking()){
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemStack currentStack = ((TileEntityImbuementAltar)tileEntity).getStack();
|
||||
ItemStack toInsert = player.getHeldItem(hand);
|
||||
|
||||
if(currentStack.isEmpty()){
|
||||
ItemStack stack = toInsert.copy();
|
||||
stack.setCount(1);
|
||||
((TileEntityImbuementAltar)tileEntity).setStack(stack);
|
||||
((TileEntityImbuementAltar)tileEntity).setLastUser(player);
|
||||
if(!player.isCreative()) toInsert.shrink(1);
|
||||
|
||||
}else{
|
||||
|
||||
if(toInsert.isEmpty()){
|
||||
player.setHeldItem(hand, currentStack);
|
||||
}else if(!player.addItemStackToInventory(currentStack)){
|
||||
player.dropItem(currentStack, false);
|
||||
}
|
||||
|
||||
((TileEntityImbuementAltar)tileEntity).setStack(ItemStack.EMPTY);
|
||||
((TileEntityImbuementAltar)tileEntity).setLastUser(null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void breakBlock(World world, BlockPos pos, IBlockState block){
|
||||
|
||||
TileEntity tileentity = world.getTileEntity(pos);
|
||||
|
||||
if(tileentity instanceof TileEntityImbuementAltar){
|
||||
InventoryHelper.spawnItemStack(world, pos.getX(), pos.getY(), pos.getZ(), ((TileEntityImbuementAltar)tileentity).getStack());
|
||||
}
|
||||
|
||||
super.breakBlock(world, pos, block);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.WizardryGuiHandler;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import net.minecraft.block.BlockHorizontal;
|
||||
import net.minecraft.block.ITileEntityProvider;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.Mirror;
|
||||
import net.minecraft.util.Rotation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
|
||||
public class BlockLectern extends BlockHorizontal implements ITileEntityProvider {
|
||||
|
||||
public BlockLectern(){
|
||||
super(Material.WOOD);
|
||||
this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH));
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
this.setHardness(2.0F);
|
||||
this.setResistance(5.0F);
|
||||
this.setSoundType(SoundType.WOOD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockStateContainer createBlockState(){
|
||||
return new BlockStateContainer.Builder(this).add(FACING).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int meta){
|
||||
EnumFacing enumfacing = EnumFacing.byIndex(meta);
|
||||
if(enumfacing.getAxis() == EnumFacing.Axis.Y) enumfacing = EnumFacing.NORTH;
|
||||
return this.getDefaultState().withProperty(FACING, enumfacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetaFromState(IBlockState state){
|
||||
return state.getValue(FACING).getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random rand){
|
||||
|
||||
EntityPlayer entityplayer = world.getClosestPlayer(pos.getX() + 0.5, pos.getY() + 0.5,
|
||||
pos.getZ() + 0.5, TileEntityLectern.BOOK_OPEN_DISTANCE, false);
|
||||
|
||||
if(entityplayer != null){
|
||||
ParticleBuilder.create(Type.DUST).pos(pos.getX() + rand.nextFloat(), pos.getY() + 1, pos.getZ() + rand.nextFloat())
|
||||
.vel(0, 0.03, 0).clr(1, 1, 0.65f).fade(0.7f, 0, 1).shaded(false).spawn(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullBlock(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceTorchOnTop(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
|
||||
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer){
|
||||
return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState withRotation(IBlockState state, Rotation rotation){
|
||||
return state.withProperty(FACING, rotation.rotate(state.getValue(FACING)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState withMirror(IBlockState state, Mirror mirror){
|
||||
return state.withRotation(mirror.toRotation(state.getValue(FACING)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int meta){
|
||||
return new TileEntityLectern();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
|
||||
EnumFacing side, float hitX, float hitY, float hitZ){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity == null || player.isSneaking()){
|
||||
return false;
|
||||
}
|
||||
|
||||
player.openGui(Wizardry.instance, WizardryGuiHandler.LECTERN, world, pos.getX(), pos.getY(), pos.getZ());
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -107,7 +107,9 @@ public class BlockPedestal extends Block implements ITileEntityProvider {
|
||||
natural = true;
|
||||
metadata -= ELEMENT.getAllowedValues().size();
|
||||
}
|
||||
return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]).withProperty(NATURAL, natural);
|
||||
Element element = Element.values()[metadata];
|
||||
if(!ELEMENT.getAllowedValues().contains(element)) return this.getDefaultState().withProperty(NATURAL, natural);
|
||||
return this.getDefaultState().withProperty(ELEMENT, element).withProperty(NATURAL, natural);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BlockPermafrost extends BlockDryFrostedIce {
|
||||
|
||||
protected static final AxisAlignedBB BOUNDING_BOX = new AxisAlignedBB(0, 0, 0, 1, 0, 1);
|
||||
protected static final AxisAlignedBB SELECTION_BOUNDING_BOX = new AxisAlignedBB(0, 0, 0, 1, 0.125, 1);
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
return BOUNDING_BOX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getSelectedBoundingBox(IBlockState state, World worldIn, BlockPos pos){
|
||||
return SELECTION_BOUNDING_BOX;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos){
|
||||
return super.getCollisionBoundingBox(blockState, worldIn, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
|
||||
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
|
||||
|
||||
if(EntityUtils.isLiving(entity) && entity.ticksExisted % 30 == 0){
|
||||
// Can't make it player damage unless we make this block a tile entity, but there will be too many for that
|
||||
entity.attackEntityFrom(DamageSource.MAGIC, Spells.permafrost.getProperty(Spell.DAMAGE).floatValue());
|
||||
int duration = Spells.permafrost.getProperty(Spell.EFFECT_DURATION).intValue();
|
||||
int amplifier = Spells.permafrost.getProperty(Spell.EFFECT_STRENGTH).intValue();
|
||||
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(WizardryPotions.frost, duration, amplifier));
|
||||
}
|
||||
|
||||
// EntityLivingBase's slipperiness code doesn't get the block below it properly so slipperiness only works for
|
||||
// full blocks...
|
||||
if(entity.onGround){
|
||||
|
||||
// Not brilliant but it's about the best I can do
|
||||
entity.motionX *= 1.12 - entity.motionX * entity.motionX;
|
||||
entity.motionZ *= 1.12 - entity.motionZ * entity.motionZ;
|
||||
|
||||
// if(entity instanceof EntityLivingBase){
|
||||
// double maxVel = 0.8;
|
||||
// double x = entity.motionX;
|
||||
// double y = entity.motionY;
|
||||
// double z = entity.motionZ;
|
||||
// double vel = MathHelper.sqrt(x*x + y*y + z*z);
|
||||
// double m = vel / maxVel;
|
||||
// if(m > 1){
|
||||
// entity.motionX /= m;
|
||||
// entity.motionZ /= m;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.item.ItemSpectralDust;
|
||||
import electroblob.wizardry.registry.*;
|
||||
import electroblob.wizardry.tileentity.TileEntityReceptacle;
|
||||
import electroblob.wizardry.util.GeometryUtils;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockTorch;
|
||||
import net.minecraft.block.ITileEntityProvider;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class BlockReceptacle extends BlockTorch implements ITileEntityProvider {
|
||||
|
||||
protected static final AxisAlignedBB STANDING_AABB = new AxisAlignedBB(4 / 16d, 0 / 16d, 4 / 16d, 12 / 16d, 8 / 16d, 12 / 16d);
|
||||
protected static final AxisAlignedBB NORTH_WALL_AABB = new AxisAlignedBB(4 / 16d, 2 / 16d, 7 / 16d, 12 / 16d, 10 / 16d, 16 / 16d);
|
||||
protected static final AxisAlignedBB SOUTH_WALL_AABB = new AxisAlignedBB(4 / 16d, 2 / 16d, 0 / 16d, 12 / 16d, 10 / 16d, 9 / 16d);
|
||||
protected static final AxisAlignedBB WEST_WALL_AABB = new AxisAlignedBB(7 / 16d, 2 / 16d, 4 / 16d, 16 / 16d, 10 / 16d, 12 / 16d);
|
||||
protected static final AxisAlignedBB EAST_WALL_AABB = new AxisAlignedBB(0 / 16d, 2 / 16d, 4 / 16d, 9 / 16d, 10 / 16d, 12 / 16d);
|
||||
|
||||
private static final double WALL_PARTICLE_OFFSET = 3 / 16d;
|
||||
|
||||
public static final Map<Element, int[]> PARTICLE_COLOURS;
|
||||
|
||||
static{
|
||||
|
||||
Map<Element, int[]> map = Maps.newEnumMap(Element.class);
|
||||
|
||||
map.put(Element.MAGIC, new int[]{0xe4c7cd, 0xfeffbe, 0x9d2cf3});
|
||||
map.put(Element.FIRE, new int[]{0xff9600, 0xfffe67, 0xd02700});
|
||||
map.put(Element.ICE, new int[]{0xa3e8f4, 0xe9f9fc, 0x138397});
|
||||
map.put(Element.LIGHTNING, new int[]{0x409ee1, 0xf5f0ff, 0x225474});
|
||||
map.put(Element.NECROMANCY, new int[]{0xa811ce, 0xf575f5, 0x382366});
|
||||
map.put(Element.EARTH, new int[]{0xa8f408, 0xc8ffb2, 0x795c28});
|
||||
map.put(Element.SORCERY, new int[]{0x56e8e3, 0xe8fcfc, 0x16a64d});
|
||||
map.put(Element.HEALING, new int[]{0xfff69e, 0xfffff6, 0xa18200});
|
||||
|
||||
PARTICLE_COLOURS = Maps.immutableEnumMap(map);
|
||||
}
|
||||
|
||||
public BlockReceptacle(){
|
||||
super();
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
this.setHardness(0);
|
||||
this.setLightLevel(0.5f);
|
||||
this.setSoundType(SoundType.STONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
switch(state.getValue(FACING)){
|
||||
case EAST:
|
||||
return EAST_WALL_AABB;
|
||||
case WEST:
|
||||
return WEST_WALL_AABB;
|
||||
case SOUTH:
|
||||
return SOUTH_WALL_AABB;
|
||||
case NORTH:
|
||||
return NORTH_WALL_AABB;
|
||||
default:
|
||||
return STANDING_AABB;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getCollisionBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return state.getBoundingBox(world, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity instanceof TileEntityReceptacle && ((TileEntityReceptacle)tileEntity).getElement() != null){
|
||||
return super.getLightValue(state, world, pos); // Return super to use float value from constructor
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDrops(NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, IBlockState state, int fortune){
|
||||
|
||||
super.getDrops(drops, world, pos, state, fortune);
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity instanceof TileEntityReceptacle){
|
||||
Element element = ((TileEntityReceptacle)tileEntity).getElement();
|
||||
if(element != null) drops.add(new ItemStack(WizardryItems.spectral_dust, 1, element.ordinal()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceBlockOnSide(World world, BlockPos pos, EnumFacing side){
|
||||
|
||||
if(side != EnumFacing.UP && side != EnumFacing.DOWN
|
||||
&& world.getBlockState(pos.offset(side.getOpposite())).getBlock() instanceof BlockImbuementAltar){
|
||||
return true;
|
||||
}
|
||||
return super.canPlaceBlockOnSide(world, pos, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkForDrop(World world, BlockPos pos, IBlockState state){
|
||||
if(state.getBlock() == this && this.canPlaceAt(world, pos, state.getValue(FACING))){
|
||||
return true;
|
||||
}
|
||||
return super.checkForDrop(world, pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer){
|
||||
|
||||
if(this.canPlaceAt(world, pos, facing)){
|
||||
return this.getDefaultState().withProperty(FACING, facing);
|
||||
}else{
|
||||
|
||||
for(EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL){
|
||||
if(this.canPlaceAt(world, pos, enumfacing)){
|
||||
return this.getDefaultState().withProperty(FACING, enumfacing);
|
||||
}
|
||||
}
|
||||
|
||||
return this.getDefaultState();
|
||||
}
|
||||
}
|
||||
|
||||
// Why is everything in BlockTorch private, for goodness sake...
|
||||
private boolean canPlaceAt(World world, BlockPos pos, EnumFacing facing){
|
||||
|
||||
BlockPos blockpos = pos.offset(facing.getOpposite());
|
||||
IBlockState state = world.getBlockState(blockpos);
|
||||
Block block = state.getBlock();
|
||||
BlockFaceShape blockfaceshape = state.getBlockFaceShape(world, blockpos, facing);
|
||||
|
||||
if(facing.equals(EnumFacing.UP) && this.canPlaceOn(world, blockpos)){
|
||||
return true;
|
||||
}else if(facing != EnumFacing.UP && facing != EnumFacing.DOWN){
|
||||
return !isExceptBlockForAttachWithPiston(block) && (blockfaceshape == BlockFaceShape.SOLID || block instanceof BlockImbuementAltar);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canPlaceOn(World world, BlockPos pos){
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
return state.getBlock().canPlaceTorchOnTop(state, world, pos);
|
||||
}
|
||||
|
||||
// See BlockFlowerPot for these two (this class is essentially based on a flower pot)
|
||||
|
||||
@Override
|
||||
public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest){
|
||||
if(willHarvest) return true; // If it will harvest, delay deletion of the block until after getDrops
|
||||
return super.removedByPlayer(state, world, pos, player, willHarvest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, @Nullable TileEntity te, ItemStack tool){
|
||||
super.harvestBlock(world, player, pos, state, te, tool);
|
||||
world.setBlockToAir(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
ItemStack stack = player.getHeldItem(hand);
|
||||
|
||||
if(tileEntity instanceof TileEntityReceptacle){
|
||||
|
||||
Element currentElement = ((TileEntityReceptacle)tileEntity).getElement();
|
||||
|
||||
if(currentElement == null){
|
||||
|
||||
if(stack.getItem() instanceof ItemSpectralDust && stack.getMetadata() >= 0
|
||||
&& stack.getMetadata() < Element.values().length){
|
||||
|
||||
((TileEntityReceptacle)tileEntity).setElement(Element.values()[stack.getMetadata()]);
|
||||
if(!player.capabilities.isCreativeMode) stack.shrink(1);
|
||||
world.playSound(pos.getX(), pos.getY(), pos.getZ(), WizardrySounds.BLOCK_RECEPTACLE_IGNITE,
|
||||
SoundCategory.BLOCKS, 0.7f, 0.7f, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
((TileEntityReceptacle)tileEntity).setElement(null);
|
||||
|
||||
ItemStack dust = new ItemStack(WizardryItems.spectral_dust, 1, currentElement.ordinal());
|
||||
|
||||
if(stack.isEmpty()){
|
||||
player.setHeldItem(hand, dust);
|
||||
}else if(!player.addItemStackToInventory(dust)){
|
||||
player.dropItem(dust, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random rand){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity instanceof TileEntityReceptacle){
|
||||
|
||||
Element element = ((TileEntityReceptacle)tileEntity).getElement();
|
||||
|
||||
if(element != null){
|
||||
|
||||
EnumFacing facing = state.getValue(FACING).getOpposite();
|
||||
|
||||
Vec3d centre = GeometryUtils.getCentre(pos);
|
||||
if(facing.getAxis().isHorizontal()){
|
||||
centre = centre.add(new Vec3d(facing.getDirectionVec()).scale(WALL_PARTICLE_OFFSET)).add(0, 0.125, 0);
|
||||
}
|
||||
|
||||
int[] colours = PARTICLE_COLOURS.get(element);
|
||||
|
||||
ParticleBuilder.create(ParticleBuilder.Type.FLASH).pos(centre).scale(0.35f).time(48).clr(colours[0]).spawn(world);
|
||||
|
||||
double r = 0.12;
|
||||
|
||||
for(int i = 0; i < 3; i++){
|
||||
|
||||
double x = r * (rand.nextDouble() * 2 - 1);
|
||||
double y = r * (rand.nextDouble() * 2 - 1);
|
||||
double z = r * (rand.nextDouble() * 2 - 1);
|
||||
|
||||
ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(centre.x + x, centre.y + y, centre.z + z)
|
||||
.vel(x * -0.03, 0.02, z * -0.03).time(24 + rand.nextInt(8)).clr(colours[1]).fade(colours[2]).spawn(world);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack){
|
||||
if(placer instanceof EntityPlayer){
|
||||
BlockPos centre = pos.offset(world.getBlockState(pos).getValue(FACING).getOpposite());
|
||||
if(world.getBlockState(centre).getBlock() == WizardryBlocks.imbuement_altar
|
||||
&& Arrays.stream(EnumFacing.HORIZONTALS).allMatch(f -> world.getBlockState(centre.offset(f)).getBlock() == WizardryBlocks.receptacle)){
|
||||
WizardryAdvancementTriggers.restore_imbuement_altar.triggerFor((EntityPlayer)placer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int meta){
|
||||
return new TileEntityReceptacle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasComparatorInputOverride(IBlockState state){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getComparatorInputOverride(IBlockState state, World world, BlockPos pos){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity instanceof TileEntityReceptacle){
|
||||
Element element = ((TileEntityReceptacle)tileEntity).getElement();
|
||||
return element == null ? 0 : element.ordinal() + 1;
|
||||
}
|
||||
|
||||
return super.getComparatorInputOverride(state, world, pos);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -69,7 +69,9 @@ public class BlockRunestone extends Block {
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int metadata){
|
||||
return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]);
|
||||
Element element = Element.values()[metadata];
|
||||
if(!ELEMENT.getAllowedValues().contains(element)) return this.getDefaultState();
|
||||
return this.getDefaultState().withProperty(ELEMENT, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ import net.minecraft.item.Item;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
@@ -54,21 +55,24 @@ public class BlockSnare extends Block implements ITileEntityProvider {
|
||||
@Override
|
||||
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
|
||||
|
||||
if(!world.isRemote && entity instanceof EntityLivingBase){
|
||||
if(entity instanceof EntityLivingBase){
|
||||
|
||||
if(world.getTileEntity(pos) instanceof TileEntityPlayerSave){
|
||||
|
||||
TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos);
|
||||
|
||||
if(AllyDesignationSystem.isValidTarget(tileentity.getCaster(), entity)){
|
||||
|
||||
entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC),
|
||||
Spells.snare.getProperty(Spell.DAMAGE).floatValue());
|
||||
DamageSource source = tileentity.getCaster() == null ? DamageSource.CACTUS
|
||||
: MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC);
|
||||
|
||||
entity.attackEntityFrom(source, Spells.snare.getProperty(Spell.DAMAGE).floatValue());
|
||||
|
||||
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS,
|
||||
Spells.snare.getProperty(Spell.EFFECT_DURATION).intValue(),
|
||||
Spells.snare.getProperty(Spell.EFFECT_STRENGTH).intValue()));
|
||||
|
||||
world.destroyBlock(pos, false);
|
||||
if(!world.isRemote) world.destroyBlock(pos, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
@@ -34,26 +33,16 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
|
||||
|
||||
// Replaces getRenderBlockPass
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockRenderLayer getRenderLayer(){
|
||||
return BlockRenderLayer.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumBlockRenderType getRenderType(IBlockState state){
|
||||
return EnumBlockRenderType.MODEL;
|
||||
}
|
||||
|
||||
// Apparently it's OK to override this, despite it being deprecated. More importantly, it being deprecated is not
|
||||
// Forge's doing, rather it is Mojang themselves misusing the @Deprecated annotation to mean 'internal, don't call'.
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
// See BlockTransportationStone for what all these do
|
||||
@Override public boolean isFullCube(IBlockState state){ return false; }
|
||||
@Override public boolean isBlockNormalCube(IBlockState state){ return false; }
|
||||
@Override public boolean isNormalCube(IBlockState state){ return false; }
|
||||
@Override public boolean isOpaqueCube(IBlockState state){ return false; }
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
|
||||
@@ -67,12 +56,12 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// Overriden to make the block always look full brightness despite not emitting
|
||||
// full light.
|
||||
@Override
|
||||
public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
return 15;
|
||||
}
|
||||
// // Overriden to make the block always look full brightness despite not emitting
|
||||
// // full light.
|
||||
// @Override
|
||||
// public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
// return 15;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(IBlockState state){
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.tileentity.TileEntityStatue;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.BlockUtils;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.ITileEntityProvider;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
@@ -19,6 +20,7 @@ import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
|
||||
public class BlockStatue extends Block implements ITileEntityProvider {
|
||||
@@ -180,77 +182,77 @@ public class BlockStatue extends Block implements ITileEntityProvider {
|
||||
|
||||
/**
|
||||
* Turns the given entity into a statue. The type of statue depends on the block instance this method was invoked on.
|
||||
* @param entity The entity to turn into a statue.
|
||||
* @param target The entity to turn into a statue.
|
||||
* @param caster The entity that caused it, or null if it was not caused by an entity
|
||||
* @param duration The time for which the entity should remain a statue. For petrified creatures, this is the minimum
|
||||
* time it can stay as a statue.
|
||||
* @return True if the entity was successfully turned into a statue, false if not (i.e. something was in the way).
|
||||
*/
|
||||
// Making this an instance method means it works equally well for both types of statue
|
||||
public boolean convertToStatue(EntityLiving entity, int duration){
|
||||
public boolean convertToStatue(EntityLiving target, @Nullable EntityLivingBase caster, int duration){
|
||||
|
||||
if(entity.deathTime > 0) return false;
|
||||
if(target.deathTime > 0) return false;
|
||||
|
||||
BlockPos pos = new BlockPos(entity);
|
||||
World world = entity.world;
|
||||
BlockPos pos = new BlockPos(target);
|
||||
World world = target.world;
|
||||
|
||||
entity.hurtTime = 0; // Stops the entity looking red while frozen and the resulting z-fighting
|
||||
entity.extinguish();
|
||||
target.hurtTime = 0; // Stops the entity looking red while frozen and the resulting z-fighting
|
||||
target.extinguish();
|
||||
|
||||
// Short mobs such as spiders and pigs
|
||||
if((entity.height < 1.2 || entity.isChild()) && WizardryUtilities.canBlockBeReplaced(world, pos)){
|
||||
if((target.height < 1.2 || target.isChild()) && BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canPlaceBlock(caster, world, pos)){
|
||||
|
||||
world.setBlockState(pos, this.getDefaultState());
|
||||
if(world.getTileEntity(pos) instanceof TileEntityStatue){
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(entity, 1, 1);
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 1);
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
|
||||
}
|
||||
|
||||
entity.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
||||
entity.setDead();
|
||||
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
||||
target.setDead();
|
||||
return true;
|
||||
}
|
||||
// Normal sized mobs like zombies and skeletons
|
||||
else if(entity.height < 2.5 && WizardryUtilities.canBlockBeReplaced(world, pos)
|
||||
&& WizardryUtilities.canBlockBeReplaced(world, pos.up())){
|
||||
else if(target.height < 2.5 && BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canBlockBeReplaced(world, pos.up())
|
||||
&& BlockUtils.canPlaceBlock(caster, world, pos) && BlockUtils.canPlaceBlock(caster, world, pos.up())){
|
||||
|
||||
world.setBlockState(pos, this.getDefaultState());
|
||||
if(world.getTileEntity(pos) instanceof TileEntityStatue){
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(entity, 1, 2);
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 2);
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
|
||||
}
|
||||
|
||||
world.setBlockState(pos.up(), this.getDefaultState());
|
||||
if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){
|
||||
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(entity, 2, 2);
|
||||
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 2);
|
||||
}
|
||||
|
||||
entity.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
||||
entity.setDead();
|
||||
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
||||
target.setDead();
|
||||
return true;
|
||||
}
|
||||
// Tall mobs like endermen
|
||||
else if(WizardryUtilities.canBlockBeReplaced(world, pos)
|
||||
&& WizardryUtilities.canBlockBeReplaced(world, pos.up())
|
||||
&& WizardryUtilities.canBlockBeReplaced(world, pos.up(2))){
|
||||
else if(BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canBlockBeReplaced(world, pos.up()) && BlockUtils.canBlockBeReplaced(world, pos.up(2))
|
||||
&& BlockUtils.canPlaceBlock(caster, world, pos) && BlockUtils.canPlaceBlock(caster, world, pos.up()) && BlockUtils.canPlaceBlock(caster, world, pos.up(2))){
|
||||
|
||||
world.setBlockState(pos, this.getDefaultState());
|
||||
if(world.getTileEntity(pos) instanceof TileEntityStatue){
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(entity, 1, 3);
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 3);
|
||||
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
|
||||
}
|
||||
|
||||
world.setBlockState(pos.up(), this.getDefaultState());
|
||||
if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){
|
||||
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(entity, 2, 3);
|
||||
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 3);
|
||||
}
|
||||
|
||||
world.setBlockState(pos.up(2), this.getDefaultState());
|
||||
if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){
|
||||
((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(entity, 3, 3);
|
||||
((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(target, 3, 3);
|
||||
}
|
||||
|
||||
entity.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
||||
entity.setDead();
|
||||
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
|
||||
target.setDead();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ package electroblob.wizardry.block;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.TileEntityPlayerSaveTimed;
|
||||
import electroblob.wizardry.tileentity.TileEntityThorns;
|
||||
import electroblob.wizardry.util.AllyDesignationSystem;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.BlockDoublePlant.EnumBlockHalf;
|
||||
@@ -22,8 +23,10 @@ import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.ChunkCache;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
@@ -34,6 +37,7 @@ import java.util.Random;
|
||||
public class BlockThorns extends BlockBush implements ITileEntityProvider {
|
||||
|
||||
public static final int GROWTH_STAGES = 8;
|
||||
public static final int GROWTH_STAGE_DURATION = 2;
|
||||
|
||||
public static final PropertyInteger AGE = PropertyInteger.create("age", 0, GROWTH_STAGES-1);
|
||||
public static final PropertyEnum<EnumBlockHalf> HALF = PropertyEnum.create("half", EnumBlockHalf.class);
|
||||
@@ -52,22 +56,27 @@ public class BlockThorns extends BlockBush implements ITileEntityProvider {
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int meta){
|
||||
return this.getDefaultState().withProperty(HALF, EnumBlockHalf.values()[meta / GROWTH_STAGES]).withProperty(AGE, meta % GROWTH_STAGES);
|
||||
return this.getDefaultState().withProperty(HALF, meta == 0 ? EnumBlockHalf.LOWER : EnumBlockHalf.UPPER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetaFromState(IBlockState state){
|
||||
return state.getValue(HALF).ordinal() * GROWTH_STAGES + state.getValue(AGE);
|
||||
return state.getValue(HALF).ordinal();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void updateTick(World world, BlockPos pos, IBlockState state, Random rand){
|
||||
//
|
||||
// super.updateTick(world, pos, state, rand);
|
||||
//
|
||||
// // Update the state, including on the client, but don't do a block update since it's only visual
|
||||
// if(state.getValue(AGE) < GROWTH_STAGES-1) world.setBlockState(pos, state.withProperty(AGE, state.getValue(AGE) + 1), 2);
|
||||
// }
|
||||
@Override
|
||||
public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
|
||||
if(state.getValue(HALF) == EnumBlockHalf.UPPER) pos = pos.down();
|
||||
// Copied from BlockFlowerPot on authority of the Forge docs, which say it needs to be here
|
||||
TileEntity tileentity = world instanceof ChunkCache ? ((ChunkCache)world).getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK) : world.getTileEntity(pos);
|
||||
|
||||
if(tileentity instanceof TileEntityThorns){
|
||||
return state.withProperty(AGE, ((TileEntityThorns)tileentity).getAge());
|
||||
}else{
|
||||
return state.withProperty(AGE, 7);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockStateContainer createBlockState(){
|
||||
@@ -107,45 +116,36 @@ public class BlockThorns extends BlockBush implements ITileEntityProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
// // Copied from BlockFlowerPot on authority of the Forge docs, which says this check is necessary
|
||||
// SoundLoopSpellDispenser tileentity = world instanceof ChunkCache ? ((ChunkCache)world).getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK) : world.getTileEntity(pos);
|
||||
//
|
||||
// if(tileentity instanceof TileEntityPlayerSaveTimed){
|
||||
// state = state.withProperty(AGE, Math.min(7, ((TileEntityPlayerSaveTimed)tileentity).timer/2));
|
||||
// }else{
|
||||
// state = state.withProperty(AGE, 7);
|
||||
// }
|
||||
//
|
||||
// return state;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
|
||||
if(!world.isRemote){
|
||||
if(applyThornDamage(world, pos, entity)){
|
||||
entity.setInWeb();
|
||||
}
|
||||
if(applyThornDamage(world, pos, state, entity)){
|
||||
entity.setInWeb(); // Needs to be called client-side for players (and besides, all of this is common code)
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean applyThornDamage(World world, BlockPos pos, Entity target){
|
||||
private static boolean applyThornDamage(World world, BlockPos pos, IBlockState state, Entity target){
|
||||
|
||||
DamageSource source = DamageSource.CACTUS;
|
||||
float damage = Spells.forest_of_thorns.getProperty(Spell.DAMAGE).floatValue();
|
||||
|
||||
TileEntity tileentity = world.getTileEntity(pos);
|
||||
TileEntity tileentity = world.getTileEntity(state.getValue(HALF) == EnumBlockHalf.UPPER ? pos.down() : pos);
|
||||
|
||||
if(tileentity instanceof TileEntityPlayerSaveTimed){
|
||||
if(AllyDesignationSystem.isValidTarget(((TileEntityPlayerSaveTimed)tileentity).getCaster(), target)){
|
||||
source = MagicDamage.causeDirectMagicDamage(((TileEntityPlayerSaveTimed)tileentity).getCaster(),
|
||||
MagicDamage.DamageType.MAGIC);
|
||||
}else{
|
||||
return false; // Don't attack or slow allies of the caster
|
||||
if(tileentity instanceof TileEntityThorns){
|
||||
|
||||
damage *= ((TileEntityThorns)tileentity).damageMultiplier;
|
||||
|
||||
EntityLivingBase caster = ((TileEntityThorns)tileentity).getCaster();
|
||||
|
||||
if(!AllyDesignationSystem.isValidTarget(caster, target)) return false; // Don't attack or slow allies of the caster
|
||||
|
||||
if(caster != null){
|
||||
source = MagicDamage.causeDirectMagicDamage(caster, MagicDamage.DamageType.MAGIC);
|
||||
}
|
||||
}
|
||||
|
||||
if(world.getTotalWorldTime() % 20 == 0) target.attackEntityFrom(source, Spells.forest_of_thorns.getProperty(Spell.DAMAGE).floatValue());
|
||||
if(target.ticksExisted % 20 == 0){
|
||||
EntityUtils.attackEntityWithoutKnockback(target, source, damage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -157,12 +157,12 @@ public class BlockThorns extends BlockBush implements ITileEntityProvider {
|
||||
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int metadata){
|
||||
return new TileEntityPlayerSaveTimed(600);
|
||||
return new TileEntityThorns();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(IBlockState state){
|
||||
return true;
|
||||
return state.getValue(HALF) == EnumBlockHalf.LOWER;
|
||||
}
|
||||
|
||||
@Override public boolean isReplaceable(IBlockAccess world, BlockPos pos){ return false; }
|
||||
@@ -172,9 +172,8 @@ public class BlockThorns extends BlockBush implements ITileEntityProvider {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLeftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event){
|
||||
if(!event.getWorld().isRemote && event.getWorld().getTotalWorldTime() % 20 == 0
|
||||
&& event.getWorld().getBlockState(event.getPos()).getBlock() == WizardryBlocks.thorns){
|
||||
applyThornDamage(event.getWorld(), event.getPos(), event.getEntity());
|
||||
if(!event.getWorld().isRemote && event.getWorld().getBlockState(event.getPos()).getBlock() == WizardryBlocks.thorns){
|
||||
applyThornDamage(event.getWorld(), event.getPos(), event.getWorld().getBlockState(event.getPos()), event.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.spell.Transportation;
|
||||
import electroblob.wizardry.util.GeometryUtils;
|
||||
import electroblob.wizardry.util.Location;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
@@ -62,18 +62,12 @@ public class BlockTransportationStone extends Block {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Forge version of the above method. I still need to override both though because vanilla uses the other one.
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
// ... and this one is for rendering.
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side){
|
||||
return side == EnumFacing.DOWN;
|
||||
@@ -147,7 +141,8 @@ public class BlockTransportationStone extends Block {
|
||||
if(locations.isEmpty()) locations.add(here);
|
||||
else{
|
||||
locations.remove(here); // Prevents duplicates
|
||||
locations.set(locations.size() - 1, here);
|
||||
if(locations.isEmpty()) locations.add(here);
|
||||
else locations.set(Math.max(locations.size() - 1, 0), here);
|
||||
}
|
||||
if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()), true);
|
||||
}
|
||||
@@ -167,7 +162,7 @@ public class BlockTransportationStone extends Block {
|
||||
for(int z = -1; z <= 1; z++){
|
||||
if(x == 0 && z == 0) continue;
|
||||
ParticleBuilder.create(ParticleBuilder.Type.PATH)
|
||||
.pos(WizardryUtilities.getCentre(centre).add(x, -0.3125, z)).clr(0x86ff65)
|
||||
.pos(GeometryUtils.getCentre(centre).add(x, -0.3125, z)).clr(0x86ff65)
|
||||
.time(200).scale(2).spawn(world);
|
||||
}
|
||||
}
|
||||
@@ -179,10 +174,11 @@ public class BlockTransportationStone extends Block {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns whether the specified location is surrounded by a complete cicle of 8 transportation stones. */
|
||||
/** Returns whether the specified location is surrounded by a complete circle of 8 transportation stones. */
|
||||
public static boolean testForCircle(World world, BlockPos pos){
|
||||
|
||||
if(world.getBlockState(pos).getMaterial().blocksMovement()) return false;
|
||||
if(world.getBlockState(pos).getMaterial().blocksMovement() || world.getBlockState(pos.up()).getMaterial()
|
||||
.blocksMovement()) return false;
|
||||
|
||||
for(int x = -1; x <= 1; x++){
|
||||
for(int z = -1; z <= 1; z++){
|
||||
|
||||
@@ -2,9 +2,14 @@ package electroblob.wizardry.client;
|
||||
|
||||
import electroblob.wizardry.CommonProxy;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.client.animation.ActionAnimation;
|
||||
import electroblob.wizardry.client.animation.PlayerAnimator;
|
||||
import electroblob.wizardry.client.audio.MovingSoundEntity;
|
||||
import electroblob.wizardry.client.audio.MovingSoundSpellCharge;
|
||||
import electroblob.wizardry.client.audio.SoundLoop;
|
||||
import electroblob.wizardry.client.audio.SoundLoopSpell;
|
||||
import electroblob.wizardry.client.gui.GuiLectern;
|
||||
import electroblob.wizardry.client.gui.GuiSpellDisplay;
|
||||
import electroblob.wizardry.client.gui.config.NamedBooleanEntry;
|
||||
import electroblob.wizardry.client.gui.config.SpellHUDSkinChooserEntry;
|
||||
@@ -12,8 +17,12 @@ import electroblob.wizardry.client.gui.handbook.GuiWizardHandbook;
|
||||
import electroblob.wizardry.client.model.ModelWizardArmour;
|
||||
import electroblob.wizardry.client.particle.*;
|
||||
import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory;
|
||||
import electroblob.wizardry.client.renderer.*;
|
||||
import electroblob.wizardry.client.renderer.entity.*;
|
||||
import electroblob.wizardry.client.renderer.entity.layers.*;
|
||||
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
|
||||
import electroblob.wizardry.client.renderer.tileentity.*;
|
||||
import electroblob.wizardry.command.SpellEmitter;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.data.DispenserCastingData;
|
||||
import electroblob.wizardry.data.SpellEmitterData;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
@@ -29,14 +38,10 @@ import electroblob.wizardry.item.ItemScroll;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.packet.*;
|
||||
import electroblob.wizardry.potion.PotionSlowTime;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.*;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.tileentity.TileEntityMagicLight;
|
||||
import electroblob.wizardry.tileentity.TileEntityShrineCore;
|
||||
import electroblob.wizardry.tileentity.TileEntityStatue;
|
||||
import electroblob.wizardry.tileentity.*;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
@@ -73,6 +78,8 @@ import net.minecraft.util.text.Style;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.village.MerchantRecipeList;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.settings.KeyConflictContext;
|
||||
import net.minecraftforge.client.settings.KeyModifier;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.NumberSliderEntry;
|
||||
@@ -80,6 +87,7 @@ import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||
import net.minecraftforge.fml.client.registry.RenderingRegistry;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -101,16 +109,24 @@ public class ClientProxy extends CommonProxy {
|
||||
private static final Map<ResourceLocation, IWizardryParticleFactory> factories = new HashMap<>();
|
||||
|
||||
// Key Bindings
|
||||
public static final KeyBinding NEXT_SPELL = new KeyBinding("key." + Wizardry.MODID + ".next_spell", Keyboard.KEY_N, "key.categories." + Wizardry.MODID);
|
||||
public static final KeyBinding PREVIOUS_SPELL = new KeyBinding("key." + Wizardry.MODID + ".previous_spell", Keyboard.KEY_B, "key.categories." + Wizardry.MODID);
|
||||
public static final KeyBinding NEXT_SPELL = new KeyBinding("key." + Wizardry.MODID + ".next_spell", KeyConflictContext.IN_GAME, Keyboard.KEY_N, "key.categories." + Wizardry.MODID);
|
||||
public static final KeyBinding PREVIOUS_SPELL = new KeyBinding("key." + Wizardry.MODID + ".previous_spell", KeyConflictContext.IN_GAME, Keyboard.KEY_B, "key.categories." + Wizardry.MODID);
|
||||
public static final KeyBinding[] SPELL_QUICK_ACCESS = new KeyBinding[ItemWand.BASE_SPELL_SLOTS + Constants.UPGRADE_STACK_LIMIT];
|
||||
|
||||
static {
|
||||
for(int i = 0; i < SPELL_QUICK_ACCESS.length; i++){
|
||||
SPELL_QUICK_ACCESS[i] = new KeyBinding("key." + Wizardry.MODID + ".spell_" + (i+1),
|
||||
KeyConflictContext.IN_GAME, KeyModifier.ALT, Keyboard.KEY_1 + i, "key.categories." + Wizardry.MODID);
|
||||
}
|
||||
}
|
||||
|
||||
// Armour Model
|
||||
public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f);
|
||||
|
||||
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style)}). */
|
||||
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style, Object...)}). */
|
||||
private static final int TOOLTIP_WRAP_WIDTH = 140;
|
||||
|
||||
// SECTION Registry
|
||||
// Registry
|
||||
// ===============================================================================================================
|
||||
|
||||
@Override
|
||||
@@ -122,6 +138,7 @@ public class ClientProxy extends CommonProxy {
|
||||
public void registerKeyBindings(){
|
||||
ClientRegistry.registerKeyBinding(NEXT_SPELL);
|
||||
ClientRegistry.registerKeyBinding(PREVIOUS_SPELL);
|
||||
for(KeyBinding key : SPELL_QUICK_ACCESS) ClientRegistry.registerKeyBinding(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,7 +146,7 @@ public class ClientProxy extends CommonProxy {
|
||||
mixedFontRenderer = new MixedFontRenderer(Minecraft.getMinecraft().gameSettings, new ResourceLocation("textures/font/ascii.png"),
|
||||
Minecraft.getMinecraft().renderEngine, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void registerResourceReloadListeners(){
|
||||
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
|
||||
@@ -148,14 +165,14 @@ public class ClientProxy extends CommonProxy {
|
||||
WizardryAntiqueAtlasIntegration.registerMarkers();
|
||||
}
|
||||
|
||||
// SECTION Misc
|
||||
// Misc
|
||||
// ===============================================================================================================
|
||||
|
||||
@Override
|
||||
public void setToNumberSliderEntry(Property property){
|
||||
property.setConfigEntryClass(NumberSliderEntry.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setToHUDChooserEntry(Property property){
|
||||
property.setConfigEntryClass(SpellHUDSkinChooserEntry.class);
|
||||
@@ -171,11 +188,65 @@ public class ClientProxy extends CommonProxy {
|
||||
return Minecraft.getMinecraft().world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPlayer getThePlayer(){
|
||||
return Minecraft.getMinecraft().player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFirstPerson(Entity entity){
|
||||
return entity == Minecraft.getMinecraft().getRenderViewEntity() && Minecraft.getMinecraft().gameSettings.thirdPersonView == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playBlinkEffect(EntityPlayer player){
|
||||
if(Minecraft.getMinecraft().player == player) RenderBlinkEffect.playBlinkEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shakeScreen(EntityPlayer player, float intensity){
|
||||
if(Minecraft.getMinecraft().player == player) ScreenShakeHandler.shakeScreen(intensity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadShader(EntityPlayer player, ResourceLocation shader){
|
||||
if(Minecraft.getMinecraft().player == player && Wizardry.settings.useShaders
|
||||
&& !Minecraft.getMinecraft().entityRenderer.isShaderActive())
|
||||
Minecraft.getMinecraft().entityRenderer.loadShader(shader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSpellHUDSkins(){
|
||||
return GuiSpellDisplay.getSkinKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBookshelfChange(World world, BlockPos pos){
|
||||
|
||||
super.notifyBookshelfChange(world, pos);
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
if(player.getDistanceSq(pos) < BlockBookshelf.PLAYER_NOTIFY_RANGE * BlockBookshelf.PLAYER_NOTIFY_RANGE){
|
||||
if(Minecraft.getMinecraft().currentScreen instanceof GuiLectern){
|
||||
((GuiLectern)Minecraft.getMinecraft().currentScreen).refreshAvailableSpells();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sound
|
||||
// ===============================================================================================================
|
||||
|
||||
@Override
|
||||
public void playMovingSound(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundEntity<>(entity, sound, category, volume, pitch, repeat));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void playChargeupSound(EntityLivingBase entity){
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(new MovingSoundSpellCharge(entity, WizardrySounds.ITEM_WAND_CHARGEUP, WizardrySounds.SPELLS, 2.5f, 1.4f, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSpellSoundLoop(EntityLivingBase entity, Spell spell, SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, float pitch){
|
||||
SoundLoop.addLoop(new SoundLoopSpell.SoundLoopSpellEntity(start, loop, end, spell, entity, volume, pitch));
|
||||
@@ -190,22 +261,20 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSpellHUDSkins(){
|
||||
return GuiSpellDisplay.getSkinKeys();
|
||||
}
|
||||
|
||||
// SECTION Items
|
||||
// Items
|
||||
// ===============================================================================================================
|
||||
|
||||
@Override
|
||||
public boolean shouldDisplayDiscovered(Spell spell, ItemStack stack){
|
||||
public boolean shouldDisplayDiscovered(Spell spell, @Nullable ItemStack stack){
|
||||
|
||||
EntityPlayerSP player = Minecraft.getMinecraft().player;
|
||||
|
||||
if(player == null) return false;
|
||||
|
||||
// Displayed recipe
|
||||
// Weirdly, the gui is actually the only way of accessing the current IMerchant or their recipes, other than a
|
||||
// brute-force search through all the entities in the world to find the merchant interacting with the player
|
||||
// Since we only need this client-side anyway, we might as well go via the gui
|
||||
if(Minecraft.getMinecraft().currentScreen instanceof GuiMerchant){
|
||||
// It doesn't actually matter if the recipe is selected or not, since the itemstack will only ever
|
||||
// match one of them anyway - and we'd have to reflect into GuiMerchant to get the selected recipe
|
||||
@@ -282,12 +351,16 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style){
|
||||
String description = style.getFormattingCode() + I18n.format(key);
|
||||
tooltip.addAll(Minecraft.getMinecraft().fontRenderer.listFormattedStringToWidth(description, TOOLTIP_WRAP_WIDTH));
|
||||
public String translate(String key, Style style, Object... args){
|
||||
return style.getFormattingCode() + I18n.format(key, args);
|
||||
}
|
||||
|
||||
// SECTION Particles
|
||||
@Override
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style, Object... args){
|
||||
tooltip.addAll(Minecraft.getMinecraft().fontRenderer.listFormattedStringToWidth(translate(key, style, args), TOOLTIP_WRAP_WIDTH));
|
||||
}
|
||||
|
||||
// Particles
|
||||
// ===============================================================================================================
|
||||
|
||||
/** Use {@link ParticleWizardry#registerParticle(ResourceLocation, IWizardryParticleFactory)}, this is internal. */
|
||||
@@ -300,10 +373,13 @@ public class ClientProxy extends CommonProxy {
|
||||
public void registerParticles(){
|
||||
// I'll be a good programmer and use the API method rather than the one above. Lead by example, as they say...
|
||||
ParticleWizardry.registerParticle(Type.BEAM, ParticleBeam::new);
|
||||
ParticleWizardry.registerParticle(Type.BLOCK_HIGHLIGHT, ParticleBlockHighlight::new);
|
||||
ParticleWizardry.registerParticle(Type.BUFF, ParticleBuff::new);
|
||||
ParticleWizardry.registerParticle(Type.CLOUD, ParticleCloud::new);
|
||||
ParticleWizardry.registerParticle(Type.DARK_MAGIC, ParticleDarkMagic::new);
|
||||
ParticleWizardry.registerParticle(Type.DUST, ParticleDust::new);
|
||||
ParticleWizardry.registerParticle(Type.FLASH, ParticleFlash::new);
|
||||
ParticleWizardry.registerParticle(Type.GUARDIAN_BEAM, ParticleGuardianBeam::new);
|
||||
ParticleWizardry.registerParticle(Type.ICE, ParticleIce::new);
|
||||
ParticleWizardry.registerParticle(Type.LEAF, ParticleLeaf::new);
|
||||
ParticleWizardry.registerParticle(Type.LIGHTNING, ParticleLightning::new);
|
||||
@@ -316,10 +392,9 @@ public class ClientProxy extends CommonProxy {
|
||||
ParticleWizardry.registerParticle(Type.SPARK, ParticleSpark::new);
|
||||
ParticleWizardry.registerParticle(Type.SPARKLE, ParticleSparkle::new);
|
||||
ParticleWizardry.registerParticle(Type.SPHERE, ParticleSphere::new);
|
||||
ParticleWizardry.registerParticle(Type.SUMMON, ParticleSummon::new);
|
||||
ParticleWizardry.registerParticle(Type.VINE, ParticleVine::new);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ParticleWizardry createParticle(ResourceLocation type, World world, double x, double y, double z){
|
||||
IWizardryParticleFactory factory = factories.get(type);
|
||||
@@ -336,7 +411,7 @@ public class ClientProxy extends CommonProxy {
|
||||
Minecraft.getMinecraft().effectRenderer.addEffect(new ParticleTornado(world, maxAge, x, z, radius, y, velX, velZ, block).setBlockPos(pos));// , world.rand.nextInt(6)));
|
||||
}
|
||||
|
||||
// SECTION Packet Handlers
|
||||
// Packet Handlers
|
||||
// ===============================================================================================================
|
||||
|
||||
@Override
|
||||
@@ -425,81 +500,88 @@ public class ClientProxy extends CommonProxy {
|
||||
// Again, no need to check if the spell succeeded, because the packet is only ever sent when it
|
||||
// succeeds.
|
||||
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, spell, (EntityLiving)caster, message.modifiers));
|
||||
}
|
||||
|
||||
if(caster instanceof ISpellCaster){
|
||||
if(spell.isContinuous || spell instanceof None){
|
||||
((ISpellCaster)caster).setContinuousSpell(spell);
|
||||
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
|
||||
if(caster instanceof ISpellCaster){
|
||||
if(spell.isContinuous || spell instanceof None){
|
||||
((ISpellCaster)caster).setContinuousSpell(spell);
|
||||
((ISpellCaster)caster).setSpellCounter(spell instanceof None ? 0 : 1);
|
||||
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else if(caster != null){
|
||||
Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handleDispenserCastSpellPacket(PacketDispenserCastSpell.Message message){
|
||||
|
||||
|
||||
World world = Minecraft.getMinecraft().world;
|
||||
|
||||
|
||||
if(world.getTileEntity(message.pos) instanceof TileEntityDispenser){ // Should always be true
|
||||
|
||||
|
||||
Spell spell = Spell.byNetworkID(message.spellID);
|
||||
|
||||
|
||||
spell.cast(world, message.x, message.y, message.z, message.direction, 0, -1, message.modifiers);
|
||||
// No need to check if the spell succeeded, because the packet is only ever sent when it succeeds.
|
||||
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.DISPENSER, spell, world, message.x, message.y,
|
||||
message.z, message.direction, message.modifiers));
|
||||
|
||||
|
||||
if(spell.isContinuous || spell instanceof None){
|
||||
|
||||
|
||||
DispenserCastingData data = DispenserCastingData.get((TileEntityDispenser)world.getTileEntity(message.pos));
|
||||
|
||||
|
||||
if(spell.isContinuous){
|
||||
data.startCasting(spell, message.x, message.y, message.z, message.duration, message.modifiers);
|
||||
}else{
|
||||
data.stopCasting();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}else{
|
||||
Wizardry.logger.warn("Recieved a PacketDispenserCastSpell, but no tileEntity was found at the supplied location.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportationPacket(PacketTransportation.Message message){
|
||||
|
||||
World world = Minecraft.getMinecraft().world;
|
||||
Entity caster = world.getEntityByID(message.casterID);
|
||||
BlockPos pos = message.destination;
|
||||
|
||||
Entity entity = world.getEntityByID(message.dismountEntityID);
|
||||
if(message.dismountEntityID != -1 && entity != null) entity.dismountRidingEntity();
|
||||
|
||||
// Moved from when the packet is sent to when it is received; fixes the sound not playing in first person.
|
||||
caster.playSound(WizardrySounds.SPELL_TRANSPORTATION_TRAVEL, 1, 1);
|
||||
// Changed to a position to avoid syncing issues
|
||||
world.playSound(pos.getX(), pos.getY(), pos.getZ(), WizardrySounds.SPELL_TRANSPORTATION_TRAVEL, WizardrySounds.SPELLS, 1, 1, false);
|
||||
|
||||
for(int i = 0; i < 20; i++){
|
||||
double radius = 1;
|
||||
float angle = world.rand.nextFloat() * (float)Math.PI * 2;
|
||||
double x = caster.posX + radius * MathHelper.cos(angle);
|
||||
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2;
|
||||
double z = caster.posZ + radius * MathHelper.sin(angle);
|
||||
double x = pos.getX() + 0.5 + radius * MathHelper.cos(angle);
|
||||
double y = pos.getY() + world.rand.nextDouble() * 2;
|
||||
double z = pos.getZ() + 0.5 + radius * MathHelper.sin(angle);
|
||||
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).clr(0.6f, 1, 0.6f)
|
||||
.time(80 + world.rand.nextInt(10)).spawn(world);
|
||||
}
|
||||
for(int i = 0; i < 20; i++){
|
||||
double radius = 1;
|
||||
float angle = world.rand.nextFloat() * (float)Math.PI * 2;
|
||||
double x = caster.posX + radius * MathHelper.cos(angle);
|
||||
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2;
|
||||
double z = caster.posZ + radius * MathHelper.sin(angle);
|
||||
double x = pos.getX() + 0.5 + radius * MathHelper.cos(angle);
|
||||
double y = pos.getY() + world.rand.nextDouble() * 2;
|
||||
double z = pos.getZ() + 0.5 + radius * MathHelper.sin(angle);
|
||||
world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, x, y, z, 0, 0.02, 0);
|
||||
}
|
||||
for(int i = 0; i < 20; i++){
|
||||
double radius = 1;
|
||||
float angle = world.rand.nextFloat() * (float)Math.PI * 2;
|
||||
double x = caster.posX + radius * MathHelper.cos(angle);
|
||||
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2;
|
||||
double z = caster.posZ + radius * MathHelper.sin(angle);
|
||||
double x = pos.getX() + 0.5 + radius * MathHelper.cos(angle);
|
||||
double y = pos.getY() + world.rand.nextDouble() * 2;
|
||||
double z = pos.getZ() + 0.5 + radius * MathHelper.sin(angle);
|
||||
world.spawnParticle(EnumParticleTypes.ENCHANTMENT_TABLE, x, y, z, 0, 0.02, 0);
|
||||
}
|
||||
}
|
||||
@@ -538,7 +620,13 @@ public class ClientProxy extends CommonProxy {
|
||||
data.randomNames = new HashMap<>();
|
||||
data.randomDescriptions = new HashMap<>();
|
||||
|
||||
for(Spell spell : Spell.getSpells(Spell.allSpells)){
|
||||
for(Spell spell : Spell.getAllSpells()){
|
||||
|
||||
if(spell.networkID() > message.names.size()){
|
||||
Wizardry.logger.warn("Received no glyph data for spell {}, skipping", spell.getRegistryName());
|
||||
continue;
|
||||
}
|
||||
|
||||
// -1 because the none spell isn't included
|
||||
// This is a case where we must use the network ID, not the metadata
|
||||
data.randomNames.put(spell, message.names.get(spell.networkID() - 1));
|
||||
@@ -565,13 +653,6 @@ public class ClientProxy extends CommonProxy {
|
||||
GuiWizardHandbook.updateUnlockStatus(message.showToasts, message.completedAdvancements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){
|
||||
Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.hostID);
|
||||
if(entity instanceof EntityLivingBase) PotionSlowTime.unblockNearbyEntities((EntityLivingBase)entity);
|
||||
else Wizardry.logger.warn("Received a PacketEndSlowTime, but the entity ID did not match any living entity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResurrectionPacket(PacketResurrection.Message message){
|
||||
Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.playerID);
|
||||
@@ -619,7 +700,7 @@ public class ClientProxy extends CommonProxy {
|
||||
}else Wizardry.logger.warn("Received a PacketConquerShrine, but there was no shrine core at the position sent");
|
||||
}
|
||||
|
||||
// SECTION Rendering
|
||||
// Rendering
|
||||
// ===============================================================================================================
|
||||
|
||||
private static final ResourceLocation ICE_WRAITH_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/ice_wraith.png");
|
||||
@@ -630,8 +711,17 @@ public class ClientProxy extends CommonProxy {
|
||||
|
||||
@Override
|
||||
public void initialiseLayers(){
|
||||
LayerStone.initialiseLayers();
|
||||
LayerFrost.initialiseLayers();
|
||||
LayerTiledOverlay.initialiseLayers(LayerStone::new);
|
||||
LayerTiledOverlay.initialiseLayers(LayerFrost::new);
|
||||
LayerTiledOverlay.initialiseLayers(LayerMindControl::new);
|
||||
LayerTiledOverlay.initialiseLayers(LayerSummonAnimation::new);
|
||||
LayerTiledOverlay.initialiseLayers(LayerDisintegrateAnimation::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialiseAnimations(){
|
||||
PlayerAnimator.init();
|
||||
ActionAnimation.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -675,7 +765,9 @@ public class ClientProxy extends CommonProxy {
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityDart.class, manager -> new RenderMagicArrow(manager,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/entity/dart.png"), false, 8.0, 2.0, 16, 5, true));
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityIceLance.class, manager -> new RenderMagicArrow(manager,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, true));
|
||||
new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, false));
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityFlamecatcherArrow.class, manager -> new RenderMagicArrow(manager,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/entity/flamecatcher_arrow.png"), false, 8, 2.0, 16, 5, true));
|
||||
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new);
|
||||
|
||||
@@ -685,6 +777,7 @@ public class ClientProxy extends CommonProxy {
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityWizard.class, RenderWizard::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityEvilWizard.class, RenderEvilWizard::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityDecoy.class, RenderDecoy::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityRemnant.class, RenderRemnant::new);
|
||||
|
||||
// Throwables
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntitySparkBomb.class,
|
||||
@@ -723,6 +816,11 @@ public class ClientProxy extends CommonProxy {
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityHammer.class, RenderHammer::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityIceSpike.class, RenderIceSpike::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityForcefield.class, RenderForcefield::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityZombieSpawner.class, RenderZombieSpawner::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityRadiantTotem.class, RenderRadiantTotem::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityBoulder.class, RenderBoulder::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityWitheringTotem.class, RenderWitheringTotem::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityIceBarrier.class, RenderIceBarrier::new);
|
||||
//RenderingRegistry.registerEntityRenderingHandler(EntityContainmentField.class, RenderContainmentField::new);
|
||||
|
||||
// Stuff that doesn't render
|
||||
@@ -734,26 +832,29 @@ public class ClientProxy extends CommonProxy {
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityStormElemental.class, RenderBlank::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityEarthquake.class, RenderBlank::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityHailstorm.class, RenderBlank::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityStormcloud.class, RenderBlank::new);
|
||||
|
||||
// Runes on ground
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityHealAura.class,
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/healing_aura.png"), 5.0f, false));
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/healing_aura.png"), 0.3f, false));
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityFireSigil.class,
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/fire_sigil.png"), 2.0f, true));
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/fire_sigil.png"), 0, true));
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityFrostSigil.class,
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/frost_sigil.png"), 2.0f, true));
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/frost_sigil.png"), 0, true));
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityLightningSigil.class,
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 2.0f, true));
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_sigil.png"), 0, true));
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class,
|
||||
manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f));
|
||||
manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png")));
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new);
|
||||
RenderingRegistry.registerEntityRenderingHandler(EntityCombustionRune.class,
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/combustion_rune.png"), 2.0f, true));
|
||||
manager -> new RenderSigil(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/combustion_rune.png"), 0, true));
|
||||
|
||||
// TESRs
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityStatue.class, renderStatue = new RenderStatue());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityMagicLight.class, new RenderMagicLight());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityLectern.class, new RenderLectern());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityImbuementAltar.class, new RenderImbuementAltar());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,10 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Utility class containing some useful static methods for drawing GUIs. Previously these were spread across the main
|
||||
* {@code WizardryUtilities} class and various individual GUI classes.
|
||||
* Utility class containing some useful static methods for drawing GUIs, as well as general rendering.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2
|
||||
@@ -124,6 +125,29 @@ public final class DrawingUtils {
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a 'glitch' rectangle, with some rows of pixels shifted randomly to give a broken effect.
|
||||
*
|
||||
* @param random A random number generator to use
|
||||
* @param x The x position of the rectangle
|
||||
* @param y The y position of the rectangle
|
||||
* @param u The x position of the top left corner of the section of the image wanted
|
||||
* @param v The y position of the top left corner of the section of the image wanted
|
||||
* @param width The width of the section
|
||||
* @param height The height of the section
|
||||
* @param textureWidth The width of the actual image.
|
||||
* @param textureHeight The height of the actual image.
|
||||
* @param flipX Whether to flip the texture in the x direction.
|
||||
* @param flipY Whether to flip the texture in the y direction.
|
||||
*/
|
||||
public static void drawGlitchRect(Random random, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, boolean flipX, boolean flipY){
|
||||
for(int i=0; i<height; i++){
|
||||
if(flipY) i = height - i - 1;
|
||||
int offset = random.nextInt(4) == 0 ? random.nextInt(6) - 3 : 0;
|
||||
drawTexturedFlippedRect(x + offset, y + i, u, v + i, width, 1, textureWidth, textureHeight, flipX, flipY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixes the two given opaque colours in the proportion specified.
|
||||
* @param colour1 The first colour to mix, as a 6-digit hexadecimal.
|
||||
@@ -156,7 +180,7 @@ public final class DrawingUtils {
|
||||
* @return The resulting integer colour code, which will be an 8-digit hexadecimal.
|
||||
*/
|
||||
public static int makeTranslucent(int colour, float opacity){
|
||||
return colour + ((int)(0xff * opacity * 0x01000000));
|
||||
return colour + ((int)(opacity * 0xff) << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,4 +268,37 @@ public final class DrawingUtils {
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a factor between 0 and 1 that results in a smooth, aesthetically-pleasing animation when used to scale
|
||||
* things. Mainly for rendering, but can be used anywhere since it's just a mathematical formula.
|
||||
* @param lifetime The lifetime of the thing being animated, in ticks (if this is negative, disappearing is ignored)
|
||||
* @param ticksExisted The current age of the thing being animated, in ticks
|
||||
* @param partialTicks The current partial tick time
|
||||
* @param startLength The length of the appearing animation, in ticks
|
||||
* @param endLength The length of the disappearing animation, in ticks
|
||||
* @return A fraction between 0 and 1, with the value at the very start and end being 0 and the constant middle
|
||||
* section having a value of 1.
|
||||
*/
|
||||
public static float smoothScaleFactor(int lifetime, int ticksExisted, float partialTicks, int startLength, int endLength){
|
||||
float age = ticksExisted + partialTicks;
|
||||
float s = MathHelper.clamp(age < startLength || lifetime < 0 ? age/startLength : (lifetime - age) / endLength, 0, 1);
|
||||
s = (float)Math.pow(s, 0.4); // Smooths the animation
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the point with the given coordinates lies within the rectangle specified. The check is identical to
|
||||
* {@link GuiContainer#isPointInRegion(int, int, int, int, int, int)}, but without the adjustment relative to the GUI.
|
||||
* @param left The minimum x coordinate of the rectangle
|
||||
* @param top The minimum y coordinate of the rectangle
|
||||
* @param width The width of the rectangle
|
||||
* @param height The height of the rectangle
|
||||
* @param x The x coordinate of the point to test
|
||||
* @param y The y coordinate of the point to test
|
||||
* @return True if the given point is in the rectangle, false otherwise
|
||||
*/
|
||||
public static boolean isPointInRegion(int left, int top, int width, int height, int x, int y){
|
||||
return x >= left - 1 && x < left + width + 1 && y >= top - 1 && y < top + height + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package electroblob.wizardry.client;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
@EventBusSubscriber(Side.CLIENT)
|
||||
public class ScreenShakeHandler {
|
||||
|
||||
/** The remaining time for which the screen shake effect will be active. */
|
||||
private static int screenShakeCounter = 0;
|
||||
private static final float SHAKINESS = 0.5f;
|
||||
|
||||
/** Starts the client-side screen shake effect. */
|
||||
public static void shakeScreen(float intensity){
|
||||
if(Wizardry.settings.screenShake){
|
||||
screenShakeCounter = (int)(intensity / SHAKINESS);
|
||||
Minecraft.getMinecraft().player.rotationPitch -= intensity * 0.5f; // Start halfway down
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){
|
||||
|
||||
if(event.player == Minecraft.getMinecraft().player && event.phase == TickEvent.Phase.END){
|
||||
|
||||
if(Wizardry.settings.screenShake){
|
||||
if(screenShakeCounter > 0){
|
||||
float magnitude = screenShakeCounter * SHAKINESS;
|
||||
Minecraft.getMinecraft().player.rotationPitch += screenShakeCounter % 2 == 0 ? magnitude : -magnitude;
|
||||
screenShakeCounter--;
|
||||
}
|
||||
}else{
|
||||
screenShakeCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +1,48 @@
|
||||
package electroblob.wizardry.client;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockMagicLight;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
|
||||
import electroblob.wizardry.data.DispenserCastingData;
|
||||
import electroblob.wizardry.data.SpellEmitterData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.item.ItemArtefact;
|
||||
import electroblob.wizardry.item.ItemFlamecatcher;
|
||||
import electroblob.wizardry.item.ItemSpectralBow;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.potion.PotionSlowTime;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.spell.*;
|
||||
import electroblob.wizardry.util.RayTracer;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.spell.Possession;
|
||||
import electroblob.wizardry.spell.SixthSense;
|
||||
import electroblob.wizardry.spell.SlowTime;
|
||||
import electroblob.wizardry.spell.Transience;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiMerchant;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.item.EntityArmorStand;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityDispenser;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.village.MerchantRecipe;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.*;
|
||||
import net.minecraftforge.client.event.FOVUpdateEvent;
|
||||
import net.minecraftforge.client.event.InputUpdateEvent;
|
||||
import net.minecraftforge.client.event.MouseEvent;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Event handler responsible for client-side only events, mostly rendering.
|
||||
*
|
||||
* General-purpose client-side event handler for things that don't fit anywhere else or groups of related behaviours
|
||||
* that are better kept together.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
@@ -58,47 +50,19 @@ import java.lang.reflect.Method;
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public final class WizardryClientEventHandler {
|
||||
|
||||
private static final ResourceLocation sixthSenseTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/sixth_sense.png");
|
||||
private static final ResourceLocation sixthSenseOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/sixth_sense_overlay.png");
|
||||
private static final ResourceLocation frostOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/frost_overlay.png");
|
||||
private static final ResourceLocation blinkOverlayTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/blink_overlay.png");
|
||||
private static final ResourceLocation pointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/pointer.png");
|
||||
private static final ResourceLocation targetPointerTexture = new ResourceLocation(Wizardry.MODID, "textures/entity/target_pointer.png");
|
||||
private WizardryClientEventHandler(){} // No instances!
|
||||
|
||||
/** The remaining time for which the blink screen overlay effect will be displayed in first-person. Since this is
|
||||
* only for the first-person player (the instance of which is itself stored in a static variable), this can simply
|
||||
* be stored statically here, rather than needing to be in {@code WizardData}. */
|
||||
private static int blinkEffectTimer;
|
||||
/** The number of ticks the blink effect lasts for. */
|
||||
private static final int BLINK_EFFECT_DURATION = 8;
|
||||
// Tick Events
|
||||
// ===============================================================================================================
|
||||
|
||||
private static final Method unpressKey;
|
||||
|
||||
static {
|
||||
unpressKey = ObfuscationReflectionHelper.findMethod(KeyBinding.class, "func_74505_d", void.class);
|
||||
}
|
||||
|
||||
/** Starts the first person blink overlay effect. */
|
||||
public static void playBlinkEffect(){
|
||||
blinkEffectTimer = BLINK_EFFECT_DURATION;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){
|
||||
|
||||
if(event.player == Minecraft.getMinecraft().player){
|
||||
|
||||
if(blinkEffectTimer > 0) blinkEffectTimer--;
|
||||
|
||||
// Only seems to work here...
|
||||
// EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player);
|
||||
// if(victim != null && victim.getHeldItemMainhand().isEmpty()){
|
||||
// Minecraft.getMinecraft().player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY);
|
||||
// }
|
||||
if(event.player == Minecraft.getMinecraft().player && event.phase == TickEvent.Phase.END){
|
||||
|
||||
// Reset shaders if their respective potions aren't active
|
||||
// This is a player so the potion effects are synced by vanilla
|
||||
if(Minecraft.getMinecraft().entityRenderer.getShaderGroup() != null){
|
||||
if(Minecraft.getMinecraft().entityRenderer.getShaderGroup() != null){ // IntelliJ is wrong, this can be null
|
||||
|
||||
String activeShader = Minecraft.getMinecraft().entityRenderer.getShaderGroup().getShaderGroupName();
|
||||
|
||||
@@ -107,26 +71,55 @@ public final class WizardryClientEventHandler {
|
||||
|| (activeShader.equals(Transience.SHADER.toString()) && !Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.transience))){
|
||||
|
||||
if(activeShader.equals(SixthSense.SHADER.toString())
|
||||
|| activeShader.equals(Transience.SHADER.toString())) playBlinkEffect();
|
||||
|| activeShader.equals(Transience.SHADER.toString())) RenderBlinkEffect.playBlinkEffect();
|
||||
|
||||
Minecraft.getMinecraft().entityRenderer.stopUseShader();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The classes referenced here used to handle their own client tick events, but since they're not client-only
|
||||
// classes, that crashed the dedicated server...
|
||||
@SubscribeEvent
|
||||
public static void onRenderHandEvent(RenderHandEvent event){
|
||||
|
||||
EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player);
|
||||
|
||||
if(victim != null){
|
||||
|
||||
victim.rotationYawHead = Minecraft.getMinecraft().player.rotationYaw;
|
||||
|
||||
if(Minecraft.getMinecraft().player.getHeldItemMainhand().isEmpty()){
|
||||
event.setCanceled(true);
|
||||
public static void onClientTickEvent(TickEvent.ClientTickEvent event){
|
||||
|
||||
if(event.phase == TickEvent.Phase.END && !net.minecraft.client.Minecraft.getMinecraft().isGamePaused()){
|
||||
|
||||
World world = net.minecraft.client.Minecraft.getMinecraft().world;
|
||||
|
||||
if(world == null) return;
|
||||
|
||||
// Somehow this was throwing a CME, I have no idea why so I'm just going to cheat and copy the list
|
||||
List<TileEntity> tileEntities = new ArrayList<>(world.loadedTileEntityList);
|
||||
|
||||
for(TileEntity tileentity : tileEntities){
|
||||
if(tileentity instanceof TileEntityDispenser){
|
||||
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
|
||||
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpellEmitterData.update(world);
|
||||
PotionSlowTime.cleanUpEntities(world);
|
||||
}
|
||||
}
|
||||
|
||||
// Input and Controls
|
||||
// ===============================================================================================================
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMouseEvent(MouseEvent event){
|
||||
|
||||
// Prevents the player looking around when paralysed
|
||||
if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.paralysis)
|
||||
&& Minecraft.getMinecraft().inGameHasFocus){
|
||||
event.setCanceled(true);
|
||||
Minecraft.getMinecraft().player.prevRotationYaw = 0;
|
||||
Minecraft.getMinecraft().player.prevRotationPitch = 0;
|
||||
Minecraft.getMinecraft().player.rotationYaw = 0;
|
||||
Minecraft.getMinecraft().player.rotationPitch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,40 +133,32 @@ public final class WizardryClientEventHandler {
|
||||
event.getMovementInput().jump = false;
|
||||
event.getMovementInput().sneak = false;
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClientTickEvent(TickEvent.ClientTickEvent event){
|
||||
|
||||
if(event.phase == TickEvent.Phase.END && !net.minecraft.client.Minecraft.getMinecraft().isGamePaused()){
|
||||
|
||||
World world = net.minecraft.client.Minecraft.getMinecraft().world;
|
||||
|
||||
if(world == null) return;
|
||||
|
||||
for(TileEntity tileentity : world.loadedTileEntityList){
|
||||
if(tileentity instanceof TileEntityDispenser){
|
||||
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
|
||||
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpellEmitterData.update(world);
|
||||
if(ItemArtefact.isArtefactActive(event.getEntityPlayer(), WizardryItems.charm_move_speed)
|
||||
&& event.getEntityPlayer().isHandActive()
|
||||
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ItemWand){
|
||||
// Normally speed is set to 20% when using items, this makes it 80%
|
||||
event.getMovementInput().moveStrafe *= 4;
|
||||
event.getMovementInput().moveForward *= 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Rendering
|
||||
// ===============================================================================================================
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMouseEvent(MouseEvent event){
|
||||
|
||||
// Prevents the player looking around when paralysed
|
||||
if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.paralysis)
|
||||
&& Minecraft.getMinecraft().inGameHasFocus){
|
||||
event.setCanceled(true);
|
||||
Minecraft.getMinecraft().player.prevRotationYaw = 0;
|
||||
Minecraft.getMinecraft().player.prevRotationPitch = 0;
|
||||
Minecraft.getMinecraft().player.rotationYaw = 0;
|
||||
Minecraft.getMinecraft().player.rotationPitch = 0;
|
||||
public static void onRenderHandEvent(RenderHandEvent event){
|
||||
|
||||
// Hide the player's empty hand in first-person when possessing
|
||||
EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player);
|
||||
|
||||
if(victim != null){
|
||||
|
||||
victim.rotationYawHead = Minecraft.getMinecraft().player.rotationYaw;
|
||||
|
||||
if(Minecraft.getMinecraft().player.getHeldItemMainhand().isEmpty()){
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,263 +166,33 @@ public final class WizardryClientEventHandler {
|
||||
public static void onFOVUpdateEvent(FOVUpdateEvent event){
|
||||
|
||||
// Bow zoom. Taken directly from AbstractClientPlayer so it works exactly like vanilla.
|
||||
if(event.getEntity().isHandActive() && event.getEntity().getActiveItemStack().getItem() instanceof ItemSpectralBow){
|
||||
if(event.getEntity().isHandActive()){
|
||||
|
||||
int maxUseTicks = event.getEntity().getItemInUseMaxCount();
|
||||
Item item = event.getEntity().getActiveItemStack().getItem();
|
||||
|
||||
float maxUseSeconds = (float)maxUseTicks / 20.0F;
|
||||
if(item instanceof ItemSpectralBow || item instanceof ItemFlamecatcher){
|
||||
|
||||
if(maxUseSeconds > 1.0F){
|
||||
maxUseSeconds = 1.0F;
|
||||
}else{
|
||||
maxUseSeconds = maxUseSeconds * maxUseSeconds;
|
||||
}
|
||||
int maxUseTicks = event.getEntity().getItemInUseMaxCount();
|
||||
|
||||
event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F);
|
||||
}
|
||||
|
||||
if(blinkEffectTimer > 0){
|
||||
float f = ((float)Math.max(blinkEffectTimer - 2, 0))/BLINK_EFFECT_DURATION;
|
||||
event.setNewfov(event.getFov() + f * f * 0.7f);
|
||||
}
|
||||
}
|
||||
float maxUseSeconds = (float)maxUseTicks / (item instanceof ItemFlamecatcher ? ItemFlamecatcher.DRAW_TIME : 20);
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onDrawBlockHighlightEvent(DrawBlockHighlightEvent event){
|
||||
// Hide the block outline for magic light blocks unless the player can dispel them
|
||||
if(event.getTarget().typeOfHit == RayTraceResult.Type.BLOCK
|
||||
&& event.getPlayer().world.getBlockState(event.getTarget().getBlockPos()).getBlock() instanceof BlockMagicLight){
|
||||
|
||||
if((!(event.getPlayer().getHeldItemMainhand().getItem() instanceof ISpellCastingItem)
|
||||
&& !(event.getPlayer().getHeldItemOffhand().getItem() instanceof ISpellCastingItem))
|
||||
|| !ItemArtefact.isArtefactActive(event.getPlayer(), WizardryItems.charm_light)){
|
||||
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Brute-force fix for crystals not showing up when a wizard is given a spell book in the trade GUI.
|
||||
@SubscribeEvent
|
||||
public static void onGuiDrawForegroundEvent(GuiContainerEvent.DrawForeground event){
|
||||
|
||||
if(event.getGuiContainer() instanceof GuiMerchant){
|
||||
|
||||
GuiMerchant gui = (GuiMerchant)event.getGuiContainer();
|
||||
// Note that gui.getMerchant() returns an NpcMerchant, not an EntityWizard.
|
||||
|
||||
// Using == the specific item rather than instanceof because that's how trades do it.
|
||||
if(gui.inventorySlots.getSlot(0).getStack().getItem() == WizardryItems.spell_book
|
||||
|| gui.inventorySlots.getSlot(1).getStack().getItem() == WizardryItems.spell_book){
|
||||
|
||||
for(MerchantRecipe trade : gui.getMerchant().getRecipes(Minecraft.getMinecraft().player)){
|
||||
if(trade.getItemToBuy().getItem() == WizardryItems.spell_book && trade.getSecondItemToBuy().isEmpty()){
|
||||
Slot slot = gui.inventorySlots.getSlot(2);
|
||||
// It still doesn't look quite right because the slot highlight is behind the item, but it'll do
|
||||
// until/unless I find a better solution.
|
||||
DrawingUtils.drawItemAndTooltip(gui, trade.getItemToSell(), slot.xPos, slot.yPos, event.getMouseX(), event.getMouseY(),
|
||||
gui.getSlotUnderMouse() == slot);
|
||||
}
|
||||
if(maxUseSeconds > 1.0F){
|
||||
maxUseSeconds = 1.0F;
|
||||
}else{
|
||||
maxUseSeconds = maxUseSeconds * maxUseSeconds;
|
||||
}
|
||||
|
||||
event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderLivingEvent(RenderLivingEvent.Post<EntityLivingBase> event){
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
WizardData data = WizardData.get(mc.player);
|
||||
RenderManager renderManager = event.getRenderer().getRenderManager();
|
||||
|
||||
ItemStack wand = mc.player.getHeldItemMainhand();
|
||||
|
||||
if(!(wand.getItem() instanceof ISpellCastingItem)){
|
||||
wand = mc.player.getHeldItemOffhand();
|
||||
}
|
||||
|
||||
// Target selection pointer
|
||||
if(mc.player.isSneaking() && wand.getItem() instanceof ISpellCastingItem && WizardryUtilities.isLiving(event.getEntity())
|
||||
&& data != null && data.selectedMinion != null){
|
||||
|
||||
// -> Moved this in here so it isn't called every tick
|
||||
RayTraceResult rayTrace = RayTracer.standardEntityRayTrace(mc.world, mc.player, 16, false);
|
||||
|
||||
if(rayTrace != null && rayTrace.entityHit == event.getEntity()){
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
// Disabling depth test allows it to be seen through everything.
|
||||
GlStateManager.disableDepth();
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
|
||||
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
|
||||
|
||||
// This counteracts the reverse rotation behaviour when in front f5 view.
|
||||
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
|
||||
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
|
||||
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
mc.renderEngine.bindTexture(targetPointerTexture);
|
||||
|
||||
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
|
||||
buffer.pos(0.2, 0.24, 0).tex(9f / 16f, 0).endVertex();
|
||||
buffer.pos(0.2, -0.24, 0).tex(9f / 16f, 11f / 16f).endVertex();
|
||||
buffer.pos(-0.2, -0.24, 0).tex(0, 11f / 16f).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.enableDepth();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
// Summoned creature selection pointer
|
||||
if(data != null && data.selectedMinion != null && data.selectedMinion.get() == event.getEntity()){
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
// Disabling depth test allows it to be seen through everything.
|
||||
GlStateManager.disableDepth();
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
|
||||
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height + 0.5, event.getZ());
|
||||
|
||||
// This counteracts the reverse rotation behaviour when in front f5 view.
|
||||
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
|
||||
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
|
||||
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
mc.renderEngine.bindTexture(pointerTexture);
|
||||
|
||||
buffer.pos(-0.2, 0.24, 0).tex(0, 0).endVertex();
|
||||
buffer.pos(0.2, 0.24, 0).tex(9f / 16f, 0).endVertex();
|
||||
buffer.pos(0.2, -0.24, 0).tex(9f / 16f, 11f / 16f).endVertex();
|
||||
buffer.pos(-0.2, -0.24, 0).tex(0, 11f / 16f).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.enableDepth();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
// Sixth sense
|
||||
if(mc.player.isPotionActive(WizardryPotions.sixth_sense) && !(event.getEntity() instanceof EntityArmorStand)
|
||||
&& event.getEntity() != mc.player && mc.player.getActivePotionEffect(WizardryPotions.sixth_sense) != null
|
||||
&& event.getEntity().getDistance(mc.player) < Spells.sixth_sense.getProperty(Spell.EFFECT_RADIUS).floatValue()
|
||||
* (1 + mc.player.getActivePotionEffect(WizardryPotions.sixth_sense).getAmplifier() * Constants.RANGE_INCREASE_PER_LEVEL)){
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
// Disabling depth test allows it to be seen through everything.
|
||||
GlStateManager.disableDepth();
|
||||
|
||||
GlStateManager.translate(event.getX(), event.getY() + event.getEntity().height * 0.6, event.getZ());
|
||||
|
||||
// This counteracts the reverse rotation behaviour when in front f5 view.
|
||||
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
|
||||
float yaw = mc.gameSettings.thirdPersonView == 2 ? renderManager.playerViewX : -renderManager.playerViewX;
|
||||
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
mc.renderEngine.bindTexture(sixthSenseTexture);
|
||||
|
||||
buffer.pos(-0.6, 0.6, 0).tex(0, 0).endVertex();
|
||||
buffer.pos(0.6, 0.6, 0).tex(1, 0).endVertex();
|
||||
buffer.pos(0.6, -0.6, 0).tex(1, 1).endVertex();
|
||||
buffer.pos(-0.6, -0.6, 0).tex(0, 1).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.enableDepth();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderGameOverlayEvent(RenderGameOverlayEvent.Post event){
|
||||
|
||||
if(event.getType() == RenderGameOverlayEvent.ElementType.HELMET){
|
||||
|
||||
if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.sixth_sense)){
|
||||
|
||||
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.disableAlpha();
|
||||
|
||||
renderScreenOverlay(event, sixthSenseOverlayTexture);
|
||||
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.frost)){
|
||||
|
||||
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.disableAlpha();
|
||||
|
||||
renderScreenOverlay(event, frostOverlayTexture);
|
||||
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
if(blinkEffectTimer > 0){
|
||||
|
||||
float alpha = ((float)blinkEffectTimer)/BLINK_EFFECT_DURATION;
|
||||
|
||||
OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GlStateManager.color(1, 1, 1, alpha);
|
||||
GlStateManager.disableAlpha();
|
||||
|
||||
renderScreenOverlay(event, blinkOverlayTexture);
|
||||
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderScreenOverlay(RenderGameOverlayEvent.Post event, ResourceLocation texture){
|
||||
/**
|
||||
* Renders an overlay across the entire screen.
|
||||
* @param resolution The screen resolution
|
||||
* @param texture The overlay texture to display
|
||||
*/
|
||||
public static void renderScreenOverlay(ScaledResolution resolution, ResourceLocation texture){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
@@ -450,11 +205,12 @@ public final class WizardryClientEventHandler {
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
buffer.pos(0.0D, (double)event.getResolution().getScaledHeight(), -90.0D).tex(0.0D, 1.0D).endVertex();
|
||||
buffer.pos((double)event.getResolution().getScaledWidth(), (double)event.getResolution().getScaledHeight(), -90.0D).tex(1.0D, 1.0D)
|
||||
.endVertex();
|
||||
buffer.pos((double)event.getResolution().getScaledWidth(), 0.0D, -90.0D).tex(1.0D, 0.0D).endVertex();
|
||||
buffer.pos(0.0D, 0.0D, -90.0D).tex(0.0D, 0.0D).endVertex();
|
||||
|
||||
buffer.pos(0, resolution.getScaledHeight(), -90).tex(0, 1).endVertex();
|
||||
buffer.pos(resolution.getScaledWidth(), resolution.getScaledHeight(), -90).tex(1, 1).endVertex();
|
||||
buffer.pos(resolution.getScaledWidth(), 0, -90).tex(1, 0).endVertex();
|
||||
buffer.pos(0, 0, -90).tex(0, 0).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.depthMask(true);
|
||||
|
||||
@@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.gui.GuiSpellDisplay;
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.packet.PacketControlInput;
|
||||
import electroblob.wizardry.packet.PacketSpellQuickAccess;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -24,6 +25,7 @@ public class WizardryControlHandler {
|
||||
|
||||
static boolean NkeyPressed = false;
|
||||
static boolean BkeyPressed = false;
|
||||
static boolean[] quickAccessKeyPressed = new boolean[ClientProxy.SPELL_QUICK_ACCESS.length];
|
||||
|
||||
// Changed to a tick event to allow mouse button keybinds
|
||||
// The 'lag' that happened previously was actually because the code only fired when a keyboard key was pressed!
|
||||
@@ -59,6 +61,19 @@ public class WizardryControlHandler {
|
||||
}else{
|
||||
BkeyPressed = false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < ClientProxy.SPELL_QUICK_ACCESS.length; i++){
|
||||
if(ClientProxy.SPELL_QUICK_ACCESS[i].isKeyDown() && Minecraft.getMinecraft().inGameHasFocus){
|
||||
if(!quickAccessKeyPressed[i]){
|
||||
quickAccessKeyPressed[i] = true;
|
||||
// Packet building
|
||||
selectSpell(wand, i);
|
||||
}
|
||||
}else{
|
||||
quickAccessKeyPressed[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,4 +133,17 @@ public class WizardryControlHandler {
|
||||
GuiSpellDisplay.playSpellSwitchAnimation(false);
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1));
|
||||
}
|
||||
|
||||
private static void selectSpell(ItemStack wand, int index){
|
||||
// GUI switch animation
|
||||
if(((ISpellCastingItem)wand.getItem()).selectSpell(wand, index)){ // Makes sure the spell is set immediately for the client
|
||||
// Packet building (no point sending it unless the client-side spell selection succeeded
|
||||
IMessage msg = new PacketSpellQuickAccess.Message(index);
|
||||
WizardryPacketHandler.net.sendToServer(msg);
|
||||
|
||||
GuiSpellDisplay.playSpellSwitchAnimation(true); // This will do, it's only an animation
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package electroblob.wizardry.client.animation;
|
||||
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.spell.Grapple;
|
||||
import electroblob.wizardry.util.GeometryUtils;
|
||||
import electroblob.wizardry.util.InventoryUtils;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.EnumAction;
|
||||
import net.minecraft.util.EnumHandSide;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
/**
|
||||
* An animation that is associated with a particular {@link net.minecraft.item.EnumAction}. This animation will display
|
||||
* when a player is using an item with that action.
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.3
|
||||
* @see electroblob.wizardry.item.SpellActions
|
||||
*/
|
||||
public abstract class ActionAnimation extends Animation {
|
||||
|
||||
private final EnumAction action;
|
||||
|
||||
public ActionAnimation(EnumAction action){
|
||||
super(action.name());
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDisplay(EntityPlayer player, boolean firstPerson){
|
||||
return !firstPerson && player.getItemInUseMaxCount() > 0 && player.getActiveItemStack().getItemUseAction() == action;
|
||||
}
|
||||
|
||||
/** Called from the client proxy to register all of wizardry's action animations. */
|
||||
public static void register(){
|
||||
|
||||
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.POINT){
|
||||
@Override
|
||||
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
|
||||
// Something (probably some sort of race condition) causes getActiveItemStack to sometimes be wrong
|
||||
if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())) return;
|
||||
|
||||
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
|
||||
|
||||
float pitch = (float)Math.toRadians(player.prevRotationPitch + (player.rotationPitch - player.prevRotationPitch) * partialTicks);
|
||||
float yaw = (float)Math.toRadians(player.prevRotationYawHead + (player.rotationYawHead - player.prevRotationYawHead) * partialTicks)
|
||||
- (float)Math.toRadians(player.prevRenderYawOffset + (player.renderYawOffset - player.prevRenderYawOffset) * partialTicks);
|
||||
|
||||
float x = -((float)Math.PI / 2) + pitch + 0.2f;
|
||||
float y = (side == EnumHandSide.RIGHT ? -0.25f : 0.25f) + yaw;
|
||||
|
||||
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
|
||||
arm.setRotation(x, y, 0);
|
||||
}
|
||||
});
|
||||
|
||||
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.POINT_UP){
|
||||
@Override
|
||||
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
|
||||
if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())) return;
|
||||
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
|
||||
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
|
||||
arm.addRotation(-2.2f, side == EnumHandSide.RIGHT ? 0.2f : -0.2f, 0);
|
||||
}
|
||||
});
|
||||
|
||||
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.POINT_DOWN){
|
||||
@Override
|
||||
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
|
||||
float tick = player.getItemInUseMaxCount() + partialTicks; // It's not the "max" use count at all!
|
||||
float y = Math.min(0.4f + tick * 0.05f, 0.7f);
|
||||
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
|
||||
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
|
||||
arm.addRotation(-0.2f, side == EnumHandSide.RIGHT ? y : -y, 0);
|
||||
}
|
||||
});
|
||||
|
||||
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.SUMMON){
|
||||
@Override
|
||||
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
|
||||
float tick = player.getItemInUseMaxCount() + partialTicks; // It's not the "max" use count at all!
|
||||
float x = -Math.min(0.4f + tick * 0.2f, 2f);
|
||||
((ModelRendererExtended)getArmForSide(model, EnumHandSide.RIGHT)).addRotation(x, 1.2f, 0);
|
||||
((ModelRendererExtended)getArmForSide(model, EnumHandSide.LEFT)).addRotation(x, -1.2f, 0);
|
||||
}
|
||||
});
|
||||
|
||||
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.GRAPPLE){
|
||||
@Override
|
||||
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
|
||||
|
||||
WizardData data = WizardData.get(player);
|
||||
RayTraceResult hit = data.getVariable(Grapple.TARGET_KEY);
|
||||
if(hit == null || hit.typeOfHit == RayTraceResult.Type.MISS) return;
|
||||
Vec3d target = hit.hitVec;
|
||||
|
||||
if(hit.entityHit instanceof EntityLivingBase){
|
||||
// If the target is an entity, we need to use the entity's centre rather than the original hit position
|
||||
// because the entity will have moved!
|
||||
target = GeometryUtils.getCentre(hit.entityHit);
|
||||
}
|
||||
|
||||
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
|
||||
|
||||
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
|
||||
|
||||
Vec3d direction = target.subtract(player.getPositionEyes(partialTicks));
|
||||
float yaw = player.prevRenderYawOffset + (player.renderYawOffset - player.prevRenderYawOffset) * partialTicks;
|
||||
|
||||
float pitch = (float)MathHelper.atan2(MathHelper.sqrt(direction.x*direction.x + direction.z*direction.z), direction.y);
|
||||
float x = pitch - (float)Math.PI * 0.9f;
|
||||
float y = -(float)Math.toRadians(yaw) - (float)MathHelper.atan2(direction.x, direction.z);
|
||||
y += (side == EnumHandSide.RIGHT ? -0.25f : 0.25f);
|
||||
if(Math.abs(pitch) < 0.2f) y = arm.rotateAngleY;
|
||||
|
||||
arm.setRotation(x, y, 0);
|
||||
}
|
||||
});
|
||||
|
||||
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.IMBUE){
|
||||
@Override
|
||||
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
|
||||
float tick = player.getItemInUseMaxCount() + partialTicks; // It's not the "max" use count at all!
|
||||
float z = Math.max(1.5f - tick * 0.1f, 0.8f);
|
||||
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
|
||||
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
|
||||
arm.addRotation(-1.2f, side == EnumHandSide.RIGHT ? -0.2f : 0.2f, side == EnumHandSide.RIGHT ? z : -z);
|
||||
if(!player.getHeldItem(InventoryUtils.getHandForSide(player, side.opposite())).isEmpty()){
|
||||
((ModelRendererExtended)getArmForSide(model, side.opposite())).addRotation(-0.8f, side == EnumHandSide.LEFT ? 0.3f : -0.3f, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.THRUST){
|
||||
@Override
|
||||
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
|
||||
if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())) return;
|
||||
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
|
||||
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
|
||||
float y = side == EnumHandSide.RIGHT ? -0.6f : 0.6f;
|
||||
arm.addRotation(-1.2f, y, 0);
|
||||
if(player.getHeldItem(InventoryUtils.getHandForSide(player, side.opposite())).isEmpty()){
|
||||
ModelRendererExtended otherArm = (ModelRendererExtended)getArmForSide(model, side.opposite());
|
||||
otherArm.setRotation(arm.rotateAngleX - 1.2f, -arm.rotateAngleY - y, otherArm.rotateAngleZ);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package electroblob.wizardry.client.animation;
|
||||
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.EnumHandSide;
|
||||
|
||||
/**
|
||||
* Represents a player animation. Use one of the predefined subclasses below for common animation types, or extend this
|
||||
* class directly to define a completely custom animation. Register instances of this class using
|
||||
* {@link PlayerAnimator#registerAnimation(Animation)}.
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.3
|
||||
* @see ActionAnimation
|
||||
*/
|
||||
public abstract class Animation {
|
||||
|
||||
private final String name;
|
||||
|
||||
public Animation(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** Returns the name of this animation, currently only used for warning messages / debugging. */
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this animation should be displayed for the given player. <i>Note that if two registered
|
||||
* animations have overlapping conditions, both will attempt to display simultaneously, so if they both animate the
|
||||
* same model part, that part may not behave as expected.</i>
|
||||
* @param player The player being animated
|
||||
* @param firstPerson True if the player being animated is the local client player, and they are in first-person
|
||||
* view. In first-person, animations are only useful for animating the player's empty hand.
|
||||
* @return True if the animation should be displayed, false if not.
|
||||
*/
|
||||
public abstract boolean shouldDisplay(EntityPlayer player, boolean firstPerson);
|
||||
|
||||
/**
|
||||
* Sets the rotation of the model parts for this animation. This method is called every time the player is rendered
|
||||
* when {@link Animation#shouldDisplay(EntityPlayer, boolean)} returns true.
|
||||
* @param player The player being animated
|
||||
* @param model The model to animate. All of the standard {@link ModelBiped} parts will already be wrapped and may
|
||||
* be safely cast to {@code ModelRendererExtended} in order to override the rotations set by the model
|
||||
* itself - see {@link ModelRendererExtended ModelRendererExtended} for details.
|
||||
* @param partialTicks The current partial tick time
|
||||
* @param firstPerson True if the player being animated is the local client player, and they are in first-person
|
||||
* view. In first-person, animations are only useful for animating the player's empty hand.
|
||||
*/
|
||||
public abstract void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson);
|
||||
|
||||
/**
|
||||
* Returns whether the boxes that form the second layer of the player's skin (for models that are instances of
|
||||
* {@link net.minecraft.client.model.ModelPlayer ModelPlayer}) should automatically be set to the same angles as
|
||||
* their corresponding first-layer parts.
|
||||
* @param player The player being rendered, for reference
|
||||
* @param firstPerson True if the player being animated is the local client player, and they are in first-person
|
||||
* view. In first-person, animations are only useful for animating the player's empty hand.
|
||||
* @return True to let {@link PlayerAnimator} auto-rotate the second skin layer, false to rotate them manually.
|
||||
*/
|
||||
public boolean autoRotateSecondLayer(EntityPlayer player, boolean firstPerson){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arm of the given model corresponding to the given side. Function is identical to the method of the
|
||||
* same name in {@link ModelBiped}.
|
||||
* @param model The model to get the arm of
|
||||
* @param side The {@link EnumHandSide} to return the arm for
|
||||
* @return The {@link ModelRenderer} corresponding to the given arm
|
||||
*/
|
||||
public static ModelRenderer getArmForSide(ModelBiped model, EnumHandSide side){
|
||||
return side == EnumHandSide.LEFT ? model.bipedLeftArm : model.bipedRightArm;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package electroblob.wizardry.client.animation;
|
||||
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.model.ModelPlayer;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
|
||||
/**
|
||||
* A wrapper around {@link ModelRenderer} which can be swapped into models to allow render pre/post events to
|
||||
* circumvent {@code ModelBase.setRotationAngles(...)} and set model part rotations themselves. Instances of this class
|
||||
* keep a reference to the original {@code ModelRenderer} and delegate all the actual rendering to it.
|
||||
* <p></p>
|
||||
* {@link PlayerAnimator PlayerAnimator} does all the necessary setup with this
|
||||
* class for player animations. It is also possible to set up custom animations for non-player entities with this class,
|
||||
* see {@link ModelRendererExtended#wrap(ModelBiped)} and {@link ModelRendererExtended#wrap(ModelBase, ModelRenderer)}.
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.3
|
||||
*/
|
||||
public class ModelRendererExtended extends ModelRenderer {
|
||||
|
||||
// We probably could have copied all the fields over instead, but this way if anyone else modifies the boxes we
|
||||
// won't overwrite their changes
|
||||
// This way also avoids reflection because we don't need to copy private fields, which is better for performance
|
||||
private ModelRenderer delegate;
|
||||
|
||||
private float actualRotationX;
|
||||
private float actualRotationY;
|
||||
private float actualRotationZ;
|
||||
|
||||
private float extraRotationX;
|
||||
private float extraRotationY;
|
||||
private float extraRotationZ;
|
||||
|
||||
private ModelRendererExtended(ModelBase baseModel, ModelRenderer delegate){
|
||||
super(baseModel, delegate.boxName);
|
||||
this.delegate = delegate;
|
||||
// Copy over any public fields that might get changed
|
||||
this.textureWidth = delegate.textureWidth;
|
||||
this.textureHeight = delegate.textureHeight;
|
||||
this.showModel = delegate.showModel;
|
||||
this.isHidden = delegate.isHidden;
|
||||
this.rotationPointX = delegate.rotationPointX;
|
||||
this.rotationPointY = delegate.rotationPointY;
|
||||
this.rotationPointZ = delegate.rotationPointZ;
|
||||
this.resetRotation();
|
||||
}
|
||||
|
||||
// Static initialisers
|
||||
|
||||
/**
|
||||
* Replaces the given part of the given {@link ModelBase} with a new {@code ModelRendererExtended} that wraps the
|
||||
* original part. This method takes care of modifying the model's box list, but <b>is unable to change any
|
||||
* individual {@link ModelRenderer} fields</b> - this method instead returns the resulting
|
||||
* {@code ModelRendererExtended} to be assigned to the appropriate field.
|
||||
* @param model The model whose part is to be wrapped
|
||||
* @param box The part of the model to wrap, must belong to the above model
|
||||
* @return The resulting wrapped model part, this should be assigned to the appropriate part field in the model. If
|
||||
* the given model part was already wrapped, this method simply returns it unchanged.
|
||||
* @throws IllegalArgumentException if the given box does not belong to the given model
|
||||
*/
|
||||
public static ModelRendererExtended wrap(ModelBase model, ModelRenderer box){
|
||||
if(box instanceof ModelRendererExtended) return (ModelRendererExtended)box; // Ignore already-wrapped parts
|
||||
ModelRendererExtended wrapper = new ModelRendererExtended(model, box);
|
||||
int index = model.boxList.indexOf(box);
|
||||
if(index < 0) throw new IllegalArgumentException(String.format("The given ModelRenderer %s does not belong to the given model %s", box, model));
|
||||
model.boxList.set(index, wrapper); // I doubt the order matters but we may as well put it at the same index
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the given {@link ModelBiped}'s parts with new {@code ModelRendererExtended} versions that wrap the
|
||||
* original parts. If the given model is a {@link ModelPlayer}, the extra boxes for player skin overlays will also
|
||||
* be wrapped.
|
||||
*/
|
||||
public static void wrap(ModelBiped model){
|
||||
// MMmmmmmm wraps
|
||||
model.bipedHead = wrap(model, model.bipedHead);
|
||||
model.bipedBody = wrap(model, model.bipedBody);
|
||||
model.bipedRightArm = wrap(model, model.bipedRightArm);
|
||||
model.bipedLeftArm = wrap(model, model.bipedLeftArm);
|
||||
model.bipedRightLeg = wrap(model, model.bipedRightLeg);
|
||||
model.bipedLeftLeg = wrap(model, model.bipedLeftLeg);
|
||||
model.bipedHeadwear = wrap(model, model.bipedHeadwear);
|
||||
|
||||
if(model instanceof ModelPlayer){
|
||||
((ModelPlayer)model).bipedBodyWear = wrap(model, ((ModelPlayer)model).bipedBodyWear);
|
||||
((ModelPlayer)model).bipedRightArmwear = wrap(model, ((ModelPlayer)model).bipedRightArmwear);
|
||||
((ModelPlayer)model).bipedLeftArmwear = wrap(model, ((ModelPlayer)model).bipedLeftArmwear);
|
||||
((ModelPlayer)model).bipedRightLegwear = wrap(model, ((ModelPlayer)model).bipedRightLegwear);
|
||||
((ModelPlayer)model).bipedLeftLegwear = wrap(model, ((ModelPlayer)model).bipedLeftLegwear);
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets the rotation of this model part to the angle set by the parent model. */
|
||||
public void resetRotation(){
|
||||
this.actualRotationX = Float.NaN;
|
||||
this.actualRotationY = Float.NaN;
|
||||
this.actualRotationZ = Float.NaN;
|
||||
this.extraRotationX = 0;
|
||||
this.extraRotationY = 0;
|
||||
this.extraRotationZ = 0;
|
||||
}
|
||||
|
||||
/** Sets the rotation of this model part, which will overwrite the angle set by the parent model. */
|
||||
public void setRotation(float x, float y, float z){
|
||||
this.actualRotationX = x;
|
||||
this.actualRotationY = y;
|
||||
this.actualRotationZ = z;
|
||||
}
|
||||
|
||||
/** Sets the extra rotation of this model part, which will be added onto the angle set by the parent model. */
|
||||
public void addRotation(float x, float y, float z){
|
||||
this.extraRotationX = x;
|
||||
this.extraRotationY = y;
|
||||
this.extraRotationZ = z;
|
||||
}
|
||||
|
||||
/** Sets the rotation of this model part to the same values as the given box. */
|
||||
public void setRotationTo(ModelRendererExtended box){
|
||||
this.actualRotationX = box.actualRotationX;
|
||||
this.actualRotationY = box.actualRotationY;
|
||||
this.actualRotationZ = box.actualRotationZ;
|
||||
this.extraRotationX = box.extraRotationX;
|
||||
this.extraRotationY = box.extraRotationY;
|
||||
this.extraRotationZ = box.extraRotationZ;
|
||||
}
|
||||
|
||||
// Delegate rendering, but fiddle with the angles first
|
||||
|
||||
@Override
|
||||
public void render(float scale){
|
||||
|
||||
// Need to copy these over each time in case they were changed
|
||||
delegate.showModel = this.showModel;
|
||||
delegate.isHidden = this.isHidden;
|
||||
delegate.rotationPointX = this.rotationPointX;
|
||||
delegate.rotationPointY = this.rotationPointY;
|
||||
delegate.rotationPointZ = this.rotationPointZ;
|
||||
|
||||
if(!Float.isNaN(actualRotationX) && !Float.isNaN(actualRotationY) && !Float.isNaN(actualRotationZ)){
|
||||
delegate.rotateAngleX = actualRotationX;
|
||||
delegate.rotateAngleY = actualRotationY;
|
||||
delegate.rotateAngleZ = actualRotationZ;
|
||||
}else{
|
||||
delegate.rotateAngleX = this.rotateAngleX + extraRotationX;
|
||||
delegate.rotateAngleY = this.rotateAngleY + extraRotationY;
|
||||
delegate.rotateAngleZ = this.rotateAngleZ + extraRotationZ;
|
||||
}
|
||||
|
||||
delegate.render(scale);
|
||||
}
|
||||
|
||||
// Delegate all other methods
|
||||
|
||||
@Override
|
||||
public void addChild(ModelRenderer renderer){
|
||||
delegate.addChild(renderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWithRotation(float scale){
|
||||
delegate.renderWithRotation(scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRender(float scale){
|
||||
// Exactly the same setup as above, just add item rotation/translation fields and setters
|
||||
// float angle = 1;
|
||||
// float radius = 10;
|
||||
// delegate.rotationPointY -= radius * MathHelper.cos(angle);
|
||||
// delegate.rotationPointZ -= radius * MathHelper.sin(angle);
|
||||
// delegate.rotateAngleX += angle;
|
||||
delegate.postRender(scale);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package electroblob.wizardry.client.animation;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.util.InventoryUtils;
|
||||
import electroblob.wizardry.util.JavaUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.AbstractClientPlayer;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.model.ModelPlayer;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||
import net.minecraft.client.renderer.entity.RenderPlayer;
|
||||
import net.minecraft.client.renderer.entity.layers.LayerBipedArmor;
|
||||
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.EnumAction;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumHandSide;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||
import net.minecraftforge.client.event.RenderSpecificHandEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Handles the setup and rendering events for custom player animations, as well as registering of animations. Addons
|
||||
* can also register their own animations here, see {@link PlayerAnimator#registerAnimation(Animation)}.
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.3
|
||||
* @see electroblob.wizardry.item.SpellActions SpellActions
|
||||
*/
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class PlayerAnimator {
|
||||
|
||||
// TODO: Attempt to extend this to all bipeds
|
||||
|
||||
private static final List<Animation> animations = new ArrayList<>();
|
||||
|
||||
/** Stores all registered layer renderers for lazy-loading of armour models later. */
|
||||
private static final Map<RenderPlayer, List<LayerRenderer<? extends EntityLivingBase>>> playerLayers = new HashMap<>();
|
||||
/** Stores the main model for each renderer plus all models for registered layer renderers. */
|
||||
private static final Map<RenderPlayer, List<ModelBiped>> playerLayerModels = new HashMap<>();
|
||||
/** Reflected into {@link RenderLivingBase}{@code #layerRenderers}. */
|
||||
private static final Field layerRenderers;
|
||||
|
||||
static {
|
||||
layerRenderers = ObfuscationReflectionHelper.findField(RenderLivingBase.class, "field_177097_h");
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new player animation. This method should be called from the {@code init()} phase via a client proxy.
|
||||
* @param animation The animation to register
|
||||
*/
|
||||
// N.B. This can (and will) be called before PlayerAnimator#init() is called
|
||||
public static void registerAnimation(Animation animation){
|
||||
if(animations.contains(animation)){
|
||||
Wizardry.logger.warn("Animation {} is already registered!", animation.getName());
|
||||
}else{
|
||||
animations.add(animation);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Figure out if calling this from postInit ensures we catch all the layers, and lazy-load it if not
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void init(){
|
||||
|
||||
if(!Wizardry.settings.spellcastingAnimations) return;
|
||||
|
||||
for(RenderPlayer renderer : Minecraft.getMinecraft().getRenderManager().getSkinMap().values()){
|
||||
|
||||
List<ModelBiped> models = new ArrayList<>();
|
||||
ModelRendererExtended.wrap(renderer.getMainModel());
|
||||
models.add(renderer.getMainModel());
|
||||
|
||||
try {
|
||||
|
||||
List<LayerRenderer<? extends EntityLivingBase>> layers = (List<LayerRenderer<? extends EntityLivingBase>>)layerRenderers.get(renderer);
|
||||
|
||||
// Save armour layers for lazy-loading later (ignore other layers so iteration is faster)
|
||||
playerLayers.put(renderer, layers.stream().filter(l -> l instanceof LayerBipedArmor).collect(Collectors.toList()));
|
||||
|
||||
for(LayerRenderer<?> layer : layers){
|
||||
|
||||
for(Field field : JavaUtils.getAllFields(layer.getClass())){
|
||||
|
||||
field.setAccessible(true);
|
||||
|
||||
// If your layer model doesn't extend ModelBiped, you DESERVE to be incompatible!
|
||||
// (Just kidding... there's nothing I can do about it anyway)
|
||||
if(field.get(layer) instanceof ModelBiped){
|
||||
ModelBiped model = (ModelBiped)field.get(layer);
|
||||
ModelRendererExtended.wrap(model);
|
||||
models.add(model);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}catch(IllegalAccessException e){
|
||||
Wizardry.logger.error("Error during reflective access of render layers: ", e);
|
||||
}
|
||||
|
||||
playerLayerModels.put(renderer, models);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateModels(EntityPlayer player, Render<?> renderer, float partialTicks, boolean firstPerson){
|
||||
|
||||
// Biped armour is special because of Forge's armour item render hook
|
||||
// This needs to be lazy-loaded because we need access to an actual item
|
||||
for(LayerRenderer<? extends EntityLivingBase> layer : playerLayers.get(renderer)){
|
||||
if(layer instanceof LayerBipedArmor){
|
||||
for(EntityEquipmentSlot slot : InventoryUtils.ARMOUR_SLOTS){
|
||||
|
||||
ItemStack armour = player.getItemStackFromSlot(slot);
|
||||
// This method could behave dynamically depending on stuff like NBT so there's not really any way to
|
||||
// optimise it further, we *have* to retrieve the model every time (shouldn't be too bad though)
|
||||
ModelBiped model = ForgeHooksClient.getArmorModel(player, armour, slot, ((LayerBipedArmor)layer).getModelFromSlot(slot));
|
||||
|
||||
List<ModelBiped> models = playerLayerModels.get(renderer);
|
||||
|
||||
if(!models.contains(model)){ // Ignore already-wrapped models
|
||||
models.add(model);
|
||||
ModelRendererExtended.wrap(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Animation animation : animations){
|
||||
|
||||
if(animation.shouldDisplay(player, firstPerson)){
|
||||
|
||||
boolean autoRotateSecondLayer = animation.autoRotateSecondLayer(player, firstPerson);
|
||||
|
||||
for(ModelBiped model : playerLayerModels.get(renderer)){
|
||||
|
||||
animation.setRotationAngles(player, model, partialTicks, firstPerson);
|
||||
|
||||
if(autoRotateSecondLayer && model instanceof ModelPlayer){
|
||||
alignSecondLayer((ModelPlayer)model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Rotates the second layer boxes of the given (wrapped) player model to match the first layer. */
|
||||
public static void alignSecondLayer(ModelPlayer model){
|
||||
((ModelRendererExtended)model.bipedBodyWear) .setRotationTo((ModelRendererExtended)model.bipedBody);
|
||||
((ModelRendererExtended)model.bipedRightArmwear).setRotationTo((ModelRendererExtended)model.bipedRightArm);
|
||||
((ModelRendererExtended)model.bipedLeftArmwear) .setRotationTo((ModelRendererExtended)model.bipedLeftArm);
|
||||
((ModelRendererExtended)model.bipedRightLegwear).setRotationTo((ModelRendererExtended)model.bipedBody);
|
||||
((ModelRendererExtended)model.bipedLeftLegwear) .setRotationTo((ModelRendererExtended)model.bipedBody);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderHandEvent(RenderSpecificHandEvent event){
|
||||
|
||||
if(!Wizardry.settings.spellcastingAnimations) return;
|
||||
|
||||
AbstractClientPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
EnumAction action = event.getItemStack().getItemUseAction();
|
||||
|
||||
if(player.isHandActive() && player.getActiveHand() == event.getHand() && SpellActions.getSpellActions().contains(action)){
|
||||
// Minecraft's item renderer helpfully doesn't have a default case for the usage action so it doesn't do any
|
||||
// transformations at all (which is VERY ANNOYING!) - the following lines are from ItemRenderer#transformSideFirstPerson
|
||||
int i = (player.getPrimaryHand() == EnumHandSide.RIGHT) == (event.getHand() == EnumHand.MAIN_HAND) ? 1 : -1;
|
||||
GlStateManager.translate((float)i * 0.56F, -0.52F + event.getEquipProgress() * -0.6F, -0.72F);
|
||||
}
|
||||
|
||||
updateModels(player, Minecraft.getMinecraft().getRenderManager().getEntityRenderObject(player), event.getPartialTicks(), true);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderPlayerPreEvent(RenderPlayerEvent.Pre event){
|
||||
|
||||
if(!Wizardry.settings.spellcastingAnimations) return;
|
||||
|
||||
// boolean firstPerson = event.getEntityPlayer() == Minecraft.getMinecraft().player
|
||||
// && Minecraft.getMinecraft().gameSettings.thirdPersonView == 0;
|
||||
|
||||
updateModels(event.getEntityPlayer(), event.getRenderer(), event.getPartialRenderTick(), false);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderPlayerPostEvent(RenderPlayerEvent.Post event){
|
||||
|
||||
if(!Wizardry.settings.spellcastingAnimations) return;
|
||||
|
||||
for(ModelBiped model : playerLayerModels.get(event.getRenderer())){
|
||||
for(ModelRenderer box : model.boxList){ // For ModelPlayer, this will include the second layer
|
||||
// Some models have extra boxes, they (probably) don't need wrapping but we need this check!
|
||||
if(box instanceof ModelRendererExtended){
|
||||
((ModelRendererExtended)box).resetRotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package electroblob.wizardry.client.audio;
|
||||
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
|
||||
/** A special type of moving sound that stops when the player stops charging up a spell, either by releasing the mouse
|
||||
* button or when the charge-up time has elapsed. */
|
||||
public class MovingSoundSpellCharge extends MovingSoundEntity<EntityLivingBase> {
|
||||
|
||||
public MovingSoundSpellCharge(EntityLivingBase entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){
|
||||
super(entity, sound, category, volume, pitch, repeat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
if(source.isHandActive()){
|
||||
|
||||
ItemStack stack = source.getActiveItemStack();
|
||||
|
||||
if(stack.getItem() instanceof ISpellCastingItem){
|
||||
|
||||
if(source.getItemInUseMaxCount() < ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack).getChargeup()){
|
||||
super.update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.donePlaying = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,16 @@ public abstract class SoundLoop implements ITickable {
|
||||
|
||||
private static final Set<SoundLoop> activeLoops = new HashSet<>();
|
||||
|
||||
// The issue we had here was that there is no way of hooking into the client tick loop between the sound manager
|
||||
// update and the world tick (other than via the sounds themselves, but playing other sounds from there results in
|
||||
// CMEs, which is why we made this class in the first place). This meant there was always a gap between consecutive
|
||||
// sounds, which could be heard in-game as a weird audio artefact. The solution is simply to overlap the sounds by
|
||||
// 1 tick, which is fairly straightforward for the end sound, but because the start sound has to finish for us to
|
||||
// know when to play the others, this doubling-up solution is required (bit of a waste of resources but meh).
|
||||
/** A dummy sound with effectively zero volume, played one tick in advance of the actual start sound so the loop
|
||||
* sound can start one tick before the actual start sound ends. */
|
||||
private final ISound dummyStart; // It's the stupidest system ever but it works!
|
||||
|
||||
private final ISound start;
|
||||
private final ISound loop;
|
||||
private final ISound end;
|
||||
@@ -34,29 +44,28 @@ public abstract class SoundLoop implements ITickable {
|
||||
private boolean looping = false;
|
||||
private boolean needsRemoving = false;
|
||||
|
||||
public SoundLoop(SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, ISoundFactory factory){
|
||||
public SoundLoop(SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, ISoundFactory factory){
|
||||
// The reason I've gone to the effort of having a factory for these is that we need SoundLoop to have control
|
||||
// over which sounds are repeated and which aren't whilst keeping them private.
|
||||
this.start = factory.create(start, category, false);
|
||||
this.loop = factory.create(loop, category, true);
|
||||
this.end = factory.create(end, category, false);
|
||||
this.dummyStart = factory.create(start, category, 0.00001f, false); // Inaudible but not actually 0
|
||||
this.start = factory.create(start, category, volume, false);
|
||||
this.loop = factory.create(loop, category, volume, true);
|
||||
this.end = factory.create(end, category, volume, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
// Check every tick if the start sound is done playing and if so, start the loop sound
|
||||
if(!looping && !Minecraft.getMinecraft().getSoundHandler().isSoundPlaying(start)){
|
||||
if(!looping && !Minecraft.getMinecraft().getSoundHandler().isSoundPlaying(dummyStart)){
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(loop);
|
||||
looping = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Stops the loop part of the sound immediately and starts playing the end part. This may be called from subclasses
|
||||
* or externally depending on the implementation. */
|
||||
/** Starts playing the end part immediately and marks the loop part to stop next tick. This may be called from
|
||||
* subclasses or externally depending on the implementation. */
|
||||
// For continuous spell sounds it's internally
|
||||
public void endLoop(){
|
||||
Minecraft.getMinecraft().getSoundHandler().stopSound(start);
|
||||
Minecraft.getMinecraft().getSoundHandler().stopSound(loop);
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(end);
|
||||
// Can't modify activeLoops directly since we'll probably be calling this method from update(), which is
|
||||
// during iteration of activeLoops so it could cause a ConcurrentModificationException
|
||||
@@ -68,12 +77,20 @@ public abstract class SoundLoop implements ITickable {
|
||||
this.needsRemoving = true;
|
||||
}
|
||||
|
||||
/** Stops the start and loop sounds immediately. */
|
||||
protected void stopStartAndLoop(){
|
||||
Minecraft.getMinecraft().getSoundHandler().stopSound(dummyStart);
|
||||
Minecraft.getMinecraft().getSoundHandler().stopSound(start);
|
||||
Minecraft.getMinecraft().getSoundHandler().stopSound(loop);
|
||||
}
|
||||
|
||||
// Static methods
|
||||
|
||||
public static void addLoop(SoundLoop loop){
|
||||
activeLoops.add(loop);
|
||||
// Do this here rather than in the constructor in case someone wants to play the loop later or reuse it
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(loop.start);
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(loop.dummyStart);
|
||||
Minecraft.getMinecraft().getSoundHandler().playDelayedSound(loop.start, 2); // 1 seems to be insufficient
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -82,13 +99,14 @@ public abstract class SoundLoop implements ITickable {
|
||||
// meaning we don't get the 'cut' between the start and loop sounds
|
||||
// FIXME: Apparently this only works for dispensers. What the heck is the difference?!
|
||||
if(event.phase == TickEvent.Phase.END){
|
||||
activeLoops.forEach(SoundLoop::update);
|
||||
activeLoops.stream().filter(s -> s.needsRemoving).forEach(SoundLoop::stopStartAndLoop);
|
||||
activeLoops.removeIf(s -> s.needsRemoving);
|
||||
activeLoops.forEach(SoundLoop::update); // Do this last to allow a 1-tick overlap
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ISoundFactory {
|
||||
ISound create(SoundEvent sound, SoundCategory category, boolean repeat);
|
||||
ISound create(SoundEvent sound, SoundCategory category, float volume, boolean repeat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package electroblob.wizardry.client.audio;
|
||||
import electroblob.wizardry.data.DispenserCastingData;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import net.minecraft.client.audio.PositionedSound;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
@@ -17,8 +17,8 @@ public abstract class SoundLoopSpell extends SoundLoop {
|
||||
|
||||
private final Spell spell;
|
||||
|
||||
public SoundLoopSpell(SoundEvent start, SoundEvent loop, SoundEvent end, ISoundFactory factory, Spell spell){
|
||||
super(start, loop, end, WizardrySounds.SPELLS, factory);
|
||||
public SoundLoopSpell(SoundEvent start, SoundEvent loop, SoundEvent end, float volume, ISoundFactory factory, Spell spell){
|
||||
super(start, loop, end, WizardrySounds.SPELLS, volume, factory);
|
||||
this.spell = spell;
|
||||
}
|
||||
|
||||
@@ -43,13 +43,13 @@ public abstract class SoundLoopSpell extends SoundLoop {
|
||||
private final EntityLivingBase source;
|
||||
|
||||
public SoundLoopSpellEntity(SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, EntityLivingBase source, float volume, float pitch){
|
||||
super(start, loop, end, (sound, category, repeat) -> new MovingSoundEntity<>(source, sound, category, volume, pitch, repeat), spell);
|
||||
super(start, loop, end, volume, (sound, category, v, repeat) -> new MovingSoundEntity<>(source, sound, category, v, pitch, repeat), spell);
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean stillCasting(Spell spell){
|
||||
return WizardryUtilities.isCasting(source, spell);
|
||||
return EntityUtils.isCasting(source, spell);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,13 +58,13 @@ public abstract class SoundLoopSpell extends SoundLoop {
|
||||
public SoundLoopSpellPosition (SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell,
|
||||
double x, double y, double z, float sndVolume, float sndPitch){
|
||||
// Huh, I actually found a use for a non-static initialiser block - hence the double curly brackets...
|
||||
super(start, loop, end, (sound, category, r) -> new PositionedSound(sound, category){{
|
||||
super(start, loop, end, sndVolume, (sound, category, v, r) -> new PositionedSound(sound, category){{
|
||||
// ...et voila, we can just set protected fields as we please using external variables
|
||||
this.xPosF = (float)x;
|
||||
this.yPosF = (float)y;
|
||||
this.zPosF = (float)z;
|
||||
this.repeat = r;
|
||||
this.volume = sndVolume;
|
||||
this.volume = v;
|
||||
this.pitch = sndPitch;
|
||||
}}, spell);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.gui.inventory.GuiContainerCreative;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.util.text.Style;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Locale;
|
||||
|
||||
@EventBusSubscriber(Side.CLIENT)
|
||||
public class CustomCreativeSearchHandler {
|
||||
|
||||
private static final int SEARCH_TOOLTIP_HOVER_TIME = 20;
|
||||
|
||||
private static final Style TOOLTIP_SYNTAX = new Style().setColor(TextFormatting.YELLOW);
|
||||
private static final Style TOOLTIP_BODY = new Style().setColor(TextFormatting.WHITE);
|
||||
|
||||
/** Reflected into {@code GuiContainerCreative#searchField} */
|
||||
private static final Field searchField;
|
||||
|
||||
private static GuiTextField currentSearchField = null;
|
||||
|
||||
private static int searchBarHoverTime;
|
||||
|
||||
static {
|
||||
searchField = ObfuscationReflectionHelper.findField(GuiContainerCreative.class, "field_147062_A");
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onInitGuiEvent(GuiScreenEvent.InitGuiEvent.Post event){
|
||||
// Reduces reflection as much as possible - searchField is created on GUI init and never reassigned so we need
|
||||
// not (and should not!) use reflection to retrieve it every time a key is typed
|
||||
if(event.getGui() instanceof GuiContainerCreative){
|
||||
try{
|
||||
currentSearchField = (GuiTextField)searchField.get(event.getGui());
|
||||
}catch(IllegalAccessException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onKeyboardInputEvent(GuiScreenEvent.KeyboardInputEvent.Post event){
|
||||
// Custom creative tab search behaviour
|
||||
if(event.getGui() instanceof GuiContainerCreative){
|
||||
|
||||
GuiContainerCreative gui = (GuiContainerCreative)event.getGui();
|
||||
CreativeTabs tab = CreativeTabs.CREATIVE_TAB_ARRAY[gui.getSelectedTabIndex()];
|
||||
|
||||
if(tab == WizardryTabs.SPELLS){
|
||||
|
||||
GuiContainerCreative.ContainerCreative container = (GuiContainerCreative.ContainerCreative)gui.inventorySlots;
|
||||
container.itemList.clear(); // Required or duplicates will appear!
|
||||
String searchText = currentSearchField.getText().toLowerCase(Locale.ROOT);
|
||||
tab.displayAllRelevantItems(container.itemList);
|
||||
|
||||
if(!searchText.isEmpty()){
|
||||
container.itemList.removeIf(s -> !Spell.byMetadata(s.getMetadata()).matches(searchText));
|
||||
container.scrollTo(0); // Seems to refresh the GUI somehow so it displays correctly
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClientTickEvent(ClientTickEvent event){
|
||||
if(event.phase == Phase.END && searchBarHoverTime > 0 && searchBarHoverTime < SEARCH_TOOLTIP_HOVER_TIME){
|
||||
searchBarHoverTime++;
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onDrawScreenPostEvent(GuiScreenEvent.DrawScreenEvent.Post event){
|
||||
|
||||
if(event.getGui() instanceof GuiContainerCreative && currentSearchField != null){
|
||||
|
||||
GuiContainerCreative gui = (GuiContainerCreative)event.getGui();
|
||||
CreativeTabs tab = CreativeTabs.CREATIVE_TAB_ARRAY[gui.getSelectedTabIndex()];
|
||||
|
||||
if(tab == WizardryTabs.SPELLS && DrawingUtils.isPointInRegion(currentSearchField.x, currentSearchField.y, currentSearchField.width, currentSearchField.height, event.getMouseX(), event.getMouseY())){
|
||||
|
||||
if(searchBarHoverTime == 0){
|
||||
searchBarHoverTime++;
|
||||
}else if(searchBarHoverTime == SEARCH_TOOLTIP_HOVER_TIME){
|
||||
event.getGui().drawHoveringText(I18n.format("container." + Wizardry.MODID + ":arcane_workbench.search_tooltip",
|
||||
TOOLTIP_SYNTAX.getFormattingCode(), TOOLTIP_BODY.getFormattingCode()), event.getMouseX(), event.getMouseY());
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
searchBarHoverTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.inventory.ContainerBookshelf;
|
||||
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class GuiBookshelf extends GuiContainer {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/gui/container/bookshelf.png");
|
||||
/** The player inventory bound to this GUI. */
|
||||
private final InventoryPlayer playerInventory;
|
||||
/** The inventory contained within the corresponding bookshelf. */
|
||||
public IInventory bookshelfInventory;
|
||||
|
||||
public GuiBookshelf(InventoryPlayer playerInv, TileEntityBookshelf bookshelfInv){
|
||||
super(new ContainerBookshelf(playerInv, bookshelfInv));
|
||||
this.playerInventory = playerInv;
|
||||
this.bookshelfInventory = bookshelfInv;
|
||||
this.allowUserInput = false;
|
||||
this.ySize = 148;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks){
|
||||
this.drawDefaultBackground();
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
this.renderHoveredToolTip(mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
|
||||
String s = this.bookshelfInventory.getDisplayName().getUnformattedText();
|
||||
this.fontRenderer.drawString(s, 8, 6, 4210752);
|
||||
this.fontRenderer.drawString(this.playerInventory.getDisplayName().getUnformattedText(), 8, this.ySize - 96 + 2, 4210752);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY){
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
this.mc.getTextureManager().bindTexture(TEXTURE);
|
||||
int i = (this.width - this.xSize) / 2;
|
||||
int j = (this.height - this.ySize) / 2;
|
||||
this.drawTexturedModalRect(i, j, 0, 0, this.xSize, this.ySize);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.spell.Resurrection;
|
||||
import electroblob.wizardry.util.InventoryUtils;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiGameOver;
|
||||
@@ -52,7 +52,7 @@ public class GuiButtonResurrect extends GuiButton {
|
||||
public static void onGuiScreenInitEvent(GuiScreenEvent.InitGuiEvent event){
|
||||
|
||||
if(event.getGui() instanceof GuiGameOver && ItemArtefact.isArtefactActive(Minecraft.getMinecraft().player, WizardryItems.amulet_resurrection)
|
||||
&& WizardryUtilities.getHotbar(Minecraft.getMinecraft().player).stream().anyMatch(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player))){
|
||||
&& InventoryUtils.getHotbar(Minecraft.getMinecraft().player).stream().anyMatch(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player))){
|
||||
|
||||
event.getButtonList().add(new GuiButtonResurrect(event.getButtonList().size(), event.getGui().width / 2 - 100,
|
||||
event.getGui().height / 4 + 120, "spell." + Spells.resurrection.getRegistryName() + ".button"));
|
||||
@@ -65,7 +65,7 @@ public class GuiButtonResurrect extends GuiButton {
|
||||
|
||||
if(event.getGui() instanceof GuiGameOver){
|
||||
|
||||
ItemStack stack = WizardryUtilities.getHotbar(Minecraft.getMinecraft().player).stream()
|
||||
ItemStack stack = InventoryUtils.getHotbar(Minecraft.getMinecraft().player).stream()
|
||||
.filter(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player)).findFirst().orElse(null);
|
||||
|
||||
if(stack != null){
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.util.ISpellSortable;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class GuiButtonSpellSort extends GuiButton {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/gui/container/spell_sort_buttons.png");
|
||||
private static final int TEXTURE_WIDTH = 32;
|
||||
private static final int TEXTURE_HEIGHT = 32;
|
||||
|
||||
public final ISpellSortable.SortType sortType;
|
||||
|
||||
private final ISpellSortable sortable;
|
||||
private final GuiScreen parent;
|
||||
|
||||
public GuiButtonSpellSort(int id, int x, int y, ISpellSortable.SortType sortType, ISpellSortable sortable, GuiScreen parent){
|
||||
super(id, x, y, 10, 10, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.sort_" + sortType.name));
|
||||
this.sortType = sortType;
|
||||
this.sortable = sortable;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
if(this.visible){
|
||||
|
||||
// Whether the button is highlighted
|
||||
this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
||||
|
||||
int k = 0;
|
||||
int l = this.sortType.ordinal() * this.height;
|
||||
|
||||
if(sortType == sortable.getSortType()){
|
||||
k += this.width;
|
||||
if(sortable.isSortDescending()) k += this.width;
|
||||
}
|
||||
|
||||
parent.mc.getTextureManager().bindTexture(TEXTURE);
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButtonForegroundLayer(int mouseX, int mouseY){
|
||||
if(hovered) parent.drawHoveringText(this.displayString, mouseX, mouseY);
|
||||
}
|
||||
|
||||
}
|
||||
+14
-10
@@ -1,6 +1,5 @@
|
||||
package electroblob.wizardry.client.gui.handbook;
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -11,12 +10,12 @@ import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
class GuiButtonTurnPage extends GuiButton {
|
||||
public class GuiButtonTurnPage extends GuiButton {
|
||||
|
||||
static final int WIDTH = 20;
|
||||
static final int HEIGHT = 12;
|
||||
public static final int WIDTH = 20;
|
||||
public static final int HEIGHT = 12;
|
||||
|
||||
enum Type {
|
||||
public enum Type {
|
||||
|
||||
NEXT_PAGE(0, 196),
|
||||
PREVIOUS_PAGE(0, 208),
|
||||
@@ -34,11 +33,15 @@ class GuiButtonTurnPage extends GuiButton {
|
||||
|
||||
public final Type type;
|
||||
|
||||
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
|
||||
private final ResourceLocation texture;
|
||||
private final int textureWidth, textureHeight;
|
||||
|
||||
public GuiButtonTurnPage(int id, int x, int y, Type type){
|
||||
public GuiButtonTurnPage(int id, int x, int y, Type type, ResourceLocation texture, int textureWidth, int textureHeight){
|
||||
super(id, x, y, WIDTH, HEIGHT, "");
|
||||
this.type = type;
|
||||
this.texture = texture;
|
||||
this.textureWidth = textureWidth;
|
||||
this.textureHeight = textureHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,12 +53,13 @@ class GuiButtonTurnPage extends GuiButton {
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
if(this.visible){
|
||||
|
||||
|
||||
boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
minecraft.getTextureManager().bindTexture(texture);
|
||||
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, flag ? type.u + width : type.u, type.v, width, height, 512, 256);
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, flag ? type.u + width : type.u, type.v, width, height, textureWidth, textureHeight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.client.gui.GuiButtonTurnPage.Type;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.packet.PacketLectern;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import electroblob.wizardry.util.GeometryUtils;
|
||||
import electroblob.wizardry.util.ISpellSortable;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.audio.SoundHandler;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.play.client.CPacketCloseWindow;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.Style;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/gui/container/lectern.png");
|
||||
/** The distance of the page buttons from the bottom outside corners of the GUI. */
|
||||
private static final int PAGE_BUTTON_INSET_X = 22, PAGE_BUTTON_INSET_Y = 13;
|
||||
/** The distance between adjacent page turn buttons. */
|
||||
private static final int PAGE_BUTTON_SPACING = 20;
|
||||
/** The distance of the sort buttons from the top left corner of the GUI. */
|
||||
private static final int SORT_BUTTON_INSET_X = 96, SORT_BUTTON_INSET_Y = 20;
|
||||
/** The distance between adjacent sort buttons. */
|
||||
private static final int SORT_BUTTON_SPACING = 13;
|
||||
/** The distance of the spell buttons from the top outside corners of the GUI. */
|
||||
private static final int SPELL_BUTTON_INSET_X = 23, SPELL_BUTTON_INSET_Y = 44;
|
||||
/** The distance between adjacent spell buttons (in both x and y). */
|
||||
private static final int SPELL_BUTTON_SPACING = 38;
|
||||
|
||||
private static final int SPELL_ROWS = 3, SPELL_COLUMNS = 3;
|
||||
public static final int SPELL_BUTTON_COUNT = SPELL_ROWS * SPELL_COLUMNS * 2; // x2 because there are 2 pages
|
||||
|
||||
private static final int SEARCH_TOOLTIP_HOVER_TIME = 20;
|
||||
|
||||
private static final Style TOOLTIP_SYNTAX = new Style().setColor(TextFormatting.YELLOW);
|
||||
private static final Style TOOLTIP_BODY = new Style().setColor(TextFormatting.WHITE);
|
||||
|
||||
private final TileEntityLectern lectern;
|
||||
|
||||
private GuiButton nextPageButton;
|
||||
private GuiButton prevPageButton;
|
||||
private GuiButton lastPageButton;
|
||||
private GuiButton firstPageButton;
|
||||
private GuiButton indexButton;
|
||||
private GuiButton locateButton;
|
||||
|
||||
private GuiButton[] sortButtons = new GuiButton[3];
|
||||
private GuiButtonSpell[] spellButtons = new GuiButtonSpell[SPELL_BUTTON_COUNT];
|
||||
|
||||
/** The spell currently being viewed, or null if the index is being viewed. */
|
||||
private Spell currentSpell;
|
||||
/** The available spells in nearby bookshelves; should not contain duplicates. */
|
||||
private List<Spell> availableSpells = new ArrayList<>();
|
||||
/** The spells matching the current search criteria, sorted according to the current sort settings. Will be a subset
|
||||
* of {@link GuiLectern#availableSpells}. */
|
||||
private List<Spell> matchingSpells;
|
||||
|
||||
private ISpellSortable.SortType sortType = ISpellSortable.SortType.TIER;
|
||||
private boolean sortDescending = false;
|
||||
|
||||
private GuiTextField searchField;
|
||||
private boolean searchNeedsClearing;
|
||||
private int searchBarHoverTime;
|
||||
|
||||
private int currentPage = 0;
|
||||
|
||||
public GuiLectern(TileEntityLectern lectern){
|
||||
super(288, 180);
|
||||
this.lectern = lectern;
|
||||
this.currentSpell = lectern.currentSpell;
|
||||
this.setTextureSize(512, 512);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spell getSpell(){
|
||||
return currentSpell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(){
|
||||
return TEXTURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortType getSortType(){
|
||||
return sortType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSortDescending(){
|
||||
return sortDescending;
|
||||
}
|
||||
|
||||
private int getPageCount(){
|
||||
return MathHelper.ceil((float)matchingSpells.size() / SPELL_BUTTON_COUNT);
|
||||
}
|
||||
|
||||
private Spell getSpellForButton(GuiButtonSpell button){
|
||||
return matchingSpells.get(currentPage * SPELL_BUTTON_COUNT + button.index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui(){
|
||||
|
||||
super.initGui();
|
||||
|
||||
final int left = this.width / 2 - this.xSize / 2;
|
||||
final int top = this.height / 2 - this.ySize / 2;
|
||||
|
||||
int buttonID = 0;
|
||||
|
||||
// Page buttons
|
||||
this.buttonList.add(nextPageButton = new GuiButtonTurnPage(buttonID++, left + xSize - PAGE_BUTTON_INSET_X - GuiButtonTurnPage.WIDTH,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_PAGE, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(prevPageButton = new GuiButtonTurnPage(buttonID++, left + PAGE_BUTTON_INSET_X,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_PAGE, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(lastPageButton = new GuiButtonTurnPage(buttonID++, left + xSize - PAGE_BUTTON_INSET_X - GuiButtonTurnPage.WIDTH - PAGE_BUTTON_SPACING,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_SECTION, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(firstPageButton = new GuiButtonTurnPage(buttonID++, left + PAGE_BUTTON_INSET_X + PAGE_BUTTON_SPACING,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_SECTION, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(indexButton = new GuiButtonTurnPage(buttonID++, left + xSize/2 - 23,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.CONTENTS, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(locateButton = new GuiButtonLocateBook(buttonID++, left + xSize/2 - 34,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT));
|
||||
|
||||
// Sort buttons
|
||||
for(SortType sortType : SortType.values()){
|
||||
this.buttonList.add(sortButtons[sortType.ordinal()] = new GuiButtonSpellSort(buttonID++,
|
||||
left + SORT_BUTTON_INSET_X + SORT_BUTTON_SPACING * sortType.ordinal(),
|
||||
top + SORT_BUTTON_INSET_Y, sortType, this, this));
|
||||
}
|
||||
|
||||
// Spell buttons
|
||||
for(int i = 0; i < SPELL_BUTTON_COUNT; i++){
|
||||
|
||||
int row = i % SPELL_COLUMNS;
|
||||
int column = (i / SPELL_COLUMNS) % SPELL_ROWS;
|
||||
|
||||
int x = i < SPELL_BUTTON_COUNT/2 ? SPELL_BUTTON_INSET_X + row * SPELL_BUTTON_SPACING
|
||||
: xSize - SPELL_BUTTON_INSET_X - GuiButtonSpell.WIDTH - (2-row) * SPELL_BUTTON_SPACING;
|
||||
int y = SPELL_BUTTON_INSET_Y + column * SPELL_BUTTON_SPACING;
|
||||
|
||||
this.buttonList.add(spellButtons[i] = new GuiButtonSpell(buttonID++, left + x, top + y, i));
|
||||
}
|
||||
|
||||
this.searchField = new GuiTextField(0, this.fontRenderer, left + 157, top + 21, 106, this.fontRenderer.FONT_HEIGHT);
|
||||
this.searchField.setMaxStringLength(50);
|
||||
this.searchField.setEnableBackgroundDrawing(false);
|
||||
this.searchField.setVisible(true);
|
||||
this.searchField.setTextColor(16777215);
|
||||
this.searchField.setCanLoseFocus(false);
|
||||
this.searchField.setFocused(true);
|
||||
|
||||
refreshAvailableSpells(); // Must be done last
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen(){
|
||||
super.updateScreen();
|
||||
if(searchBarHoverTime > 0 && searchBarHoverTime < SEARCH_TOOLTIP_HOVER_TIME) searchBarHoverTime++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed(){
|
||||
WizardryPacketHandler.net.sendToServer(new PacketLectern.Message(lectern.getPos(), currentSpell));
|
||||
super.onGuiClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackgroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
if(currentSpell == Spells.none){
|
||||
drawIndexPage(left, top);
|
||||
}else{
|
||||
super.drawBackgroundLayer(left, top, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawForegroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
|
||||
if(currentSpell == Spells.none){
|
||||
this.fontRenderer.drawString(I18n.format("gui." + Wizardry.MODID + ":lectern.title"),
|
||||
left + 20, top + SORT_BUTTON_INSET_Y, 0);
|
||||
}else{
|
||||
super.drawForegroundLayer(left, top, mouseX, mouseY);
|
||||
}
|
||||
|
||||
this.buttonList.forEach(b -> b.drawButtonForegroundLayer(mouseX, mouseY));
|
||||
|
||||
// Search tooltip
|
||||
if(DrawingUtils.isPointInRegion(searchField.x, searchField.y, searchField.width, searchField.height, mouseX, mouseY)){
|
||||
if(searchBarHoverTime == 0){
|
||||
searchBarHoverTime++;
|
||||
}else if(searchBarHoverTime == SEARCH_TOOLTIP_HOVER_TIME){
|
||||
drawHoveringText(I18n.format("container." + Wizardry.MODID + ":arcane_workbench.search_tooltip",
|
||||
TOOLTIP_SYNTAX.getFormattingCode(), TOOLTIP_BODY.getFormattingCode()), mouseX, mouseY);
|
||||
}
|
||||
}else{
|
||||
searchBarHoverTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void drawIndexPage(int left, int top){
|
||||
|
||||
for(int i = 0; i < SPELL_BUTTON_COUNT; i++){
|
||||
|
||||
int index = currentPage * SPELL_BUTTON_COUNT + i;
|
||||
Spell spell = index < matchingSpells.size() ? matchingSpells.get(index) : Spells.none;
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(spell, null);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
|
||||
|
||||
int row = i % SPELL_COLUMNS;
|
||||
int column = (i / SPELL_COLUMNS) % SPELL_ROWS;
|
||||
|
||||
int x = i < SPELL_BUTTON_COUNT/2 ? SPELL_BUTTON_INSET_X + row * SPELL_BUTTON_SPACING
|
||||
: xSize - SPELL_BUTTON_INSET_X - GuiButtonSpell.WIDTH - (2-row) * SPELL_BUTTON_SPACING;
|
||||
int y = SPELL_BUTTON_INSET_Y + column * SPELL_BUTTON_SPACING;
|
||||
|
||||
DrawingUtils.drawTexturedRect(left + x + 1, top + y + 1, 0, 0, 32, 32, 32, 32);
|
||||
}
|
||||
|
||||
mc.renderEngine.bindTexture(getTexture());
|
||||
DrawingUtils.drawTexturedRect(left, top, 0, 256, xSize, ySize, textureWidth, textureHeight);
|
||||
|
||||
this.searchField.drawTextBox();
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
mc.renderEngine.bindTexture(getTexture());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
searchNeedsClearing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton button){
|
||||
|
||||
int lastPage = getPageCount() - 1;
|
||||
|
||||
if(button == indexButton){
|
||||
currentSpell = Spells.none;
|
||||
// currentPage = 0;
|
||||
|
||||
}else if(button == locateButton){
|
||||
// Close the GUI
|
||||
this.mc.player.connection.sendPacket(new CPacketCloseWindow(this.mc.player.openContainer.windowId));
|
||||
this.mc.displayGuiScreen(null);
|
||||
|
||||
// Find the location(s) of the current spell's book(s) and highlight them
|
||||
for(IInventory bookshelf : BlockBookshelf.findNearbyBookshelves(lectern.getWorld(), lectern.getPos())){
|
||||
|
||||
for(int i = 0; i < bookshelf.getSizeInventory(); i++){
|
||||
|
||||
ItemStack stack = bookshelf.getStackInSlot(i);
|
||||
|
||||
if(stack.getItem() instanceof ItemSpellBook){
|
||||
|
||||
Spell spell = Spell.byMetadata(stack.getMetadata());
|
||||
|
||||
if(spell == this.currentSpell){
|
||||
|
||||
BlockPos pos = (((TileEntity)bookshelf).getPos());
|
||||
|
||||
for(EnumFacing side : EnumFacing.VALUES){
|
||||
ParticleBuilder.create(ParticleBuilder.Type.BLOCK_HIGHLIGHT).pos(
|
||||
GeometryUtils.getFaceCentre(pos, side)
|
||||
.add(new Vec3d(side.getDirectionVec())
|
||||
.scale(GeometryUtils.ANTI_Z_FIGHTING_OFFSET)))
|
||||
.face(side).clr(0.9f, 0.5f, 0.8f).fade(0.7f, 0, 1).spawn(mc.world);
|
||||
}
|
||||
|
||||
mc.world.playSound(pos, WizardrySounds.BLOCK_LECTERN_LOCATE_SPELL, SoundCategory.BLOCKS, 1, 0.7f, false);
|
||||
|
||||
break; // This bookshelf has the spell, skip to the next bookshelf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else if(button == nextPageButton){
|
||||
if(currentPage < lastPage) currentPage++;
|
||||
|
||||
}else if(button == prevPageButton){
|
||||
if(currentPage > 0) currentPage--;
|
||||
|
||||
}else if(button == lastPageButton){
|
||||
currentPage = lastPage;
|
||||
|
||||
}else if(button == firstPageButton){
|
||||
currentPage = 0;
|
||||
|
||||
}else if(button instanceof GuiButtonSpell){
|
||||
currentSpell = getSpellForButton((GuiButtonSpell)button);
|
||||
|
||||
}else if(button instanceof GuiButtonSpellSort){
|
||||
|
||||
SortType sortType = (((GuiButtonSpellSort)button).sortType);
|
||||
|
||||
if(this.sortType == sortType){
|
||||
this.sortDescending = !this.sortDescending;
|
||||
}else{
|
||||
this.sortType = sortType;
|
||||
this.sortDescending = false;
|
||||
}
|
||||
|
||||
updateMatchingSpells();
|
||||
}
|
||||
|
||||
updateButtonVisiblity();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
|
||||
if(this.searchNeedsClearing){
|
||||
this.searchNeedsClearing = false;
|
||||
this.searchField.setText("");
|
||||
this.currentPage = 0;
|
||||
}
|
||||
|
||||
if(this.searchField.textboxKeyTyped(typedChar, keyCode)){
|
||||
this.currentPage = 0;
|
||||
updateMatchingSpells();
|
||||
updateButtonVisiblity();
|
||||
}else{
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateButtonVisiblity(){
|
||||
|
||||
if(currentSpell == Spells.none){
|
||||
|
||||
this.searchField.setVisible(true);
|
||||
|
||||
int lastPage = getPageCount() - 1;
|
||||
|
||||
prevPageButton.visible = currentPage > 0;
|
||||
firstPageButton.visible = currentPage > 0;
|
||||
nextPageButton.visible = currentPage < lastPage;
|
||||
lastPageButton.visible = currentPage < lastPage;
|
||||
|
||||
indexButton.visible = false;
|
||||
locateButton.visible = false;
|
||||
|
||||
for(GuiButton button : sortButtons) button.visible = true;
|
||||
|
||||
for(GuiButtonSpell button : spellButtons){
|
||||
button.visible = currentPage * SPELL_BUTTON_COUNT + button.index < matchingSpells.size();
|
||||
}
|
||||
|
||||
}else{
|
||||
this.searchField.setVisible(false);
|
||||
this.buttonList.forEach(b -> b.visible = false); // Hide all buttons...
|
||||
indexButton.visible = true; // ... except the index button and locate button
|
||||
locateButton.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMatchingSpells(){
|
||||
matchingSpells = availableSpells.stream()
|
||||
.filter(s -> s.matches(searchField.getText().toLowerCase(Locale.ROOT)))
|
||||
.sorted(sortDescending ? sortType.comparator.reversed() : sortType.comparator)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// TODO: Config option to always display all spells when in creative
|
||||
/** Called on initialisation and whenever a bookshelf is added or removed, to update the list of spells. */
|
||||
public void refreshAvailableSpells(){
|
||||
|
||||
availableSpells.clear();
|
||||
|
||||
// No need to exclude the lectern TE because it's not an IInventory!
|
||||
for(IInventory bookshelf : BlockBookshelf.findNearbyBookshelves(lectern.getWorld(), lectern.getPos())){
|
||||
|
||||
for(int i=0; i<bookshelf.getSizeInventory(); i++){
|
||||
|
||||
ItemStack stack = bookshelf.getStackInSlot(i);
|
||||
|
||||
if(stack.getItem() instanceof ItemSpellBook){
|
||||
Spell spell = Spell.byMetadata(stack.getMetadata());
|
||||
if(spell != Spells.none && !availableSpells.contains(spell)) availableSpells.add(spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!availableSpells.contains(currentSpell)) currentSpell = Spells.none;
|
||||
|
||||
updateMatchingSpells();
|
||||
updateButtonVisiblity();
|
||||
|
||||
}
|
||||
|
||||
private class GuiButtonLocateBook extends GuiButton {
|
||||
|
||||
public GuiButtonLocateBook(int id, int x, int y){
|
||||
super(id, x, y, 12, 12, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
if(this.visible){
|
||||
|
||||
boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
minecraft.getTextureManager().bindTexture(TEXTURE);
|
||||
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, flag ? width : 0, 184, width, height, textureWidth, textureHeight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GuiButtonSpell extends GuiButtonInvisible {
|
||||
|
||||
private static final int WIDTH = 34, HEIGHT = 34;
|
||||
|
||||
private final int index;
|
||||
|
||||
public GuiButtonSpell(int id, int x, int y, int index){
|
||||
super(id, x, y, WIDTH, HEIGHT);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playPressSound(SoundHandler soundHandler){
|
||||
soundHandler.playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_PAGE_TURN, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
if(visible){
|
||||
super.drawButton(minecraft, mouseX, mouseY, partialTicks);
|
||||
if(hovered){
|
||||
mc.renderEngine.bindTexture(getTexture());
|
||||
DrawingUtils.drawTexturedRect(x, y, 40, 180, width, height, textureWidth, textureHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButtonForegroundLayer(int mouseX, int mouseY){
|
||||
if(visible && hovered){
|
||||
Spell spell = getSpellForButton(this);
|
||||
if(Wizardry.proxy.shouldDisplayDiscovered(spell, null)){
|
||||
drawHoveringText(Collections.singletonList(spell.getDisplayName()), mouseX, mouseY, fontRenderer);
|
||||
}else{
|
||||
drawHoveringText(Collections.singletonList(SpellGlyphData.getGlyphName(spell, mc.world)),
|
||||
mouseX, mouseY, mc.standardGalacticFontRenderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,121 +1,35 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.util.Map;
|
||||
public class GuiSpellBook extends GuiSpellInfo {
|
||||
|
||||
public class GuiSpellBook extends GuiScreen {
|
||||
private final ItemSpellBook book;
|
||||
private final Spell spell;
|
||||
|
||||
private int xSize, ySize;
|
||||
private Spell spell;
|
||||
public GuiSpellBook(ItemStack stack){
|
||||
|
||||
private static final Map<Tier, ResourceLocation> textures = ImmutableMap.of(
|
||||
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
|
||||
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
|
||||
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
|
||||
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
|
||||
super(288, 180);
|
||||
|
||||
public GuiSpellBook(Spell spell){
|
||||
super();
|
||||
xSize = 288;
|
||||
ySize = 180;
|
||||
this.spell = spell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it.
|
||||
*/
|
||||
public void drawScreen(int par1, int par2, float par3){
|
||||
|
||||
int xPos = this.width / 2 - xSize / 2;
|
||||
int yPos = this.height / 2 - this.ySize / 2;
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
boolean discovered = true;
|
||||
if(Wizardry.settings.discoveryMode && !player.isCreative() && WizardData.get(player) != null
|
||||
&& !WizardData.get(player).hasSpellBeenDiscovered(spell)){
|
||||
discovered = false;
|
||||
if(!(stack.getItem() instanceof ItemSpellBook)){
|
||||
throw new ClassCastException("Cannot create spell book GUI for item that does not extend ItemSpellBook!");
|
||||
}
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1); // Just in case
|
||||
|
||||
// Draws spell illustration on opposite page, underneath the book so it shows through the hole.
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
|
||||
DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.getTier()));
|
||||
DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawString(spell.getDisplayName(), xPos + 17, yPos + 15, 0);
|
||||
this.fontRenderer.drawString(spell.getType().getDisplayName(), xPos + 17, yPos + 26, 0x777777);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.world), xPos + 17,
|
||||
yPos + 15, 0);
|
||||
this.mc.standardGalacticFontRenderer.drawString(spell.getType().getDisplayName(), xPos + 17, yPos + 26,
|
||||
0x777777);
|
||||
}
|
||||
|
||||
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
|
||||
|
||||
if(spell.getTier() == Tier.NOVICE){
|
||||
// Basic is usually white but this doesn't show up.
|
||||
this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
|
||||
}else{
|
||||
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
|
||||
}
|
||||
|
||||
String element = "Element: " + spell.getElement().getFormattingCode() + spell.getElement().getDisplayName();
|
||||
if(!discovered) element = "Element: ?";
|
||||
this.fontRenderer.drawString(element, xPos + 17, yPos + 57, 0);
|
||||
|
||||
String manaCost = "Mana Cost: " + spell.getCost();
|
||||
if(spell.isContinuous) manaCost = "Mana Cost: " + spell.getCost() + "/second";
|
||||
if(!discovered) manaCost = "Mana Cost: ?";
|
||||
this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 69, 0);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawSplitString(spell.getDescription(), xPos + 17, yPos + 83, 118, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawSplitString(
|
||||
SpellGlyphData.getGlyphDescription(spell, player.world), xPos + 17, yPos + 83, 118, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void initGui(){
|
||||
super.initGui();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
|
||||
this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1));
|
||||
}
|
||||
|
||||
public void onGuiClosed(){
|
||||
super.onGuiClosed();
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
this.book = (ItemSpellBook)stack.getItem();
|
||||
this.spell = (Spell.byMetadata(stack.getItemDamage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesGuiPauseGame(){
|
||||
return Wizardry.settings.booksPauseGame;
|
||||
public Spell getSpell(){
|
||||
return spell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(){
|
||||
return book.getGuiTexture(spell);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
@@ -39,12 +39,14 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class GuiSpellDisplay {
|
||||
|
||||
private static final ResourceLocation INDEX = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud/_index.json");
|
||||
|
||||
private static final ResourceLocation CHARGE_METER = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_charge_meter.png");
|
||||
|
||||
/** A map which stores all loaded HUD skin objects. This gets wiped on resource pack reload and repopulated with
|
||||
* mappings as specified by {@code _index.json} (these stack between resource packs). The keys in the map correspond
|
||||
* to the keys in {@code _index.json}, and are sorted in that order, with skins belonging to resource packs sorted
|
||||
@@ -53,6 +55,12 @@ public class GuiSpellDisplay {
|
||||
private static final Map<String, Skin> skins = new LinkedHashMap<>(14); // 14 is the number of skins packaged with the mod
|
||||
|
||||
private static final Gson gson = new Gson();
|
||||
private static final Random random = new Random();
|
||||
|
||||
/** Width of the charge meter. */
|
||||
private static final int CHARGE_METER_WIDTH = 25;
|
||||
/** Height of the charge meter. */
|
||||
private static final int CHARGE_METER_HEIGHT = 9;
|
||||
|
||||
/** Width and height of the spell icon (very unlikely to change!) */
|
||||
private static final int SPELL_ICON_SIZE = 32;
|
||||
@@ -96,11 +104,11 @@ public class GuiSpellDisplay {
|
||||
// Normally when extending Gui, you'd have to have an instance to access its methods. However, we're not actually
|
||||
// using any of them, so this class may as well not bother and just be a static event handler. Neat!
|
||||
@SubscribeEvent
|
||||
public static void draw(RenderGameOverlayEvent event){
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
public static void draw(RenderGameOverlayEvent.Post event){
|
||||
|
||||
EntityPlayer player = mc.player;
|
||||
if(!Wizardry.settings.showSpellHUD && !Wizardry.settings.showChargeMeter) return; // Optimisation
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
if(player.isSpectator()) return; // Spectators shouldn't have the spell HUD!
|
||||
|
||||
@@ -113,12 +121,89 @@ public class GuiSpellDisplay {
|
||||
wand = player.getHeldItemOffhand();
|
||||
mainHand = false;
|
||||
// If the player isn't holding a spellcasting item that shows the HUD, then nothing else needs to be done.
|
||||
if(!(wand.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)wand.getItem()).showSpellHUD(player, wand))) return;
|
||||
if(!(wand.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)wand.getItem()).showSpellHUD(player, wand)))
|
||||
return;
|
||||
}
|
||||
|
||||
int width = event.getResolution().getScaledWidth();
|
||||
int height = event.getResolution().getScaledHeight();
|
||||
|
||||
switch(event.getType()){
|
||||
case CROSSHAIRS:
|
||||
renderChargeMeter(player, wand, width, height, event.getPartialTicks());
|
||||
break;
|
||||
case HOTBAR:
|
||||
renderSpellHUD(player, wand, mainHand, width, height, event.getPartialTicks(), false);
|
||||
break;
|
||||
case TEXT:
|
||||
renderSpellHUD(player, wand, mainHand, width, height, event.getPartialTicks(), true);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the spell charge meter around the crosshairs.
|
||||
* @param player A reference to the client player
|
||||
* @param wand The wand the HUD is for
|
||||
* @param width The width of the screen
|
||||
* @param height The height of the screen
|
||||
* @param partialTicks The current partial tick time
|
||||
*/
|
||||
private static void renderChargeMeter(EntityPlayer player, ItemStack wand, int width, int height, float partialTicks){
|
||||
|
||||
if(!Wizardry.settings.showChargeMeter) return;
|
||||
if(Minecraft.getMinecraft().gameSettings.showDebugInfo) return; // Don't show charge meter in the debug screen
|
||||
if(Minecraft.getMinecraft().gameSettings.thirdPersonView != 0) return; // Don't show in third person
|
||||
if(wand != player.getActiveItemStack()) return; // Don't show when using the other held item
|
||||
|
||||
if(!(wand.getItem() instanceof ISpellCastingItem)) throw new IllegalArgumentException("The given stack must contain an ISpellCastingItem!");
|
||||
|
||||
Spell spell = ((ISpellCastingItem)wand.getItem()).getCurrentSpell(wand);
|
||||
|
||||
int chargeup = spell.getChargeup();
|
||||
|
||||
if(WizardData.get(player) != null){
|
||||
// Pretty sure this is accessible client-side since it's only assigned from common code
|
||||
chargeup = (int)(chargeup * WizardData.get(player).itemCastingModifiers.get(SpellModifiers.CHARGEUP));
|
||||
}
|
||||
|
||||
if(chargeup <= 0) return;
|
||||
|
||||
// WHY WHY WHY are these methods named so misleadingly?! Sort yourselves out MCP!
|
||||
// (getItemInUseCount returns the max count MINUS the use count, and getItemInUseMaxCount returns the use count)
|
||||
if(player.getItemInUseMaxCount() == 0) return; // Not charging
|
||||
float charge = (player.getItemInUseMaxCount() + partialTicks) / chargeup;
|
||||
if(charge > 1) return; // Done charging
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(CHARGE_METER);
|
||||
|
||||
int x1 = width/2 - CHARGE_METER_WIDTH/2;
|
||||
int y = height/2 - CHARGE_METER_HEIGHT/2;
|
||||
int w = (int)(CHARGE_METER_WIDTH/2 * charge);
|
||||
int u = CHARGE_METER_WIDTH - w;
|
||||
|
||||
DrawingUtils.drawTexturedRect(x1, y, 0, 0, w, CHARGE_METER_HEIGHT, 32, 32);
|
||||
DrawingUtils.drawTexturedRect(x1 + u, y, u, 0, w, CHARGE_METER_HEIGHT, 32, 32);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the main spell HUD in the corner of the screen.
|
||||
* @param player A reference to the client player
|
||||
* @param wand The wand the HUD is for
|
||||
* @param mainHand True if the wand is in the player's main hand, false if it is in their offhand
|
||||
* @param width The width of the screen
|
||||
* @param height The height of the screen
|
||||
* @param partialTicks The current partial tick time
|
||||
* @param textLayer True to render the text layer, false to render the background (hotbar layer)
|
||||
*/
|
||||
private static void renderSpellHUD(EntityPlayer player, ItemStack wand, boolean mainHand, int width, int height, float partialTicks, boolean textLayer){
|
||||
|
||||
if(!Wizardry.settings.showSpellHUD) return;
|
||||
|
||||
if(!(wand.getItem() instanceof ISpellCastingItem)) throw new IllegalArgumentException("The given stack must contain an ISpellCastingItem!");
|
||||
|
||||
boolean flipX = Wizardry.settings.spellHUDPosition.flipX;
|
||||
boolean flipY = Wizardry.settings.spellHUDPosition.flipY;
|
||||
|
||||
@@ -126,16 +211,16 @@ public class GuiSpellDisplay {
|
||||
// ............. | This bit is true if the wand is on the left, false if it is on the right
|
||||
flipX = flipX == ((mainHand ? player.getPrimaryHand() : player.getPrimaryHand().opposite()) == EnumHandSide.LEFT);
|
||||
}
|
||||
|
||||
|
||||
Skin skin = skins.get(Wizardry.settings.spellHUDSkin);
|
||||
|
||||
|
||||
if(skin == null){
|
||||
|
||||
|
||||
Wizardry.logger.info("The spell HUD skin '" + Wizardry.settings.spellHUDSkin + "' specified in the config"
|
||||
+ " did not match any of the loaded skins; using the default skin as a fallback.");
|
||||
|
||||
|
||||
skin = skins.get(Settings.DEFAULT_HUD_SKIN_KEY);
|
||||
|
||||
|
||||
if(skin == null){
|
||||
Wizardry.logger.warn("The default spell HUD skin is missing! A resource pack must have overridden it"
|
||||
+ " with an invalid JSON file (default.json), please try again without any resource packs.");
|
||||
@@ -144,7 +229,7 @@ public class GuiSpellDisplay {
|
||||
}
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
|
||||
// 'Origin' of the spell hud (bottom left corner of the actual texture, always in the corner of the screen)
|
||||
int x = flipX ? width : 0;
|
||||
int y = flipY ? 0: height;
|
||||
@@ -165,45 +250,45 @@ public class GuiSpellDisplay {
|
||||
y = MathHelper.ceil(y/scale);
|
||||
}
|
||||
|
||||
Spell spell = WandHelper.getCurrentSpell(wand);
|
||||
int cooldown = WandHelper.getCurrentCooldown(wand);
|
||||
int maxCooldown = WandHelper.getCurrentMaxCooldown(wand);
|
||||
Spell spell = ((ISpellCastingItem)wand.getItem()).getCurrentSpell(wand);
|
||||
int cooldown = ((ISpellCastingItem)wand.getItem()).getCurrentCooldown(wand);
|
||||
int maxCooldown = ((ISpellCastingItem)wand.getItem()).getCurrentMaxCooldown(wand);
|
||||
|
||||
if(textLayer){
|
||||
|
||||
if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){
|
||||
|
||||
float animationProgress = Math.signum(switchTimer) * ((SPELL_SWITCH_TIME - Math.abs(switchTimer) +
|
||||
event.getPartialTicks()) / SPELL_SWITCH_TIME);
|
||||
|
||||
String prevSpellName = getFormattedSpellName(WandHelper.getPreviousSpell(wand), player, WandHelper.getPreviousCooldown(wand));
|
||||
partialTicks) / SPELL_SWITCH_TIME);
|
||||
|
||||
String prevSpellName = getFormattedSpellName(((ISpellCastingItem)wand.getItem()).getPreviousSpell(wand), player, 0);
|
||||
String spellName = getFormattedSpellName(spell, player, cooldown);
|
||||
String nextSpellName = getFormattedSpellName(WandHelper.getNextSpell(wand), player, WandHelper.getNextCooldown(wand));
|
||||
String nextSpellName = getFormattedSpellName(((ISpellCastingItem)wand.getItem()).getNextSpell(wand), player, 0);
|
||||
|
||||
skin.drawText(x, y, flipX, flipY, prevSpellName, spellName, nextSpellName, animationProgress);
|
||||
|
||||
}else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){
|
||||
}else{
|
||||
|
||||
boolean discovered = true;
|
||||
|
||||
if(!player.isCreative() && WizardData.get(player) != null){
|
||||
discovered = WizardData.get(player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
|
||||
|
||||
ResourceLocation icon = discovered ? spell.getIcon() : Spells.none.getIcon();
|
||||
|
||||
float progress = 1;
|
||||
// Doesn't really matter what progress is when in creative, but we might as well avoid the calculation.
|
||||
if(!player.isCreative() && !spell.isContinuous){
|
||||
if(!player.isCreative()){
|
||||
// Subtracted partial tick time to make it smoother
|
||||
progress = maxCooldown == 0 ? 1 : (maxCooldown - (float)cooldown + event.getPartialTicks()) / maxCooldown;
|
||||
progress = maxCooldown == 0 ? 1 : (maxCooldown - (float)cooldown + partialTicks) / maxCooldown;
|
||||
}
|
||||
|
||||
skin.drawBackground(x, y, flipX, flipY, icon, progress, player.isCreative());
|
||||
|
||||
|
||||
skin.drawBackground(x, y, flipX, flipY, icon, progress, player.isCreative(), player.isPotionActive(WizardryPotions.arcane_jammer));
|
||||
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the name of the given spell, with formatting added according to its cooldown and whether the given player
|
||||
* has discovered it.
|
||||
@@ -220,9 +305,11 @@ public class GuiSpellDisplay {
|
||||
discovered = WizardData.get(player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
|
||||
// Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect
|
||||
String format = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.getElement().getFormattingCode();
|
||||
// Makes spells greyed out if they are in cooldown
|
||||
String format = cooldown > 0 ? "\u00A78" : spell.getElement().getFormattingCode();
|
||||
if(!discovered) format = "\u00A79";
|
||||
// Obfuscates the spell name if the player has the arcane jammer effect
|
||||
if(player.isPotionActive(WizardryPotions.arcane_jammer)) format = format + "\u00A7k";
|
||||
|
||||
String name = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.world);
|
||||
name = format + name;
|
||||
@@ -251,7 +338,7 @@ public class GuiSpellDisplay {
|
||||
|
||||
for(IResource indexFile : indexFiles){
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(indexFile.getInputStream()));
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(indexFile.getInputStream(), StandardCharsets.UTF_8));
|
||||
|
||||
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
||||
JsonObject json = je.getAsJsonObject();
|
||||
@@ -361,7 +448,7 @@ public class GuiSpellDisplay {
|
||||
try {
|
||||
// This time we only want the highest priority file
|
||||
IResource metadataFile = Minecraft.getMinecraft().getResourceManager().getResource(metadata);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(metadataFile.getInputStream()));
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(metadataFile.getInputStream(), StandardCharsets.UTF_8));
|
||||
|
||||
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
||||
|
||||
@@ -454,8 +541,9 @@ public class GuiSpellDisplay {
|
||||
* @param icon A {@code ResourceLocation} corresponding to the icon of the selected spell.
|
||||
* @param cooldownBarProgress The fraction of the cooldown bar to draw; must be between 0 and 1 (inclusive).
|
||||
* @param creativeMode True to draw the creative mode HUD, false for the survival mode version.
|
||||
* @param jammed True to show the 'glitch' effect (user for arcane jammer), false to draw normally.
|
||||
*/
|
||||
public void drawBackground(int x, int y, boolean flipX, boolean flipY, ResourceLocation icon, float cooldownBarProgress, boolean creativeMode){
|
||||
public void drawBackground(int x, int y, boolean flipX, boolean flipY, ResourceLocation icon, float cooldownBarProgress, boolean creativeMode, boolean jammed){
|
||||
|
||||
// Moves the origin if the HUD does not mirror; neatens the rest of the code.
|
||||
if(flipX && !mirrorX) x -= width;
|
||||
@@ -472,8 +560,13 @@ public class GuiSpellDisplay {
|
||||
int x1 = flipX && mirrorX ? x - spellIconInsetX - SPELL_ICON_SIZE : x + spellIconInsetX;
|
||||
// y is upside-down so this is the other way round
|
||||
int y1 = flipY && mirrorY ? y + spellIconInsetY : y - spellIconInsetY - SPELL_ICON_SIZE;
|
||||
|
||||
DrawingUtils.drawTexturedRect(x1, y1, 0, 0, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE);
|
||||
|
||||
if(jammed){
|
||||
random.setSeed(Minecraft.getMinecraft().world.getTotalWorldTime() / 2);
|
||||
DrawingUtils.drawGlitchRect(random, x1, y1, 0, 0, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE, false, false);
|
||||
}else{
|
||||
DrawingUtils.drawTexturedRect(x1, y1, 0, 0, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE, SPELL_ICON_SIZE);
|
||||
}
|
||||
|
||||
// Background of spell hud
|
||||
mc.renderEngine.bindTexture(texture);
|
||||
@@ -482,7 +575,11 @@ public class GuiSpellDisplay {
|
||||
y1 = flipY && mirrorY ? y : y - height;
|
||||
// The 128 here is a uv value, not a dimension, and hence is left as a hardcoded number.
|
||||
// TODO: Since the HUD is wider than it is tall, perhaps the creative mode texture should be in the bottom half instead of the right half?
|
||||
DrawingUtils.drawTexturedFlippedRect(x1, y1, creativeMode ? 128 : 0, 0, width, height, 256, 256, flipX && mirrorX, flipY && mirrorY);
|
||||
if(jammed){
|
||||
DrawingUtils.drawGlitchRect(random, x1, y1, creativeMode ? 128 : 0, 0, width, height, 256, 256, flipX && mirrorX, flipY && mirrorY);
|
||||
}else{
|
||||
DrawingUtils.drawTexturedFlippedRect(x1, y1, creativeMode ? 128 : 0, 0, width, height, 256, 256, flipX && mirrorX, flipY && mirrorY);
|
||||
}
|
||||
|
||||
// Cooldown bar
|
||||
if(!creativeMode && cooldownBarProgress > 0 && (showCooldownWhenFull || cooldownBarProgress < 1)){
|
||||
@@ -494,8 +591,12 @@ public class GuiSpellDisplay {
|
||||
|
||||
int u = cooldownBarX; // This doesn't change, even when cooldownBarMirrorX is true, because it should
|
||||
int v = height; // always start with the left-hand in the actual texture file
|
||||
|
||||
DrawingUtils.drawTexturedFlippedRect(x1, y1, u, v, l, cooldownBarHeight, 256, 256, flipX && cooldownBarMirrorX, flipY && cooldownBarMirrorY);
|
||||
|
||||
if(jammed){
|
||||
DrawingUtils.drawGlitchRect(random, x1, y1, u, v, l, cooldownBarHeight, 256, 256, flipX && cooldownBarMirrorX, flipY && cooldownBarMirrorY);
|
||||
}else{
|
||||
DrawingUtils.drawTexturedFlippedRect(x1, y1, u, v, l, cooldownBarHeight, 256, 256, flipX && cooldownBarMirrorX, flipY && cooldownBarMirrorY);
|
||||
}
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
/** Abstract base class for both {@link GuiSpellBook} and {@link GuiLectern}. Centralises code common to both
|
||||
* those classes. */
|
||||
public abstract class GuiSpellInfo extends GuiScreen {
|
||||
|
||||
protected static final String TRANSLATION_KEY_PREFIX = "gui." + Wizardry.MODID + ":spell_book";
|
||||
|
||||
protected final int xSize, ySize;
|
||||
protected int textureWidth = 512;
|
||||
protected int textureHeight = 256;
|
||||
|
||||
public GuiSpellInfo(int xSize, int ySize){
|
||||
super();
|
||||
this.xSize = xSize;
|
||||
this.ySize = ySize;
|
||||
}
|
||||
|
||||
protected void setTextureSize(int width, int height){
|
||||
this.textureWidth = width;
|
||||
this.textureHeight = height;
|
||||
}
|
||||
|
||||
/** Returns the spell to be displayed by this GUI. */
|
||||
public abstract Spell getSpell();
|
||||
|
||||
/** Returns the main texture for the background of this GUI. */
|
||||
public abstract ResourceLocation getTexture();
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks){
|
||||
int left = this.width/2 - xSize/2;
|
||||
int top = this.height/2 - this.ySize/2;
|
||||
this.drawDefaultBackground();
|
||||
this.drawBackgroundLayer(left, top, mouseX, mouseY);
|
||||
super.drawScreen(mouseX, mouseY, partialTicks); // Just draws the buttons
|
||||
this.drawForegroundLayer(left, top, mouseX, mouseY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the background of the spell info GUI. This is called before buttons are drawn.
|
||||
* @param left The x-coordinate of the left-hand edge of the GUI
|
||||
* @param top The y-coordinate of the top edge of the GUI
|
||||
* @param mouseX The current x position of the mouse pointer
|
||||
* @param mouseY The current y position of the mouse pointer
|
||||
*/
|
||||
protected void drawBackgroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(getSpell(), null);
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1); // Just in case
|
||||
|
||||
// Draws spell illustration on opposite page, underneath the book so it shows through the hole.
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? getSpell().getIcon() : Spells.none.getIcon());
|
||||
DrawingUtils.drawTexturedRect(left + 146, top + 20, 0, 0, 128, 128, 128, 128);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(getTexture());
|
||||
DrawingUtils.drawTexturedRect(left, top, 0, 0, xSize, ySize, textureWidth, textureHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the foreground of the spell info GUI. This is called after buttons are drawn.
|
||||
* @param left The x-coordinate of the left-hand edge of the GUI
|
||||
* @param top The y-coordinate of the top edge of the GUI
|
||||
* @param mouseX The current x position of the mouse pointer
|
||||
* @param mouseY The current y position of the mouse pointer
|
||||
*/
|
||||
protected void drawForegroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(getSpell(), null);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawString(getSpell().getDisplayName(), left + 17, top + 15, 0);
|
||||
this.fontRenderer.drawString(getSpell().getType().getDisplayName(), left + 17, top + 26, 0x777777);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(getSpell(), mc.world), left + 17,
|
||||
top + 15, 0);
|
||||
this.mc.standardGalacticFontRenderer.drawString(getSpell().getType().getDisplayName(), left + 17, top + 26,
|
||||
0x777777);
|
||||
}
|
||||
|
||||
// Novice is usually white but this doesn't show up
|
||||
String tier = I18n.format(TRANSLATION_KEY_PREFIX + ".tier", getSpell().getTier() == Tier.NOVICE ?
|
||||
"\u00A77" + getSpell().getTier().getDisplayName() : getSpell().getTier().getDisplayNameWithFormatting());
|
||||
this.fontRenderer.drawString(tier, left + 17, top + 45, 0);
|
||||
|
||||
String element = I18n.format(TRANSLATION_KEY_PREFIX + ".element", getSpell().getElement().getFormattingCode() + getSpell().getElement().getDisplayName());
|
||||
if(!discovered) element = I18n.format(TRANSLATION_KEY_PREFIX + ".element_undiscovered");
|
||||
this.fontRenderer.drawString(element, left + 17, top + 57, 0);
|
||||
|
||||
String manaCost = I18n.format(TRANSLATION_KEY_PREFIX + ".mana_cost", getSpell().getCost());
|
||||
if(getSpell().isContinuous) manaCost = I18n.format(TRANSLATION_KEY_PREFIX + ".mana_cost_continuous", getSpell().getCost());
|
||||
if(!discovered) manaCost = I18n.format(TRANSLATION_KEY_PREFIX + ".mana_cost_undiscovered");
|
||||
this.fontRenderer.drawString(manaCost, left + 17, top + 69, 0);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawSplitString(getSpell().getDescription(), left + 17, top + 83, 118, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawSplitString(
|
||||
SpellGlyphData.getGlyphDescription(getSpell(), mc.world), left + 17, top + 83, 118, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui(){
|
||||
super.initGui();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed(){
|
||||
super.onGuiClosed();
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesGuiPauseGame(){
|
||||
return Wizardry.settings.booksPauseGame;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiMerchant;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.ContainerMerchant;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.village.MerchantRecipe;
|
||||
import net.minecraft.village.MerchantRecipeList;
|
||||
import net.minecraftforge.client.event.GuiContainerEvent;
|
||||
import net.minecraftforge.client.event.GuiOpenEvent;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent.ActionPerformedEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
@EventBusSubscriber(Side.CLIENT)
|
||||
public class WizardTradeTweaksHandler {
|
||||
|
||||
private static final ResourceLocation NEW_SPELL_ICON = new ResourceLocation(Wizardry.MODID, "textures/gui/container/new_spell_indicator.png");
|
||||
|
||||
private static final int ICON_WIDTH = 8;
|
||||
private static final int ICON_HEIGHT = 8;
|
||||
|
||||
private static final int ANIMATION_FRAMES = 4;
|
||||
private static final int ANIMATION_FRAME_TIME = 2; // In ticks
|
||||
private static final int ANIMATION_PERIOD = 40; // In frame durations
|
||||
|
||||
private static int tradeIndex; // Mirrors GuiMerchant#selectedMerchantRecipe (don't want to reflect into it every frame)
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public static void onGuiOpenEvent(GuiOpenEvent event){
|
||||
if(event.getGui() instanceof GuiMerchant) tradeIndex = 0;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onActionPerformedPostEvent(ActionPerformedEvent.Post event){
|
||||
|
||||
if(event.getGui() instanceof GuiMerchant){
|
||||
|
||||
MerchantRecipeList recipes = ((GuiMerchant)event.getGui()).getMerchant().getRecipes(Minecraft.getMinecraft().player);
|
||||
|
||||
if(recipes == null) return;
|
||||
|
||||
if(event.getButton().id == 1){ // Next
|
||||
tradeIndex = Math.min(tradeIndex + 1, recipes.size());
|
||||
}else if(event.getButton().id == 2){ // Previous
|
||||
tradeIndex = Math.max(tradeIndex - 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Brute-force fix for crystals not showing up when a wizard is given a spell book in the trade GUI.
|
||||
@SubscribeEvent
|
||||
public static void onGuiDrawForegroundEvent(GuiContainerEvent.DrawForeground event){
|
||||
|
||||
if(event.getGuiContainer() instanceof GuiMerchant){
|
||||
|
||||
GuiMerchant gui = (GuiMerchant)event.getGuiContainer();
|
||||
// Note that gui.getMerchant() returns an NpcMerchant, not an EntityWizard.
|
||||
MerchantRecipeList trades = gui.getMerchant().getRecipes(Minecraft.getMinecraft().player);
|
||||
|
||||
if(trades == null) return;
|
||||
|
||||
// Using == the specific item rather than instanceof because that's how trades do it.
|
||||
if(gui.inventorySlots.getSlot(0).getStack().getItem() == WizardryItems.spell_book
|
||||
|| gui.inventorySlots.getSlot(1).getStack().getItem() == WizardryItems.spell_book){
|
||||
|
||||
for(MerchantRecipe trade : trades){
|
||||
if(trade.getItemToBuy().getItem() == WizardryItems.spell_book && trade.getSecondItemToBuy().isEmpty()){
|
||||
Slot slot = gui.inventorySlots.getSlot(2);
|
||||
// It still doesn't look quite right because the slot highlight is behind the item, but it'll do
|
||||
// until/unless I find a better solution.
|
||||
DrawingUtils.drawItemAndTooltip(gui, trade.getItemToSell(), slot.xPos, slot.yPos, event.getMouseX(), event.getMouseY(),
|
||||
gui.getSlotUnderMouse() == slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New spell indicator
|
||||
if(gui.inventorySlots instanceof ContainerMerchant){
|
||||
|
||||
// Can't use getCurrentRecipe because that only gets updated when the correct items are given
|
||||
MerchantRecipe recipe = trades.get(tradeIndex);
|
||||
|
||||
if(recipe != null && recipe.getItemToSell().getItem() instanceof ItemSpellBook){
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
Spell spell = Spell.byMetadata(recipe.getItemToSell().getMetadata());
|
||||
|
||||
if(Wizardry.settings.discoveryMode && !player.isCreative() && Wizardry.proxy.shouldDisplayDiscovered(spell, recipe.getItemToSell())
|
||||
&& WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){
|
||||
|
||||
int x = gui.inventorySlots.getSlot(2).xPos + 14;
|
||||
int y = gui.inventorySlots.getSlot(2).yPos - 17;
|
||||
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GlStateManager.color(1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(NEW_SPELL_ICON);
|
||||
|
||||
int frame = Math.max(player.ticksExisted/ANIMATION_FRAME_TIME % ANIMATION_PERIOD - (ANIMATION_PERIOD - ANIMATION_FRAMES), 0);
|
||||
DrawingUtils.drawTexturedRect(x, y, 0, frame * ICON_HEIGHT, ICON_WIDTH, ICON_HEIGHT, ICON_WIDTH, ICON_HEIGHT * ANIMATION_FRAMES);
|
||||
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
// int mouseX = event.getMouseX() - gui.getGuiLeft();
|
||||
// int mouseY = event.getMouseY() - gui.getGuiTop();
|
||||
//
|
||||
// if(mouseX >= x + 1 && mouseX < x + w + 1 && mouseY >= y - 1 && mouseY < y + h + 1){
|
||||
// GuiUtils.drawHoveringText(Collections.singletonList("You haven't discovered this spell yet"), mouseX,
|
||||
// mouseY, gui.width, gui.height, 150, Minecraft.getMinecraft().fontRenderer);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,15 +25,18 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
|
||||
private static List<IConfigElement> getConfigEntries(){
|
||||
|
||||
List<IConfigElement> configList = new ArrayList<IConfigElement>(1);
|
||||
List<IConfigElement> configList = new ArrayList<>(1);
|
||||
|
||||
configList.add(new DummyCategoryElement("gameplayConfig", "config." + Wizardry.MODID + ".category." + Settings.GAMEPLAY_CATEGORY, GameplayCategory.class));
|
||||
configList.add(new DummyCategoryElement("worldgenConfig", "config." + Wizardry.MODID + ".category." + Settings.WORLDGEN_CATEGORY, WorldgenCategory.class));
|
||||
configList.add(new DummyCategoryElement("commandsConfig", "config." + Wizardry.MODID + ".category." + Settings.COMMANDS_CATEGORY, CommandsCategory.class));
|
||||
configList.add(new DummyCategoryElement("clientConfig", "config." + Wizardry.MODID + ".category." + Settings.CLIENT_CATEGORY, ClientCategory.class));
|
||||
configList.add(new DummyCategoryElement("spellsConfig", "config." + Wizardry.MODID + ".category." + Settings.SPELLS_CATEGORY, SpellsCategory.class));
|
||||
configList.add(new DummyCategoryElement("resistancesConfig", "config." + Wizardry.MODID + ".category." + Settings.RESISTANCES_CATEGORY, ResistancesCategory.class));
|
||||
configList.add(new DummyCategoryElement("compatibilityConfig", "config." + Wizardry.MODID + ".category." + Settings.COMPATIBILITY_CATEGORY, CompatibilityCategory.class));
|
||||
configList.add(new DummyCategoryElement("gameplayConfig", "config." + Wizardry.MODID + ".category." + Settings.GAMEPLAY_CATEGORY, GameplayCategory.class));
|
||||
configList.add(new DummyCategoryElement("difficultyConfig", "config." + Wizardry.MODID + ".category." + Settings.DIFFICULTY_CATEGORY, DifficultyCategory.class));
|
||||
configList.add(new DummyCategoryElement("worldgenConfig", "config." + Wizardry.MODID + ".category." + Settings.WORLDGEN_CATEGORY, WorldgenCategory.class));
|
||||
configList.add(new DummyCategoryElement("tweaksConfig", "config." + Wizardry.MODID + ".category." + Settings.TWEAKS_CATEGORY, TweaksCategory.class));
|
||||
configList.add(new DummyCategoryElement("commandsConfig", "config." + Wizardry.MODID + ".category." + Settings.COMMANDS_CATEGORY, CommandsCategory.class));
|
||||
configList.add(new DummyCategoryElement("clientConfig", "config." + Wizardry.MODID + ".category." + Settings.CLIENT_CATEGORY, ClientCategory.class));
|
||||
configList.add(new DummyCategoryElement("spellsConfig", "config." + Wizardry.MODID + ".category." + Settings.SPELLS_CATEGORY, SpellsCategory.class));
|
||||
configList.add(new DummyCategoryElement("artefactsConfig", "config." + Wizardry.MODID + ".category." + Settings.ARTEFACTS_CATEGORY, ArtefactsCategory.class));
|
||||
configList.add(new DummyCategoryElement("resistancesConfig", "config." + Wizardry.MODID + ".category." + Settings.RESISTANCES_CATEGORY, ResistancesCategory.class));
|
||||
configList.add(new DummyCategoryElement("compatibilityConfig", "config." + Wizardry.MODID + ".category." + Settings.COMPATIBILITY_CATEGORY, CompatibilityCategory.class));
|
||||
|
||||
configList.addAll(new ConfigElement(Wizardry.settings.getConfigCategory(Configuration.CATEGORY_GENERAL)).getChildElements());
|
||||
|
||||
@@ -79,6 +82,16 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
@Override protected String getCategory() { return Settings.GAMEPLAY_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Difficulty category of the config gui. */
|
||||
public static class DifficultyCategory extends CategoryBase {
|
||||
|
||||
public DifficultyCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.DIFFICULTY_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Worldgen category of the config gui. */
|
||||
public static class WorldgenCategory extends CategoryBase {
|
||||
|
||||
@@ -89,6 +102,16 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
@Override protected String getCategory() { return Settings.WORLDGEN_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Tweaks category of the config gui. */
|
||||
public static class TweaksCategory extends CategoryBase {
|
||||
|
||||
public TweaksCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.TWEAKS_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Commands category of the config gui. */
|
||||
public static class CommandsCategory extends CategoryBase {
|
||||
|
||||
@@ -119,6 +142,16 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
@Override protected String getCategory() { return Settings.SPELLS_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Artefacts category of the config gui. */
|
||||
public static class ArtefactsCategory extends CategoryBase {
|
||||
|
||||
public ArtefactsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.ARTEFACTS_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Resistances category of the config gui. */
|
||||
public static class ResistancesCategory extends CategoryBase {
|
||||
|
||||
|
||||
@@ -65,15 +65,15 @@ public class GuiSelectHUDSkin extends GuiSelectString {
|
||||
float scale = Math.min((previewRight - previewLeft - 2*previewBorder)/(float)skin.getWidth(),
|
||||
(previewBottom - previewTop - 2*previewBorder)/(float)skin.getHeight());
|
||||
|
||||
float x = (previewLeft + previewRight)/2 - (skin.getWidth()*scale)/2;
|
||||
float y = (previewBottom + previewTop)/2 + (skin.getHeight()*scale)/2;
|
||||
float x = (previewLeft + previewRight)/2f - (skin.getWidth()*scale)/2;
|
||||
float y = (previewBottom + previewTop)/2f + (skin.getHeight()*scale)/2;
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
|
||||
skin.drawBackground((int)(x/scale), (int)(y/scale), false, false,
|
||||
Spells.magic_missile.getIcon(), 0.6f, false);
|
||||
Spells.magic_missile.getIcon(), 0.6f, false, false);
|
||||
|
||||
skin.drawText((int)(x/scale), (int)(y/scale), false, false,
|
||||
Spells.none.getDisplayNameWithFormatting(),
|
||||
|
||||
@@ -3,7 +3,7 @@ package electroblob.wizardry.client.gui.handbook;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.JavaUtils;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
@@ -50,7 +50,7 @@ class Contents {
|
||||
|
||||
/** Returns an unmodifiable, flattened collection of all the buttons in this contents. */
|
||||
Collection<GuiButton> getButtons(){
|
||||
return WizardryUtilities.flatten(buttons);
|
||||
return JavaUtils.flatten(buttons);
|
||||
}
|
||||
|
||||
void addEntry(Section section){
|
||||
|
||||
@@ -8,7 +8,8 @@ import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.ClientProxy;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.client.gui.GuiButtonInvisible;
|
||||
import electroblob.wizardry.client.gui.handbook.GuiButtonTurnPage.Type;
|
||||
import electroblob.wizardry.client.gui.GuiButtonTurnPage;
|
||||
import electroblob.wizardry.client.gui.GuiButtonTurnPage.Type;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
@@ -34,6 +35,7 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of
|
||||
@@ -53,7 +55,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json");
|
||||
|
||||
static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
|
||||
static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook/handbook.png");
|
||||
|
||||
/** Global Gson instance for the handbook. */
|
||||
private static final Gson gson = new Gson();
|
||||
@@ -184,7 +186,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge);
|
||||
addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge);
|
||||
addFormatTag("version", Wizardry.VERSION);
|
||||
addFormatTag("mcversion", Minecraft.getMinecraft().getVersion());
|
||||
addFormatTag("mcversion", "1.12.2");
|
||||
|
||||
addFormatTag("colour_novice", "\u00A77");
|
||||
addFormatTag("colour_apprentice", Tier.APPRENTICE.getFormattingCode());
|
||||
@@ -243,6 +245,8 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
this.drawDefaultBackground();
|
||||
|
||||
int left = this.width / 2 - GUI_WIDTH / 2;
|
||||
int top = this.height / 2 - GUI_HEIGHT / 2;
|
||||
|
||||
@@ -348,19 +352,19 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
this.buttonList.clear();
|
||||
|
||||
this.buttonList.add(next = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH - BUTTON_INSET_X - GuiButtonTurnPage.WIDTH,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_PAGE));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_PAGE, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(previous = new GuiButtonTurnPage(nextButtonId++, left + BUTTON_INSET_X,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_PAGE));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_PAGE, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(nextSection = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH - BUTTON_INSET_X - GuiButtonTurnPage.WIDTH - BUTTON_SPACING,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_SECTION));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_SECTION, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(previousSection = new GuiButtonTurnPage(nextButtonId++, left + BUTTON_INSET_X + BUTTON_SPACING,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_SECTION));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_SECTION, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(menu = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH/2 - 28,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.CONTENTS));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.CONTENTS, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(bookmark = new GuiButtonInvisible(nextButtonId++, left + 130, top + 172, 11, 19) {
|
||||
@Override
|
||||
@@ -397,6 +401,11 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
*/
|
||||
public static void loadHandbookFile(IResourceManager manager){
|
||||
|
||||
if(manager == null){
|
||||
Wizardry.logger.error("Tried to reload the handbook file, but received a null resource manager. Aborting!");
|
||||
return;
|
||||
}
|
||||
|
||||
IResource handbookFile = getHandbookResource(manager);
|
||||
|
||||
if(handbookFile != null){
|
||||
@@ -409,7 +418,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
bookmarkSection = null; // Also need to wipe the reference to the old bookmarked section
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream()));
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream(), StandardCharsets.UTF_8));
|
||||
|
||||
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
||||
JsonObject json = je.getAsJsonObject();
|
||||
@@ -561,4 +570,4 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
sections.values().forEach(s -> s.updateUnlockStatus(showToasts, completedAdvancements));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.JavaUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
@@ -63,7 +63,7 @@ class Section {
|
||||
}
|
||||
|
||||
Collection<GuiButton> getButtons(){
|
||||
return WizardryUtilities.flatten(buttons);
|
||||
return JavaUtils.flatten(buttons);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BakedModelBookshelf implements IBakedModel {
|
||||
|
||||
private final IBakedModel bookshelf;
|
||||
private final IBakedModel[][] books;
|
||||
|
||||
public BakedModelBookshelf(IBakedModel bookshelf, IBakedModel[][] books){
|
||||
this.bookshelf = bookshelf;
|
||||
this.books = books;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand){
|
||||
|
||||
IBakedModel fallback = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes().getModelManager().getMissingModel();
|
||||
if(state == null) return fallback.getQuads(null, side, rand);
|
||||
|
||||
// It took me waaay too long to realise I needed a new list here
|
||||
List<BakedQuad> quads = new ArrayList<>(bookshelf.getQuads(state, side, rand)); // Lists ain't immutable, chief
|
||||
|
||||
IExtendedBlockState extendedState = (IExtendedBlockState)state;
|
||||
|
||||
for(int i = 0; i<BlockBookshelf.SLOT_COUNT; i++){
|
||||
Integer value = extendedState.getValue(BlockBookshelf.BOOKS[i]);
|
||||
if(value == null || value < 0) return fallback.getQuads(null, side, rand);
|
||||
if(value < books.length) quads.addAll(books[value][i].getQuads(state, side, rand)); // Empty slots use books.length
|
||||
}
|
||||
|
||||
return quads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer(){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delegate everything else to the main bookshelf model
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion(){
|
||||
return bookshelf.isAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d(){
|
||||
return bookshelf.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture(){
|
||||
return bookshelf.getParticleTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides(){
|
||||
return bookshelf.getOverrides();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.*;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A special type of model that generates override models dynamically. This allows the same overrides to be applied to
|
||||
* multiple item models without needing an override version of each one just to point to a texture.
|
||||
* <p></p>
|
||||
* To use this system in a model file:<p></p>
|
||||
* 1. Make a base model file and define the item overrides in it. <b>This model must be placed in the folder
|
||||
* {@code models/item/override_generators}</b> (unfortunately the folder has to be predefined, see below).<br>
|
||||
* 2. Make the model files your overrides point to. These should define everything about the model except textures.<br>
|
||||
* 3. In each model that should generate overrides dynamically, define a single override that points to the location of
|
||||
* the model from step 1 (the predicate doesn't matter).<br>
|
||||
* <p></p>
|
||||
* It is advisable to make the parent of the override model (from step 2) the same as the parent of the model to
|
||||
* be overridden, so that they share any necessary properties and texture variables. For example, both
|
||||
* {@code ebwizardry:item/magic_wand.json} and {@code ebwizardry:item/wand_point.json} have {@code item/handheld} as
|
||||
* their parent. The override model will reference the textures in the original model, so if the override defines a
|
||||
* face with the texture {@code "#face"}, the texture used will be the file associated with {@code "face"} in the
|
||||
* original model. For simple models, this will just be the standard {@code "layer0"}.
|
||||
* @since Wizardry 4.3
|
||||
* @author Electroblob
|
||||
*/
|
||||
// Okay, it's not *that* bad if you only have one override, but imagine having to duplicate every single wand model 5
|
||||
// times if we wanted 5 animations...
|
||||
// The nice thing is resource packs don't lose any flexibility this way, they can still redefine the models themselves
|
||||
// and specify custom models for the overrides if they want, or they can keep using this system - in fact, they GAIN
|
||||
// flexibility because they can also overwrite the base wand.json model and specify global overrides too
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class BakedModelGenerateOverrides implements IBakedModel {
|
||||
|
||||
// I tried having this as a prefix that gets removed at runtime, which worked fine but it spammed the log with
|
||||
// errors because the prefixed file doesn't actually exist, so even though it's never used the game still complains
|
||||
private static final String OVERRIDE_GENERATORS = "override_generators";
|
||||
|
||||
private final IBakedModel delegate;
|
||||
private final ItemOverrideList overrides;
|
||||
|
||||
public BakedModelGenerateOverrides(IBakedModel delegate, ItemOverrideList overrides){
|
||||
this.delegate = delegate;
|
||||
this.overrides = overrides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides(){
|
||||
return overrides; // The only thing that's not delegated
|
||||
}
|
||||
|
||||
// Delegate everything else
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand){
|
||||
return delegate.getQuads(state, side, rand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion(){
|
||||
return delegate.isAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d(){
|
||||
return delegate.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer(){
|
||||
return delegate.isBuiltInRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture(){
|
||||
return delegate.getParticleTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCameraTransforms getItemCameraTransforms(){
|
||||
return delegate.getItemCameraTransforms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion(IBlockState state){
|
||||
return delegate.isAmbientOcclusion(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(ItemCameraTransforms.TransformType cameraTransformType){
|
||||
return delegate.handlePerspective(cameraTransformType);
|
||||
}
|
||||
|
||||
// Baking
|
||||
|
||||
@SubscribeEvent
|
||||
public static void bake(ModelBakeEvent event){
|
||||
|
||||
for(ModelResourceLocation location : event.getModelRegistry().getKeys()){
|
||||
|
||||
IBakedModel original = event.getModelRegistry().getObject(location);
|
||||
|
||||
if(original != null){
|
||||
original.getOverrides().getOverrides().stream().map(ItemOverride::getLocation)
|
||||
.filter(l -> l.getPath().contains(OVERRIDE_GENERATORS)).findFirst()
|
||||
.ifPresent(l -> event.getModelRegistry().putObject(location,
|
||||
substituteWandModel(event.getModelManager(), location, original, l)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have to use ModelBakeEvent for this because we need the original model to be baked with the vanilla system
|
||||
private static IBakedModel substituteWandModel(ModelManager modelManager, ModelResourceLocation location, IBakedModel original, ResourceLocation overrideLocation){
|
||||
|
||||
try {
|
||||
|
||||
IModel unbakedOriginal = ModelLoaderRegistry.getModel(location);
|
||||
IModel referenceModel = ModelLoaderRegistry.getModel(overrideLocation);
|
||||
ModelBlock vanillaOriginal = unbakedOriginal.asVanillaModel().orElse(null);
|
||||
ModelBlock vanillaRefModel = referenceModel.asVanillaModel().orElse(null);
|
||||
|
||||
if(vanillaOriginal != null && vanillaRefModel != null){
|
||||
|
||||
// So... many... data structures...
|
||||
List<ItemOverride> overrides = vanillaRefModel.getOverrides();
|
||||
Map<ResourceLocation, IBakedModel> replacementMap = new HashMap<>();
|
||||
|
||||
for(ItemOverride override : overrides){
|
||||
IModel replacement = ModelLoaderRegistry.getModel(override.getLocation()).retexture(ImmutableMap.copyOf(vanillaOriginal.textures));
|
||||
replacementMap.put(override.getLocation(), replacement.bake(unbakedOriginal.getDefaultState(), DefaultVertexFormats.ITEM, ModelLoader.defaultTextureGetter()));
|
||||
}
|
||||
|
||||
ItemOverrideListMapped overrideList = new ItemOverrideListMapped(overrides, replacementMap);
|
||||
return new BakedModelGenerateOverrides(original, overrideList);
|
||||
}
|
||||
|
||||
}catch(Exception exception){
|
||||
Wizardry.logger.error("Error baking item display override models: ", exception);
|
||||
}
|
||||
|
||||
return modelManager.getMissingModel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
* <br>
|
||||
* <i>N.B. This doesn't cover item models, and all of the code/model solutions to this that I have tried haven't worked.
|
||||
* However, I noticed that the shade tag seems to work perfectly for items, so instead I've simply duplicated the block
|
||||
* models into the item models folder and add {@code "shade":false} where appropriate. (If it works, it works, right?)</i>
|
||||
* models into the item models folder and add {@code "shade":false} where appropriate. (If it works, it works, right?)</i>
|
||||
*
|
||||
* @author Electroblob
|
||||
* @author raoulvdberge
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverride;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/** A version of {@link ItemOverrideList} that uses a predefined map to substitute a specific baked model depending on
|
||||
* the location the currently-applicable override points to. */
|
||||
public class ItemOverrideListMapped extends ItemOverrideList {
|
||||
|
||||
private final Map<ResourceLocation, IBakedModel> replacementMap;
|
||||
|
||||
public ItemOverrideListMapped(List<ItemOverride> overrides, Map<ResourceLocation, IBakedModel> replacementMap){
|
||||
super(overrides);
|
||||
this.replacementMap = ImmutableMap.copyOf(replacementMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity){
|
||||
|
||||
if(!stack.isEmpty() && stack.getItem().hasCustomProperties()){
|
||||
|
||||
// Get the location the original override points to...
|
||||
ResourceLocation location = applyOverride(stack, world, entity); // I wonder why this is deprecated?
|
||||
|
||||
if(location != null){
|
||||
return replacementMap.get(location); // ... then substitute in the corresponding generated model
|
||||
}
|
||||
}
|
||||
|
||||
return originalModel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ModelBookshelf implements IModel {
|
||||
|
||||
private static final ResourceLocation DEFAULT_BOOK_TEXTURE = new ResourceLocation(Wizardry.MODID, "blocks/books");
|
||||
|
||||
private static final List<ResourceLocation> bookModelLocations = new ArrayList<>();
|
||||
|
||||
private final ModelResourceLocation bookshelfModelLocation;
|
||||
private final String variant;
|
||||
|
||||
static {
|
||||
for(int i = 0; i < BlockBookshelf.SLOT_COUNT; i++){
|
||||
bookModelLocations.add(new ResourceLocation(Wizardry.MODID, "bookshelf_parts/books" + i));
|
||||
}
|
||||
}
|
||||
|
||||
public ModelBookshelf(String bookshelfModelName){
|
||||
String[] args = bookshelfModelName.split("#", 2);
|
||||
String model = args[0];
|
||||
variant = args.length == 2 ? args[1] : null;
|
||||
bookshelfModelLocation = new ModelResourceLocation(new ResourceLocation(Wizardry.MODID, "bookshelf_parts/" + model), variant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter){
|
||||
|
||||
try {
|
||||
|
||||
IModel bookshelfModel = ModelLoaderRegistry.getModel(bookshelfModelLocation);
|
||||
// I don't know why default state works here (surely it ought to be the state param?), but it works so who cares
|
||||
IBakedModel bookshelf = bookshelfModel.bake(bookshelfModel.getDefaultState(), format, bakedTextureGetter);
|
||||
|
||||
ImmutableList<ResourceLocation> textures = BlockBookshelf.getBookTextures();
|
||||
|
||||
IBakedModel[][] books = new IBakedModel[textures.size()][BlockBookshelf.SLOT_COUNT];
|
||||
|
||||
for(int i = 0; i < textures.size(); i++){
|
||||
|
||||
ImmutableMap<String, String> retexturer = ImmutableMap.of("books", textures.get(i).toString());
|
||||
|
||||
for(int j = 0; j < BlockBookshelf.SLOT_COUNT; j++){
|
||||
IModel bookModel = ModelLoaderRegistry.getModel(new ModelResourceLocation(bookModelLocations.get(j), variant)).retexture(retexturer);
|
||||
books[i][j] = bookModel.bake(bookModel.getDefaultState(), format, bakedTextureGetter); // Same here!
|
||||
}
|
||||
}
|
||||
|
||||
// To clarify: the whole point of doing this was to avoid having to bake 4 * 2^12 models per bookshelf type
|
||||
// Therefore we have to have a baked bookshelf model that's kind of dynamic
|
||||
return new BakedModelBookshelf(bookshelf, books);
|
||||
|
||||
}catch(Exception exception){
|
||||
Wizardry.logger.error("Error baking bookshelf models: ", exception);
|
||||
return ModelLoaderRegistry.getMissingModel().bake(state, format, bakedTextureGetter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies(){
|
||||
return bookModelLocations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures(){
|
||||
|
||||
// I simply have no idea how I'm *supposed* to do it, so I'm using the best solution I can come up with
|
||||
// This is at least better than manually registering it with TextureStitchEvent
|
||||
// However I'm also pretty sure that if a texture pack decides to change the texture that the book models point
|
||||
// to, it won't work... but since nobody ever will, I don't really care!
|
||||
|
||||
// Why am I confused?
|
||||
// 1. How come it magically finds the bookshelf texture, but not the book texture?
|
||||
// 2. Why don't the textures get retrieved automatically based on getDependencies? Surely that's the point?
|
||||
// 3. Is it correct to use getModel() to get the dependency models upon construction of this class so I can
|
||||
// access their textures properly? Or is that too early?
|
||||
// 4. If so, what's the point of getDependencies, and why should I override it?
|
||||
return BlockBookshelf.getBookTextures();// ImmutableList.of(DEFAULT_BOOK_TEXTURE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelBox;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
// Made with Blockbench 3.5.2
|
||||
public class ModelBoulder extends ModelBase {
|
||||
|
||||
private final ModelRenderer mainGroup;
|
||||
private final ModelRenderer box1;
|
||||
private final ModelRenderer box2;
|
||||
private final ModelRenderer box3;
|
||||
private final ModelRenderer box4;
|
||||
private final ModelRenderer box5;
|
||||
private final ModelRenderer box6;
|
||||
|
||||
public ModelBoulder(){
|
||||
|
||||
textureWidth = 64;
|
||||
textureHeight = 32;
|
||||
|
||||
mainGroup = new ModelRenderer(this);
|
||||
mainGroup.setRotationPoint(0.0F, 24.0F, 0.0F);
|
||||
|
||||
box1 = new ModelRenderer(this);
|
||||
box1.setRotationPoint(0.0F, -19.0F, 0.0F);
|
||||
mainGroup.addChild(box1);
|
||||
box1.cubeList.add(new ModelBox(box1, 0, 0, -11.0F, -11.0F, 11.0F, 22, 22, 8, 0.0F, false));
|
||||
|
||||
box2 = new ModelRenderer(this);
|
||||
box2.setRotationPoint(0.0F, -19.0F, 0.0F);
|
||||
mainGroup.addChild(box2);
|
||||
setRotationAngle(box2, -1.5708F, 0.0F, 0.0F);
|
||||
box2.cubeList.add(new ModelBox(box2, 0, 0, -11.0F, -11.0F, 11.0F, 22, 22, 8, 0.0F, false));
|
||||
|
||||
box3 = new ModelRenderer(this);
|
||||
box3.setRotationPoint(0.0F, -19.0F, 0.0F);
|
||||
mainGroup.addChild(box3);
|
||||
setRotationAngle(box3, 0.0F, -1.5708F, 0.0F);
|
||||
box3.cubeList.add(new ModelBox(box3, 0, 0, -11.0F, -11.0F, 11.0F, 22, 22, 8, 0.0F, false));
|
||||
|
||||
box4 = new ModelRenderer(this);
|
||||
box4.setRotationPoint(0.0F, -19.0F, 0.0F);
|
||||
mainGroup.addChild(box4);
|
||||
setRotationAngle(box4, 0.0F, 1.5708F, 0.0F);
|
||||
box4.cubeList.add(new ModelBox(box4, 0, 0, -11.0F, -11.0F, 11.0F, 22, 22, 8, 0.0F, false));
|
||||
|
||||
box5 = new ModelRenderer(this);
|
||||
box5.setRotationPoint(0.0F, -19.0F, 0.0F);
|
||||
mainGroup.addChild(box5);
|
||||
setRotationAngle(box5, 1.5708F, 0.0F, 0.0F);
|
||||
box5.cubeList.add(new ModelBox(box5, 0, 0, -11.0F, -11.0F, 11.0F, 22, 22, 8, 0.0F, false));
|
||||
|
||||
box6 = new ModelRenderer(this);
|
||||
box6.setRotationPoint(0.0F, -19.0F, 0.0F);
|
||||
mainGroup.addChild(box6);
|
||||
setRotationAngle(box6, 3.1416F, 0.0F, 0.0F);
|
||||
box6.cubeList.add(new ModelBox(box6, 0, 0, -11.0F, -11.0F, 11.0F, 22, 22, 8, 0.0F, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
|
||||
mainGroup.render(f5);
|
||||
}
|
||||
|
||||
public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z){
|
||||
modelRenderer.rotateAngleX = x;
|
||||
modelRenderer.rotateAngleY = y;
|
||||
modelRenderer.rotateAngleZ = z;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelBox;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
||||
// Made with Blockbench 3.5.4
|
||||
public class ModelIceBarrier extends ModelBase {
|
||||
|
||||
private final ModelRenderer mainGroup;
|
||||
|
||||
public ModelIceBarrier(){
|
||||
|
||||
textureWidth = 64;
|
||||
textureHeight = 64;
|
||||
|
||||
mainGroup = new ModelRenderer(this);
|
||||
mainGroup.setRotationPoint(0.0F, 24.0F, 0.0F);
|
||||
setRotationAngle(mainGroup, 0.0F, 0.0F, 0.7854F);
|
||||
mainGroup.cubeList.add(new ModelBox(mainGroup, 0, 0, -14.5F, -14.5F, -1.5F, 29, 29, 3, 0.0F, false));
|
||||
mainGroup.cubeList.add(new ModelBox(mainGroup, 0, 32, -9.0F, -9.0F, -4.0F, 18, 18, 8, 0.0F, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {
|
||||
mainGroup.render(f5);
|
||||
}
|
||||
|
||||
public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) {
|
||||
modelRenderer.rotateAngleX = x;
|
||||
modelRenderer.rotateAngleY = y;
|
||||
modelRenderer.rotateAngleZ = z;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ICustomModelLoader;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
|
||||
public class ModelLoaderBookshelf implements ICustomModelLoader {
|
||||
|
||||
private static final String SMART_MODEL_PREFIX = "models/block/smart_model/";
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager){
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accepts(ResourceLocation modelLocation){
|
||||
return modelLocation.getNamespace().equals(Wizardry.MODID) && modelLocation.getPath().startsWith(SMART_MODEL_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModel loadModel(ResourceLocation modelLocation){
|
||||
return new ModelBookshelf(modelLocation.getPath().substring(SMART_MODEL_PREFIX.length()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
/** Based on ModelEnderCrystal */
|
||||
public class ModelRemnant extends ModelBase {
|
||||
|
||||
private final ModelRenderer cube = new ModelRenderer(this, "cube");
|
||||
|
||||
public ModelRemnant(){
|
||||
this.cube.setTextureOffset(0, 0).addBox(-4.0F, -4.0F, -4.0F, 8, 8, 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Entity entity, float rotationSpeed, float expandFraction, float age, float netHeadYaw, float headPitch, float scale){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
// GlStateManager.scale(2.0F, 2.0F, 2.0F);
|
||||
// GlStateManager.translate(0.0F, -0.5F, 0.0F);
|
||||
|
||||
GlStateManager.disableCull();
|
||||
|
||||
GlStateManager.translate(0.0F, entity.height/2, 0.0F);
|
||||
|
||||
float s = expandFraction + MathHelper.sin(age * 0.1f) * 0.06f;
|
||||
|
||||
GlStateManager.scale(s, s, s);
|
||||
|
||||
GlStateManager.rotate(age * rotationSpeed/2, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(60.0F, 0.7071F, 0.0F, 0.7071F);
|
||||
GlStateManager.rotate(age * rotationSpeed, 0.0F, 1.0F, 0.0F);
|
||||
this.cube.render(scale);
|
||||
|
||||
GlStateManager.scale(0.875F, 0.875F, 0.875F);
|
||||
GlStateManager.rotate(60.0F, 0.7071F, 0.0F, 0.7071F);
|
||||
GlStateManager.rotate(age * rotationSpeed, 0.0F, 1.0F, 0.0F);
|
||||
this.cube.render(scale);
|
||||
|
||||
GlStateManager.enableCull();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockStatue;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -13,6 +14,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
ModelRenderer hatSegment4;
|
||||
ModelRenderer hatSegment5;
|
||||
ModelRenderer hatSegment6;
|
||||
ModelRenderer hatBobble;
|
||||
ModelRenderer robe;
|
||||
|
||||
public ModelWizardArmour(float delta){
|
||||
@@ -75,6 +77,13 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
hatSegment6.mirror = true;
|
||||
setRotation(hatSegment6, -0.5585054F, 0F, 0F);
|
||||
|
||||
hatBobble = new ModelRenderer(this, 52, 47);
|
||||
hatBobble.addBox(0F, 0F, 0F, 3, 3, 3);
|
||||
hatBobble.setRotationPoint(-1.5F, -15.1F, 4F);
|
||||
hatBobble.setTextureSize(64, 64);
|
||||
hatBobble.mirror = true;
|
||||
setRotation(hatBobble, -0.65F, 0F, 0F);
|
||||
|
||||
bipedBody = new ModelRenderer(this, 16, 16);
|
||||
bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta);
|
||||
bipedBody.setRotationPoint(0F, 0F, 0F);
|
||||
@@ -97,6 +106,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
bipedHead.addChild(hatSegment4);
|
||||
bipedHead.addChild(hatSegment5);
|
||||
bipedHead.addChild(hatSegment6);
|
||||
bipedHead.addChild(hatBobble);
|
||||
}
|
||||
|
||||
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
|
||||
@@ -129,6 +139,8 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
this.robe.rotateAngleX = (this.bipedLeftLeg.rotateAngleX + this.bipedRightLeg.rotateAngleX) / 2f;
|
||||
this.robe.rotateAngleY = this.bipedBody.rotateAngleY;
|
||||
this.robe.rotateAngleZ = (this.bipedLeftLeg.rotateAngleZ + this.bipedRightLeg.rotateAngleZ) / 2f;
|
||||
|
||||
this.hatBobble.showModel = Wizardry.tisTheSeason;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ import electroblob.wizardry.block.BlockCrystal;
|
||||
import electroblob.wizardry.block.BlockPedestal;
|
||||
import electroblob.wizardry.block.BlockRunestone;
|
||||
import electroblob.wizardry.item.IMultiTexturedItem;
|
||||
import electroblob.wizardry.item.ItemBlockMultiTexturedElemental;
|
||||
import electroblob.wizardry.item.ItemBlockMultiTextured;
|
||||
import electroblob.wizardry.item.ItemCrystal;
|
||||
import electroblob.wizardry.item.ItemSpectralDust;
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import net.minecraft.block.BlockPlanks;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.block.statemap.StateMap;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
@@ -19,11 +22,15 @@ import net.minecraft.util.NonNullList;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.client.event.ModelRegistryEvent;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class responsible for registering all of wizardry's item and block models.
|
||||
*
|
||||
@@ -36,233 +43,94 @@ public final class WizardryModels {
|
||||
|
||||
private WizardryModels(){} // No instances!
|
||||
|
||||
/** Keeps track of all items whose models have been registered manually to exclude them from automatic registry of
|
||||
* standard item models. Internal only, this gets cleared once model registry is complete. */
|
||||
private static final List<Item> registeredItems = new ArrayList<>();
|
||||
|
||||
@SubscribeEvent
|
||||
public static void register(ModelRegistryEvent event){
|
||||
|
||||
// ItemBlocks
|
||||
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.arcane_workbench));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_ore));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.crystal_flower));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.transportation_stone));
|
||||
|
||||
ModelLoader.setCustomStateMapper(WizardryBlocks.crystal_block, new StateMap.Builder()
|
||||
.withName(BlockCrystal.ELEMENT).withSuffix("_crystal_block").build());
|
||||
// Yay unchecked casting! But we know it's always ok here, and it makes everything much neater.
|
||||
ItemBlockMultiTexturedElemental crystalBlockItem = (ItemBlockMultiTexturedElemental)Item.getItemFromBlock(WizardryBlocks.crystal_block);
|
||||
ItemBlockMultiTextured crystalBlockItem = (ItemBlockMultiTextured)Item.getItemFromBlock(WizardryBlocks.crystal_block);
|
||||
registerMultiTexturedModel(crystalBlockItem);
|
||||
|
||||
ModelLoader.setCustomStateMapper(WizardryBlocks.runestone, new StateMap.Builder()
|
||||
.withName(BlockRunestone.ELEMENT).withSuffix("_runestone").build());
|
||||
ItemBlockMultiTexturedElemental runestoneItem = (ItemBlockMultiTexturedElemental)Item.getItemFromBlock(WizardryBlocks.runestone);
|
||||
ItemBlockMultiTextured runestoneItem = (ItemBlockMultiTextured)Item.getItemFromBlock(WizardryBlocks.runestone);
|
||||
registerMultiTexturedModel(runestoneItem);
|
||||
|
||||
ModelLoader.setCustomStateMapper(WizardryBlocks.runestone_pedestal, new StateMap.Builder()
|
||||
.withName(BlockPedestal.ELEMENT).ignore(BlockPedestal.NATURAL).withSuffix("_runestone_pedestal").build()); // Don't care about NATURAL property
|
||||
ItemBlockMultiTexturedElemental pedestalItem = (ItemBlockMultiTexturedElemental)Item.getItemFromBlock(WizardryBlocks.runestone_pedestal);
|
||||
ItemBlockMultiTextured pedestalItem = (ItemBlockMultiTextured)Item.getItemFromBlock(WizardryBlocks.runestone_pedestal);
|
||||
registerMultiTexturedModel(pedestalItem);
|
||||
|
||||
ModelLoader.setCustomStateMapper(WizardryBlocks.gilded_wood, new StateMap.Builder()
|
||||
.withName(BlockPlanks.VARIANT).withSuffix("_gilded_wood").build());
|
||||
ItemBlockMultiTextured gildedWoodItem = (ItemBlockMultiTextured)Item.getItemFromBlock(WizardryBlocks.gilded_wood);
|
||||
registerMultiTexturedModel(gildedWoodItem);
|
||||
|
||||
// Explanation for all this here -> https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe05_block_dynamic_block_model2
|
||||
ModelLoaderRegistry.registerLoader(new ModelLoaderBookshelf());
|
||||
|
||||
// Items
|
||||
|
||||
registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal);
|
||||
|
||||
registerItemModel(WizardryItems.magic_wand);
|
||||
registerItemModel(WizardryItems.apprentice_wand);
|
||||
registerItemModel(WizardryItems.advanced_wand);
|
||||
registerItemModel(WizardryItems.master_wand);
|
||||
registerWandModel(WizardryItems.magic_wand);
|
||||
registerWandModel(WizardryItems.apprentice_wand);
|
||||
registerWandModel(WizardryItems.advanced_wand);
|
||||
registerWandModel(WizardryItems.master_wand);
|
||||
|
||||
registerItemModel(WizardryItems.spell_book);
|
||||
registerItemModel(WizardryItems.spell_book); // Also need this or auto-registry will ignore it
|
||||
// Wildcard registered for wizard trades.
|
||||
registerItemModel(WizardryItems.spell_book, OreDictionary.WILDCARD_VALUE, "normal");
|
||||
registerItemModel(WizardryItems.arcane_tome);
|
||||
registerItemModel(WizardryItems.wizard_handbook);
|
||||
|
||||
registerItemModel(WizardryItems.novice_fire_wand);
|
||||
registerItemModel(WizardryItems.novice_ice_wand);
|
||||
registerItemModel(WizardryItems.novice_lightning_wand);
|
||||
registerItemModel(WizardryItems.novice_necromancy_wand);
|
||||
registerItemModel(WizardryItems.novice_earth_wand);
|
||||
registerItemModel(WizardryItems.novice_sorcery_wand);
|
||||
registerItemModel(WizardryItems.novice_healing_wand);
|
||||
registerWandModel(WizardryItems.novice_fire_wand);
|
||||
registerWandModel(WizardryItems.novice_ice_wand);
|
||||
registerWandModel(WizardryItems.novice_lightning_wand);
|
||||
registerWandModel(WizardryItems.novice_necromancy_wand);
|
||||
registerWandModel(WizardryItems.novice_earth_wand);
|
||||
registerWandModel(WizardryItems.novice_sorcery_wand);
|
||||
registerWandModel(WizardryItems.novice_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.apprentice_fire_wand);
|
||||
registerItemModel(WizardryItems.apprentice_ice_wand);
|
||||
registerItemModel(WizardryItems.apprentice_lightning_wand);
|
||||
registerItemModel(WizardryItems.apprentice_necromancy_wand);
|
||||
registerItemModel(WizardryItems.apprentice_earth_wand);
|
||||
registerItemModel(WizardryItems.apprentice_sorcery_wand);
|
||||
registerItemModel(WizardryItems.apprentice_healing_wand);
|
||||
registerWandModel(WizardryItems.apprentice_fire_wand);
|
||||
registerWandModel(WizardryItems.apprentice_ice_wand);
|
||||
registerWandModel(WizardryItems.apprentice_lightning_wand);
|
||||
registerWandModel(WizardryItems.apprentice_necromancy_wand);
|
||||
registerWandModel(WizardryItems.apprentice_earth_wand);
|
||||
registerWandModel(WizardryItems.apprentice_sorcery_wand);
|
||||
registerWandModel(WizardryItems.apprentice_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.advanced_fire_wand);
|
||||
registerItemModel(WizardryItems.advanced_ice_wand);
|
||||
registerItemModel(WizardryItems.advanced_lightning_wand);
|
||||
registerItemModel(WizardryItems.advanced_necromancy_wand);
|
||||
registerItemModel(WizardryItems.advanced_earth_wand);
|
||||
registerItemModel(WizardryItems.advanced_sorcery_wand);
|
||||
registerItemModel(WizardryItems.advanced_healing_wand);
|
||||
registerWandModel(WizardryItems.advanced_fire_wand);
|
||||
registerWandModel(WizardryItems.advanced_ice_wand);
|
||||
registerWandModel(WizardryItems.advanced_lightning_wand);
|
||||
registerWandModel(WizardryItems.advanced_necromancy_wand);
|
||||
registerWandModel(WizardryItems.advanced_earth_wand);
|
||||
registerWandModel(WizardryItems.advanced_sorcery_wand);
|
||||
registerWandModel(WizardryItems.advanced_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.master_fire_wand);
|
||||
registerItemModel(WizardryItems.master_ice_wand);
|
||||
registerItemModel(WizardryItems.master_lightning_wand);
|
||||
registerItemModel(WizardryItems.master_necromancy_wand);
|
||||
registerItemModel(WizardryItems.master_earth_wand);
|
||||
registerItemModel(WizardryItems.master_sorcery_wand);
|
||||
registerItemModel(WizardryItems.master_healing_wand);
|
||||
registerWandModel(WizardryItems.master_fire_wand);
|
||||
registerWandModel(WizardryItems.master_ice_wand);
|
||||
registerWandModel(WizardryItems.master_lightning_wand);
|
||||
registerWandModel(WizardryItems.master_necromancy_wand);
|
||||
registerWandModel(WizardryItems.master_earth_wand);
|
||||
registerWandModel(WizardryItems.master_sorcery_wand);
|
||||
registerWandModel(WizardryItems.master_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.spectral_sword);
|
||||
registerItemModel(WizardryItems.spectral_pickaxe);
|
||||
registerItemModel(WizardryItems.spectral_bow);
|
||||
registerMultiTexturedModel((ItemSpectralDust)WizardryItems.spectral_dust);
|
||||
|
||||
registerItemModel(WizardryItems.small_mana_flask);
|
||||
registerItemModel(WizardryItems.medium_mana_flask);
|
||||
registerItemModel(WizardryItems.large_mana_flask);
|
||||
|
||||
registerItemModel(WizardryItems.crystal_shard);
|
||||
registerItemModel(WizardryItems.grand_crystal);
|
||||
|
||||
registerItemModel(WizardryItems.astral_diamond);
|
||||
|
||||
registerItemModel(WizardryItems.purifying_elixir);
|
||||
|
||||
registerItemModel(WizardryItems.storage_upgrade);
|
||||
registerItemModel(WizardryItems.siphon_upgrade);
|
||||
registerItemModel(WizardryItems.condenser_upgrade);
|
||||
registerItemModel(WizardryItems.range_upgrade);
|
||||
registerItemModel(WizardryItems.duration_upgrade);
|
||||
registerItemModel(WizardryItems.cooldown_upgrade);
|
||||
registerItemModel(WizardryItems.blast_upgrade);
|
||||
registerItemModel(WizardryItems.attunement_upgrade);
|
||||
registerItemModel(WizardryItems.melee_upgrade);
|
||||
|
||||
registerItemModel(WizardryItems.flaming_axe);
|
||||
registerItemModel(WizardryItems.frost_axe);
|
||||
|
||||
registerItemModel(WizardryItems.firebomb);
|
||||
registerItemModel(WizardryItems.poison_bomb);
|
||||
registerItemModel(WizardryItems.smoke_bomb);
|
||||
registerItemModel(WizardryItems.spark_bomb);
|
||||
|
||||
registerItemModel(WizardryItems.blank_scroll);
|
||||
registerItemModel(WizardryItems.scroll);
|
||||
registerItemModel(WizardryItems.identification_scroll);
|
||||
|
||||
registerItemModel(WizardryItems.armour_upgrade);
|
||||
|
||||
registerItemModel(WizardryItems.magic_silk);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat);
|
||||
registerItemModel(WizardryItems.wizard_robe);
|
||||
registerItemModel(WizardryItems.wizard_leggings);
|
||||
registerItemModel(WizardryItems.wizard_boots);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat_fire);
|
||||
registerItemModel(WizardryItems.wizard_robe_fire);
|
||||
registerItemModel(WizardryItems.wizard_leggings_fire);
|
||||
registerItemModel(WizardryItems.wizard_boots_fire);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat_ice);
|
||||
registerItemModel(WizardryItems.wizard_robe_ice);
|
||||
registerItemModel(WizardryItems.wizard_leggings_ice);
|
||||
registerItemModel(WizardryItems.wizard_boots_ice);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat_lightning);
|
||||
registerItemModel(WizardryItems.wizard_robe_lightning);
|
||||
registerItemModel(WizardryItems.wizard_leggings_lightning);
|
||||
registerItemModel(WizardryItems.wizard_boots_lightning);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat_necromancy);
|
||||
registerItemModel(WizardryItems.wizard_robe_necromancy);
|
||||
registerItemModel(WizardryItems.wizard_leggings_necromancy);
|
||||
registerItemModel(WizardryItems.wizard_boots_necromancy);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat_earth);
|
||||
registerItemModel(WizardryItems.wizard_robe_earth);
|
||||
registerItemModel(WizardryItems.wizard_leggings_earth);
|
||||
registerItemModel(WizardryItems.wizard_boots_earth);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat_sorcery);
|
||||
registerItemModel(WizardryItems.wizard_robe_sorcery);
|
||||
registerItemModel(WizardryItems.wizard_leggings_sorcery);
|
||||
registerItemModel(WizardryItems.wizard_boots_sorcery);
|
||||
|
||||
registerItemModel(WizardryItems.wizard_hat_healing);
|
||||
registerItemModel(WizardryItems.wizard_robe_healing);
|
||||
registerItemModel(WizardryItems.wizard_leggings_healing);
|
||||
registerItemModel(WizardryItems.wizard_boots_healing);
|
||||
|
||||
registerItemModel(WizardryItems.spectral_helmet);
|
||||
registerItemModel(WizardryItems.spectral_chestplate);
|
||||
registerItemModel(WizardryItems.spectral_leggings);
|
||||
registerItemModel(WizardryItems.spectral_boots);
|
||||
|
||||
registerItemModel(WizardryItems.lightning_hammer);
|
||||
|
||||
registerItemModel(WizardryItems.ring_condensing);
|
||||
registerItemModel(WizardryItems.ring_siphoning);
|
||||
registerItemModel(WizardryItems.ring_battlemage);
|
||||
registerItemModel(WizardryItems.ring_combustion);
|
||||
registerItemModel(WizardryItems.ring_fire_melee);
|
||||
registerItemModel(WizardryItems.ring_fire_biome);
|
||||
registerItemModel(WizardryItems.ring_disintegration);
|
||||
registerItemModel(WizardryItems.ring_ice_melee);
|
||||
registerItemModel(WizardryItems.ring_ice_biome);
|
||||
registerItemModel(WizardryItems.ring_arcane_frost);
|
||||
registerItemModel(WizardryItems.ring_shattering);
|
||||
registerItemModel(WizardryItems.ring_lightning_melee);
|
||||
registerItemModel(WizardryItems.ring_storm);
|
||||
registerItemModel(WizardryItems.ring_seeking);
|
||||
registerItemModel(WizardryItems.ring_hammer);
|
||||
registerItemModel(WizardryItems.ring_soulbinding);
|
||||
registerItemModel(WizardryItems.ring_leeching);
|
||||
registerItemModel(WizardryItems.ring_necromancy_melee);
|
||||
registerItemModel(WizardryItems.ring_mind_control);
|
||||
registerItemModel(WizardryItems.ring_poison);
|
||||
registerItemModel(WizardryItems.ring_earth_melee);
|
||||
registerItemModel(WizardryItems.ring_earth_biome);
|
||||
registerItemModel(WizardryItems.ring_full_moon);
|
||||
registerItemModel(WizardryItems.ring_extraction);
|
||||
registerItemModel(WizardryItems.ring_mana_return);
|
||||
registerItemModel(WizardryItems.ring_blockwrangler);
|
||||
registerItemModel(WizardryItems.ring_conjurer);
|
||||
registerItemModel(WizardryItems.ring_defender);
|
||||
registerItemModel(WizardryItems.ring_paladin);
|
||||
registerItemModel(WizardryItems.ring_interdiction);
|
||||
|
||||
registerItemModel(WizardryItems.amulet_arcane_defence);
|
||||
registerItemModel(WizardryItems.amulet_warding);
|
||||
registerItemModel(WizardryItems.amulet_wisdom);
|
||||
registerItemModel(WizardryItems.amulet_fire_protection);
|
||||
registerItemModel(WizardryItems.amulet_fire_cloaking);
|
||||
registerItemModel(WizardryItems.amulet_ice_immunity);
|
||||
registerItemModel(WizardryItems.amulet_ice_protection);
|
||||
registerItemModel(WizardryItems.amulet_potential);
|
||||
registerItemModel(WizardryItems.amulet_channeling);
|
||||
registerItemModel(WizardryItems.amulet_lich);
|
||||
registerItemModel(WizardryItems.amulet_wither_immunity);
|
||||
registerItemModel(WizardryItems.amulet_glide);
|
||||
registerItemModel(WizardryItems.amulet_banishing);
|
||||
registerItemModel(WizardryItems.amulet_anchoring);
|
||||
registerItemModel(WizardryItems.amulet_recovery);
|
||||
registerItemModel(WizardryItems.amulet_transience);
|
||||
registerItemModel(WizardryItems.amulet_resurrection);
|
||||
registerItemModel(WizardryItems.amulet_auto_shield);
|
||||
|
||||
registerItemModel(WizardryItems.charm_haggler);
|
||||
registerItemModel(WizardryItems.charm_experience_tome);
|
||||
registerItemModel(WizardryItems.charm_auto_smelt);
|
||||
registerItemModel(WizardryItems.charm_lava_walking);
|
||||
registerItemModel(WizardryItems.charm_storm);
|
||||
registerItemModel(WizardryItems.charm_minion_health);
|
||||
registerItemModel(WizardryItems.charm_minion_variants);
|
||||
registerItemModel(WizardryItems.charm_flight);
|
||||
registerItemModel(WizardryItems.charm_growth);
|
||||
registerItemModel(WizardryItems.charm_abseiling);
|
||||
registerItemModel(WizardryItems.charm_silk_touch);
|
||||
registerItemModel(WizardryItems.charm_stop_time);
|
||||
registerItemModel(WizardryItems.charm_light);
|
||||
registerItemModel(WizardryItems.charm_transportation);
|
||||
registerItemModel(WizardryItems.charm_feeding);
|
||||
// Automatic item model registry
|
||||
for(Item item : Item.REGISTRY){
|
||||
if(!registeredItems.contains(item) && item.getRegistryName().getNamespace().equals(Wizardry.MODID)){
|
||||
registerItemModel(item); // Standard item model
|
||||
}
|
||||
}
|
||||
|
||||
registeredItems.clear(); // Might as well clean this up
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -279,9 +147,13 @@ public final class WizardryModels {
|
||||
|
||||
if(location.getNamespace().equals(Wizardry.MODID)){
|
||||
|
||||
if(location.getPath().contains("runestone") || location.getPath().contains("runestone_pedestal")){
|
||||
IBakedModel original = event.getModelRegistry().getObject(location);
|
||||
IBakedModel original = event.getModelRegistry().getObject(location);
|
||||
|
||||
if(location.getPath().contains("runestone") || location.getPath().contains("runestone_pedestal")
|
||||
|| location.getPath().endsWith("imbuement_altar")){ // Ends with to exclude inactive version
|
||||
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "overlay"));
|
||||
}else if(location.getPath().contains("spectral_block")){
|
||||
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "spectral_block"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,24 +163,32 @@ public final class WizardryModels {
|
||||
|
||||
/**
|
||||
* Registers an item model, using the item's registry name as the model name (this convention makes it easier to
|
||||
* keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus
|
||||
* all the other metadata values that the item can take, as defined in
|
||||
* {@link Item#getSubItems(CreativeTabs, NonNullList)}. The creative tab supplied
|
||||
* to the aforementioned method will be whichever one the item is in.
|
||||
* keep track of everything). Variant defaults to "normal". Registers the model for all metadata values.
|
||||
*/
|
||||
private static void registerItemModel(Item item){
|
||||
|
||||
if(item.getHasSubtypes()){
|
||||
NonNullList<ItemStack> items = NonNullList.create();
|
||||
item.getSubItems(item.getCreativeTab(), items); // Client-only method, but we're client-side so this is OK.
|
||||
for(ItemStack stack : items){
|
||||
ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(),
|
||||
new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
}
|
||||
}
|
||||
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
|
||||
ModelLoader.setCustomModelResourceLocation(item, 0,
|
||||
new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
ModelBakery.registerItemVariants(item, new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
// Assigns the model for all metadata values
|
||||
ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
registeredItems.add(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a wand model, using the item's registry name as the model name (this convention makes it easier to
|
||||
* keep track of everything).
|
||||
*/
|
||||
private static void registerWandModel(Item item){
|
||||
|
||||
if(Wizardry.tisTheSeason){
|
||||
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
|
||||
ModelBakery.registerItemVariants(item, new ModelResourceLocation("ebwizardry:festive_wand", "inventory"));
|
||||
// Assigns the model for all metadata values
|
||||
ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation("ebwizardry:festive_wand", "inventory"));
|
||||
registeredItems.add(item);
|
||||
}else{
|
||||
registerItemModel(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,6 +208,8 @@ public final class WizardryModels {
|
||||
new ModelResourceLocation(item.getModelName(stack), "inventory"));
|
||||
}
|
||||
}
|
||||
|
||||
registeredItems.add(item);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,6 +220,7 @@ public final class WizardryModels {
|
||||
private static void registerItemModel(Item item, int metadata, String variant){
|
||||
ModelLoader.setCustomModelResourceLocation(item, metadata,
|
||||
new ModelResourceLocation(item.getRegistryName(), variant));
|
||||
registeredItems.add(item); // Still ought to do this in case I ever use this method alone for an item
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.util.GeometryUtils;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleBlockHighlight extends ParticleWizardry {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "particle/block_highlight");
|
||||
|
||||
public ParticleBlockHighlight(World world, double x, double y, double z){
|
||||
|
||||
super(world, x, y, z, TEXTURE);
|
||||
|
||||
this.particleGravity = 0;
|
||||
this.setMaxAge(160);
|
||||
// 5 makes it the exact size of a block face, plus a little bit to account for the anti-z-fighting offset
|
||||
this.particleScale = 5 * (1 + 2 * (float)GeometryUtils.ANTI_Z_FIGHTING_OFFSET);
|
||||
this.shaded = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
// Fading
|
||||
if(this.particleAge > this.particleMaxAge/2){
|
||||
this.setAlphaF(1 - ((float)this.particleAge - this.particleMaxAge/2f) / (this.particleMaxAge/2f));
|
||||
}
|
||||
|
||||
EnumFacing facing = EnumFacing.fromAngle(yaw);
|
||||
if(pitch == 90) facing = EnumFacing.UP;
|
||||
if(pitch == -90) facing = EnumFacing.DOWN;
|
||||
|
||||
// Disappears if there is no block behind it (this is the same check used to spawn it)
|
||||
if(!world.getBlockState(new BlockPos(posX, posY, posZ).offset(facing.getOpposite())).getMaterial().isSolid()){
|
||||
this.setExpired();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
|
||||
event.getMap().registerSprite(TEXTURE);
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public class ParticleBuff extends ParticleWizardry {
|
||||
float rotationYZ, float rotationXY, float rotationXZ){
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
updateEntityLinking(viewer, partialTicks);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushAttrib();
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleCloud extends ParticleWizardry {
|
||||
|
||||
private static final ResourceLocation[] TEXTURES = generateTextures("cloud", 4);
|
||||
|
||||
public ParticleCloud(World world, double x, double y, double z){
|
||||
|
||||
super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]);
|
||||
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
this.particleMaxAge = 48 + this.rand.nextInt(12);
|
||||
this.particleScale *= 6;
|
||||
this.setGravity(false);
|
||||
this.setAlphaF(0);
|
||||
this.canCollide = false;
|
||||
this.shaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
// Fading
|
||||
float fadeTime = this.particleMaxAge * 0.3f;
|
||||
this.setAlphaF(MathHelper.clamp(Math.min(this.particleAge / fadeTime, (this.particleMaxAge - this.particleAge) / fadeTime), 0, 1));
|
||||
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
|
||||
for(ResourceLocation texture : TEXTURES){
|
||||
event.getMap().registerSprite(texture);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,15 +17,4 @@ public class ParticleDust extends ParticleWizardry {
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
this.move(this.motionX, this.motionY, this.motionZ);
|
||||
|
||||
if(this.particleMaxAge-- <= 0){
|
||||
this.setExpired();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,15 +35,10 @@ public class ParticleFlash extends ParticleWizardry {
|
||||
int i = this.getBrightnessForRender(partialTicks);
|
||||
int j = i >> 16 & 65535;
|
||||
int k = i & 65535;
|
||||
buffer.pos((double)(f5 - rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 - rotationYZ * f4 - rotationXZ * f4)).tex(0.5D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos((double)(f5 - rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 - rotationYZ * f4 + rotationXZ * f4)).tex(0.5D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos((double)(f5 + rotationX * f4 + rotationXY * f4), (double)(f6 + rotationZ * f4), (double)(f7 + rotationYZ * f4 + rotationXZ * f4)).tex(0.25D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos((double)(f5 + rotationX * f4 - rotationXY * f4), (double)(f6 - rotationZ * f4), (double)(f7 + rotationYZ * f4 - rotationXZ * f4)).tex(0.25D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightnessForRender(float partialTicks){
|
||||
return 15728880;
|
||||
buffer.pos(f5 - rotationX * f4 - rotationXY * f4, f6 - rotationZ * f4, f7 - rotationYZ * f4 - rotationXZ * f4).tex(0.5D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos(f5 - rotationX * f4 + rotationXY * f4, f6 + rotationZ * f4, f7 - rotationYZ * f4 + rotationXZ * f4).tex(0.5D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos(f5 + rotationX * f4 + rotationXY * f4, f6 + rotationZ * f4, f7 + rotationYZ * f4 + rotationXZ * f4).tex(0.25D, 0.125D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
buffer.pos(f5 + rotationX * f4 - rotationXY * f4, f6 - rotationZ * f4, f7 + rotationYZ * f4 - rotationXZ * f4).tex(0.25D, 0.375D).color(this.particleRed, this.particleGreen, this.particleBlue, this.particleAlpha).lightmap(j, k).endVertex();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class ParticleGuardianBeam extends ParticleTargeted {
|
||||
|
||||
/** Half the width of the beam. */
|
||||
private static final float THICKNESS = 0.15f;
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation("minecraft:textures/entity/guardian_beam.png");
|
||||
|
||||
public ParticleGuardianBeam(World world, double x, double y, double z){
|
||||
super(world, x, y, z); // Does't use TextureAtlasSprite
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
this.setMaxAge(3);
|
||||
this.particleScale = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFXLayer(){
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void draw(Tessellator tessellator, double length, float partialTicks){
|
||||
|
||||
float scale = this.particleScale;
|
||||
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
// Enables texture tiling (Also used for guardian beam, beacon beam and ender crystal beam, amongst others)
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
|
||||
GlStateManager.rotate(Minecraft.getMinecraft().player.ticksExisted + partialTicks, 0, 0, 1);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
float t = THICKNESS * scale;
|
||||
float v1 = 2 * (particleAge + partialTicks) / particleMaxAge;
|
||||
float v2 = v1 + (float)length * 2; // Multiply by 2 to make it squished like it is in vanilla
|
||||
|
||||
buffer.pos(-t, 0, 0) .tex(0, v1) .color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
buffer.pos( t, 0, 0) .tex(0.5, v1) .color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
buffer.pos( t, 0, length).tex(0.5, v2).color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
buffer.pos(-t, 0, length).tex(0, v2).color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
|
||||
buffer.pos(0, -t, 0) .tex(0, v1) .color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
buffer.pos(0, t, 0) .tex(0.5, v1) .color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
buffer.pos(0, t, length).tex(0.5, v2).color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
buffer.pos(0, -t, length).tex(0, v2).color(particleRed, particleGreen, particleBlue, 1).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
// GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
// GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
// Makes the rain go weird
|
||||
//GlStateManager.enableLighting();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,8 +40,6 @@ public class ParticlePath extends ParticleWizardry {
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ParticleSphere extends ParticleWizardry {
|
||||
float rotationXY, float rotationXZ){
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
updateEntityLinking(viewer, partialTicks);
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks);
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class ParticleSummon extends ParticleWizardry {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/summon.png");
|
||||
private final boolean mirror;
|
||||
|
||||
public ParticleSummon(World world, double x, double y, double z){
|
||||
super(world, x, y, z);
|
||||
this.mirror = random.nextBoolean();
|
||||
this.setMaxAge(10);
|
||||
this.setGravity(false);
|
||||
this.canCollide = false;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void onUpdate(){
|
||||
// super.onUpdate();
|
||||
// if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge;
|
||||
// }
|
||||
|
||||
/* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png
|
||||
* to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the
|
||||
* render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine
|
||||
* for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was
|
||||
* presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning
|
||||
* you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten
|
||||
* anyway since they bind their own textures. It is of course important to bind the texture every time you render a
|
||||
* custom particle, but I don't see how you could do it any other way, since you don't have access to
|
||||
* EffectRenderer. */
|
||||
@Override
|
||||
public int getFXLayer(){
|
||||
// This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer.
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ,
|
||||
float rotationYZ, float rotationXY, float rotationXZ){
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushAttrib();
|
||||
|
||||
float scale = 0.6f;
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
if(mirror) GlStateManager.scale(-1, 1, 1);
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableAlpha();
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE);
|
||||
// Makes the particle colour add to the colour of the texture pixels, rather than the default multiplying
|
||||
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_ADD);
|
||||
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
|
||||
// Does the texture translation wrapping thing (the cool stuff)
|
||||
// GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
// GlStateManager.loadIdentity();
|
||||
//
|
||||
// GlStateManager.translate((this.particleAge + partialTicks)/(float)this.particleMaxAge * -2, 0, 0);
|
||||
//
|
||||
// GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
|
||||
|
||||
buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
|
||||
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
|
||||
|
||||
// Increases from 0 to 1 in steps of 0.125 evenly throughout the particle's lifetime
|
||||
float f = 0.125f * MathHelper.floor((float)this.particleAge/(float)this.particleMaxAge * 8 - 0.000001f);
|
||||
float g = f + 0.125f;
|
||||
float hrepeat = 1;
|
||||
float yScale = 3f;
|
||||
|
||||
this.setRBGColorF(1, 1, 1);
|
||||
|
||||
buffer.pos(x-1, y, z-1).tex(0, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z-1).tex(0, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y, z-1).tex(0.25*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y+yScale, z-1).tex(0.25*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y, z+1).tex(0.5*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x+1, y+yScale, z+1).tex(0.5*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y, z+1).tex(0.75*hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z+1).tex(0.75*hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y, z-1).tex(hrepeat, g).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
buffer.pos(x-1, y+yScale, z-1).tex(hrepeat, f).color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex();
|
||||
|
||||
Tessellator.getInstance().draw();
|
||||
|
||||
// Undoes the texture transformations
|
||||
// GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
// GlStateManager.loadIdentity();
|
||||
// GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.enableLighting();
|
||||
// Reverses the colour addition change from before
|
||||
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
|
||||
|
||||
GlStateManager.popAttrib();
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
@@ -15,6 +16,8 @@ import javax.annotation.Nullable;
|
||||
/** Superclass for particles with a second target entity or target position. */
|
||||
public abstract class ParticleTargeted extends ParticleWizardry {
|
||||
|
||||
private static final double THIRD_PERSON_AXIAL_OFFSET = 1.2;
|
||||
|
||||
protected double targetX;
|
||||
protected double targetY;
|
||||
protected double targetZ;
|
||||
@@ -73,16 +76,26 @@ public abstract class ParticleTargeted extends ParticleWizardry {
|
||||
float rotationXY, float rotationXZ){
|
||||
|
||||
// Copied from ParticleWizardry, needs to be here since we're not calling super
|
||||
updateEntityLinking(partialTicks);
|
||||
updateEntityLinking(viewer, partialTicks);
|
||||
|
||||
float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks);
|
||||
float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks);
|
||||
float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks);
|
||||
|
||||
// Translates the particle a short distance in front of the entity
|
||||
if(this.entity != null && this.shouldApplyOriginOffset()){
|
||||
if(this.entity != viewer || Minecraft.getMinecraft().gameSettings.thirdPersonView != 0){
|
||||
Vec3d look = entity.getLook(partialTicks).scale(THIRD_PERSON_AXIAL_OFFSET);
|
||||
x += look.x;
|
||||
y += look.y;
|
||||
z += look.z;
|
||||
}
|
||||
}
|
||||
|
||||
if(this.target != null){
|
||||
|
||||
this.targetX = this.target.prevPosX + (this.target.posX - this.target.prevPosX) * partialTicks;
|
||||
double correction = this.target.getEntityBoundingBox().minY - this.target.posY;
|
||||
double correction = this.target.posY - this.target.posY;
|
||||
this.targetY = this.target.prevPosY + (this.target.posY - this.target.prevPosY) * partialTicks
|
||||
+ target.height/2 + correction;
|
||||
this.targetZ = this.target.prevPosZ + (this.target.posZ - this.target.prevPosZ) * partialTicks;
|
||||
@@ -133,6 +146,12 @@ public abstract class ParticleTargeted extends ParticleWizardry {
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
/** Returns whether the origin of this particle should be moved a short distance in front of the entity it is
|
||||
* linked to, if any. */
|
||||
protected boolean shouldApplyOriginOffset(){
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called from {@link ParticleTargeted#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)},
|
||||
* once the appropriate calculations and transformations have been applied, to actually render the particle. Subclasses
|
||||
* override this <i>instead</i> of overriding {@code renderParticle} directly, and inside render the particle <b>along
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ParticleTornado extends ParticleDigging {
|
||||
public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos,
|
||||
double velX, double velZ, IBlockState block){
|
||||
super(world, 0, 0, 0, 0, 0, 0, block);
|
||||
float angle = this.rand.nextFloat() * (float)Math.PI * 2;
|
||||
this.angle = this.rand.nextFloat() * (float)Math.PI * 2;
|
||||
double x = originX - MathHelper.cos(angle) * radius;
|
||||
double z = originZ + radius * MathHelper.sin(angle);
|
||||
this.radius = radius;
|
||||
|
||||
@@ -46,6 +46,11 @@ public class ParticleVine extends ParticleTargeted {
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldApplyOriginOffset(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void draw(Tessellator tessellator, double length, float partialTicks){
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package electroblob.wizardry.client.particle;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.ClientProxy;
|
||||
import electroblob.wizardry.entity.ICustomHitbox;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
@@ -27,7 +27,7 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* Abstract superclass for all of wizardry's particles. This replaces {@code ParticleCustomTexture} (the functionality of
|
||||
* which is no longer necessary since wizardry now uses {@code TextureAtlasSprite}s to do the rendering), and fits into
|
||||
* {@code ParticleBuilder} by exposing all the necessary variables through getters, allowing them to be set on the fly
|
||||
* {@code ParticleBuilder} by exposing all the necessary variables through setters, allowing them to be set on the fly
|
||||
* rather than needing to be passed into the constructor.
|
||||
* <p></p>
|
||||
* The new system is as follows:
|
||||
@@ -206,7 +206,7 @@ public abstract class ParticleWizardry extends Particle {
|
||||
this.entity = entity;
|
||||
// Set these to the correct values
|
||||
if(entity != null){
|
||||
this.setPosition(this.entity.posX + relativeX, this.entity.getEntityBoundingBox().minY
|
||||
this.setPosition(this.entity.posX + relativeX, this.entity.posY
|
||||
+ relativeY, this.entity.posZ + relativeZ);
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
@@ -336,7 +336,7 @@ public abstract class ParticleWizardry extends Particle {
|
||||
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float lookZ, float lookY,
|
||||
float lookX, float lookXY, float lookYZ){
|
||||
|
||||
updateEntityLinking(partialTicks);
|
||||
updateEntityLinking(viewer, partialTicks);
|
||||
|
||||
if(Float.isNaN(this.yaw) || Float.isNaN(this.pitch)){
|
||||
// Normal behaviour (rotates to face the viewer)
|
||||
@@ -369,12 +369,18 @@ public abstract class ParticleWizardry extends Particle {
|
||||
super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY);
|
||||
}
|
||||
|
||||
protected void updateEntityLinking(float partialTicks){
|
||||
protected void updateEntityLinking(Entity viewer, float partialTicks){
|
||||
// TODO: Still not working, it seems this bug was a thing back in 4.2.x anyway
|
||||
if(this.entity != null){
|
||||
// This is kind of cheating but we know it's always a constant velocity so it works fine
|
||||
prevPosX = posX + entity.prevPosX - entity.posX - relativeMotionX * (1-partialTicks);
|
||||
prevPosY = posY + entity.prevPosY - entity.posY - relativeMotionY * (1-partialTicks);
|
||||
prevPosZ = posZ + entity.prevPosZ - entity.posZ - relativeMotionZ * (1-partialTicks);
|
||||
}else if(this.getFXLayer() == 3){
|
||||
// Not sure why, but when fx layer is 3, the interp pos is wrong when not linked to an entity
|
||||
interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks;
|
||||
interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks;
|
||||
interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,12 +473,12 @@ public abstract class ParticleWizardry extends Particle {
|
||||
|
||||
double searchRadius = 20;
|
||||
|
||||
List<Entity> nearbyEntities = WizardryUtilities.getEntitiesWithinRadius(searchRadius, this.posX,
|
||||
List<Entity> nearbyEntities = EntityUtils.getEntitiesWithinRadius(searchRadius, this.posX,
|
||||
this.posY, this.posZ, world, Entity.class);
|
||||
|
||||
nearbyEntities.removeIf(e -> !(e instanceof ICustomHitbox && ((ICustomHitbox)e).contains(new Vec3d(this.posX, this.posY, this.posZ))));
|
||||
|
||||
if(nearbyEntities.size() > 0) this.setExpired();
|
||||
if(nearbyEntities.stream().anyMatch(e -> e instanceof ICustomHitbox
|
||||
&& ((ICustomHitbox)e).calculateIntercept(new Vec3d(posX, posY, posZ),
|
||||
new Vec3d(prevPosX, prevPosY, prevPosZ), 0) != null)) this.setExpired();
|
||||
|
||||
}
|
||||
|
||||
@@ -525,30 +531,42 @@ public abstract class ParticleWizardry extends Particle {
|
||||
|
||||
|
||||
// =============================================== Helper Methods ===============================================
|
||||
|
||||
|
||||
/** Internal overload for {@link ParticleWizardry#generateTextures(String, String, int)} which uses wizardry's mod
|
||||
* ID automatically. */
|
||||
public static ResourceLocation[] generateTextures(String stem, int n){
|
||||
return generateTextures(Wizardry.MODID, stem, n);
|
||||
}
|
||||
|
||||
/** Static helper method that generates an array of n ResourceLocations using the particle file naming convention,
|
||||
* which is the given stem plus an underscore plus the integer index. */
|
||||
public static ResourceLocation[] generateTextures(String stem, int n){
|
||||
public static ResourceLocation[] generateTextures(String modID, String stem, int n){
|
||||
|
||||
ResourceLocation[] textures = new ResourceLocation[n];
|
||||
|
||||
for(int i=0; i<n; i++){
|
||||
textures[i] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i);
|
||||
textures[i] = new ResourceLocation(modID, "particle/" + stem + "_" + i);
|
||||
}
|
||||
|
||||
return textures;
|
||||
}
|
||||
|
||||
/** Internal overload for {@link ParticleWizardry#generateTextures(String, String, int, int)} which uses wizardry's
|
||||
* mod ID automatically. */
|
||||
static ResourceLocation[][] generateTextures(String stem, int m, int n){
|
||||
return generateTextures(Wizardry.MODID, stem, m, n);
|
||||
}
|
||||
|
||||
/** Static helper method that generates a 2D m x n array of ResourceLocations using the particle file naming
|
||||
* convention, which is the given stem plus an underscore plus the first index, plus an underscore plus the second
|
||||
* index. Useful for animated particles that also pick a random animation strip. */
|
||||
public static ResourceLocation[][] generateTextures(String stem, int m, int n){
|
||||
public static ResourceLocation[][] generateTextures(String modID, String stem, int m, int n){
|
||||
|
||||
ResourceLocation[][] textures = new ResourceLocation[m][n];
|
||||
|
||||
for(int i=0; i<m; i++){
|
||||
for(int j=0; j<n; j++){
|
||||
textures[i][j] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i + "_" + j);
|
||||
textures[i][j] = new ResourceLocation(modID, "particle/" + stem + "_" + i + "_" + j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockStatue;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.model.ModelPlayer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||
import net.minecraft.client.renderer.entity.RenderPlayer;
|
||||
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Layer used to render the frost texture on a creature with the frostbite effect. Handles dynamic tiling of the texture.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.2
|
||||
*/
|
||||
public class LayerFrost implements LayerRenderer<EntityLivingBase> {
|
||||
|
||||
protected ModelBase model;
|
||||
private final RenderLivingBase<?> renderer;
|
||||
|
||||
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/frost_overlay.png");
|
||||
|
||||
public static void initialiseLayers(){
|
||||
|
||||
for(Render<? extends Entity> renderer : Minecraft.getMinecraft().getRenderManager().entityRenderMap.values()){
|
||||
// Because the zombie classes are now split properly, their renderers play nicely like everything else.
|
||||
if(renderer instanceof RenderLivingBase){
|
||||
// Adds a frost layer to all the living entity renderers in the game. Whether it is actually rendered
|
||||
// is decided in doRenderLayer below on a per-entity basis.
|
||||
((RenderLivingBase<?>)renderer).addLayer(new LayerFrost((RenderLivingBase<?>)renderer));
|
||||
}
|
||||
}
|
||||
|
||||
for(RenderPlayer renderer : Minecraft.getMinecraft().getRenderManager().getSkinMap().values()){
|
||||
renderer.addLayer(new LayerFrost(renderer));
|
||||
}
|
||||
}
|
||||
|
||||
public LayerFrost(RenderLivingBase<?> renderer){
|
||||
this.renderer = renderer;
|
||||
this.model = renderer.getMainModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
|
||||
float ageInTicks, float netHeadYaw, float headPitch, float scale){
|
||||
|
||||
if(entity.isPotionActive(WizardryPotions.frost) || entity.getEntityData().getBoolean(BlockStatue.FROZEN_NBT_KEY)){
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
int i = this.getBlockBrightnessForEntity(entity, partialTicks);
|
||||
|
||||
int j = i % 65536;
|
||||
int k = i / 65536;
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
|
||||
|
||||
// Frost texture
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
this.renderer.bindTexture(texture);
|
||||
this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw,
|
||||
headPitch, scale);
|
||||
GlStateManager.disableBlend();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private int getBlockBrightnessForEntity(Entity entity, float partialTicks){
|
||||
|
||||
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(MathHelper.floor(entity.posX), 0,
|
||||
MathHelper.floor(entity.posZ));
|
||||
|
||||
if(entity.world.isBlockLoaded(pos)){
|
||||
pos.setY(MathHelper.floor(entity.posY + (double)entity.getEyeHeight()));
|
||||
return entity.world.getCombinedLight(pos, 0);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderEntityModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
|
||||
float ageInTicks, float netHeadYaw, float headPitch, float scale){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
// Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam)
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
|
||||
GlStateManager.depthMask(true); // Some entities set depth mask to false (i.e. no sorting of faces by depth)
|
||||
// In particular, LayerSpiderEyes sets it to false when the spider is invisible, for some reason.
|
||||
|
||||
// Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example,
|
||||
// but with translation instead of scaling.
|
||||
// NOTE: You can do all sorts of fun stuff with this, just by applying transformations in the 2D texture space.
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.loadIdentity();
|
||||
double scaleX = 1, scaleY = 1;
|
||||
// It's more logical to use the model's texture size, but some classes don't bother setting it properly
|
||||
// (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead.
|
||||
if(model.boxList != null && model.boxList.get(0) != null){
|
||||
scaleX = (double)model.boxList.get(0).textureWidth / 16d;
|
||||
scaleY = (double)model.boxList.get(0).textureHeight / 16d;
|
||||
}else{ // Fallback to model fields; should never be needed
|
||||
scaleX = (double)model.textureWidth / 16d;
|
||||
scaleY = (double)model.textureHeight / 16d;
|
||||
}
|
||||
GlStateManager.scale(scaleX, scaleY, 1);
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
// Hides the hat layer for bipeds
|
||||
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = true;
|
||||
|
||||
if(this.model instanceof ModelPlayer){
|
||||
((ModelPlayer)this.model).bipedBodyWear.isHidden = true;
|
||||
((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true;
|
||||
((ModelPlayer)this.model).bipedRightArmwear.isHidden = true;
|
||||
((ModelPlayer)this.model).bipedLeftLegwear.isHidden = true;
|
||||
((ModelPlayer)this.model).bipedRightLegwear.isHidden = true;
|
||||
}
|
||||
|
||||
this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks);
|
||||
this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
|
||||
|
||||
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = false;
|
||||
|
||||
// Undoes the texture scaling
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.loadIdentity();
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCombineTextures(){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
|
||||
import electroblob.wizardry.block.BlockStatue;
|
||||
import electroblob.wizardry.client.ClientProxy;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Layer used to render the stone texture on a petrified creature. Handles dynamic tiling of the stone texture.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.2
|
||||
*/
|
||||
public class LayerStone implements LayerRenderer<EntityLivingBase> {
|
||||
|
||||
protected ModelBase model;
|
||||
private final RenderLivingBase<?> renderer;
|
||||
|
||||
private static final ResourceLocation texture = new ResourceLocation("textures/blocks/stone.png");
|
||||
|
||||
public static void initialiseLayers(){
|
||||
|
||||
for(Render<? extends Entity> renderer : Minecraft.getMinecraft().getRenderManager().entityRenderMap.values()){
|
||||
// Because the zombie classes are now split properly, their renderers play nicely like everything else.
|
||||
if(renderer instanceof RenderLivingBase){
|
||||
// Adds a stone layer to all the living entity renderers in the game. Whether it is actually rendered
|
||||
// is decided in doRenderLayer below on a per-entity basis.
|
||||
((RenderLivingBase<?>)renderer).addLayer(new LayerStone((RenderLivingBase<?>)renderer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LayerStone(RenderLivingBase<?> renderer){
|
||||
this.renderer = renderer;
|
||||
this.model = renderer.getMainModel();
|
||||
}
|
||||
|
||||
// FIXME: Does not work with zombie pigmen, I have no idea why.
|
||||
// I believe the issue is with the TESR actually, since LayerFrost works fine
|
||||
|
||||
@Override
|
||||
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
|
||||
float ageInTicks, float netHeadYaw, float headPitch, float scale){
|
||||
|
||||
if(entity.getEntityData().getBoolean(BlockStatue.PETRIFIED_NBT_KEY)){
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
int i = this.getBlockBrightnessForEntity(entity, partialTicks);
|
||||
|
||||
int j = i % 65536;
|
||||
int k = i / 65536;
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
|
||||
|
||||
ResourceLocation breakingTexture = ClientProxy.renderStatue.getBlockBreakingTexture();
|
||||
|
||||
if(breakingTexture != null){
|
||||
// Block breaking animation
|
||||
// TODO: Spider eyes and enderman eyes (any others?) show through the stone when the block is being
|
||||
// broken...
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
this.renderer.bindTexture(breakingTexture);
|
||||
this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw,
|
||||
headPitch, scale);
|
||||
GlStateManager.disableBlend();
|
||||
}else{
|
||||
// Stone texture
|
||||
this.renderer.bindTexture(texture);
|
||||
this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw,
|
||||
headPitch, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getBlockBrightnessForEntity(Entity entity, float partialTicks){
|
||||
|
||||
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(MathHelper.floor(entity.posX), 0,
|
||||
MathHelper.floor(entity.posZ));
|
||||
|
||||
if(entity.world.isBlockLoaded(pos)){
|
||||
pos.setY(MathHelper.floor(entity.posY + (double)entity.getEyeHeight()));
|
||||
return entity.world.getCombinedLight(pos, 0);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void renderEntityModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
|
||||
float ageInTicks, float netHeadYaw, float headPitch, float scale){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
// Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam)
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
|
||||
GlStateManager.depthMask(true); // Some entities set depth mask to false (i.e. no sorting of faces by depth)
|
||||
// In particular, LayerSpiderEyes sets it to false when the spider is invisible, for some reason.
|
||||
|
||||
// Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example,
|
||||
// but with translation instead of scaling.
|
||||
// NOTE: You can do all sorts of fun stuff with this, just by applying transformations in the 2D texture space.
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.loadIdentity();
|
||||
double scaleX = 1, scaleY = 1;
|
||||
// It's more logical to use the model's texture size, but some classes don't bother setting it properly
|
||||
// (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead.
|
||||
if(model.boxList != null && model.boxList.get(0) != null){
|
||||
scaleX = (double)model.boxList.get(0).textureWidth / 16d;
|
||||
scaleY = (double)model.boxList.get(0).textureHeight / 16d;
|
||||
}else{ // Fallback to model fields; should never be needed
|
||||
scaleX = (double)model.textureWidth / 16d;
|
||||
scaleY = (double)model.textureHeight / 16d;
|
||||
}
|
||||
GlStateManager.scale(scaleX, scaleY, 1);
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
// Hides the hat layer for bipeds
|
||||
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = true;
|
||||
|
||||
this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks);
|
||||
this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
|
||||
|
||||
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = false;
|
||||
|
||||
// Undoes the texture scaling
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.loadIdentity();
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCombineTextures(){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
|
||||
/** Instances of this class can calculate their distance from the camera viewpoint and sort themselves accordingly. */
|
||||
class RayHelper implements Comparable<RayHelper> {
|
||||
public class RayHelper implements Comparable<RayHelper> {
|
||||
|
||||
int ordinal;
|
||||
double x1, y1, z1;
|
||||
double x2, y2, z2;
|
||||
public double x1, y1, z1;
|
||||
public double x2, y2, z2;
|
||||
double offsetX, offsetY, offsetZ;
|
||||
|
||||
RayHelper(int ordinal, double x1, double y1, double z1, double x2, double y2, double z2, double offsetX,
|
||||
public RayHelper(int ordinal, double x1, double y1, double z1, double x2, double y2, double z2, double offsetX,
|
||||
double offsetY, double offsetZ){
|
||||
this.ordinal = ordinal;
|
||||
this.x1 = x1;
|
||||
@@ -37,13 +37,7 @@ class RayHelper implements Comparable<RayHelper> {
|
||||
|
||||
@Override
|
||||
public int compareTo(RayHelper ray){
|
||||
if(this.getDistanceFromViewpoint() > ray.getDistanceFromViewpoint()){
|
||||
return -1;
|
||||
}else if(this.getDistanceFromViewpoint() < ray.getDistanceFromViewpoint()){
|
||||
return 1;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
return Double.compare(ray.getDistanceFromViewpoint(), this.getDistanceFromViewpoint());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
|
||||
import electroblob.wizardry.entity.construct.EntityFireRing;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class RenderFireRing extends Render<EntityFireRing> {
|
||||
|
||||
private final ResourceLocation texture;
|
||||
private float scale = 1.0f;
|
||||
|
||||
public RenderFireRing(RenderManager renderManager, ResourceLocation texture, float scale){
|
||||
super(renderManager);
|
||||
this.texture = texture;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(EntityFireRing entity, double par2, double par4, double par6, float par8, float par9){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
float yOffset = 0;
|
||||
|
||||
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
|
||||
|
||||
this.bindTexture(texture);
|
||||
float f6 = 1.0F;
|
||||
float f7 = 0.5F;
|
||||
float f8 = 0.5F;
|
||||
|
||||
GlStateManager.rotate(-90, 1, 0, 0);
|
||||
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
|
||||
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.disableRescaleNormal();
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
// Fire
|
||||
|
||||
GlStateManager.disableLighting();
|
||||
TextureAtlasSprite icon = Minecraft.getMinecraft().getBlockRendererDispatcher()
|
||||
.getModelForState(Blocks.FIRE.getDefaultState()).getParticleTexture();
|
||||
int sides = 16;
|
||||
float height = 1.0f;
|
||||
|
||||
for(int k = 0; k < sides; k++){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate((float)par2, (float)par4 + 0.05f, (float)par6);
|
||||
float f1 = 1.0f;
|
||||
GlStateManager.scale(f1, f1, f1);
|
||||
float f2 = 0.5F;
|
||||
float f3 = 0.0F;
|
||||
float f4 = 0.2f;
|
||||
float f5 = (float)(entity.posY - entity.getEntityBoundingBox().minY);
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
float f61 = 0.0F;
|
||||
int i = 0;
|
||||
|
||||
GlStateManager.rotate((360f / (float)sides) * k, 0, 1, 0);
|
||||
GlStateManager.translate(0, 0, -2.3f);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
while(f4 > 0.0F){
|
||||
|
||||
this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
|
||||
float f71 = icon.getMinU();
|
||||
float f81 = icon.getMinV();
|
||||
float f9 = icon.getMaxU();
|
||||
float f10 = icon.getMaxV();
|
||||
|
||||
if(i / 2 % 2 == 0){
|
||||
float f11 = f9;
|
||||
f9 = f71;
|
||||
f71 = f11;
|
||||
}
|
||||
|
||||
buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10)
|
||||
.endVertex();
|
||||
buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10)
|
||||
.endVertex();
|
||||
buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81)
|
||||
.endVertex();
|
||||
buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81)
|
||||
.endVertex();
|
||||
f4 -= 0.45F;
|
||||
f5 -= 0.45F;
|
||||
f2 *= 0.9F;
|
||||
f61 += 0.03F;
|
||||
++i;
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
for(int k = 0; k < sides; k++){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate((float)par2, (float)par4 + 0.05f, (float)par6);
|
||||
float f1 = 1.0f;
|
||||
GlStateManager.scale(f1, f1, f1);
|
||||
float f2 = 0.5F;
|
||||
float f3 = 0.0F;
|
||||
float f4 = 0.2f;
|
||||
float f5 = (float)(entity.posY - entity.getEntityBoundingBox().minY);
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
float f61 = 0.0F;
|
||||
int i = 0;
|
||||
|
||||
GlStateManager.rotate((360f / (float)sides) * k, 0, 1, 0);
|
||||
GlStateManager.translate(0, 0, 2.3f);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
while(f4 > 0.0F){
|
||||
|
||||
this.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
|
||||
float f71 = icon.getMinU();
|
||||
float f81 = icon.getMinV();
|
||||
float f9 = icon.getMaxU();
|
||||
float f10 = icon.getMaxV();
|
||||
|
||||
if(i / 2 % 2 == 0){
|
||||
float f11 = f9;
|
||||
f9 = f71;
|
||||
f71 = f11;
|
||||
}
|
||||
|
||||
buffer.pos((double)(f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f9, (double)f10)
|
||||
.endVertex();
|
||||
buffer.pos((double)(-f2 - f3), (double)(0.0F - f5), (double)f61).tex((double)f71, (double)f10)
|
||||
.endVertex();
|
||||
buffer.pos((double)(-f2 - f3), (double)(height - f5), (double)f61).tex((double)f71, (double)f81)
|
||||
.endVertex();
|
||||
buffer.pos((double)(f2 - f3), (double)(height - f5), (double)f61).tex((double)f9, (double)f81)
|
||||
.endVertex();
|
||||
f4 -= 0.45F;
|
||||
f5 -= 0.45F;
|
||||
f2 *= 0.9F;
|
||||
f61 += 0.03F;
|
||||
++i;
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(EntityFireRing entity){
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+7
-27
@@ -1,9 +1,9 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.effect;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.potion.PotionContainment;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.GeometryUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
@@ -24,14 +24,14 @@ import org.lwjgl.opengl.GL11;
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class RenderContainmentField {
|
||||
|
||||
private static final ResourceLocation[] textures = new ResourceLocation[8];
|
||||
private static final ResourceLocation[] TEXTURES = new ResourceLocation[8];
|
||||
|
||||
private static final float ANIMATION_SPEED = 0.004f;
|
||||
private static final float FADE_DISTANCE_SQUARED = 15;
|
||||
|
||||
static {
|
||||
for(int i=0; i<textures.length; i++){
|
||||
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/containment_field_" + i + ".png");
|
||||
for(int i = 0; i< TEXTURES.length; i++){
|
||||
TEXTURES[i] = new ResourceLocation(Wizardry.MODID, "textures/environment/containment_field_" + i + ".png");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class RenderContainmentField {
|
||||
|
||||
if(player.isPotionActive(WizardryPotions.containment)){
|
||||
|
||||
Vec3d centre = WizardryUtilities.getCentre(NBTUtil.getPosFromTag(player.getEntityData().getCompoundTag(PotionContainment.ENTITY_TAG)));
|
||||
Vec3d centre = GeometryUtils.getCentre(NBTUtil.getPosFromTag(player.getEntityData().getCompoundTag(PotionContainment.ENTITY_TAG)));
|
||||
float r = PotionContainment.getContainmentDistance(player.getActivePotionEffect(WizardryPotions.containment).getAmplifier());
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
@@ -65,7 +65,7 @@ public class RenderContainmentField {
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures[(player.ticksExisted % (textures.length * 2))/2]);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURES[(player.ticksExisted % (TEXTURES.length * 2))/2]);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
|
||||
@@ -245,24 +245,4 @@ public class RenderContainmentField {
|
||||
buffer.pos(x, y, z).tex(u, v).color(1, 1, 1, f * alpha).endVertex();
|
||||
}
|
||||
|
||||
// Useful to keep this mapping in case I ever want to draw cubes again
|
||||
|
||||
// Vec3d[] vertices = WizardryUtilities.getVertices(entity.getEntityBoundingBox().offset(entity.getPositionVector().scale(-1)));
|
||||
//
|
||||
// // Outside
|
||||
// drawFace(tessellator, vertices[0], vertices[1], vertices[3], vertices[2], u1, v1, u2, v2); // Bottom
|
||||
// drawFace(tessellator, vertices[6], vertices[7], vertices[2], vertices[3], u1, v1, u2, v2); // South
|
||||
// drawFace(tessellator, vertices[5], vertices[6], vertices[1], vertices[2], u1, v1, u2, v2); // East
|
||||
// drawFace(tessellator, vertices[4], vertices[5], vertices[0], vertices[1], u1, v1, u2, v2); // North
|
||||
// drawFace(tessellator, vertices[7], vertices[4], vertices[3], vertices[0], u1, v1, u2, v2); // West
|
||||
// drawFace(tessellator, vertices[5], vertices[4], vertices[6], vertices[7], u1, v1, u2, v2); // Top
|
||||
//
|
||||
// // Inside
|
||||
// drawFace(tessellator, vertices[1], vertices[0], vertices[2], vertices[3], u1, v1, u2, v2); // Bottom
|
||||
// drawFace(tessellator, vertices[7], vertices[6], vertices[3], vertices[2], u1, v1, u2, v2); // South
|
||||
// drawFace(tessellator, vertices[6], vertices[5], vertices[2], vertices[1], u1, v1, u2, v2); // East
|
||||
// drawFace(tessellator, vertices[5], vertices[4], vertices[1], vertices[0], u1, v1, u2, v2); // North
|
||||
// drawFace(tessellator, vertices[4], vertices[7], vertices[0], vertices[3], u1, v1, u2, v2); // West
|
||||
// drawFace(tessellator, vertices[4], vertices[5], vertices[7], vertices[6], u1, v1, u2, v2); // Top
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package electroblob.wizardry.client.renderer.effect;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockReceptacle;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.misc.DonationPerksHandler;
|
||||
import electroblob.wizardry.util.GeometryUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
@EventBusSubscriber(Side.CLIENT)
|
||||
public class RenderDonationPerks {
|
||||
|
||||
private static final ResourceLocation FLARE_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/totem/flare.png");
|
||||
private static final ResourceLocation[] CUBE_TEXTURES = new ResourceLocation[14];
|
||||
|
||||
private static final float BOBBING_PERIOD = 25;
|
||||
private static final float ROTATION_PERIOD = 60;
|
||||
private static final double ROTATION_RADIUS = 0.7;
|
||||
private static final double HEIGHT_FRACTION = 0.8;
|
||||
private static final double BOBBING_DISTANCE = 0.2;
|
||||
private static final double FOLLOW_DISTANCE = 1.4;
|
||||
|
||||
static {
|
||||
for(int i = 0; i< CUBE_TEXTURES.length; i++) CUBE_TEXTURES[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/totem/cube_" + i + ".png");
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderPlayerEvent(RenderPlayerEvent.Post event){
|
||||
|
||||
EntityPlayer player = event.getEntityPlayer();
|
||||
float partialTicks = event.getPartialRenderTick();
|
||||
|
||||
Element element = DonationPerksHandler.getElement(player);
|
||||
|
||||
if(element != null){
|
||||
|
||||
int c1 = BlockReceptacle.PARTICLE_COLOURS.get(element)[0];
|
||||
int r1 = (c1 & 0xFF0000) >> 16;
|
||||
int g1 = (c1 & 0xFF00) >> 8;
|
||||
int b1 = (c1 & 0xFF);
|
||||
|
||||
int c2 = BlockReceptacle.PARTICLE_COLOURS.get(element)[2];
|
||||
int r2 = (c2 & 0xFF0000) >> 16;
|
||||
int g2 = (c2 & 0xFF00) >> 8;
|
||||
int b2 = (c2 & 0xFF);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
|
||||
GlStateManager.depthMask(false);
|
||||
GlStateManager.disableCull();
|
||||
|
||||
double x1 = player.chasingPosX - player.posX;
|
||||
double y1 = player.chasingPosY - player.posY;
|
||||
double z1 = player.chasingPosZ - player.posZ;
|
||||
|
||||
double x2 = player.prevChasingPosX - player.prevPosX;
|
||||
double y2 = player.prevChasingPosY - player.prevPosY;
|
||||
double z2 = player.prevChasingPosZ - player.prevPosZ;
|
||||
|
||||
double dx = x2 + (x1 - x2) * partialTicks;
|
||||
double dy = y2 + (y1 - y2) * partialTicks;
|
||||
double dz = z2 + (z1 - z2) * partialTicks;
|
||||
|
||||
float t = player.ticksExisted + partialTicks;
|
||||
float hMoveFraction = MathHelper.clamp((float)(dx * dx + dz * dz) / 0.3f, 0, 1);
|
||||
float vMoveFraction = MathHelper.clamp((float)(dy * dy) / 0.3f, 0, 1);
|
||||
|
||||
double x = event.getX() + ROTATION_RADIUS * MathHelper.sin(t / ROTATION_PERIOD) * (1 - hMoveFraction) + FOLLOW_DISTANCE * dx;
|
||||
double y = event.getY() + HEIGHT_FRACTION * player.height + BOBBING_DISTANCE * MathHelper.sin(t / BOBBING_PERIOD) * (1 - vMoveFraction) + FOLLOW_DISTANCE * dy;
|
||||
double z = event.getZ() + ROTATION_RADIUS * MathHelper.cos(t / ROTATION_PERIOD) * (1 - hMoveFraction) + FOLLOW_DISTANCE * dz;
|
||||
GlStateManager.translate(x, y, z);
|
||||
|
||||
GlStateManager.scale(0.4, 0.4, 0.4);
|
||||
|
||||
// Makes the colour add to the colour of the texture pixels, rather than the default multiplying
|
||||
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_ADD);
|
||||
GlStateManager.color(r1/255f, g1/255f, b1/255f);
|
||||
drawFlare(tessellator);
|
||||
|
||||
// Reverses the colour addition change
|
||||
GlStateManager.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
|
||||
GlStateManager.color(r2/255f, g2/255f, b2/255f);
|
||||
drawCube(player, tessellator, partialTicks);
|
||||
|
||||
GlStateManager.color(1, 1, 1,1);
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.depthMask(true);
|
||||
GlStateManager.enableCull();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void drawFlare(Tessellator tessellator){
|
||||
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(FLARE_TEXTURE);
|
||||
|
||||
// This counteracts the reverse rotation behaviour when in front f5 view.
|
||||
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
|
||||
float yaw = Minecraft.getMinecraft().gameSettings.thirdPersonView == 2
|
||||
? Minecraft.getMinecraft().getRenderManager().playerViewX
|
||||
: -Minecraft.getMinecraft().getRenderManager().playerViewX;
|
||||
GlStateManager.rotate(180.0F - Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
float r = 0.5f;
|
||||
|
||||
buffer.pos(-r, r, 0).tex(0, 0).endVertex();
|
||||
buffer.pos( r, r, 0).tex(1, 0).endVertex();
|
||||
buffer.pos( r, -r, 0).tex(1, 1).endVertex();
|
||||
buffer.pos(-r, -r, 0).tex(0, 1).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
private static void drawCube(EntityPlayer player, Tessellator tessellator, float partialTicks){
|
||||
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
float age = player.ticksExisted + partialTicks;
|
||||
float rotationSpeed = 2;
|
||||
|
||||
GlStateManager.rotate(age * rotationSpeed/2, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(60.0F, 0.7071F, 0.0F, 0.7071F);
|
||||
GlStateManager.rotate(age * rotationSpeed, 0.0F, 1.0F, 0.0F);
|
||||
|
||||
GlStateManager.scale(0.5, 0.5, 0.5);
|
||||
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(CUBE_TEXTURES[player.ticksExisted % CUBE_TEXTURES.length]);
|
||||
|
||||
Vec3d[] vertices = GeometryUtils.getVertices(new AxisAlignedBB(-0.5, -0.5, -0.5, 0.5, 0.5, 0.5));
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
// Outside
|
||||
drawFace(buffer, vertices[0], vertices[1], vertices[3], vertices[2], 0.5f, 0, 0.75f, 0.5f); // Bottom
|
||||
drawFace(buffer, vertices[6], vertices[7], vertices[2], vertices[3], 0.75f, 0.5f, 1, 1); // South
|
||||
drawFace(buffer, vertices[5], vertices[6], vertices[1], vertices[2], 0, 0.5f, 0.25f, 1); // East
|
||||
drawFace(buffer, vertices[4], vertices[5], vertices[0], vertices[1], 0.25f, 0.5f, 0.5f, 1); // North
|
||||
drawFace(buffer, vertices[7], vertices[4], vertices[3], vertices[0], 0.5f, 0.5f, 0.75f, 1); // West
|
||||
drawFace(buffer, vertices[5], vertices[4], vertices[6], vertices[7], 0.25f, 0, 0.5f, 0.5f); // Top
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
private static void drawFace(BufferBuilder buffer, Vec3d topLeft, Vec3d topRight, Vec3d bottomLeft, Vec3d bottomRight, float u1, float v1, float u2, float v2){
|
||||
buffer.pos(topLeft.x, topLeft.y, topLeft.z).tex(u1, v1).endVertex();
|
||||
buffer.pos(topRight.x, topRight.y, topRight.z).tex(u2, v1).endVertex();
|
||||
buffer.pos(bottomRight.x, bottomRight.y, bottomRight.z).tex(u2, v2).endVertex();
|
||||
buffer.pos(bottomLeft.x, bottomLeft.y, bottomLeft.z).tex(u1, v2).endVertex();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package electroblob.wizardry.client.renderer.effect;
|
||||
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraftforge.client.event.RenderLivingEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@EventBusSubscriber(Side.CLIENT)
|
||||
public class RenderMirage {
|
||||
|
||||
private static final int BLINK_PERIOD_1 = 47; // Use two prime numbers to make it look as chaotic as possible
|
||||
private static final int BLINK_PERIOD_2 = 71;
|
||||
|
||||
private static final double MAX_OFFSET = 3;
|
||||
|
||||
private static final Random random = new Random(); // Seed will be set later
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderLivingEvent(RenderLivingEvent.Pre<?> event){
|
||||
if(event.getEntity().isPotionActive(WizardryPotions.mirage)){
|
||||
random.setSeed(event.getEntity().ticksExisted / BLINK_PERIOD_1
|
||||
+ event.getEntity().ticksExisted / BLINK_PERIOD_2);
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE); // GhoOOoOostly OooOOOo00oOOo
|
||||
GlStateManager.color(1, 1, 1, 0.5f);
|
||||
GlStateManager.translate((random.nextDouble() * 2 - 1) * MAX_OFFSET,
|
||||
(random.nextDouble() * 2 - 1) * MAX_OFFSET, (random.nextDouble() * 2 - 1) * MAX_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderLivingEvent(RenderLivingEvent.Post<?> event){
|
||||
if(event.getEntity().isPotionActive(WizardryPotions.mirage)){
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+7
-10
@@ -1,8 +1,8 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.effect;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
@@ -11,7 +11,6 @@ import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@@ -32,7 +31,7 @@ public class RenderShadowWard {
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
if(WizardryUtilities.isCasting(player, Spells.shadow_ward)){
|
||||
if(EntityUtils.isCasting(player, Spells.shadow_ward)){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
@@ -52,7 +51,7 @@ public class RenderShadowWard {
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.translate(0, 0, 1.2);
|
||||
GlStateManager.rotate(player.world.getTotalWorldTime() * -2, 0, 0, 1);
|
||||
GlStateManager.rotate(player.ticksExisted * -2, 0, 0, 1);
|
||||
GlStateManager.scale(1.1, 1.1, 1.1);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
@@ -94,7 +93,7 @@ public class RenderShadowWard {
|
||||
|
||||
EntityPlayer player = event.getEntityPlayer();
|
||||
|
||||
if(WizardryUtilities.isCasting(player, Spells.shadow_ward)){
|
||||
if(EntityUtils.isCasting(player, Spells.shadow_ward)){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
@@ -103,9 +102,7 @@ public class RenderShadowWard {
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
Vec3d delta = player.getPositionEyes(event.getPartialRenderTick())
|
||||
.subtract(Minecraft.getMinecraft().player.getPositionEyes(event.getPartialRenderTick()));
|
||||
GlStateManager.translate(delta.x, delta.y, delta.z);
|
||||
GlStateManager.translate(event.getX(), event.getY(), event.getZ());
|
||||
|
||||
GlStateManager.rotate(180, 0, 1, 0);
|
||||
GlStateManager.rotate(-player.renderYawOffset, 0, 1, 0);
|
||||
@@ -116,7 +113,7 @@ public class RenderShadowWard {
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
GlStateManager.translate(0, 1.2, 0);
|
||||
GlStateManager.rotate(player.world.getTotalWorldTime() * -2, 0, 0, 1);
|
||||
GlStateManager.rotate(player.ticksExisted * -2, 0, 0, 1);
|
||||
GlStateManager.scale(1.1, 1.1, 1.1);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
+57
-10
@@ -1,10 +1,10 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.effect;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.Shield;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
@@ -13,7 +13,6 @@ import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@@ -34,7 +33,7 @@ public class RenderShield {
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
if(WizardData.get(player).getVariable(Shield.SHIELD_KEY) != null && WizardryUtilities.isCasting(player, Spells.shield)){
|
||||
if(WizardData.get(player).getVariable(Shield.SHIELD_KEY) != null && EntityUtils.isCasting(player, Spells.shield)){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
@@ -50,7 +49,25 @@ public class RenderShield {
|
||||
GlStateManager.rotate(-player.rotationYaw, 0, 1, 0);
|
||||
GlStateManager.rotate(player.rotationPitch, 1, 0, 0);
|
||||
|
||||
GlStateManager.translate(0, 0, 0.8);
|
||||
GlStateManager.translate(0, 0, 1);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
// Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example,
|
||||
// but with translation instead of scaling.
|
||||
// You can do all sorts of fun stuff with this, just by applying transformations in the 2D texture space.
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE); // Switch to the 2D texture space
|
||||
GlStateManager.loadIdentity();
|
||||
|
||||
GlStateManager.translate(0.5, 0.5, 0);
|
||||
|
||||
float s = 1 - ((player.ticksExisted + event.getPartialTicks()) % 5) / 5 * 0.52f;
|
||||
s = s*s;
|
||||
GlStateManager.scale(s, s, 1);
|
||||
|
||||
GlStateManager.translate(-0.5, -0.5, 0);
|
||||
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW); // Switch back to the 3D model space
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
|
||||
@@ -58,6 +75,13 @@ public class RenderShield {
|
||||
|
||||
render(tessellator);
|
||||
|
||||
// Undo the texture scaling
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.loadIdentity();
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
|
||||
GlStateManager.shadeModel(GL11.GL_FLAT);
|
||||
@@ -76,7 +100,7 @@ public class RenderShield {
|
||||
|
||||
EntityPlayer player = event.getEntityPlayer();
|
||||
|
||||
if(WizardData.get(player).getVariable(Shield.SHIELD_KEY) != null && WizardryUtilities.isCasting(player, Spells.shield)){
|
||||
if(WizardData.get(player).getVariable(Shield.SHIELD_KEY) != null && EntityUtils.isCasting(player, Spells.shield)){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
@@ -89,9 +113,7 @@ public class RenderShield {
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
Vec3d delta = player.getPositionEyes(event.getPartialRenderTick())
|
||||
.subtract(Minecraft.getMinecraft().player.getPositionEyes(event.getPartialRenderTick()));
|
||||
GlStateManager.translate(delta.x, delta.y, delta.z);
|
||||
GlStateManager.translate(event.getX(), event.getY(), event.getZ());
|
||||
|
||||
GlStateManager.translate(0, 1.3, 0);
|
||||
|
||||
@@ -99,7 +121,25 @@ public class RenderShield {
|
||||
GlStateManager.rotate(-player.renderYawOffset, 0, 1, 0);
|
||||
// GlStateManager.rotate(-player.rotationPitch, 1, 0, 0);
|
||||
|
||||
GlStateManager.translate(0, 0, 0.8);
|
||||
GlStateManager.translate(0, 0, 1);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
// Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example,
|
||||
// but with translation instead of scaling.
|
||||
// You can do all sorts of fun stuff with this, just by applying transformations in the 2D texture space.
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE); // Switch to the 2D texture space
|
||||
GlStateManager.loadIdentity();
|
||||
|
||||
GlStateManager.translate(0.5, 0.5, 0);
|
||||
|
||||
float s = 1 - ((player.ticksExisted + event.getPartialRenderTick()) % 5) / 5 * 0.52f;
|
||||
s = s*s;
|
||||
GlStateManager.scale(s, s, 1);
|
||||
|
||||
GlStateManager.translate(-0.5, -0.5, 0);
|
||||
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW); // Switch back to the 3D model space
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
|
||||
@@ -107,6 +147,13 @@ public class RenderShield {
|
||||
|
||||
render(tessellator);
|
||||
|
||||
// Undo the texture scaling
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
GlStateManager.loadIdentity();
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
|
||||
GlStateManager.shadeModel(GL11.GL_FLAT);
|
||||
+4
-7
@@ -1,8 +1,8 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.effect;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
@@ -12,7 +12,6 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.client.event.RenderPlayerEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
@@ -32,7 +31,7 @@ public class RenderWings {
|
||||
|
||||
EntityPlayer player = event.getEntityPlayer();
|
||||
|
||||
if(WizardryUtilities.isCasting(player, Spells.flight)){
|
||||
if(EntityUtils.isCasting(player, Spells.flight)){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
@@ -41,9 +40,7 @@ public class RenderWings {
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
|
||||
|
||||
Vec3d delta = player.getPositionEyes(event.getPartialRenderTick())
|
||||
.subtract(Minecraft.getMinecraft().player.getPositionEyes(event.getPartialRenderTick()));
|
||||
GlStateManager.translate(delta.x, delta.y, delta.z);
|
||||
GlStateManager.translate(event.getX(), event.getY(), event.getZ());
|
||||
|
||||
// GlStateManager.rotate(-entityplayer.rotationYawHead, 0, 1, 0);
|
||||
GlStateManager.rotate(-player.renderYawOffset, 0, 1, 0);
|
||||
+22
-26
@@ -1,6 +1,8 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.entity;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.client.renderer.RayHelper;
|
||||
import electroblob.wizardry.entity.construct.EntityBlackHole;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.*;
|
||||
@@ -16,17 +18,18 @@ import java.util.Collections;
|
||||
|
||||
public class RenderBlackHole extends Render<EntityBlackHole> {
|
||||
|
||||
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID,
|
||||
"textures/entity/dark_ray.png");
|
||||
private static final ResourceLocation texture2 = new ResourceLocation(Wizardry.MODID,
|
||||
"textures/entity/black_hole.png");
|
||||
// TODO: Remove RayHelper and the ray texture entirely and use colours with depth mask off (like imbuement altar)
|
||||
private static final ResourceLocation RAY_TEXTURE = new ResourceLocation(Wizardry.MODID,
|
||||
"textures/entity/black_hole/ray.png");
|
||||
private static final ResourceLocation CENTRE_TEXTURE = new ResourceLocation(Wizardry.MODID,
|
||||
"textures/entity/black_hole/centre.png");
|
||||
|
||||
public RenderBlackHole(RenderManager renderManager){
|
||||
super(renderManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(EntityBlackHole blackhole, double x, double y, double z, float fa, float fb){
|
||||
public void doRender(EntityBlackHole entity, double x, double y, double z, float entityYaw, float partialTicks){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
@@ -48,17 +51,10 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
|
||||
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if(blackhole.ticksExisted < 10){
|
||||
GlStateManager.scale((float)blackhole.ticksExisted / 10, (float)blackhole.ticksExisted / 10,
|
||||
(float)blackhole.ticksExisted / 10);
|
||||
}
|
||||
if(blackhole.ticksExisted > blackhole.lifetime - 10){
|
||||
GlStateManager.scale((float)(blackhole.lifetime - blackhole.ticksExisted) / 10,
|
||||
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10,
|
||||
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10);
|
||||
}
|
||||
float s = DrawingUtils.smoothScaleFactor(entity.lifetime, entity.ticksExisted, partialTicks, 10, 10);
|
||||
GlStateManager.scale(s, s, s);
|
||||
|
||||
this.bindTexture(texture);
|
||||
this.bindTexture(RAY_TEXTURE);
|
||||
|
||||
// In theory this stuff should sort the rays into the correct render order based on the distance from
|
||||
// the 'camera' (i.e. the player's viewpoint)
|
||||
@@ -66,24 +62,24 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
|
||||
// coordinates which were inconsistent with my calculated ones. Since I know those will give the desired
|
||||
// effect anyway, I just used them directly instead.
|
||||
|
||||
ArrayList<RayHelper> rays = new ArrayList<RayHelper>(1);
|
||||
ArrayList<RayHelper> rays = new ArrayList<>(1);
|
||||
|
||||
for(int j = 0; j < 30; j++){
|
||||
|
||||
float scale = 3.0f;
|
||||
float radius = 3.0f * entity.getSizeMultiplier();
|
||||
|
||||
int a = blackhole.randomiser[j];
|
||||
int b = blackhole.randomiser2[j];
|
||||
int a = entity.randomiser[j];
|
||||
int b = entity.randomiser2[j];
|
||||
|
||||
int sliceAngle = 20 + a;
|
||||
|
||||
double x1 = scale * MathHelper.sin((blackhole.ticksExisted + 40 * j) * ((float)Math.PI / 180f));
|
||||
double x1 = radius * MathHelper.sin((entity.ticksExisted + 40 * j) * ((float)Math.PI / 180f));
|
||||
// double y1 = 0.7*MathHelper.cos((blackhole.timer - 40*j)*(Math.PI/180))*j/10;
|
||||
double z1 = scale * MathHelper.cos((blackhole.ticksExisted + 40 * j) * ((float)Math.PI / 180));
|
||||
double z1 = radius * MathHelper.cos((entity.ticksExisted + 40 * j) * ((float)Math.PI / 180));
|
||||
|
||||
double x2 = scale * MathHelper.sin((blackhole.ticksExisted + 40 * j - sliceAngle) * ((float)Math.PI / 180));
|
||||
double x2 = radius * MathHelper.sin((entity.ticksExisted + 40 * j - sliceAngle) * ((float)Math.PI / 180));
|
||||
// double y2 = 0.7*MathHelper.sin((blackhole.timer - 40*j)*(Math.PI/180))*j/10;
|
||||
double z2 = scale * MathHelper.cos((blackhole.ticksExisted + 40 * j - sliceAngle) * ((float)Math.PI / 180));
|
||||
double z2 = radius * MathHelper.cos((entity.ticksExisted + 40 * j - sliceAngle) * ((float)Math.PI / 180));
|
||||
|
||||
double absoluteX = x1 * MathHelper.cos(31 * b);
|
||||
double absoluteY = z1 * MathHelper.sin(31 * a) + x1 * MathHelper.cos(31 * a) * MathHelper.sin(31 * b);
|
||||
@@ -143,7 +139,7 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
this.bindTexture(texture2);
|
||||
this.bindTexture(CENTRE_TEXTURE);
|
||||
|
||||
buffer.pos(-0.4, 0.4, 0).tex(0, 0).endVertex();
|
||||
buffer.pos(0.4, 0.4, 0).tex(1, 0).endVertex();
|
||||
@@ -165,7 +161,7 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(EntityBlackHole entity){
|
||||
return texture;
|
||||
return RAY_TEXTURE;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.entity;
|
||||
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
@@ -0,0 +1,51 @@
|
||||
package electroblob.wizardry.client.renderer.entity;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.client.model.ModelBoulder;
|
||||
import electroblob.wizardry.entity.construct.EntityBoulder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class RenderBoulder extends Render<EntityBoulder> {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/boulder.png");
|
||||
|
||||
private ModelBoulder model = new ModelBoulder();
|
||||
|
||||
public RenderBoulder(RenderManager manager){
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(EntityBoulder entity, double x, double y, double z, float yaw, float partialTicks){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate(x, y + entity.height/2, z);
|
||||
GlStateManager.rotate(180, 0F, 0F, 1F);
|
||||
GlStateManager.rotate(yaw - 90, 0, 1, 0);
|
||||
GlStateManager.rotate(entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * partialTicks, 0, 0, 1);
|
||||
GlStateManager.translate(0, -entity.height/2, 0);
|
||||
|
||||
// Pass in -1 for the lifetime as the boulder crumbles when the time expires
|
||||
float s = DrawingUtils.smoothScaleFactor(-1, entity.ticksExisted, partialTicks, 10, 10);
|
||||
s *= entity.getSizeMultiplier();
|
||||
GlStateManager.scale(s, s, s);
|
||||
|
||||
GlStateManager.translate(0, 0.875, 0); // No idea why it starts 7/8 of a block too low, but it does
|
||||
|
||||
this.bindTexture(TEXTURE);
|
||||
|
||||
model.render(entity, 0, 0, 0, 0, 0, 0.0625f);
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceLocation getEntityTexture(EntityBoulder entity){
|
||||
return TEXTURE;
|
||||
}
|
||||
|
||||
}
|
||||
+27
-27
@@ -1,8 +1,9 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.entity;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.entity.construct.EntityBubble;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
@@ -11,21 +12,21 @@ import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class RenderBubble extends Render<EntityBubble> {
|
||||
|
||||
private static final ResourceLocation particleTextures = new ResourceLocation("textures/particle/particles.png");
|
||||
private static final ResourceLocation darkOrbTexture = new ResourceLocation(Wizardry.MODID,
|
||||
"textures/entity/dark_orb.png");
|
||||
private static final ResourceLocation PARTICLE_TEXTURES = new ResourceLocation("textures/particle/particles.png");
|
||||
private static final ResourceLocation ENTRAPMENT_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/entrapment.png");
|
||||
|
||||
public RenderBubble(RenderManager renderManager){
|
||||
super(renderManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(EntityBubble entity, double par2, double par4, double par6, float par8, float par9){
|
||||
public void doRender(EntityBubble entity, double x, double y, double z, float entityYaw, float partialTicks){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
@@ -33,18 +34,20 @@ public class RenderBubble extends Render<EntityBubble> {
|
||||
|
||||
float yOffset = 0;
|
||||
|
||||
if(WizardryUtilities.getRider(entity) != null){
|
||||
yOffset = WizardryUtilities.getRider(entity).height / 2;
|
||||
Entity rider = EntityUtils.getRider(entity);
|
||||
|
||||
if(rider != null){
|
||||
yOffset = rider.height / 2;
|
||||
}
|
||||
|
||||
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
|
||||
GlStateManager.translate((float)x, (float)y + yOffset, (float)z);
|
||||
|
||||
this.bindTexture(((EntityBubble)entity).isDarkOrb ? darkOrbTexture : particleTextures);
|
||||
this.bindTexture(entity.isDarkOrb ? ENTRAPMENT_TEXTURE : PARTICLE_TEXTURES);
|
||||
float f6 = 1.0F;
|
||||
float f7 = 0.5F;
|
||||
float f8 = 0.5F;
|
||||
|
||||
if(((EntityBubble)entity).isDarkOrb){
|
||||
if(entity.isDarkOrb){
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
|
||||
}else{
|
||||
@@ -63,35 +66,32 @@ public class RenderBubble extends Render<EntityBubble> {
|
||||
GlStateManager.rotate(180.0F - this.renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||
|
||||
float f11 = 3.0F;
|
||||
GlStateManager.scale(f11, f11, f11);
|
||||
// Bubble 'bursts' so doesn't shrink when is disappears
|
||||
float s = 3 * DrawingUtils.smoothScaleFactor(entity.isDarkOrb ? entity.lifetime : -1, entity.ticksExisted, partialTicks, 10, 10);
|
||||
GlStateManager.scale(s, s, s);
|
||||
|
||||
double pixelwidth = (1.0d / 128);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
// tessellator.setColorRGBA_I(k1, 128);
|
||||
// buffer.normal(0.0F, 1.0F, 0.0F);
|
||||
|
||||
if(((EntityBubble)entity).isDarkOrb){
|
||||
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(0, 1).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(1, 1).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(1, 0).endVertex();
|
||||
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(0, 0).endVertex();
|
||||
if(entity.isDarkOrb){
|
||||
buffer.pos(0.0F - f7, 0.0F - f8, 0.0D).tex(0, 1).endVertex();
|
||||
buffer.pos(f6 - f7, 0.0F - f8, 0.0D).tex(1, 1).endVertex();
|
||||
buffer.pos(f6 - f7, 1.0F - f8, 0.0D).tex(1, 0).endVertex();
|
||||
buffer.pos(0.0F - f7, 1.0F - f8, 0.0D).tex(0, 0).endVertex();
|
||||
}else{
|
||||
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 24).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.0D).tex(pixelwidth * 8, pixelwidth * 24).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth * 8, pixelwidth * 17).endVertex();
|
||||
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.0D).tex(pixelwidth, pixelwidth * 17).endVertex();
|
||||
buffer.pos(0.0F - f7, 0.0F - f8, 0.0D).tex(pixelwidth, pixelwidth * 24).endVertex();
|
||||
buffer.pos(f6 - f7, 0.0F - f8, 0.0D).tex(pixelwidth * 8, pixelwidth * 24).endVertex();
|
||||
buffer.pos(f6 - f7, 1.0F - f8, 0.0D).tex(pixelwidth * 8, pixelwidth * 17).endVertex();
|
||||
buffer.pos(0.0F - f7, 1.0F - f8, 0.0D).tex(pixelwidth, pixelwidth * 17).endVertex();
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
if(((EntityBubble)entity).isDarkOrb){
|
||||
GlStateManager.enableLighting();
|
||||
}
|
||||
if(entity.isDarkOrb) GlStateManager.enableLighting();
|
||||
GlStateManager.disableRescaleNormal();
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
+14
-15
@@ -1,6 +1,7 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
package electroblob.wizardry.client.renderer.entity;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.entity.construct.EntityDecay;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
@@ -14,17 +15,17 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class RenderDecay extends Render<EntityDecay> {
|
||||
|
||||
private static final ResourceLocation[] textures = new ResourceLocation[10];
|
||||
private static final ResourceLocation[] TEXTURES = new ResourceLocation[10];
|
||||
|
||||
public RenderDecay(RenderManager renderManager){
|
||||
super(renderManager);
|
||||
for(int i = 0; i < 10; i++){
|
||||
textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/decay_" + i + ".png");
|
||||
TEXTURES[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/decay/decay_" + i + ".png");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doRender(EntityDecay entity, double par2, double par4, double par6, float par8, float par9){
|
||||
public void doRender(EntityDecay entity, double x, double y, double z, float entityYaw, float partialTicks){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
@@ -34,28 +35,26 @@ public class RenderDecay extends Render<EntityDecay> {
|
||||
|
||||
float yOffset = 0;
|
||||
|
||||
GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6);
|
||||
GlStateManager.translate((float)x, (float)y + yOffset, (float)z);
|
||||
|
||||
this.bindTexture(textures[((EntityDecay)entity).textureIndex]);
|
||||
this.bindTexture(TEXTURES[entity.textureIndex]);
|
||||
float f6 = 1.0F;
|
||||
float f7 = 0.5F;
|
||||
float f8 = 0.5F;
|
||||
|
||||
GlStateManager.rotate(-90, 1, 0, 0);
|
||||
|
||||
float scale = 2 * Math.min(1, (float)(entity.lifetime - entity.ticksExisted) / 50f);
|
||||
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
float s = 2 * DrawingUtils.smoothScaleFactor(entity.lifetime, entity.ticksExisted, partialTicks, 10, 50);
|
||||
GlStateManager.scale(s, s, s);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
// tessellator.setColorRGBA_I(k1, 128);
|
||||
// buffer.normal(0.0F, 1.0F, 0.0F);
|
||||
buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex();
|
||||
buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex();
|
||||
buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex();
|
||||
|
||||
buffer.pos(0.0F - f7, 0.0F - f8, 0.01).tex(0, 1).endVertex();
|
||||
buffer.pos(f6 - f7, 0.0F - f8, 0.01).tex(1, 1).endVertex();
|
||||
buffer.pos(f6 - f7, 1.0F - f8, 0.01).tex(1, 0).endVertex();
|
||||
buffer.pos(0.0F - f7, 1.0F - f8, 0.01).tex(0, 0).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user