forked from VoxeLibre/VoxeLibre
Compare commits
980 Commits
mineclonxx
...
doc-refact
Author | SHA1 | Date |
---|---|---|
AFCMS | d4e342313d | |
epCode | 138a3cd154 | |
Lizzy Fleckenstein | c57ead6985 | |
Lizzy Fleckenstein | 772f48ed58 | |
Lizzy Fleckenstein | 079cedaa34 | |
Lizzy Fleckenstein | 1b0d6a2c2d | |
NO11 | 656891ec61 | |
NO11 | 90bab9026b | |
NO11 | 5b43303873 | |
NO11 | 211b078d3a | |
NO11 | bb77443892 | |
AFCMS | 5fc3256930 | |
AFCMS | ee9577b625 | |
AFCMS | fd387a65af | |
AFCMS | 190d5cad33 | |
AFCMS | 4c9eeed499 | |
NO11 | 6105a9ef22 | |
AFCMS | 49044ac15e | |
AFCMS | 9e074af07f | |
AFCMS | 388ab6d8df | |
AFCMS | 981f3d5d74 | |
AFCMS | 3f3abbbee1 | |
AFCMS | 42d3830c48 | |
AFCMS | 8592670f9b | |
AFCMS | d3a237384d | |
AFCMS | 79cf98c8e3 | |
AFCMS | 00f4cfa5b5 | |
AFCMS | 0cc11d0bbb | |
AFCMS | f61102279f | |
AFCMS | f5a91f7c24 | |
AFCMS | 540508638c | |
AFCMS | 03c9c0b830 | |
AFCMS | 36f3c26139 | |
AFCMS | 0d13e1ffdd | |
AFCMS | be9fff4fe2 | |
AFCMS | ad16fe7072 | |
AFCMS | dd3b5a98ae | |
AFCMS | fddaacdeae | |
AFCMS | 8286fd2a4d | |
AFCMS | f76b66eec6 | |
cora | 66f132a645 | |
AFCMS | b6dd8d5c44 | |
AFCMS | 335405f131 | |
AFCMS | 470f7b70bc | |
AFCMS | b0a3cffad0 | |
AFCMS | 9f41c6fc64 | |
AFCMS | 36dc18e9da | |
AFCMS | 5f8d79b37a | |
AFCMS | 21b7647731 | |
AFCMS | 4fd0bf2c3f | |
AFCMS | 5975b20cff | |
AFCMS | 58510b00ee | |
AFCMS | c19c05443e | |
AFCMS | ce9258b764 | |
AFCMS | 8536e2c033 | |
AFCMS | 8baea02f24 | |
AFCMS | 52b1473657 | |
AFCMS | 3fbcacac3b | |
AFCMS | d43b2149e6 | |
AFCMS | b814fe47f9 | |
AFCMS | 962ae359af | |
AFCMS | ddc157acbf | |
AFCMS | 4fd0ea8a88 | |
AFCMS | e6f72e0c60 | |
AFCMS | dc10448c6e | |
AFCMS | 43f418c6c0 | |
AFCMS | 21fdf492e2 | |
AFCMS | c580c1ccad | |
AFCMS | e75a2e3a67 | |
AFCMS | a9c49853aa | |
AFCMS | 4bc473bc29 | |
AFCMS | 8f6a97eefe | |
AFCMS | be5eb621fd | |
AFCMS | 203c7e2c84 | |
AFCMS | 892f4b96c9 | |
AFCMS | b7bf566190 | |
AFCMS | fdfb586b16 | |
AFCMS | ac459d3914 | |
AFCMS | 621a5a53a8 | |
AFCMS | 60736d04b8 | |
AFCMS | df1eeba6b6 | |
AFCMS | 8ac5d32416 | |
AFCMS | 402a1d0088 | |
AFCMS | b8488ce55e | |
AFCMS | f9a86947e5 | |
AFCMS | 30e83088d4 | |
AFCMS | b3c0e7c1bd | |
AFCMS | bbde3b551f | |
AFCMS | 56310a3624 | |
AFCMS | fcc2087b97 | |
AFCMS | a1acf6d3c1 | |
AFCMS | 82396bd994 | |
AFCMS | 45ab5c8e25 | |
AFCMS | b58e61b988 | |
AFCMS | a200252ab8 | |
AFCMS | 0cac8f3f44 | |
AFCMS | 9edcc60ba2 | |
AFCMS | 0113d290b7 | |
AFCMS | e91ee174a4 | |
AFCMS | c1a717238b | |
AFCMS | a71a0e9161 | |
AFCMS | 1870a89af0 | |
AFCMS | 1b3763654e | |
AFCMS | 84a800f22b | |
Lizzy Fleckenstein | fb60bd0253 | |
AFCMS | a9bf923df9 | |
AFCMS | daa3b8a46c | |
Elias Åström | 067affcabb | |
Elias Åström | 4d13eddcd6 | |
Elias Åström | f7052943ec | |
Lizzy Fleckenstein | 04436ea5f7 | |
NO11 | cb82e3c9c5 | |
AFCMS | 4992a05c2b | |
kay27 | 9ae1119438 | |
NO11 | 9e095980c8 | |
NO11 | be9fb5be47 | |
NO11 | f4c302e582 | |
Code-Sploit | bcea5a35ef | |
AFCMS | 86d1e0ac12 | |
AFCMS | 866c097d56 | |
AFCMS | d5ec2ccbd8 | |
AFCMS | 0ad03acf46 | |
AFCMS | 3097df731d | |
jordan4ibanez | ad4e86deca | |
jordan4ibanez | 052bb540ba | |
AFCMS | 074e8c8389 | |
NO11 | 7e132866bf | |
NO11 | 11d700b785 | |
NO11 | 9fa51dc6b9 | |
NO11 | 6ffb7f525a | |
AFCMS | 1601437510 | |
AFCMS | 81ee51b0c2 | |
AFCMS | 813f5ff6d4 | |
AFCMS | 45201481c1 | |
kay27 | f054eb1ce6 | |
kay27 | f3c540af5d | |
NO11 | a3d3055e8a | |
NO11 | 925e482362 | |
kay27 | 96be84161f | |
NO11 | 7b78d500fd | |
NO11 | 358ea695e1 | |
NO11 | f6b8133381 | |
NO11 | 96aec38947 | |
AFCMS | c383d300e1 | |
AFCMS | 8ef8cdb03a | |
AFCMS | 836570af60 | |
AFCMS | d221e5ab0a | |
kay27 | 31b56e77ee | |
kay27 | 4bb27a0d79 | |
jordan4ibanez | 37350e81c9 | |
Lizzy Fleckenstein | 4b327bcf99 | |
Lizzy Fleckenstein | 35a2a2b912 | |
Lizzy Fleckenstein | f53ff8418f | |
Lizzy Fleckenstein | 1bd647507b | |
Lizzy Fleckenstein | f5b2a5f5c1 | |
Lizzy Fleckenstein | be0cf5788d | |
Elias Fleckenstein | 52ebc3343f | |
Lizzy Fleckenstein | a9817fea4b | |
Lizzy Fleckenstein | 70db02306f | |
Elias Fleckenstein | 0ff4780066 | |
Lizzy Fleckenstein | f7280dc4f0 | |
Lizzy Fleckenstein | 75d9450002 | |
Lizzy Fleckenstein | cb2bc52cbb | |
Lizzy Fleckenstein | 0d29688b13 | |
Lizzy Fleckenstein | 78ce97aaf6 | |
Lizzy Fleckenstein | 3b3d67a99c | |
Lizzy Fleckenstein | 7513bc600a | |
Lizzy Fleckenstein | f96258ca5c | |
Lizzy Fleckenstein | 33c6e5cdad | |
Lizzy Fleckenstein | 2c5eca3999 | |
AFCMS | f0ec64528c | |
AFCMS | cbb014ed38 | |
Lizzy Fleckenstein | 74e3c6555d | |
Lizzy Fleckenstein | ecc2010fe5 | |
Lizzy Fleckenstein | 5bb1657bd8 | |
Lizzy Fleckenstein | f063d14caf | |
Lizzy Fleckenstein | 02da1abcf9 | |
Lizzy Fleckenstein | 0d287001f7 | |
Benjamin Schötz | f528b31d48 | |
Benjamin Schötz | a77f99a1ec | |
AFCMS | 45965c0799 | |
Lizzy Fleckenstein | 1eaf662833 | |
Lizzy Fleckenstein | 63d4e57a8d | |
Lizzy Fleckenstein | ecea8f1662 | |
Lizzy Fleckenstein | ef08977112 | |
Lizzy Fleckenstein | 1f87874870 | |
Lizzy Fleckenstein | 9a3ae17564 | |
Lizzy Fleckenstein | bd74dbe321 | |
Lizzy Fleckenstein | ca9cd8cbe0 | |
Lizzy Fleckenstein | d9a670dcb8 | |
Lizzy Fleckenstein | f22b3fd457 | |
Lizzy Fleckenstein | 1079ab74d4 | |
Lizzy Fleckenstein | 2228b30658 | |
Lizzy Fleckenstein | e11185638f | |
Lizzy Fleckenstein | 1ed6aeca5e | |
Lizzy Fleckenstein | 5d3e74c844 | |
Lizzy Fleckenstein | c6e80b5882 | |
NO11 | 1c05461e67 | |
NO11 | ee749c874b | |
Lizzy Fleckenstein | 8cccbd7caa | |
Lizzy Fleckenstein | ae1212be7f | |
kay27 | 7e3dd715af | |
jordan4ibanez | 55177c03ec | |
jordan4ibanez | b74078a06c | |
Lizzy Fleckenstein | ab4b6d214e | |
Lizzy Fleckenstein | f8b9f16799 | |
Lizzy Fleckenstein | 404097dcc0 | |
Lizzy Fleckenstein | db78c19880 | |
Lizzy Fleckenstein | 7be749a122 | |
Lizzy Fleckenstein | fed1410b7f | |
NO11 | 8b64022bfd | |
NO11 | 71ff38add8 | |
Lizzy Fleckenstein | 6550e3e8e2 | |
Lizzy Fleckenstein | 87e41cc9a9 | |
Lizzy Fleckenstein | ec08032b62 | |
Lizzy Fleckenstein | 199488cc74 | |
Lizzy Fleckenstein | 33c0aa23c5 | |
kay27 | d29c71c69a | |
Marcin Serwin | 6fac49550e | |
jordan4ibanez | cf46f0d8b8 | |
jordan4ibanez | e0c94ccb8a | |
kay27 | a6ac6f5c76 | |
NO11 | 32c03dc27e | |
NO11 | 3195df3864 | |
NO11 | f1b7476825 | |
NO11 | 7a00e8acf7 | |
Lizzy Fleckenstein | 13a0fa2314 | |
Lizzy Fleckenstein | 61c6d6e276 | |
Lizzy Fleckenstein | 528f5e6b86 | |
AFCMS | d0f4dd4309 | |
epCode | 61e4db6bcf | |
AFCMS | ae83e44149 | |
Lizzy Fleckenstein | 819d59dbe7 | |
AFCMS | 173f67870e | |
AFCMS | 0a2fcdc4e8 | |
Elias Fleckenstein | 79aac4c494 | |
Lizzy Fleckenstein | a41aace9d7 | |
epCode | 9f015f2c58 | |
AFCMS | 72e53a82d7 | |
Lizzy Fleckenstein | 0867d6e406 | |
Lizzy Fleckenstein | 347cc7ee7c | |
Lizzy Fleckenstein | 6dc6fc8ec3 | |
Lizzy Fleckenstein | b43f59332a | |
Lizzy Fleckenstein | 3b1d71382f | |
Lizzy Fleckenstein | 05be20fcb8 | |
Lizzy Fleckenstein | 5df1df8e21 | |
Lizzy Fleckenstein | fed4596cb4 | |
Lizzy Fleckenstein | a77a916cc2 | |
Lizzy Fleckenstein | 8a59d7b9c6 | |
Lizzy Fleckenstein | f6d34db76e | |
NO11 | 8df9fe76d8 | |
Lizzy Fleckenstein | a2983e1fda | |
Lizzy Fleckenstein | e710795eed | |
NO11 | 4d2210c4e5 | |
NO11 | 749f1a4a62 | |
NO11 | e5a44dcb75 | |
Lizzy Fleckenstein | dd68b79782 | |
epCode | aac9d6a105 | |
NO11 | dada1e9815 | |
jordan4ibanez | 8a78b1f8ef | |
Lizzy Fleckenstein | edc89898bb | |
Lizzy Fleckenstein | fede04eaa6 | |
Lizzy Fleckenstein | 57662b319c | |
Lizzy Fleckenstein | 3e3f53efbd | |
Lizzy Fleckenstein | 97e69e04aa | |
Lizzy Fleckenstein | cab2167520 | |
Lizzy Fleckenstein | b2407e407a | |
Lizzy Fleckenstein | aeaec68c1b | |
Lizzy Fleckenstein | 302175691a | |
AFCMS | 228759e49b | |
Lizzy Fleckenstein | 6aecae6eea | |
Lizzy Fleckenstein | 939229cb21 | |
Lizzy Fleckenstein | 58d67aace6 | |
Lizzy Fleckenstein | ddb7e8388a | |
Lizzy Fleckenstein | 9eba2add3f | |
NO11 | 642351a1d2 | |
Elias Åström | 73cd482e55 | |
AFCMS | 414adff8fb | |
Elias Åström | 7f3e5bda7e | |
Lizzy Fleckenstein | a03e7f6f3a | |
Lizzy Fleckenstein | 62ed39bd76 | |
Lizzy Fleckenstein | a836ac9879 | |
Lizzy Fleckenstein | 827cd2d7b1 | |
Lizzy Fleckenstein | 78355c5c57 | |
Lizzy Fleckenstein | 50b6f03977 | |
Elias Fleckenstein | 3669ccf907 | |
Lizzy Fleckenstein | 818f33ff74 | |
Sven792 | 038066f0c5 | |
NO11 | c46c07f836 | |
epCode | 62adbb9625 | |
Lizzy Fleckenstein | f9c2d710e2 | |
Lizzy Fleckenstein | 222104b3cb | |
Lizzy Fleckenstein | 9f7b371bfc | |
Lizzy Fleckenstein | 8b23388d63 | |
Lizzy Fleckenstein | acbdc937b4 | |
Lizzy Fleckenstein | 74a3b2654f | |
Lizzy Fleckenstein | dccb71e2fb | |
Lizzy Fleckenstein | 1e7ba2b605 | |
Lizzy Fleckenstein | fe5f61c747 | |
kay27 | 1e5ae0bbac | |
epCode | c7d91baadf | |
epCode | 9c3fcae9e1 | |
Lizzy Fleckenstein | 4c25091430 | |
Lizzy Fleckenstein | ca74f23094 | |
NO11 | 7a5ce1c717 | |
NO11 | e8c15867ad | |
Lizzy Fleckenstein | 20a4e038f5 | |
Lizzy Fleckenstein | c80b1c5140 | |
Lizzy Fleckenstein | 7efc177188 | |
Lizzy Fleckenstein | d8d4cb5def | |
Lizzy Fleckenstein | 52a49e640e | |
Lizzy Fleckenstein | 69485f8505 | |
NO11 | 0c5ca70187 | |
Elias Fleckenstein | ec1ef1affa | |
jordan4ibanez | c03717139b | |
jordan4ibanez | 44a25de12f | |
NO11 | aa533edda2 | |
Lizzy Fleckenstein | c9b4ddb923 | |
Lizzy Fleckenstein | 53b0ad7347 | |
Lizzy Fleckenstein | d9195cc520 | |
NO11 | 49f6ccaa4a | |
NO11 | 3668b2dee6 | |
Lizzy Fleckenstein | a2c3eb95bb | |
Lizzy Fleckenstein | d08a226a51 | |
NO11 | 9bc2f2d866 | |
Lizzy Fleckenstein | 2827542002 | |
Lizzy Fleckenstein | 3ad5b30ea5 | |
Lizzy Fleckenstein | 1cf53caa7a | |
Lizzy Fleckenstein | d1198e8d74 | |
Lizzy Fleckenstein | 4f0bb444fe | |
Lizzy Fleckenstein | f0d7715080 | |
Lizzy Fleckenstein | 5d9c3cd85b | |
Doloment | 956dab78ce | |
Elias Åström | fc9928c0b6 | |
Elias Åström | 573b1dc44b | |
Elias Åström | dd69dcfd9f | |
Lizzy Fleckenstein | 76271199c6 | |
kay27 | 11b66e83a2 | |
AFCMS | 4aa6421faf | |
AFCMS | f967aa3d51 | |
Lizzy Fleckenstein | a7e102426a | |
Lizzy Fleckenstein | bcd058feb1 | |
Lizzy Fleckenstein | baebe3c2d2 | |
Lizzy Fleckenstein | 205572cc69 | |
Lizzy Fleckenstein | f8b54db392 | |
Lizzy Fleckenstein | bbd115fde0 | |
Lizzy Fleckenstein | 7c7af7d664 | |
Lizzy Fleckenstein | f79e12c8ae | |
Lizzy Fleckenstein | 5c928575f8 | |
Lizzy Fleckenstein | 8e37b51cac | |
Lizzy Fleckenstein | 6724a8d0ed | |
NO11 | 06699c2cc4 | |
Lizzy Fleckenstein | 6bbea11fb8 | |
Lizzy Fleckenstein | c7c47c1ca7 | |
Lizzy Fleckenstein | d952423dda | |
Lizzy Fleckenstein | 4d515e95c6 | |
Lizzy Fleckenstein | ca75a893db | |
AFCMS | 6a55136517 | |
AFCMS | 02f393998f | |
AFCMS | 22a2fdbf5f | |
AFCMS | 5f076d372a | |
Lizzy Fleckenstein | bd3c08d367 | |
Lizzy Fleckenstein | 10f81dbf0c | |
Lizzy Fleckenstein | 01c79c5a18 | |
Lizzy Fleckenstein | 095f78b785 | |
AFCMS | 457f61a532 | |
AFCMS | 1a58b0c510 | |
AFCMS | 3dd490ed6b | |
Lizzy Fleckenstein | 5d5ed91519 | |
AFCMS | 2d6e0241cd | |
AFCMS | 1df916bd7b | |
jordan4ibanez | 044e9d22ad | |
epCode | 31dfeae445 | |
epCode | cd04f6d7ce | |
AFCMS | 60e74fc41d | |
AFCMS | a602f64ea5 | |
epCode | 9feaec95d9 | |
epCode | 0ca6c06198 | |
AFCMS | b497778192 | |
AFCMS | b1f7294578 | |
epCode | f0fab4e708 | |
Elias Fleckenstein | 0c5096db13 | |
NO11 | 3fbeab7c85 | |
AFCMS | d865d95639 | |
NO11 | a8760c0375 | |
AFCMS | 54f81b7740 | |
NO11 | bbffda3635 | |
Nils Dagsson Moskopp | 2575e20e7e | |
epCode | 5fe30d7287 | |
Benjamin Schötz | bffd032a8b | |
Benjamin Schötz | e4c8ba795a | |
Lizzy Fleckenstein | 8931ffb7d3 | |
Lizzy Fleckenstein | 727d7be6ab | |
Lizzy Fleckenstein | ec6d68322a | |
epCode | 18cdd13c06 | |
Lizzy Fleckenstein | 9c75cd1a79 | |
Lizzy Fleckenstein | a3af1cdf6e | |
Lizzy Fleckenstein | 4e37cc114c | |
Lizzy Fleckenstein | 5d9bb7cacd | |
Lizzy Fleckenstein | 49e7def70a | |
Lizzy Fleckenstein | ad3defdfb3 | |
Lizzy Fleckenstein | c41bd3932c | |
Lizzy Fleckenstein | 875bb3db84 | |
Elias Fleckenstein | 76af838f4c | |
j1233 | 46b1762872 | |
j1233 | a069406f40 | |
Elias Fleckenstein | 97f8c92d95 | |
Lizzy Fleckenstein | 963adfb4e2 | |
Lizzy Fleckenstein | 6d0abb2973 | |
Lizzy Fleckenstein | e74838136d | |
Lizzy Fleckenstein | d0ddd38d4e | |
Lizzy Fleckenstein | ce0148d9a8 | |
Nicu | 36391d8583 | |
epCode | 5b93ee5e40 | |
epCode | 8d22102c66 | |
epCode | a93562a60c | |
epCode | 399ed85717 | |
jordan4ibanez | 67c1bc973a | |
NO11 | 1c50f9aed6 | |
NO11 | 311c4dc3fb | |
NO11 | 94e7bbfb80 | |
NO11 | 7a14d1d593 | |
NO11 | bc2a79cddf | |
NO11 | 52d7ffa78f | |
NO11 | f768972469 | |
NO11 | 9c68528b8b | |
NO11 | 1597e093b5 | |
NO11 | f15a28109c | |
NO11 | 81d0ce5ea7 | |
epCode | f498d3ae02 | |
NO11 | e334a71361 | |
NO11 | 67fff50fc4 | |
NO11 | e96eb79a3f | |
NO11 | de3f236bf2 | |
NO11 | 940621b676 | |
NO11 | 9519c8ebaa | |
NO11 | 28719264df | |
NO11 | 4ac115cf90 | |
NO11 | 1f4ac3d8e0 | |
Code-Sploit | cd0d2d2296 | |
kay27 | 3077498a63 | |
Code-Sploit | 84764389dc | |
Lizzy Fleckenstein | 78d387e2df | |
Lizzy Fleckenstein | 421ab9f660 | |
Lizzy Fleckenstein | 422385ad02 | |
Lizzy Fleckenstein | 20bd91a14e | |
Lizzy Fleckenstein | 5ddd1d0193 | |
Lizzy Fleckenstein | 037832a177 | |
epCode | 424685d3d3 | |
Lizzy Fleckenstein | 5028728fbc | |
Lizzy Fleckenstein | 6f770bc962 | |
Lizzy Fleckenstein | 6887948718 | |
Lizzy Fleckenstein | f540bc2bb1 | |
Lizzy Fleckenstein | 5fb7913355 | |
Lizzy Fleckenstein | d3a3253563 | |
Lizzy Fleckenstein | c3868084af | |
Lizzy Fleckenstein | 0d5933b95e | |
Lizzy Fleckenstein | 615b15f133 | |
Lizzy Fleckenstein | ed7099fefc | |
Lizzy Fleckenstein | db5626fcb4 | |
Lizzy Fleckenstein | 523a0c54d6 | |
Lizzy Fleckenstein | e0feba115d | |
Lizzy Fleckenstein | b914e088cc | |
Lizzy Fleckenstein | c0a31f0e9c | |
Lizzy Fleckenstein | 24f8f9166b | |
Lizzy Fleckenstein | af044e6a96 | |
Lizzy Fleckenstein | 2313012f60 | |
epCode | ce49cd02ac | |
kay27 | 40c733c913 | |
kay27 | a76fe2b487 | |
kay27 | b14ca5a843 | |
epCode | 3ff214ec2d | |
epCode | f6db31eae3 | |
Lizzy Fleckenstein | 9ba1917209 | |
kay27 | ea41c82834 | |
Lizzy Fleckenstein | 2116b2b9d0 | |
epCode | 08b7340ff5 | |
kay27 | 7a8079bb64 | |
NO11 | cdd12a0c71 | |
NO11 | 652f8d48ed | |
NO11 | 988f298375 | |
NO11 | c73cd8b810 | |
NO11 | ebd4380c98 | |
NO11 | 3d732c2412 | |
NO11 | 03e112ef9b | |
NO11 | 9b81a4d83e | |
NO11 | cbcaef19c6 | |
NO11 | 9e5fb7f533 | |
epCode | 849823af1f | |
kay27 | d50fd06c82 | |
kay27 | 3375e903ce | |
AFCMS | f5f6e232cc | |
Lizzy Fleckenstein | c6ffccfef5 | |
Lizzy Fleckenstein | cbd2731e06 | |
kay27 | a733eb8e0c | |
Nils Dagsson Moskopp | 7c8cf6f79f | |
kay27 | f0c2eb86a2 | |
kay27 | 26ce10d25c | |
kay27 | 6b31e85385 | |
jordan4ibanez | 6279f5eb41 | |
jordan4ibanez | 9789cf5dcd | |
jordan4ibanez | 26847bbb54 | |
jordan4ibanez | 4fca50dead | |
jordan4ibanez | 310dcf9660 | |
jordan4ibanez | ba9866db49 | |
jordan4ibanez | 282ba2614a | |
jordan4ibanez | 26ef8c2674 | |
jordan4ibanez | f5cc2bab09 | |
jordan4ibanez | 71c50042e6 | |
jordan4ibanez | ae0c235c1f | |
jordan4ibanez | 668b67158c | |
jordan4ibanez | c259fc2a28 | |
jordan4ibanez | 249a3c8891 | |
jordan4ibanez | 34b66acc9d | |
jordan4ibanez | 89f35c06af | |
jordan4ibanez | cb093b774c | |
jordan4ibanez | abc68f4dc6 | |
jordan4ibanez | 38dcbcb3d4 | |
jordan4ibanez | d65a5e3be0 | |
kay27 | de41a4c26b | |
kay27 | 5e0bd2281c | |
jordan4ibanez | 346efee399 | |
jordan4ibanez | 18f73ba31f | |
jordan4ibanez | 213d24cc86 | |
jordan4ibanez | b9d175e6a5 | |
jordan4ibanez | fa95545252 | |
jordan4ibanez | 0842a36aa6 | |
iliekprogrammar | 18ee1d476a | |
iliekprogrammar | d50665d2d5 | |
AFCMS | e228c1d70b | |
iliekprogrammar | 5ccb12586d | |
iliekprogrammar | 2db0e176b3 | |
kay27 | 8e30bc8dbd | |
AFCMS | f7ddfe2891 | |
AFCMS | 11114c6847 | |
Lizzy Fleckenstein | d77affca91 | |
Lizzy Fleckenstein | 6a1a634cba | |
Lizzy Fleckenstein | 6c35ff1fc5 | |
Lizzy Fleckenstein | 567f157541 | |
Lizzy Fleckenstein | f282cd0c4d | |
Lizzy Fleckenstein | 3449b3eb7c | |
iliekprogrammar | 986ae950ec | |
iliekprogrammar | 61cef21cd1 | |
TechDudie | db9e8d23d9 | |
TechDudie | f664a87dac | |
Lizzy Fleckenstein | 6e2a7c8a7e | |
Lizzy Fleckenstein | c451866a36 | |
Lizzy Fleckenstein | 3c1a38904a | |
Lizzy Fleckenstein | b2c09c8ba0 | |
jordan4ibanez | 4f2a6b2db0 | |
jordan4ibanez | ec6eb51726 | |
jordan4ibanez | 6cdf7c98c2 | |
jordan4ibanez | 0970981252 | |
jordan4ibanez | 6c4c22e3b9 | |
jordan4ibanez | 9b1cc19718 | |
jordan4ibanez | 7cecc71b91 | |
jordan4ibanez | da057ee9e8 | |
jordan4ibanez | 6aaf25bbc9 | |
jordan4ibanez | 7826311175 | |
jordan4ibanez | 4a1faa44de | |
jordan4ibanez | 8ab9de74dc | |
jordan4ibanez | acd2b8e691 | |
jordan4ibanez | 21334bc49d | |
jordan4ibanez | 56f94af6ce | |
jordan4ibanez | 9f7899c01a | |
jordan4ibanez | 4ec3fd0ba6 | |
jordan4ibanez | 00db03320b | |
kay27 | 069e089ae4 | |
Lizzy Fleckenstein | 430f958fae | |
Lizzy Fleckenstein | f65c40f805 | |
Doloment | 51f121d516 | |
jordan4ibanez | 9e1b662c03 | |
jordan4ibanez | 8e2493dd9a | |
Elias Fleckenstein | 89a9b16465 | |
Lizzy Fleckenstein | ea08fee9ba | |
Doloment | 1e17989ef2 | |
Lizzy Fleckenstein | 3c73ad3b98 | |
Lizzy Fleckenstein | 91e2372df0 | |
Elias Fleckenstein | 058c6ef9f4 | |
Lizzy Fleckenstein | 38a12e59da | |
Lizzy Fleckenstein | 1d587b8895 | |
Lizzy Fleckenstein | 83b9cf3ad2 | |
Doloment | 31a7a4fbb6 | |
Lizzy Fleckenstein | 962a13847e | |
Lizzy Fleckenstein | f350fa6272 | |
Doloment | 055c406d7a | |
Lizzy Fleckenstein | a348909ba3 | |
Lizzy Fleckenstein | 5bdb3bc274 | |
Lizzy Fleckenstein | ba15f01ca9 | |
Lizzy Fleckenstein | c93a865098 | |
Lizzy Fleckenstein | d07e415b37 | |
Lizzy Fleckenstein | 175cb44fb1 | |
AFCMS | 91da727184 | |
AFCMS | 339e3e2792 | |
kay27 | beb2484224 | |
AFCMS | 28402ca663 | |
Lizzy Fleckenstein | e407ad2254 | |
Elias Fleckenstein | b1c4476a04 | |
kay27 | b1f27dba6a | |
kay27 | 4bc93040d5 | |
kay27 | 5fc3bb11ef | |
ztianyang | 1e1d31b57b | |
epCode | a6f0ad13a0 | |
epCode | 93684baa86 | |
Tianyang Zhang | 8bb8a0e3b2 | |
Saku Laesvuori | c5e1734c1c | |
Lizzy Fleckenstein | 90f312f772 | |
Lizzy Fleckenstein | 1144006cdd | |
kay27 | f54f4ebcf9 | |
Lizzy Fleckenstein | 598692cf8c | |
Lizzy Fleckenstein | ff538d51bd | |
Lizzy Fleckenstein | 49446bbb7b | |
Saku Laesvuori | 4a085c9526 | |
epCode | ac87e0604e | |
jordan4ibanez | f8229def5e | |
jordan4ibanez | 90fd65ac66 | |
epCode | 40b07e466b | |
jordan4ibanez | 0b0a180343 | |
jordan4ibanez | 1b511936f5 | |
jordan4ibanez | 441ce5522a | |
jordan4ibanez | a807ee6372 | |
jordan4ibanez | f1863baedc | |
jordan4ibanez | 0641f09915 | |
jordan4ibanez | bb6cce06e5 | |
jordan4ibanez | c572db92aa | |
jordan4ibanez | b14bc21829 | |
jordan4ibanez | 269ed6b3eb | |
jordan4ibanez | da3d5025a8 | |
jordan4ibanez | 43c47bbe0f | |
jordan4ibanez | 844db8aa7b | |
jordan4ibanez | 22cbfa32de | |
jordan4ibanez | 0840ad98a2 | |
jordan4ibanez | ea54936d28 | |
jordan4ibanez | 1cbd3a998d | |
jordan4ibanez | 61e812e40a | |
jordan4ibanez | b83b4c55fa | |
jordan4ibanez | 18d7be4a4f | |
AFCMS | b68c4b07c1 | |
AFCMS | ca01b3641b | |
AFCMS | 0db47dbf02 | |
AFCMS | 59d687c579 | |
AFCMS | c457c4ce3c | |
AFCMS | ead33e3520 | |
AFCMS | e20e0fab71 | |
AFCMS | 695ad9120b | |
AFCMS | 0da8339352 | |
NO11 | 39aaf0f21f | |
AFCMS | c0fcbffd70 | |
AFCMS | cbc1052f6b | |
jordan4ibanez | 5f361cde29 | |
jordan4ibanez | 1e3676c391 | |
kay27 | fd51910b89 | |
jordan4ibanez | 2f272b3dff | |
epCode | 0dbe66f3b4 | |
AFCMS | 15803fddc2 | |
epCode | 5356e97b77 | |
AFCMS | 626990adeb | |
iliekprogrammar | c44054b51c | |
iliekprogrammar | 9885f36c62 | |
iliekprogrammar | bfff643ff4 | |
iliekprogrammar | ccea673dcc | |
iliekprogrammar | 08e280d9b4 | |
iliekprogrammar | 52c788f197 | |
iliekprogrammar | 089d6aa5c8 | |
iliekprogrammar | 9518086b6b | |
AFCMS | 0740854b5d | |
epCode | 86b63c8bc4 | |
epCode | 38e4e7293a | |
epCode | 97424f7d0a | |
epCode | a14959ac70 | |
AFCMS | 3b8916ef65 | |
AFCMS | a040355dce | |
AFCMS | d4e0d4d1c1 | |
AFCMS | c35dab1d08 | |
AFCMS | 613779a851 | |
AFCMS | 59c13b6df8 | |
AFCMS | 857a0c5565 | |
AFCMS | 41a8cd0e15 | |
AFCMS | 7a5c2d617b | |
AFCMS | 369c8b9b8a | |
AFCMS | 7ec7012572 | |
AFCMS | c70ea7c843 | |
AFCMS | f60941003d | |
AFCMS | 3a514ecdad | |
AFCMS | 600e8bede2 | |
AFCMS | 84819bf9f5 | |
AFCMS | f8a627915e | |
AFCMS | a2fcd28a3d | |
AFCMS | f51deb0737 | |
epCode | 5a7d128861 | |
Elias Fleckenstein | 68d49a43b2 | |
ArTee3 | 1b9737b431 | |
iliekprogrammar | ecdbc30b63 | |
kay27 | d1a0299b92 | |
kay27 | 80d845adb6 | |
kay27 | 2e3a5efaf9 | |
kay27 | b587b1f2a5 | |
kay27 | 1818fcf592 | |
kay27 | bbd52043f1 | |
kay27 | 05260d03d5 | |
kay27 | cb2aae5a55 | |
AFCMS | d07cf64d11 | |
AFCMS | 5a4355b859 | |
kay27 | 628ca226a6 | |
iliekprogrammar | 24da94ec3b | |
iliekprogrammar | e76a0ba6e8 | |
AFCMS | c7389dc0a4 | |
AFCMS | 890a569b13 | |
kay27 | 54e7529754 | |
AFCMS | cdb67d96a6 | |
AFCMS | 6f9c1856b8 | |
AFCMS | e56d9d2ab8 | |
AFCMS | 52939ff6a4 | |
AFCMS | 39ac3f208d | |
AFCMS | 2a5dcd1634 | |
AFCMS | 19db2a479f | |
AFCMS | fb50b256ed | |
AFCMS | ce123d4676 | |
AFCMS | 57ce5143b9 | |
AFCMS | 3ba7a40251 | |
AFCMS | 6a6b5970b3 | |
AFCMS | 30e50a64ef | |
AFCMS | cb294a5cad | |
AFCMS | 9bb5e748b9 | |
AFCMS | 61c9d065fb | |
AFCMS | e2fd0823b9 | |
AFCMS | 826d60e16e | |
AFCMS | e2adead700 | |
AFCMS | e11941c107 | |
AFCMS | e3c99c5be2 | |
AFCMS | 202e30a782 | |
AFCMS | 50bdf03189 | |
AFCMS | 8c002671c0 | |
Lizzy Fleckenstein | 0372057fe3 | |
Lizzy Fleckenstein | 6f8d0d4de0 | |
AFCMS | 9c8ec7d4ec | |
AFCMS | 041300cde4 | |
AFCMS | 88fc515cff | |
AFCMS | 01eba30058 | |
AFCMS | 35b2bd72f8 | |
AFCMS | 41768e95a1 | |
AFCMS | c0308c7c08 | |
AFCMS | 50c35ff5e8 | |
AFCMS | 53d7134437 | |
AFCMS | 78bad87a72 | |
AFCMS | 0e5bbd6d3d | |
kay27 | 25f6a9ee23 | |
AFCMS | 8258dae1b8 | |
AFCMS | e4a6244fdd | |
AFCMS | b9301f12ce | |
AFCMS | 86a18802dc | |
Lizzy Fleckenstein | 97991d138c | |
Code-Sploit | 630e7e8acb | |
Lizzy Fleckenstein | d555fce8bc | |
Code-Sploit | 322578df6a | |
epCode | dbc6dd8cb3 | |
Lizzy Fleckenstein | 46c6328432 | |
Lizzy Fleckenstein | 43a60e0c57 | |
Lizzy Fleckenstein | a47eda44e9 | |
Lizzy Fleckenstein | fe937665f9 | |
kay27 | 6addb7db18 | |
Elias Åström | 0d7c2c4988 | |
kay27 | 3e58e989a1 | |
kay27 | 06280e3bba | |
Blue Blancmange | 44c4999b37 | |
epCode | 647a53c354 | |
ArTee3 | 910c9083e5 | |
kay27 | 66a64439c6 | |
kay27 | 7fe3217cd0 | |
epCode | 01df02667b | |
kay27 | 03feb36558 | |
kay27 | 1f925b6c84 | |
Lizzy Fleckenstein | 9a4d26c2ae | |
Lizzy Fleckenstein | 2d1ac1c7fa | |
Lizzy Fleckenstein | f0c2a0a1e9 | |
ArTee3 | 1fa2bd3477 | |
Elias Åström | 7f56e5efa4 | |
Elias Åström | c1e295de5f | |
Elias Åström | dac3c21628 | |
Elias Åström | b0c7941b3a | |
iliekprogrammar | ca635b69be | |
iliekprogrammar | ebf9f8c918 | |
Elias Åström | 0996a83ba0 | |
Elias Åström | 1621c23308 | |
iliekprogrammar | 23f69dfd1e | |
Elias Åström | 1873080046 | |
Elias Åström | 46541a4adc | |
Elias Åström | 10154d5778 | |
epCode | c877d6e922 | |
iliekprogrammar | 12745bd450 | |
iliekprogrammar | 03be45b983 | |
iliekprogrammar | 34dbddb40a | |
kay27 | b871433c47 | |
Nicu | a40e1c4737 | |
Nicu | df8fdda2c5 | |
iliekprogrammar | 249b5cfd1e | |
iliekprogrammar | f5f85a2148 | |
Lizzy Fleckenstein | d168bfa791 | |
Lizzy Fleckenstein | c20bd768ec | |
Lizzy Fleckenstein | 67cedf1308 | |
Lizzy Fleckenstein | 9391628813 | |
Lizzy Fleckenstein | 327bb68927 | |
Lizzy Fleckenstein | 906aa3b434 | |
Lizzy Fleckenstein | ecd27a4cdb | |
Lizzy Fleckenstein | 55df2a57f4 | |
Lizzy Fleckenstein | 4ff987ccc5 | |
Lizzy Fleckenstein | f3c37f49b9 | |
Lizzy Fleckenstein | f3580efced | |
Lizzy Fleckenstein | 4a53ba67ab | |
epCode | d02fc0c83d | |
epCode | e474ce6397 | |
ZeDique la Ruleta | b71566aad6 | |
epCode | 4fbb95bed3 | |
ZeDique la Ruleta | 2571c6124b | |
Nicu | e61f1e38f2 | |
AFCMS | a482a18a67 | |
Elias Åström | ed30fa0868 | |
Elias Åström | 8d473a42ca | |
Elias Åström | 0f2c487dca | |
Elias Åström | dc41c594aa | |
Elias Åström | bfe51316ee | |
Elias Åström | 13268965ee | |
Elias Åström | 521f96b4ab | |
Lizzy Fleckenstein | df59cc12a8 | |
Lizzy Fleckenstein | 3df3e957e2 | |
Lizzy Fleckenstein | 0e206e9974 | |
Lizzy Fleckenstein | 6ac0d628ef | |
Lizzy Fleckenstein | 413fbc9c60 | |
Elias Åström | c8b543991f | |
Elias Åström | 8f9650abe4 | |
Elias Åström | 4c46eb2b4b | |
Elias Åström | fe770c19a5 | |
Elias Åström | 0112825a9f | |
Elias Åström | cff0130506 | |
Elias Åström | 7b93f68ed8 | |
Elias Åström | ece4c892f4 | |
Elias Åström | bec1f786a6 | |
Elias Åström | 6458565bf9 | |
Elias Åström | 2e9b3c2259 | |
Elias Åström | 5193730652 | |
Elias Åström | e77473e800 | |
Elias Åström | 922bdbc601 | |
Elias Åström | 3241dbbec5 | |
Elias Åström | b47733507d | |
Elias Åström | f0528b11d7 | |
Elias Åström | 503b3a8149 | |
Elias Åström | 5b5a254b1a | |
Elias Åström | 0c90dda04c | |
Elias Åström | fa86d4e5eb | |
Elias Åström | f8461d5e90 | |
Elias Åström | fb6f5eae7a | |
AFCMS | 558fa57cc6 | |
epCode | 61ef6ebc03 | |
epCode | e52d58d15a | |
epCode | 6b1ce182d3 | |
AFCMS | 5df668f6af | |
AFCMS | ae18ca7602 | |
Elias Åström | 5c3bb22036 | |
Elias Åström | 7441f0269b | |
Elias Fleckenstein | a06d0f7474 | |
ZeDique la Ruleta | 6c49c46697 | |
epCode | b82da05590 | |
epCode | 86f2d639f9 | |
Elias Åström | 0805431231 | |
epCode | 33c589369f | |
AFCMS | 6645c4cb30 | |
AFCMS | 8f30e223e2 | |
AFCMS | 5d17a6b699 | |
AFCMS | f35f80d79a | |
Code-Sploit | 834dfcf9af | |
Code-Sploit | f06a56d7c4 | |
AFCMS | 77167e901d | |
AFCMS | 2da8be9f78 | |
AFCMS | 71bb18cd76 | |
kay27 | cad23bd851 | |
AFCMS | c1da231f9d | |
Lizzy Fleckenstein | cb0d49a5a5 | |
Lizzy Fleckenstein | 19e5670e85 | |
AFCMS | 731d42196a | |
Elias Fleckenstein | 502666932f | |
iliekprogrammar | c30e9e511d | |
iliekprogrammar | 8519730ee4 | |
AFCMS | bd9713ab50 | |
AFCMS | 4b2c963222 | |
iliekprogrammar | 440dd5700d | |
epCode | 39c357672c | |
AFCMS | fe6b7cb89b | |
AFCMS | c8a7ca729e | |
AFCMS | 5098932b98 | |
AFCMS | 671de95357 | |
AFCMS | 2dcaf8fdcb | |
AFCMS | 9eda34b0ff | |
AFCMS | 9d19c3db4b | |
AFCMS | bb9df764c4 | |
AFCMS | e069962c48 | |
iliekprogrammar | 09f97584bc | |
kay27 | d5c82cb2cf | |
iliekprogrammar | 8c0c1380b1 | |
iliekprogrammar | 10c46e91ff | |
iliekprogrammar | b23495b9c1 | |
AFCMS | 53510ea32a | |
AFCMS | 6e561be37c | |
iliekprogrammar | 1b00346790 | |
iliekprogrammar | 7ce6485717 | |
kay27 | 53bfda827a | |
Code-Sploit | 08f522ffff | |
iliekprogrammar | 7a5aa54035 | |
epCode | dd7facfc03 | |
epCode | 1bdf141198 | |
epCode | 975efb2288 | |
Elias Åström | 69e38debe5 | |
AFCMS | 68df2c447a | |
AFCMS | 3ef10cfb30 | |
epCode | 8115575f20 | |
epCode | 46be7c0388 | |
epCode | 90a0858495 | |
epCode | 1d65daa2c9 | |
epCode | 9419db6d35 | |
epCode | 40471399cb | |
AFCMS | a84b70bde6 | |
AFCMS | 36cc040c41 | |
AFCMS | 752f74e554 | |
Lizzy Fleckenstein | 75c2787583 | |
Lizzy Fleckenstein | 88372778c9 | |
AFCMS | 6c3d4524a0 | |
Lizzy Fleckenstein | 0a5b1e75d0 | |
Lizzy Fleckenstein | 87e4bed630 | |
Lizzy Fleckenstein | 8e28690303 | |
AFCMS | ad87169120 | |
AFCMS | 81167b4431 | |
epCode | cb10a5508b | |
epCode | eeb1f88e08 | |
epCode | 360070bb6a | |
AFCMS | 06e8e972cc | |
AFCMS | 8c87014a01 | |
AFCMS | fb8b0e877e | |
AFCMS | bed3dd87ad | |
AFCMS | 1a60d08a37 | |
epCode | 19337489f6 | |
AFCMS | 6fd6717302 | |
AFCMS | 787d997e51 | |
AFCMS | 3b7b055e2c | |
AFCMS | d37d6fe07f | |
AFCMS | 7b5d67cdbe | |
AFCMS | 134005180c | |
AFCMS | 20e0aed58a | |
AFCMS | 21ddae3dc1 | |
AFCMS | 5124a97add | |
AFCMS | 31eff23ce8 | |
AFCMS | 9a910e033b | |
epCode | d12009538e | |
AFCMS | d3a2faefe2 | |
kay27 | 6e6809f360 | |
kay27 | 15fa1e5b7a | |
AFCMS | d274f6f444 | |
AFCMS | bddc4a3ac7 | |
AFCMS | a6bceb08ee | |
kay27 | 8ed28adf7c | |
kay27 | 66febf158a | |
kay27 | 45c0c576f7 | |
AFCMS | 3635b848d5 | |
kay27 | f3fb80200d | |
Elias Fleckenstein | 95111e1d8d | |
AFCMS | b0c57beacd | |
Elias Fleckenstein | 2fba745724 | |
AFCMS | e3eb8c7ac8 | |
AFCMS | 1f1f9f54a2 | |
AFCMS | b1ab79b857 | |
Lizzy Fleckenstein | 2125c51c9c | |
AFCMS | d71e296602 | |
AFCMS | 71353ac934 | |
AFCMS | 0e8b5c403a | |
Lizzy Fleckenstein | 09671b7ac9 | |
Lizzy Fleckenstein | 31441a02e5 | |
AFCMS | 68d8eb4c9c | |
Lizzy Fleckenstein | d57db0444f | |
Lizzy Fleckenstein | 713f933a99 | |
Lizzy Fleckenstein | ee084f33a7 | |
epCode | 5f544bd5b3 | |
epCode | 65734d0fa4 |
|
@ -0,0 +1,55 @@
|
||||||
|
unused_args = false
|
||||||
|
allow_defined_top = true
|
||||||
|
max_line_length = false
|
||||||
|
redefined = false
|
||||||
|
|
||||||
|
globals = {
|
||||||
|
"minetest", "core",
|
||||||
|
}
|
||||||
|
|
||||||
|
read_globals = {
|
||||||
|
"DIR_DELIM",
|
||||||
|
"dump", "dump2",
|
||||||
|
"vector",
|
||||||
|
"VoxelManip", "VoxelArea",
|
||||||
|
"PseudoRandom", "PcgRandom", "PerlinNoise", "PerlinNoiseMap",
|
||||||
|
"ItemStack",
|
||||||
|
"Settings",
|
||||||
|
"unpack",
|
||||||
|
|
||||||
|
table = {
|
||||||
|
fields = {
|
||||||
|
"copy",
|
||||||
|
"indexof",
|
||||||
|
"insert_all",
|
||||||
|
"key_value_swap",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
string = {
|
||||||
|
fields = {
|
||||||
|
"split",
|
||||||
|
"trim",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
math = {
|
||||||
|
fields = {
|
||||||
|
"hypot",
|
||||||
|
"sign",
|
||||||
|
"factorial"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
------
|
||||||
|
--MODS
|
||||||
|
------
|
||||||
|
|
||||||
|
--GENERAL
|
||||||
|
"default",
|
||||||
|
|
||||||
|
--ENTITIES
|
||||||
|
"cmi",
|
||||||
|
|
||||||
|
--HUD
|
||||||
|
"sfinv", "sfinv_buttons", "unified_inventory", "cmsg", "inventory_plus",
|
||||||
|
}
|
13
API.md
13
API.md
|
@ -17,6 +17,10 @@ Items can have these fields:
|
||||||
anvil.
|
anvil.
|
||||||
See `mcl_banners` for an example.
|
See `mcl_banners` for an example.
|
||||||
|
|
||||||
|
Tools can have these fields:
|
||||||
|
* `_mcl_diggroups`: Specifies the digging groups that a tool can dig and how
|
||||||
|
efficiently. See `_mcl_autogroup` for more information.
|
||||||
|
|
||||||
All nodes can have these fields:
|
All nodes can have these fields:
|
||||||
|
|
||||||
* `_mcl_hardness`: Hardness of the block, ranges from 0 to infinity (represented by -1). Determines digging times. Default: 0
|
* `_mcl_hardness`: Hardness of the block, ranges from 0 to infinity (represented by -1). Determines digging times. Default: 0
|
||||||
|
@ -39,7 +43,7 @@ A lot of things are possible by using one of the APIs in the mods. Note that not
|
||||||
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
|
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
|
||||||
|
|
||||||
## Mobs
|
## Mobs
|
||||||
* Mobs: `ENTITIES/mcl_mods`
|
* Mobs: `ENTITIES/mcl_mobs`
|
||||||
|
|
||||||
MineClone 2 uses its own mobs framework, called “Mobs Redo: MineClone 2 Edition” or “MRM” for short.
|
MineClone 2 uses its own mobs framework, called “Mobs Redo: MineClone 2 Edition” or “MRM” for short.
|
||||||
This is a fork of Mobs Redo [`mobs`] by TenPlus1.
|
This is a fork of Mobs Redo [`mobs`] by TenPlus1.
|
||||||
|
@ -67,6 +71,9 @@ chances are good that it works out of the box.
|
||||||
* Get flowing direction of liquids: `CORE/flowlib`
|
* Get flowing direction of liquids: `CORE/flowlib`
|
||||||
* `on_walk_over` callback for nodes: `CORE/walkover`
|
* `on_walk_over` callback for nodes: `CORE/walkover`
|
||||||
* Get node names close to player (to reduce constant querying): `PLAYER/mcl_playerinfo`
|
* Get node names close to player (to reduce constant querying): `PLAYER/mcl_playerinfo`
|
||||||
|
* Explosion API
|
||||||
|
* Music discs API
|
||||||
|
* Flowers and flower pots
|
||||||
|
|
||||||
### Unstable APIs
|
### Unstable APIs
|
||||||
The following APIs may be subject to change in future. You could already use these APIs but there will probably be breaking changes in the future, or the API is not as fleshed out as it should be. Use at your own risk!
|
The following APIs may be subject to change in future. You could already use these APIs but there will probably be breaking changes in the future, or the API is not as fleshed out as it should be. Use at your own risk!
|
||||||
|
@ -79,12 +86,10 @@ The following APIs may be subject to change in future. You could already use the
|
||||||
|
|
||||||
### Planned APIs
|
### Planned APIs
|
||||||
|
|
||||||
* Flowers
|
|
||||||
* Saplings and trees
|
* Saplings and trees
|
||||||
* Custom banner patterns
|
* Custom banner patterns
|
||||||
* Custom dimensions
|
* Custom dimensions
|
||||||
* Custom portals
|
* Custom portals
|
||||||
* Music discs
|
|
||||||
* Dispenser and dropper support
|
* Dispenser and dropper support
|
||||||
* Proper sky and weather APIs
|
* Proper sky and weather APIs
|
||||||
* Explosion API
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Contributing to MineClone 2
|
# Contributing to MineClone 2
|
||||||
So you want to MineClone 2?
|
So you want to contribute to MineClone 2?
|
||||||
Wow, thank you! :-)
|
Wow, thank you! :-)
|
||||||
|
|
||||||
But first, some things to note:
|
But first, some things to note:
|
||||||
|
@ -7,13 +7,11 @@ But first, some things to note:
|
||||||
MineClone 2's development target is to make a free software clone of Minecraft,
|
MineClone 2's development target is to make a free software clone of Minecraft,
|
||||||
***version 1.12***, ***PC edition***, *** + Optifine features supported by the Minetest Engine ***.
|
***version 1.12***, ***PC edition***, *** + Optifine features supported by the Minetest Engine ***.
|
||||||
|
|
||||||
MineClone 2 is maintained by two persons. Namely, kay27 and EliasFleckenstein. You can find us
|
MineClone 2 is maintained by three persons. Namely, kay27, EliasFleckenstein and jordan4ibanez. You can find us
|
||||||
in the Minetest forums (forums.minetest.net), in IRC in the #minetest
|
in the Minetest forums (forums.minetest.net), in IRC in the #mineclone2
|
||||||
channel on irc.freenode.net. And finally, you can send e-mails to
|
channel on irc.freenode.net. And finally, you can send e-mails to
|
||||||
<eliasfleckenstein@web.de> or <kay27@bk.ru>.
|
<eliasfleckenstein@web.de> or <kay27@bk.ru>.
|
||||||
|
|
||||||
There is **no** guarantee we will accept anything from anybody.
|
|
||||||
|
|
||||||
By sending us patches or asking us to include your changes in this game,
|
By sending us patches or asking us to include your changes in this game,
|
||||||
you agree that they fall under the terms of the LGPLv2.1, which basically
|
you agree that they fall under the terms of the LGPLv2.1, which basically
|
||||||
means they will become part of a free software.
|
means they will become part of a free software.
|
||||||
|
@ -26,8 +24,7 @@ For small and medium changes:
|
||||||
|
|
||||||
* Fork the repository
|
* Fork the repository
|
||||||
* Do your change in a new branch
|
* Do your change in a new branch
|
||||||
* Upload the repository somewhere where it can be accessed from the Internet and
|
* Create a pull request to get your changes merged into master
|
||||||
notify us
|
|
||||||
|
|
||||||
For small changes, sending us a patch is also good.
|
For small changes, sending us a patch is also good.
|
||||||
|
|
||||||
|
@ -41,40 +38,52 @@ reserve the right to revert everything that we don't like.
|
||||||
For bigger changes, we strongly recommend to use feature branches and
|
For bigger changes, we strongly recommend to use feature branches and
|
||||||
discuss with me first.
|
discuss with me first.
|
||||||
|
|
||||||
Contributors will be credited in `README.md`.
|
If your code causes bugs and crashes, it is your responsibility to fix them as soon as possible.
|
||||||
|
|
||||||
## Quality remarks
|
We mostly use plain merging rather than rebasing or squash merging.
|
||||||
Again: There is ***no*** guarantee we will accept anything from anybody.
|
|
||||||
But we will gladly take in code from others when we feel it saves us work
|
|
||||||
in the long run.
|
|
||||||
|
|
||||||
### Inclusion criteria
|
Your commit names should be relatively descriptive, e.g. when saying "Fix #issueid", the commit message should also contain the title of the issue.
|
||||||
Depending on what you add, the chances for inclusion vary:
|
|
||||||
|
|
||||||
### High chance for inclusion
|
Contributors will be credited in `CREDITS.md`.
|
||||||
* Gameplay features in Minecraft which are missing in MineClone 2
|
|
||||||
|
|
||||||
### Medium chance for inclusion (discuss first)
|
## Code Style
|
||||||
* Features which don't a impact on gameplay
|
|
||||||
* GUI improvement
|
|
||||||
* Features from pocket or console edition
|
|
||||||
|
|
||||||
### Low chance for inclusion (discuss/optimize first)
|
Each mod must provide `mod.conf`.
|
||||||
* Overhaul of architecture / mod structure
|
Each mod which add API functions should store functions inside a global table named like the mod.
|
||||||
* Mass-itemstring changes all over the place
|
Public functions should not use self references but rather just access the table directly.
|
||||||
* Added files have a unusual high file size
|
Functions should be defined in this way:
|
||||||
* Indentation looks like crazy
|
```
|
||||||
* Single commits which add several unrelated things
|
function mcl_xyz.stuff(param) end
|
||||||
* Gameplay features which don't exist in Minecraft
|
```
|
||||||
|
Insteed of this way:
|
||||||
|
```
|
||||||
|
mcl_xyz.stuff = function(param) end
|
||||||
|
```
|
||||||
|
Indentation must be unified, more likely with tabs.
|
||||||
|
|
||||||
### Instant rejection
|
Time sensitive mods should make a local copy of most used API functions to improve performances.
|
||||||
* Proprietary **anything**
|
```
|
||||||
* Code contains `minetest.env` anywhere
|
local vector = vector
|
||||||
|
local get_node = minetest.get_node
|
||||||
|
```
|
||||||
|
|
||||||
## Coding style guide
|
|
||||||
* Indentations should reflect the code flow
|
## Features > 1.12
|
||||||
* Use tabs, not spaces for indentation (tab size = 8)
|
|
||||||
* Never use `minetest.env`
|
If you want to make a feature that was added in a Minecraft version later than 1.12, you should fork MineClone5 (mineclone5 branch in the repository) and add your changes to this.
|
||||||
|
|
||||||
|
## What we accept
|
||||||
|
|
||||||
|
* Every MC features up to version 1.12 JE.
|
||||||
|
* Every already finished and working good features from versions above (only when making a MineClone5 PR / Contribution).
|
||||||
|
* Except features which couldn't be done easily and bugfree because of Minetest engine limitations. Eg. we CAN extend world boundaries by playing with map chunks, just teleporting player onto next layer after 31000 , but it would cost too much (time, code, bugs, performance, stability, etc).
|
||||||
|
* Some features, approved by the rest of the community, I mean maybe some voting and really missing any negative feedback.
|
||||||
|
|
||||||
|
## What we reject
|
||||||
|
|
||||||
|
* Any features which cause critical bugs, sending them to rework/fix or trying to fix immediately.
|
||||||
|
* Some small portions of big entirely missing features which just definitely break gamplay balance give nothing useful
|
||||||
|
* Controversial features, which some people support while others do not should be discussed well, with publishing forum announcements, at least during the week. In case if there are still doubts - send them into the mod.
|
||||||
|
|
||||||
## Reporting bugs
|
## Reporting bugs
|
||||||
Report all bugs and missing Minecraft features here:
|
Report all bugs and missing Minecraft features here:
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
## Creator of MineClone
|
||||||
|
* davedevils
|
||||||
|
|
||||||
|
## Creator of MineClone2
|
||||||
|
* Wuzzy
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
* Fleckenstein
|
||||||
|
* kay27
|
||||||
|
* jordan4ibanez
|
||||||
|
|
||||||
|
## Developers
|
||||||
|
* bzoss
|
||||||
|
* AFCMS
|
||||||
|
* epCode
|
||||||
|
* ryvnf
|
||||||
|
* iliekprogrammar
|
||||||
|
* MysticTempest
|
||||||
|
* Rootyjr
|
||||||
|
* Nicu
|
||||||
|
* aligator
|
||||||
|
* Code-Sploit
|
||||||
|
* NO11
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
* Laurent Rocher
|
||||||
|
* HimbeerserverDE
|
||||||
|
* TechDudie
|
||||||
|
* Alexander Minges
|
||||||
|
* ArTee3
|
||||||
|
* ZeDique la Ruleta
|
||||||
|
* pitchum
|
||||||
|
* wuniversales
|
||||||
|
* Bu-Gee
|
||||||
|
* David McMackins II
|
||||||
|
* Nicholas Niro
|
||||||
|
* Wouters Dorian
|
||||||
|
* Blue Blancmange
|
||||||
|
* Jared Moody
|
||||||
|
* Li0n
|
||||||
|
* Midgard
|
||||||
|
* Saku Laesvuori
|
||||||
|
* Yukitty
|
||||||
|
* ZedekThePD
|
||||||
|
* aldum
|
||||||
|
* dBeans
|
||||||
|
* nickolas360
|
||||||
|
* yutyo
|
||||||
|
* ztianyang
|
||||||
|
* j45
|
||||||
|
|
||||||
|
## MineClone5
|
||||||
|
* kay27
|
||||||
|
* Debiankaios
|
||||||
|
* epCode
|
||||||
|
* NO11
|
||||||
|
* j45
|
||||||
|
|
||||||
|
## Original Mod Authors
|
||||||
|
* Wuzzy
|
||||||
|
* Fleckenstein
|
||||||
|
* BlockMen
|
||||||
|
* TenPlus1
|
||||||
|
* PilzAdam
|
||||||
|
* ryvnf
|
||||||
|
* stujones11
|
||||||
|
* Arcelmi
|
||||||
|
* celeron55
|
||||||
|
* maikerumine
|
||||||
|
* GunshipPenguin
|
||||||
|
* Qwertymine3
|
||||||
|
* Rochambeau
|
||||||
|
* rubenwardy
|
||||||
|
* stu
|
||||||
|
* jordan4ibanez
|
||||||
|
* 4aiman
|
||||||
|
* Kahrl
|
||||||
|
* Krock
|
||||||
|
* UgnilJoZ
|
||||||
|
* lordfingle
|
||||||
|
* 22i
|
||||||
|
* bzoss
|
||||||
|
* kilbith
|
||||||
|
* xeranas
|
||||||
|
* kddekadenz
|
||||||
|
* sofar
|
||||||
|
* 4Evergreen4
|
||||||
|
* jordan4ibanez
|
||||||
|
* paramat
|
||||||
|
|
||||||
|
## 3D Models
|
||||||
|
* 22i
|
||||||
|
* tobyplowy
|
||||||
|
* epCode
|
||||||
|
|
||||||
|
## Textures
|
||||||
|
* XSSheep
|
||||||
|
* Wuzzy
|
||||||
|
* kingoscargames
|
||||||
|
* leorockway
|
||||||
|
* xMrVizzy
|
||||||
|
* yutyo
|
||||||
|
* NO11
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
* Wuzzy
|
||||||
|
* Rocher Laurent
|
||||||
|
* wuniversales
|
||||||
|
* kay27
|
||||||
|
* pitchum
|
||||||
|
|
||||||
|
## Special thanks
|
||||||
|
* celeron55 for creating Minetest
|
||||||
|
* Jordach for the jukebox music compilation from Big Freaking Dig
|
||||||
|
* The workaholics who spent way too much time writing for the Minecraft Wiki. It's an invaluable resource for creating this game
|
||||||
|
* Notch and Jeb for being the major forces behind Minecraft
|
|
@ -21,7 +21,7 @@ The basic digging time groups determine by which tools a node can be dug.
|
||||||
* `swordy=1`: Diggable by sword (any material), and this node is *not* a cobweb
|
* `swordy=1`: Diggable by sword (any material), and this node is *not* a cobweb
|
||||||
* `swordy_cobweb=1`: Diggable by sword (any material), and this node is a cobweb
|
* `swordy_cobweb=1`: Diggable by sword (any material), and this node is a cobweb
|
||||||
* `shearsy=1`: Diggable by shears, and this node is *not* wool
|
* `shearsy=1`: Diggable by shears, and this node is *not* wool
|
||||||
* `shearsy=wool=1`: Diggable by shears, and this node is wool
|
* `shearsy_wool=1`: Diggable by shears, and this node is wool
|
||||||
* `handy=1`: Breakable by hand and this node gives it useful drop when dug by hand. All nodes which are breakable by pickaxe, axe, shovel, sword or shears are also automatically breakable by hand, but not neccess
|
* `handy=1`: Breakable by hand and this node gives it useful drop when dug by hand. All nodes which are breakable by pickaxe, axe, shovel, sword or shears are also automatically breakable by hand, but not neccess
|
||||||
* `creative_breakable=1`: Block is breakable by hand in creative mode. This group is implied if the node belongs to any other digging group
|
* `creative_breakable=1`: Block is breakable by hand in creative mode. This group is implied if the node belongs to any other digging group
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Legal information
|
||||||
|
This is a fan game, not developed or endorsed by Mojang AB.
|
||||||
|
|
||||||
|
Copying is an act of love. Please copy and share! <3
|
||||||
|
Here's the detailed legalese for those who need it:
|
||||||
|
|
||||||
|
## License of source code
|
||||||
|
MineClone 2 (by kay27, EliasFleckenstein, Wuzzy, davedevils and countless others)
|
||||||
|
is an imitation of Minecraft.
|
||||||
|
|
||||||
|
MineClone 2 is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License (in the LICENSE.txt file) for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
In the mods you might find in the read-me or license
|
||||||
|
text files a different license. This counts as dual-licensing.
|
||||||
|
You can choose which license applies to you: Either the
|
||||||
|
license of MineClone 2 (GNU GPLv3) or the mod's license.
|
||||||
|
|
||||||
|
MineClone 2 is a direct continuation of the discontinued MineClone
|
||||||
|
project by davedevils.
|
||||||
|
|
||||||
|
Mod credits:
|
||||||
|
See `README.txt` or `README.md` in each mod directory for information about other authors.
|
||||||
|
For mods that do not have such a file, the license is the source code license
|
||||||
|
of MineClone 2 and the author is Wuzzy.
|
||||||
|
|
||||||
|
## License of media (textures and sounds)
|
||||||
|
No non-free licenses are used anywhere.
|
||||||
|
|
||||||
|
The textures, unless otherwise noted, are based on the Pixel Perfection resource pack for Minecraft 1.11,
|
||||||
|
authored by XSSheep. Most textures are verbatim copies, while some textures have been changed or redone
|
||||||
|
from scratch.
|
||||||
|
The glazed terracotta textures have been created by (MysticTempest)[https://github.com/MysticTempest].
|
||||||
|
Source: <https://www.planetminecraft.com/texture_pack/131pixel-perfection/>
|
||||||
|
License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)
|
||||||
|
|
||||||
|
The main menu images are release under: [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
|
||||||
|
|
||||||
|
All other files, unless mentioned otherwise, fall under:
|
||||||
|
Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||||
|
http://creativecommons.org/licenses/by-sa/3.0/
|
||||||
|
|
||||||
|
See README.txt in each mod directory for detailed information about other authors.
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
# Missing features in Minetest to recreate Minecraft features
|
|
||||||
|
|
||||||
A side goal of the MineClone 2 project is to find any shortcomings of Minetest which make it impossible to recreate a Minecraft feature exactly.
|
|
||||||
This file lists some of the missing features in Minetest which MineClone 2 would require.
|
|
||||||
|
|
||||||
## No workaround possible
|
|
||||||
For these features, no easy Lua workaround could be found.
|
|
||||||
|
|
||||||
### Lua API
|
|
||||||
#### Tools/wielded item
|
|
||||||
- “Lock” hotbar for a brief time after using an item, making it impossible to switch item or to attach/mine/build until the delay is over (For eating with delay)
|
|
||||||
- Tool charging: Holding down the mouse and releasing it, applying a “power level” (For bow and arrows, more charge = higher arrow range) ([issue 5212](https://github.com/minetest/minetest/issues/5212))
|
|
||||||
- [Dual Wielding](http://minecraft.gamepedia.com/Dual_wield)
|
|
||||||
- Eating/drinking animation ([issue 2811](https://github.com/minetest/minetest/issues/2811))
|
|
||||||
|
|
||||||
#### Nodes
|
|
||||||
- Light level 15 for nodes (not sunlight)
|
|
||||||
- Nodes makes light level drop by 2 or or more per node ([issue 5209](https://github.com/minetest/minetest/issues/5209))
|
|
||||||
|
|
||||||
## Interface
|
|
||||||
- Inventory: Hold down right mouse button while holding an item stack to drop items into the slots as you move the mouse. Makes crafting MUCH faster
|
|
||||||
- Sneak+Leftclick on crafting output crafts as many items as possible and immediately puts it into the player inventory ([issue 5211](https://github.com/minetest/minetest/issues/5211))
|
|
||||||
- Sneak+click puts items in different inventories depending on the item type (maybe group-based)? Required for sneak-clicking to armor slots
|
|
||||||
|
|
||||||
## Workaround theoretically possible
|
|
||||||
For these features, a workaround (or hack ;-)) by using Lua is theoretically possible. But engine support would be clearly better, more performant, more reliable, etc.
|
|
||||||
|
|
||||||
### Lua API
|
|
||||||
#### Nodes
|
|
||||||
- Change walking speed on block (soul sand)
|
|
||||||
- Change jumping height on block (soul sand),
|
|
||||||
- Change object movement speed *through* a block, but for non-liquids (for cobweb)
|
|
||||||
- Add `on_walk_over` event
|
|
||||||
- Set frequency in which players lose breath. 2 seconds are hardcoded in Minetest, in Minecraft it's 1 second
|
|
||||||
- Set damage frequency of `damage_per_second`. In Minecraft many things damage players every half-second rather than every second
|
|
||||||
- Possible to damage players directly when they are with the head inside. This allows to add Minecraft-like suffocation
|
|
||||||
- Sneak+click on inventory slot should be able to put items into additional “fallback inventories” if the first inventory is full. Useful for large chests
|
|
||||||
|
|
||||||
#### Nice-to-haye
|
|
||||||
- Utility function to rotate pillar-like nodes, requiring only 3 possible orientations (X, Y, Z). Basically this is `minetest.rotate_node` but with less orientations; the purpur pillar would mess up if a mirrored rotation would be possible. This is already implemented in MCL2, See `mcl_util` for more infos
|
|
191
README.md
191
README.md
|
@ -1,8 +1,10 @@
|
||||||
|
# (Currently in feature freeze)
|
||||||
|
|
||||||
# MineClone 2
|
# MineClone 2
|
||||||
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
||||||
Developed by many people. Not developed or endorsed by Mojang AB.
|
Developed by many people. Not developed or endorsed by Mojang AB.
|
||||||
|
|
||||||
Version: 0.71.0
|
Version: 0.72.0 (in development)
|
||||||
|
|
||||||
### Gameplay
|
### Gameplay
|
||||||
You start in a randomly-generated world made entirely of cubes. You can explore
|
You start in a randomly-generated world made entirely of cubes. You can explore
|
||||||
|
@ -65,16 +67,8 @@ map builders. They can not be obtained in-game or in the creative inventory.
|
||||||
Use the `/giveme` chat command to obtain them. See the in-game help for
|
Use the `/giveme` chat command to obtain them. See the in-game help for
|
||||||
an explanation.
|
an explanation.
|
||||||
|
|
||||||
#### Incomplete items
|
|
||||||
These items do not work yet, but you can get them with `/giveme` for testing:
|
|
||||||
|
|
||||||
* Minecart with Chest: `mcl_minecarts:chest_minecart`
|
|
||||||
* Minecart with Furnace: `mcl_minecarts:furnace_minecart`
|
|
||||||
* Minecart with Hopper: `mcl_minecarts:hopper_minecart`
|
|
||||||
* Minecart with Command Block: `mcl_minecarts:command_block_minecart`
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
This game requires [Minetest](http://minetest.net) to run (version 5.0.0 or
|
This game requires [Minetest](http://minetest.net) to run (version 5.3.0 or
|
||||||
later). So you need to install Minetest first. Only stable versions of Minetest
|
later). So you need to install Minetest first. Only stable versions of Minetest
|
||||||
are officially supported.
|
are officially supported.
|
||||||
There is no support for running MineClone 2 in development versions of Minetest.
|
There is no support for running MineClone 2 in development versions of Minetest.
|
||||||
|
@ -83,23 +77,37 @@ To install MineClone 2 (if you haven't already), move this directory into the
|
||||||
“games” directory of your Minetest data directory. Consult the help of
|
“games” directory of your Minetest data directory. Consult the help of
|
||||||
Minetest to learn more.
|
Minetest to learn more.
|
||||||
|
|
||||||
|
## Reporting bugs
|
||||||
|
Please report all bugs and missing Minecraft features here:
|
||||||
|
|
||||||
|
<https://git.minetest.land/MineClone2/MineClone2/issues>
|
||||||
|
|
||||||
|
## Chating with the community
|
||||||
|
Join our discord server at:
|
||||||
|
|
||||||
|
<https://discord.gg/84GKcxczG3>
|
||||||
|
|
||||||
## Project description
|
## Project description
|
||||||
The main goal of **MineClone 2** is to be a clone of Minecraft and to be released as free software.
|
The main goal of **MineClone 2** is to be a clone of Minecraft and to be released as free software.
|
||||||
|
|
||||||
* **Target of development: Minecraft, PC Edition, version 1.12** (later known as “Java Edition”)
|
* **Target of development: Minecraft, PC Edition, version 1.12** (later known as “Java Edition”)
|
||||||
* MineClone2 also includes Optifine features supported by the Minetest
|
* MineClone2 also includes Optifine features supported by the Minetest
|
||||||
* Features of later Minecraft versions might sneak in, but they have a low priority
|
* In general, Minecraft is aimed to be cloned as good as possible
|
||||||
* In general, Minecraft is aimed to be cloned as good as Minetest currently permits (no hacks)
|
|
||||||
* Cloning the gameplay has highest priority
|
* Cloning the gameplay has highest priority
|
||||||
* MineClone 2 will use different graphics and sounds, but with a similar style
|
* MineClone 2 will use different assets, but with a similar style
|
||||||
* Cloning the interface has no priority. It will only be roughly imitated
|
* Limitations found in Minetest will be documented in the course of development
|
||||||
* Limitations found in Minetest will be written down and reported in the course of development
|
* Features of later Minecraft versions are collected in the mineclone5 branch
|
||||||
|
|
||||||
|
## Using features from newer versions of Minecraft
|
||||||
|
For > 1.12 features, checkout MineClone5. It includes features from newer Minecraft versions.
|
||||||
|
Download it here: https://git.minetest.land/MineClone2/MineClone2/src/branch/mineclone5
|
||||||
|
|
||||||
## Completion status
|
## Completion status
|
||||||
This game is currently in **alpha** stage.
|
This game is currently in **beta** stage.
|
||||||
It is playable, but unfinished, many bugs are to be expected.
|
It is playable, but not yet feature-complete.
|
||||||
Backwards-compability is *not* guaranteed, updating your world might cause small and
|
Backwards-compability is not entirely guaranteed, updating your world might cause small bugs.
|
||||||
big bugs (such as “missing node” errors or even crashes).
|
If you want to use the git version of MineClone2 in production, consider using the production branch.
|
||||||
|
It is updated weekly and contains relatively stable code for servers.
|
||||||
|
|
||||||
The following main features are available:
|
The following main features are available:
|
||||||
|
|
||||||
|
@ -128,7 +136,7 @@ The following main features are available:
|
||||||
* Clock
|
* Clock
|
||||||
* Compass
|
* Compass
|
||||||
* Sponge
|
* Sponge
|
||||||
* Slime block (does not interact with redstone)
|
* Slime block
|
||||||
* Small plants and saplings
|
* Small plants and saplings
|
||||||
* Dyes
|
* Dyes
|
||||||
* Banners
|
* Banners
|
||||||
|
@ -140,19 +148,19 @@ The following main features are available:
|
||||||
* Creative inventory
|
* Creative inventory
|
||||||
* Farming
|
* Farming
|
||||||
* Writable books
|
* Writable books
|
||||||
* A few server commands
|
* Commands
|
||||||
|
* Villages
|
||||||
|
* The End
|
||||||
* And more!
|
* And more!
|
||||||
|
|
||||||
The following features are incomplete:
|
The following features are incomplete:
|
||||||
|
|
||||||
* Generated structures (especially villages)
|
|
||||||
* Some monsters and animals
|
* Some monsters and animals
|
||||||
* Redstone-related things
|
* Redstone-related things
|
||||||
* The End
|
|
||||||
* Special minecarts
|
* Special minecarts
|
||||||
* A couple of non-trivial blocks and items
|
* A couple of non-trivial blocks and items
|
||||||
|
|
||||||
Bonus features (not found in Minecraft 1.11):
|
Bonus features (not found in Minecraft 1.12):
|
||||||
|
|
||||||
* Built-in crafting guide which shows you crafting and smelting recipes
|
* Built-in crafting guide which shows you crafting and smelting recipes
|
||||||
* In-game help system containing extensive help about gameplay basics, blocks, items and more
|
* In-game help system containing extensive help about gameplay basics, blocks, items and more
|
||||||
|
@ -177,143 +185,14 @@ Technical differences from Minecraft:
|
||||||
* Different textures (Pixel Perfection)
|
* Different textures (Pixel Perfection)
|
||||||
* Different sounds (various sources)
|
* Different sounds (various sources)
|
||||||
* Different engine (Minetest)
|
* Different engine (Minetest)
|
||||||
|
* Different easter eggs
|
||||||
|
|
||||||
… and finally, MineClone 2 is free software (“free” as in “freedom”)!
|
… and finally, MineClone 2 is free software (“free” as in “freedom”)!
|
||||||
|
|
||||||
## Reporting bugs
|
|
||||||
Please report all bugs and missing Minecraft features here:
|
|
||||||
|
|
||||||
<https://git.minetest.land/MineClone2/MineClone2/issues>
|
|
||||||
|
|
||||||
## Other readme files
|
## Other readme files
|
||||||
|
|
||||||
* `LICENSE.txt`: The GPLv3 license text
|
* `LICENSE.txt`: The GPLv3 license text
|
||||||
* `CONTRIBUTING.md`: Information for those who want to contribute
|
* `CONTRIBUTING.md`: Information for those who want to contribute
|
||||||
* `MISSING_ENGINE_FEATURES.md`: List of missing features in Minetest which MineClone 2 would need for improvement
|
|
||||||
* `API.md`: For Minetest modders who want to mod this game
|
* `API.md`: For Minetest modders who want to mod this game
|
||||||
|
* `LEGAL.md`: Legal information
|
||||||
## Credits
|
* `CREDITS.md`: List of everyone who contributed
|
||||||
There are so many people to list (sorry). Check out the respective mod directories for details. This section is only a rough overview of the core authors of this game.
|
|
||||||
|
|
||||||
### Coding
|
|
||||||
* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082): Main programmer of most mods (retired)
|
|
||||||
* davedevils: Creator of MineClone on which MineClone 2 is based on
|
|
||||||
* [ex-bart](https://github.com/ex-bart): Redstone comparators
|
|
||||||
* [Rootyjr](https://github.com/Rootyjr): Fishing rod and bugfixes
|
|
||||||
* [aligator](https://github.com/aligator): Improvement of doors
|
|
||||||
* [ryvnf](https://github.com/ryvnf): Explosion mechanics
|
|
||||||
* MysticTempest: Bugfixes
|
|
||||||
* [bzoss](https://github.com/bzoss): Status effects, potions, brewing stand
|
|
||||||
* kay27 <kay27@bk.ru>: Experience system, bugfixes, optimizations (Current maintainer)
|
|
||||||
* [EliasFleckenstein03](https://github.com/EliasFleckenstein03): End crystals, enchanting, burning mobs / players, animated chests, bugfixes (Current maintainer)
|
|
||||||
* epCode: Better player animations, new logo
|
|
||||||
* 2mac: Fix bug with powered rail
|
|
||||||
* Lots of other people: TO BE WRITTEN (see mod directories for details)
|
|
||||||
|
|
||||||
#### Mod credits (summary)
|
|
||||||
|
|
||||||
* `controls`: Arcelmi
|
|
||||||
* `flowlib`: Qwertymine13
|
|
||||||
* `walkover`: lordfingle
|
|
||||||
* `drippingwater`: kddekadenz
|
|
||||||
* `mobs_mc`: maikerumine, 22i and others
|
|
||||||
* `awards`: rubenwardy
|
|
||||||
* `screwdriver`: RealBadAngel, Maciej Kastakin, Minetest contributors
|
|
||||||
* `xpanes`: Minetest contributors
|
|
||||||
* `mesecons` mods: Jeija and contributors
|
|
||||||
* `wieldview`: Stuart Jones
|
|
||||||
* `mcl_meshhand`: Based on `newhand` by jordan4ibanez
|
|
||||||
* `mcl_mobs`: Based on Mobs Redo [`mobs`] by TenPlus1 and contributors
|
|
||||||
* Most other mods: Wuzzy
|
|
||||||
|
|
||||||
Detailed credits for each mod can be found in the individual mod directories.
|
|
||||||
|
|
||||||
### Graphics
|
|
||||||
* [XSSheep](http://www.minecraftforum.net/members/XSSheep): Main author; creator of the Pixel Perfection resource pack of Minecraft 1.11
|
|
||||||
* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082): Main menu imagery and various edits and additions of texture pack
|
|
||||||
* [kingoscargames](https://github.com/kingoscargames): Various edits and additions of existing textures
|
|
||||||
* [leorockway](https://github.com/leorockway): Some edits of mob textures
|
|
||||||
* [xMrVizzy](https://minecraft.curseforge.com/members/xMrVizzy): Glazed terracotta (textures are subject to be replaced later)
|
|
||||||
* yutyo <tanakinci2002@gmail.com>: MineClone 2 logo
|
|
||||||
* Other authors: GUI images
|
|
||||||
|
|
||||||
### Translations
|
|
||||||
* Wuzzy: German
|
|
||||||
* Rocher Laurent <rocherl@club-internet.fr>: French
|
|
||||||
* wuniversales: Spanish
|
|
||||||
* kay27 <kay27@bk.ru>: Russian
|
|
||||||
|
|
||||||
### Models
|
|
||||||
* [22i](https://github.com/22i): Creator of all models
|
|
||||||
* [tobyplowy](https://github.com/tobyplowy): UV-mapping fixes to said models
|
|
||||||
|
|
||||||
### Sounds and music
|
|
||||||
Various sources. See the respective mod directories for details.
|
|
||||||
|
|
||||||
### Special thanks
|
|
||||||
|
|
||||||
* davedevils for starting MineClone, the original version of this game
|
|
||||||
* Wuzzy for starting and maintaining MineClone2 for several years
|
|
||||||
* celeron55 for creating Minetest
|
|
||||||
* Minetest's modding community for providing a huge selection of mods, some of which ended up in MineClone 2
|
|
||||||
* Jordach for the jukebox music compilation from Big Freaking Dig
|
|
||||||
* The workaholics who spent way too much time writing for the Minecraft Wiki. It's an invaluable resource for creating this game
|
|
||||||
* Notch and Jeb for being the major forces behind Minecraft
|
|
||||||
* XSSheep for creating the Pixel Perfection resource pack
|
|
||||||
* [22i](https://github.com/22i) for providing great models and support
|
|
||||||
* [maikerumine](http://github.com/maikerumine) for kicking off mobs and biomes
|
|
||||||
|
|
||||||
## Info for programmers
|
|
||||||
You find interesting and useful infos in `API.md`.
|
|
||||||
|
|
||||||
## Legal information
|
|
||||||
This is a fan game, not developed or endorsed by Mojang AB.
|
|
||||||
|
|
||||||
Copying is an act of love. Please copy and share! <3
|
|
||||||
Here's the detailed legalese for those who need it:
|
|
||||||
|
|
||||||
### License of source code
|
|
||||||
MineClone 2 (by kay27, EliasFleckenstein, Wuzzy, davedevils and countless others)
|
|
||||||
is an imitation of Minecraft.
|
|
||||||
|
|
||||||
MineClone 2 is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License (in the LICENSE.txt file) for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
In the mods you might find in the read-me or license
|
|
||||||
text files a different license. This counts as dual-licensing.
|
|
||||||
You can choose which license applies to you: Either the
|
|
||||||
license of MineClone 2 (GNU GPLv3) or the mod's license.
|
|
||||||
|
|
||||||
MineClone 2 is a direct continuation of the discontinued MineClone
|
|
||||||
project by davedevils.
|
|
||||||
|
|
||||||
Mod credits:
|
|
||||||
See `README.txt` or `README.md` in each mod directory for information about other authors.
|
|
||||||
For mods that do not have such a file, the license is the source code license
|
|
||||||
of MineClone 2 and the author is Wuzzy.
|
|
||||||
|
|
||||||
### License of media (textures and sounds)
|
|
||||||
No non-free licenses are used anywhere.
|
|
||||||
|
|
||||||
The textures, unless otherwise noted, are based on the Pixel Perfection resource pack for Minecraft 1.11,
|
|
||||||
authored by XSSheep. Most textures are verbatim copies, while some textures have been changed or redone
|
|
||||||
from scratch.
|
|
||||||
The glazed terracotta textures have been created by (MysticTempest)[https://github.com/MysticTempest].
|
|
||||||
Source: <https://www.planetminecraft.com/texture_pack/131pixel-perfection/>
|
|
||||||
License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)
|
|
||||||
|
|
||||||
The main menu images are release under: [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
|
|
||||||
|
|
||||||
All other files, unless mentioned otherwise, fall under:
|
|
||||||
Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
|
||||||
http://creativecommons.org/licenses/by-sa/3.0/
|
|
||||||
|
|
||||||
See README.txt in each mod directory for detailed information about other authors.
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
A survival sandbox game. Survive, gather, hunt, mine, build, explore, and do much more. Faithful clone of Minecraft 1.11. This is a work in progress! Expect bugs!
|
A survival sandbox game. Survive, gather, hunt, mine, build, explore, and do much more. Faithful clone of Minecraft 1.12. This is a work in progress! Expect bugs!
|
||||||
|
|
Binary file not shown.
|
@ -1,5 +1,8 @@
|
||||||
# This is a game specific minetest.conf file, do not edit
|
# This is a game specific minetest.conf file, do not edit
|
||||||
|
|
||||||
|
# If any of these settings are set in your minetest.conf file in ~/.minetest (Linux) or in the root directory of the game (Run in place/Windows)
|
||||||
|
# They will override these settings
|
||||||
|
|
||||||
# Basic game rules
|
# Basic game rules
|
||||||
time_speed = 72
|
time_speed = 72
|
||||||
|
|
||||||
|
@ -32,4 +35,13 @@ mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_de
|
||||||
# MCL2-specific stuff
|
# MCL2-specific stuff
|
||||||
keepInventory = false
|
keepInventory = false
|
||||||
|
|
||||||
dedicated_server_step = 0.001
|
# Performance settings
|
||||||
|
dedicated_server_step = 0.05 #tick rate
|
||||||
|
# abm_interval = 0.25
|
||||||
|
# max_objects_per_block = 4096
|
||||||
|
# max_packets_per_iteration = 10096
|
||||||
|
|
||||||
|
# Clientmodding to support official client
|
||||||
|
enable_client_modding = true
|
||||||
|
csm_restriction_flags = 0
|
||||||
|
enable_mod_channels = true
|
||||||
|
|
|
@ -4,6 +4,11 @@ Specifically, this mod has 2 purposes:
|
||||||
1) Automatically adding the group “solid” for blocks considered “solid” in Minecraft.
|
1) Automatically adding the group “solid” for blocks considered “solid” in Minecraft.
|
||||||
2) Generating digging time group for all nodes based on node metadata (it's complicated)
|
2) Generating digging time group for all nodes based on node metadata (it's complicated)
|
||||||
|
|
||||||
|
This mod also requires another mod called “mcl_autogroup” to function properly.
|
||||||
|
“mcl_autogroup” exposes the API used to register digging groups, while this mod
|
||||||
|
uses those digging groups to set the digging time groups for all the nodes and
|
||||||
|
tools.
|
||||||
|
|
||||||
See init.lua for more infos.
|
See init.lua for more infos.
|
||||||
|
|
||||||
The leading underscore in the name “_mcl_autogroup” was added to force Minetest to load this mod as late as possible.
|
The leading underscore in the name “_mcl_autogroup” was added to force Minetest to load this mod as late as possible.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.
|
|
|
@ -1,169 +1,361 @@
|
||||||
--[[ Mining times. Yeah, mining times … Alright, this is going to be FUN!
|
--[[
|
||||||
|
This mod implements a HACK to make 100% sure the digging times of all tools
|
||||||
|
match Minecraft's perfectly. The digging times system of Minetest is very
|
||||||
|
different, so this weird group trickery has to be used. In Minecraft, each
|
||||||
|
block has a hardness and the actual Minecraft digging time is determined by
|
||||||
|
this:
|
||||||
|
|
||||||
This mod does include a HACK to make 100% sure the digging times of all tools match Minecraft's perfectly.
|
|
||||||
The digging times system of Minetest is very different, so this weird group trickery has to be used.
|
|
||||||
In Minecraft, each block has a hardness and the actual Minecraft digging time is determined by this:
|
|
||||||
1) The block's hardness
|
1) The block's hardness
|
||||||
2) The tool being used
|
2) The tool being used (the tool speed and its efficiency level)
|
||||||
3) Whether the tool is considered as “eligible” for the block
|
3) Whether the tool is considered as "eligible" for the block
|
||||||
(e.g. only diamond pick eligible for obsidian)
|
(e.g. only diamond pick eligible for obsidian)
|
||||||
See Minecraft Wiki <http://minecraft.gamepedia.com/Minecraft_Wiki> for more information.
|
|
||||||
|
|
||||||
In MineClone 2, all diggable node have the hardness set in the custom field “_mcl_hardness” (0 by default).
|
See Minecraft Wiki <http://minecraft.gamepedia.com/Minecraft_Wiki> for more
|
||||||
The nodes are also required to specify the “eligible” tools in groups like “pickaxey”, “shovely”, etc.
|
information.
|
||||||
This mod then calculates the real digging time based on the node meta data. The real digging times
|
|
||||||
are then added into mcl_autogroup.digtimes where the table indices are group rating and the values are the
|
|
||||||
digging times in seconds. These digging times can be then added verbatim into the tool definitions.
|
|
||||||
|
|
||||||
Example:
|
How the mod is used
|
||||||
mcl_autogroup.digtimes.pickaxey_dig_diamond[1] = 0.2
|
===================
|
||||||
|
|
||||||
→ This means that when a node has been assigned the group “pickaxey_dig_diamond=1”, it can be dug by the
|
In MineClone 2, all diggable nodes have the hardness set in the custom field
|
||||||
diamond pickaxe in 0.2 seconds.
|
"_mcl_hardness" (0 by default). These values are used together with digging
|
||||||
|
groups by this mod to create the correct digging times for nodes. Digging
|
||||||
|
groups are registered using the following code:
|
||||||
|
|
||||||
|
mcl_autogroup.register_diggroup("shovely")
|
||||||
|
mcl_autogroup.register_diggroup("pickaxey", {
|
||||||
|
levels = { "wood", "gold", "stone", "iron", "diamond" }
|
||||||
|
})
|
||||||
|
|
||||||
|
The first line registers a simple digging group. The second line registers a
|
||||||
|
digging group with 5 different levels (in this case one for each material of a
|
||||||
|
pickaxes).
|
||||||
|
|
||||||
This strange setup with mcl_autogroup has been done to minimize the amount of required digging times
|
Nodes indicate that they belong to a particular digging group by being member of
|
||||||
a single tool needs to use. If this is not being done, the loading time will increase considerably
|
the digging group in their node definition. "mcl_core:dirt" for example has
|
||||||
(>10s).
|
shovely=1 in its groups. If the digging group has multiple levels the value of
|
||||||
|
the group indicates which digging level the node requires.
|
||||||
|
"mcl_core:stone_with_gold" for example has pickaxey=4 because it requires a
|
||||||
|
pickaxe of level 4 be mined.
|
||||||
|
|
||||||
]]
|
For tools to be able to dig nodes of digging groups they need to use the have
|
||||||
|
the custom field "_mcl_diggroups" function to get the groupcaps. The value of
|
||||||
|
this field is a table which defines which groups the tool can dig and how
|
||||||
|
efficiently.
|
||||||
|
|
||||||
local materials = { "wood", "gold", "stone", "iron", "diamond" }
|
_mcl_diggroups = {
|
||||||
local basegroups = { "pickaxey", "axey", "shovely" }
|
handy = { speed = 1, level = 1, uses = 0 },
|
||||||
local minigroups = { "handy", "shearsy", "swordy", "shearsy_wool", "swordy_cobweb" }
|
pickaxey = { speed = 1, level = 0, uses = 0 },
|
||||||
local divisors = {
|
}
|
||||||
["wood"] = 2,
|
|
||||||
["gold"] = 12,
|
|
||||||
["stone"] = 4,
|
|
||||||
["iron"] = 6,
|
|
||||||
["diamond"] = 8,
|
|
||||||
["handy"] = 1,
|
|
||||||
["shearsy"] = 15,
|
|
||||||
["swordy"] = 1.5,
|
|
||||||
["shearsy_wool"] = 5,
|
|
||||||
["swordy_cobweb"] = 15,
|
|
||||||
}
|
|
||||||
local max_efficiency_level = 5
|
|
||||||
|
|
||||||
mcl_autogroup = {}
|
The "uses" field indicate how many uses (0 for infinite) a tool has when used on
|
||||||
mcl_autogroup.digtimes = {}
|
the specified digging group. The "speed" field is a multiplier to the dig speed
|
||||||
mcl_autogroup.creativetimes = {} -- Copy of digtimes, except that all values are 0. Used for creative mode
|
on that digging group.
|
||||||
|
|
||||||
for m=1, #materials do
|
The "level" field indicates which levels of the group the tool can harvest. A
|
||||||
for g=1, #basegroups do
|
level of 0 means that the tool cannot harvest blocks of that node. A level of 1
|
||||||
mcl_autogroup.digtimes[basegroups[g].."_dig_"..materials[m]] = {}
|
or above means that the tool can harvest nodes with that level or below. See
|
||||||
mcl_autogroup.creativetimes[basegroups[g].."_dig_"..materials[m]] = {}
|
"mcl_tools/init.lua" for examples on how "_mcl_diggroups" is used in practice.
|
||||||
for e=1, max_efficiency_level do
|
|
||||||
mcl_autogroup.digtimes[basegroups[g].."_dig_"..materials[m].."_efficiency_"..e] = {}
|
Information about the mod
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The mod is split up into two parts, mcl_autogroup and _mcl_autogroup.
|
||||||
|
mcl_autogroup contains the API functions used to register custom digging groups.
|
||||||
|
_mcl_autogroup contains most of the code. The leading underscore in the name
|
||||||
|
"_mcl_autogroup" is used to force Minetest to load that part of the mod as late
|
||||||
|
as possible. Minetest loads mods in reverse alphabetical order.
|
||||||
|
|
||||||
|
This also means that it is very important that no mod adds _mcl_autogroup as a
|
||||||
|
dependency.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
assert(minetest.get_modpath("mcl_autogroup"), "This mod requires the mod mcl_autogroup to function")
|
||||||
|
|
||||||
|
-- Returns a table containing the unique "_mcl_hardness" for nodes belonging to
|
||||||
|
-- each diggroup.
|
||||||
|
local function get_hardness_values_for_groups()
|
||||||
|
local maps = {}
|
||||||
|
local values = {}
|
||||||
|
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
||||||
|
maps[g] = {}
|
||||||
|
values[g] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, ndef in pairs(minetest.registered_nodes) do
|
||||||
|
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
||||||
|
if ndef.groups[g] ~= nil then
|
||||||
|
maps[g][ndef._mcl_hardness or 0] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for g, map in pairs(maps) do
|
||||||
|
for k, _ in pairs(map) do
|
||||||
|
table.insert(values[g], k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
||||||
|
table.sort(values[g])
|
||||||
|
end
|
||||||
|
return values
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns a table containing a table indexed by "_mcl_hardness_value" to get
|
||||||
|
-- its index in the list of unique hardnesses for each diggroup.
|
||||||
|
local function get_hardness_lookup_for_groups(hardness_values)
|
||||||
|
local map = {}
|
||||||
|
for g, values in pairs(hardness_values) do
|
||||||
|
map[g] = {}
|
||||||
|
for k, v in pairs(values) do
|
||||||
|
map[g][v] = k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return map
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Array of unique hardness values for each group which affects dig time.
|
||||||
|
local hardness_values = get_hardness_values_for_groups()
|
||||||
|
|
||||||
|
-- Map indexed by hardness values which return the index of that value in
|
||||||
|
-- hardness_value. Used for quick lookup.
|
||||||
|
local hardness_lookup = get_hardness_lookup_for_groups(hardness_values)
|
||||||
|
|
||||||
|
--[[local function compute_creativetimes(group)
|
||||||
|
local creativetimes = {}
|
||||||
|
|
||||||
|
for index, hardness in pairs(hardness_values[group]) do
|
||||||
|
table.insert(creativetimes, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
return creativetimes
|
||||||
|
end]]
|
||||||
|
|
||||||
|
-- Get the list of digging times for using a specific tool on a specific
|
||||||
|
-- diggroup.
|
||||||
|
--
|
||||||
|
-- Parameters:
|
||||||
|
-- group - the group which it is digging
|
||||||
|
-- can_harvest - if the tool can harvest the block
|
||||||
|
-- speed - dig speed multiplier for tool (default 1)
|
||||||
|
-- efficiency - efficiency level for the tool if applicable
|
||||||
|
local function get_digtimes(group, can_harvest, speed, efficiency)
|
||||||
|
local speed = speed or 1
|
||||||
|
if efficiency then
|
||||||
|
speed = speed + efficiency * efficiency + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local digtimes = {}
|
||||||
|
|
||||||
|
for index, hardness in pairs(hardness_values[group]) do
|
||||||
|
local digtime = (hardness or 0) / speed
|
||||||
|
if can_harvest then
|
||||||
|
digtime = digtime * 1.5
|
||||||
|
else
|
||||||
|
digtime = digtime * 5
|
||||||
|
end
|
||||||
|
|
||||||
|
if digtime <= 0.05 then
|
||||||
|
digtime = 0
|
||||||
|
else
|
||||||
|
digtime = math.ceil(digtime * 20) / 20
|
||||||
|
end
|
||||||
|
table.insert(digtimes, digtime)
|
||||||
|
end
|
||||||
|
|
||||||
|
return digtimes
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get one groupcap field for using a specific tool on a specific group.
|
||||||
|
local function get_groupcap(group, can_harvest, multiplier, efficiency, uses)
|
||||||
|
return {
|
||||||
|
times = get_digtimes(group, can_harvest, multiplier, efficiency),
|
||||||
|
uses = uses,
|
||||||
|
maxlevel = 0,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add the groupcaps from a field in "_mcl_diggroups" to the groupcaps of a
|
||||||
|
-- tool.
|
||||||
|
local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency)
|
||||||
|
if not groupcaps_def then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for g, capsdef in pairs(groupcaps_def) do
|
||||||
|
local mult = capsdef.speed or 1
|
||||||
|
local uses = capsdef.uses
|
||||||
|
local def = mcl_autogroup.registered_diggroups[g]
|
||||||
|
local max_level = def.levels and #def.levels or 1
|
||||||
|
|
||||||
|
assert(capsdef.level, toolname .. ' is missing level for ' .. g)
|
||||||
|
local level = math.min(capsdef.level, max_level)
|
||||||
|
|
||||||
|
if def.levels then
|
||||||
|
groupcaps[g .. "_dig_default"] = get_groupcap(g, false, mult, efficiency, uses)
|
||||||
|
if level > 0 then
|
||||||
|
groupcaps[g .. "_dig_" .. def.levels[level]] = get_groupcap(g, true, mult, efficiency, uses)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
groupcaps[g .. "_dig"] = get_groupcap(g, level > 0, mult, efficiency, uses)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for g=1, #minigroups do
|
|
||||||
mcl_autogroup.digtimes[minigroups[g].."_dig"] = {}
|
-- Checks if the given node would drop its useful drop if dug by a given tool.
|
||||||
mcl_autogroup.creativetimes[minigroups[g].."_dig"] = {}
|
-- Returns true if it will yield its useful drop, false otherwise.
|
||||||
for e=1, max_efficiency_level do
|
function mcl_autogroup.can_harvest(nodename, toolname)
|
||||||
mcl_autogroup.digtimes[minigroups[g].."_dig_efficiency_"..e] = {}
|
local ndef = minetest.registered_nodes[nodename]
|
||||||
mcl_autogroup.creativetimes[minigroups[g].."_dig_efficiency_"..e] = {}
|
|
||||||
|
if minetest.get_item_group(nodename, "dig_immediate") >= 2 then
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check if it can be dug by tool
|
||||||
|
local tdef = minetest.registered_tools[toolname]
|
||||||
|
if tdef and tdef._mcl_diggroups then
|
||||||
|
for g, gdef in pairs(tdef._mcl_diggroups) do
|
||||||
|
if ndef.groups[g] then
|
||||||
|
if ndef.groups[g] <= gdef.level then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if it can be dug by hand
|
||||||
|
local tdef = minetest.registered_tools[""]
|
||||||
|
if tdef then
|
||||||
|
for g, gdef in pairs(tdef._mcl_diggroups) do
|
||||||
|
if ndef.groups[g] then
|
||||||
|
if ndef.groups[g] <= gdef.level then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local overwrite = function()
|
-- Get one groupcap field for using a specific tool on a specific group.
|
||||||
|
--[[local function get_groupcap(group, can_harvest, multiplier, efficiency, uses)
|
||||||
|
return {
|
||||||
|
times = get_digtimes(group, can_harvest, multiplier, efficiency),
|
||||||
|
uses = uses,
|
||||||
|
maxlevel = 0,
|
||||||
|
}
|
||||||
|
end]]
|
||||||
|
|
||||||
|
-- Returns the tool_capabilities from a tool definition or a default set of
|
||||||
|
-- tool_capabilities
|
||||||
|
local function get_tool_capabilities(tdef)
|
||||||
|
if tdef.tool_capabilities then
|
||||||
|
return tdef.tool_capabilities
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If the damage group and punch interval from hand is not included,
|
||||||
|
-- then the user will not be able to attack with the tool.
|
||||||
|
local hand_toolcaps = minetest.registered_tools[""].tool_capabilities
|
||||||
|
return {
|
||||||
|
full_punch_interval = hand_toolcaps.full_punch_interval,
|
||||||
|
damage_groups = hand_toolcaps.damage_groups
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the groupcaps for a tool. This function returns "groupcaps" table of
|
||||||
|
-- digging which should be put in the "tool_capabilities" of the tool definition
|
||||||
|
-- or in the metadata of an enchanted tool.
|
||||||
|
--
|
||||||
|
-- Parameters:
|
||||||
|
-- toolname - Name of the tool being enchanted (like "mcl_tools:diamond_pickaxe")
|
||||||
|
-- efficiency - The efficiency level the tool is enchanted with (default 0)
|
||||||
|
--
|
||||||
|
-- NOTE:
|
||||||
|
-- This function can only be called after mod initialization. Otherwise a mod
|
||||||
|
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
||||||
|
-- loading order.
|
||||||
|
function mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||||
|
local tdef = minetest.registered_tools[toolname]
|
||||||
|
local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {})
|
||||||
|
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
|
||||||
|
return groupcaps
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the wear from using a tool on a digging group.
|
||||||
|
--
|
||||||
|
-- Parameters
|
||||||
|
-- toolname - Name of the tool used
|
||||||
|
-- diggroup - The name of the diggroup the tool is used on
|
||||||
|
--
|
||||||
|
-- NOTE:
|
||||||
|
-- This function can only be called after mod initialization. Otherwise a mod
|
||||||
|
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
||||||
|
-- loading order.
|
||||||
|
function mcl_autogroup.get_wear(toolname, diggroup)
|
||||||
|
local tdef = minetest.registered_tools[toolname]
|
||||||
|
local uses = tdef._mcl_diggroups[diggroup].uses
|
||||||
|
return math.ceil(65535 / uses)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function overwrite()
|
||||||
for nname, ndef in pairs(minetest.registered_nodes) do
|
for nname, ndef in pairs(minetest.registered_nodes) do
|
||||||
local groups_changed = false
|
|
||||||
local newgroups = table.copy(ndef.groups)
|
local newgroups = table.copy(ndef.groups)
|
||||||
if (nname ~= "ignore" and ndef.diggable) then
|
if (nname ~= "ignore" and ndef.diggable) then
|
||||||
-- Automatically assign the “solid” group for solid nodes
|
-- Automatically assign the "solid" group for solid nodes
|
||||||
if (ndef.walkable == nil or ndef.walkable == true)
|
if (ndef.walkable == nil or ndef.walkable == true)
|
||||||
and (ndef.collision_box == nil or ndef.collision_box.type == "regular")
|
and (ndef.collision_box == nil or ndef.collision_box.type == "regular")
|
||||||
and (ndef.node_box == nil or ndef.node_box.type == "regular")
|
and (ndef.node_box == nil or ndef.node_box.type == "regular")
|
||||||
and (ndef.groups.not_solid == 0 or ndef.groups.not_solid == nil) then
|
and (ndef.groups.not_solid == 0 or ndef.groups.not_solid == nil) then
|
||||||
newgroups.solid = 1
|
newgroups.solid = 1
|
||||||
groups_changed = true
|
|
||||||
end
|
end
|
||||||
-- Automatically assign the “opaque” group for opaque nodes
|
-- Automatically assign the "opaque" group for opaque nodes
|
||||||
if (not (ndef.paramtype == "light" or ndef.sunlight_propagates)) and
|
if (not (ndef.paramtype == "light" or ndef.sunlight_propagates)) and
|
||||||
(ndef.groups.not_opaque == 0 or ndef.groups.not_opaque == nil) then
|
(ndef.groups.not_opaque == 0 or ndef.groups.not_opaque == nil) then
|
||||||
newgroups.opaque = 1
|
newgroups.opaque = 1
|
||||||
groups_changed = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function calculate_group(hardness, material, diggroup, newgroups, actual_rating, expected_rating, efficiency)
|
--local creative_breakable = false
|
||||||
local time, validity_factor
|
|
||||||
if actual_rating >= expected_rating then
|
|
||||||
-- Valid tool
|
|
||||||
validity_factor = 1.5
|
|
||||||
else
|
|
||||||
-- Wrong tool (higher digging time)
|
|
||||||
validity_factor = 5
|
|
||||||
end
|
|
||||||
local speed_multiplier = divisors[material]
|
|
||||||
if efficiency then
|
|
||||||
speed_multiplier = speed_multiplier + efficiency * efficiency + 1
|
|
||||||
end
|
|
||||||
time = (hardness * validity_factor) / speed_multiplier
|
|
||||||
if time <= 0.05 then
|
|
||||||
time = 0
|
|
||||||
else
|
|
||||||
time = math.ceil(time * 20) / 20
|
|
||||||
end
|
|
||||||
table.insert(mcl_autogroup.digtimes[diggroup], time)
|
|
||||||
if not efficiency then
|
|
||||||
table.insert(mcl_autogroup.creativetimes[diggroup], 0)
|
|
||||||
end
|
|
||||||
newgroups[diggroup] = #mcl_autogroup.digtimes[diggroup]
|
|
||||||
return newgroups
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Hack in digging times
|
-- Assign groups used for digging this node depending on
|
||||||
local hardness = ndef._mcl_hardness
|
-- the registered digging groups
|
||||||
if not hardness then
|
for g, gdef in pairs(mcl_autogroup.registered_diggroups) do
|
||||||
hardness = 0
|
--creative_breakable = true
|
||||||
end
|
local index = hardness_lookup[g][ndef._mcl_hardness or 0]
|
||||||
|
if ndef.groups[g] then
|
||||||
|
if gdef.levels then
|
||||||
|
newgroups[g .. "_dig_default"] = index
|
||||||
|
|
||||||
-- Handle pickaxey, axey and shovely
|
for i = ndef.groups[g], #gdef.levels do
|
||||||
for _, basegroup in pairs(basegroups) do
|
newgroups[g .. "_dig_" .. gdef.levels[i]] = index
|
||||||
if (hardness ~= -1 and ndef.groups[basegroup]) then
|
|
||||||
for g=1,#materials do
|
|
||||||
local diggroup = basegroup.."_dig_"..materials[g]
|
|
||||||
newgroups = calculate_group(hardness, materials[g], diggroup, newgroups, g, ndef.groups[basegroup])
|
|
||||||
for e=1,max_efficiency_level do
|
|
||||||
newgroups = calculate_group(hardness, materials[g], diggroup .. "_efficiency_" .. e, newgroups, g, ndef.groups[basegroup], e)
|
|
||||||
end
|
end
|
||||||
groups_changed = true
|
else
|
||||||
end
|
newgroups[g .. "_dig"] = index
|
||||||
end
|
|
||||||
end
|
|
||||||
for m=1, #minigroups do
|
|
||||||
local minigroup = minigroups[m]
|
|
||||||
if hardness ~= -1 then
|
|
||||||
local diggroup = minigroup.."_dig"
|
|
||||||
-- actual rating
|
|
||||||
local ar = ndef.groups[minigroup]
|
|
||||||
if ar == nil then
|
|
||||||
ar = 0
|
|
||||||
end
|
|
||||||
if (minigroup == "handy")
|
|
||||||
or
|
|
||||||
(ndef.groups.shearsy_wool and minigroup == "shearsy_wool" and ndef.groups.wool)
|
|
||||||
or
|
|
||||||
(ndef.groups.swordy_cobweb and minigroup == "swordy_cobweb" and nname == "mcl_core:cobweb")
|
|
||||||
or
|
|
||||||
(ndef.groups[minigroup] and minigroup ~= "swordy_cobweb" and minigroup ~= "shearsy_wool") then
|
|
||||||
newgroups = calculate_group(hardness, minigroup, diggroup, newgroups, ar, 1)
|
|
||||||
for e=1,max_efficiency_level do
|
|
||||||
newgroups = calculate_group(hardness, minigroup, diggroup .. "_efficiency_" .. e, newgroups, ar, 1, e)
|
|
||||||
end
|
|
||||||
groups_changed = true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if groups_changed then
|
-- Automatically assign the node to the
|
||||||
minetest.override_item(nname, {
|
-- creative_breakable group if it belongs to any digging
|
||||||
groups = newgroups
|
-- group.
|
||||||
})
|
newgroups["creative_breakable"] = 1
|
||||||
end
|
|
||||||
|
minetest.override_item(nname, {
|
||||||
|
groups = newgroups
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for tname, tdef in pairs(minetest.registered_tools) do
|
||||||
|
-- Assign groupcaps for digging the registered digging groups
|
||||||
|
-- depending on the _mcl_diggroups in the tool definition
|
||||||
|
if tdef._mcl_diggroups then
|
||||||
|
local toolcaps = table.copy(get_tool_capabilities(tdef))
|
||||||
|
toolcaps.groupcaps = mcl_autogroup.get_groupcaps(tname)
|
||||||
|
|
||||||
|
minetest.override_item(tname, {
|
||||||
|
tool_capabilities = toolcaps
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
name = _mcl_autogroup
|
name = _mcl_autogroup
|
||||||
|
author = ryvnf
|
||||||
|
description = MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.
|
||||||
|
|
|
@ -81,11 +81,11 @@ if v6_use_snow_biomes then
|
||||||
end
|
end
|
||||||
local v6_freq_desert = tonumber(minetest.get_mapgen_setting("mgv6_freq_desert") or 0.45)
|
local v6_freq_desert = tonumber(minetest.get_mapgen_setting("mgv6_freq_desert") or 0.45)
|
||||||
|
|
||||||
local NOISE_MAGIC_X = 1619
|
--local NOISE_MAGIC_X = 1619
|
||||||
local NOISE_MAGIC_Y = 31337
|
--local NOISE_MAGIC_Y = 31337
|
||||||
local NOISE_MAGIC_Z = 52591
|
--local NOISE_MAGIC_Z = 52591
|
||||||
local NOISE_MAGIC_SEED = 1013
|
--local NOISE_MAGIC_SEED = 1013
|
||||||
local noise2d = function(x, y, seed)
|
local function noise2d(x, y, seed)
|
||||||
-- TODO: implement noise2d function for biome blend
|
-- TODO: implement noise2d function for biome blend
|
||||||
return 0
|
return 0
|
||||||
--[[
|
--[[
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
name = biomeinfo
|
name = biomeinfo
|
||||||
|
author = Wuzzy
|
||||||
description = Simple API to get data about biomes.
|
description = Simple API to get data about biomes.
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# controls
|
||||||
|
|
||||||
|
## controls.players
|
||||||
|
Table containing player controls at runtime.
|
||||||
|
WARNING: Never use this table in writing
|
||||||
|
|
||||||
|
## controls.register_on_press(func)
|
||||||
|
Register a function that will be executed with (player, keyname) every time a player press a key.
|
||||||
|
|
||||||
|
## controls.registered_on_press
|
||||||
|
Table containing functions registered with controls.register_on_press().
|
||||||
|
|
||||||
|
## controls.register_on_release(func)
|
||||||
|
Register a function that will be executed with (player, keyname, clock_from_last_press) every time a player release a key.
|
||||||
|
|
||||||
|
## controls.registered_on_release
|
||||||
|
Table containing functions registered with controls.register_on_release().
|
||||||
|
|
||||||
|
## controls.register_on_hold(func)
|
||||||
|
Register a function that will be executed with (player, keyname, clock_from_start_hold) every time a player hold a key.
|
||||||
|
|
||||||
|
## controls.registered_on_hold
|
||||||
|
Table containing functions registered with controls.register_on_hold().
|
|
@ -1,3 +1,6 @@
|
||||||
|
local get_connected_players = minetest.get_connected_players
|
||||||
|
local clock = os.clock
|
||||||
|
|
||||||
controls = {}
|
controls = {}
|
||||||
controls.players = {}
|
controls.players = {}
|
||||||
|
|
||||||
|
@ -42,7 +45,7 @@ minetest.register_on_leaveplayer(function(player)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
for _, player in pairs(minetest.get_connected_players()) do
|
for _, player in pairs(get_connected_players()) do
|
||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
local player_controls = player:get_player_control()
|
local player_controls = player:get_player_control()
|
||||||
if controls.players[player_name] then
|
if controls.players[player_name] then
|
||||||
|
@ -53,15 +56,15 @@ minetest.register_globalstep(function(dtime)
|
||||||
for _, func in pairs(controls.registered_on_press) do
|
for _, func in pairs(controls.registered_on_press) do
|
||||||
func(player, cname)
|
func(player, cname)
|
||||||
end
|
end
|
||||||
controls.players[player_name][cname] = {true, os.clock()}
|
controls.players[player_name][cname] = {true, clock()}
|
||||||
elseif cbool==true and controls.players[player_name][cname][1]==true then
|
elseif cbool==true and controls.players[player_name][cname][1]==true then
|
||||||
for _, func in pairs(controls.registered_on_hold) do
|
for _, func in pairs(controls.registered_on_hold) do
|
||||||
func(player, cname, os.clock()-controls.players[player_name][cname][2])
|
func(player, cname, clock()-controls.players[player_name][cname][2])
|
||||||
end
|
end
|
||||||
--Release a key
|
--Release a key
|
||||||
elseif cbool==false and controls.players[player_name][cname][1]==true then
|
elseif cbool==false and controls.players[player_name][cname][1]==true then
|
||||||
for _, func in pairs(controls.registered_on_release) do
|
for _, func in pairs(controls.registered_on_release) do
|
||||||
func(player, cname, os.clock()-controls.players[player_name][cname][2])
|
func(player, cname, clock()-controls.players[player_name][cname][2])
|
||||||
end
|
end
|
||||||
controls.players[player_name][cname] = {false}
|
controls.players[player_name][cname] = {false}
|
||||||
end
|
end
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
name=controls
|
name = controls
|
||||||
|
author = Arcelmi
|
||||||
|
description = Controls framework by Arcelmi
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# flowlib
|
||||||
|
Simple flow functions.
|
||||||
|
|
||||||
|
## flowlib.is_touching(realpos, nodepos, radius)
|
||||||
|
Return true if a sphere of <radius> at <realpos> collide with node at <nodepos>.
|
||||||
|
* realpos: position
|
||||||
|
* nodepos: position
|
||||||
|
* radius: number
|
||||||
|
|
||||||
|
## flowlib.is_water(pos)
|
||||||
|
Return true if node at <pos> is water, false overwise.
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## flowlib.node_is_water(node)
|
||||||
|
Return true if <node> is water, false overwise.
|
||||||
|
* node: node
|
||||||
|
|
||||||
|
## flowlib.is_lava(pos)
|
||||||
|
Return true if node at <pos> is lava, false overwise.
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## flowlib.node_is_lava(node)
|
||||||
|
Return true if <node> is lava, false overwise.
|
||||||
|
* node: node
|
||||||
|
|
||||||
|
## flowlib.is_liquid(pos)
|
||||||
|
Return true if node at <pos> is liquid, false overwise.
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## flowlib.node_is_liquid(node)
|
||||||
|
Return true if <node> is liquid, false overwise.
|
||||||
|
* node: node
|
||||||
|
|
||||||
|
## flowlib.quick_flow(pos, node)
|
||||||
|
Return direction where the water is flowing (to be use to push mobs, items...).
|
||||||
|
* pos: position
|
||||||
|
* node: node
|
||||||
|
|
||||||
|
## flowlib.move_centre(pos, realpos, node, radius)
|
||||||
|
Return the pos of the nearest not water block near from <pos> in a sphere of <radius> at <realpos>.
|
||||||
|
WARNING: This function is never used in mcl2, use at your own risk. The informations described here may be wrong.
|
||||||
|
* pos: position
|
||||||
|
* realpos: position, position of the entity
|
||||||
|
* node: node
|
||||||
|
* radius: number
|
|
@ -1,95 +1,100 @@
|
||||||
|
local math = math
|
||||||
|
|
||||||
|
local get_node = minetest.get_node
|
||||||
|
local get_item_group = minetest.get_item_group
|
||||||
|
|
||||||
|
local registered_nodes = minetest.registered_nodes
|
||||||
|
|
||||||
flowlib = {}
|
flowlib = {}
|
||||||
|
|
||||||
--sum of direction vectors must match an array index
|
--sum of direction vectors must match an array index
|
||||||
|
|
||||||
|
--(sum,root)
|
||||||
|
--(0,1), (1,1+0=1), (2,1+1=2), (3,1+2^2=5), (4,2^2+2^2=8)
|
||||||
|
|
||||||
|
local inv_roots = {
|
||||||
|
[0] = 1,
|
||||||
|
[1] = 1,
|
||||||
|
[2] = 0.70710678118655,
|
||||||
|
[4] = 0.5,
|
||||||
|
[5] = 0.44721359549996,
|
||||||
|
[8] = 0.35355339059327,
|
||||||
|
}
|
||||||
|
|
||||||
local function to_unit_vector(dir_vector)
|
local function to_unit_vector(dir_vector)
|
||||||
--(sum,root)
|
local sum = dir_vector.x * dir_vector.x + dir_vector.z * dir_vector.z
|
||||||
-- (0,1), (1,1+0=1), (2,1+1=2), (3,1+2^2=5), (4,2^2+2^2=8)
|
return {x = dir_vector.x * inv_roots[sum], y = dir_vector.y, z = dir_vector.z * inv_roots[sum]}
|
||||||
local inv_roots = {[0] = 1, [1] = 1, [2] = 0.70710678118655, [4] = 0.5
|
|
||||||
, [5] = 0.44721359549996, [8] = 0.35355339059327}
|
|
||||||
local sum = dir_vector.x*dir_vector.x + dir_vector.z*dir_vector.z
|
|
||||||
return {x=dir_vector.x*inv_roots[sum],y=dir_vector.y
|
|
||||||
,z=dir_vector.z*inv_roots[sum]}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local is_touching = function(realpos,nodepos,radius)
|
local function is_touching(realpos,nodepos,radius)
|
||||||
local boarder = 0.5 - radius
|
local boarder = 0.5 - radius
|
||||||
return (math.abs(realpos - nodepos) > (boarder))
|
return math.abs(realpos - nodepos) > (boarder)
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.is_touching = is_touching
|
flowlib.is_touching = is_touching
|
||||||
|
|
||||||
local is_water = function(pos)
|
local function is_water(pos)
|
||||||
return (minetest.get_item_group(minetest.get_node(
|
return get_item_group(get_node(pos).name, "water") ~= 0
|
||||||
{x=pos.x,y=pos.y,z=pos.z}).name
|
|
||||||
, "water") ~= 0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.is_water = is_water
|
flowlib.is_water = is_water
|
||||||
|
|
||||||
local node_is_water = function(node)
|
local function node_is_water(node)
|
||||||
return (minetest.get_item_group(node.name, "water") ~= 0)
|
return get_item_group(node.name, "water") ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.node_is_water = node_is_water
|
flowlib.node_is_water = node_is_water
|
||||||
|
|
||||||
local is_lava = function(pos)
|
local function is_lava(pos)
|
||||||
return (minetest.get_item_group(minetest.get_node(
|
return get_item_group(get_node(pos).name, "lava") ~= 0
|
||||||
{x=pos.x,y=pos.y,z=pos.z}).name
|
|
||||||
, "lava") ~= 0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.is_lava = is_lava
|
flowlib.is_lava = is_lava
|
||||||
|
|
||||||
local node_is_lava = function(node)
|
local function node_is_lava(node)
|
||||||
return (minetest.get_item_group(node.name, "lava") ~= 0)
|
return get_item_group(node.name, "lava") ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.node_is_lava = node_is_lava
|
flowlib.node_is_lava = node_is_lava
|
||||||
|
|
||||||
|
|
||||||
local is_liquid = function(pos)
|
local function is_liquid(pos)
|
||||||
return (minetest.get_item_group(minetest.get_node(
|
return get_item_group(get_node(pos).name, "liquid") ~= 0
|
||||||
{x=pos.x,y=pos.y,z=pos.z}).name
|
|
||||||
, "liquid") ~= 0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.is_liquid = is_liquid
|
flowlib.is_liquid = is_liquid
|
||||||
|
|
||||||
local node_is_liquid = function(node)
|
local function node_is_liquid(node)
|
||||||
return (minetest.get_item_group(node.name, "liquid") ~= 0)
|
return minetest.get_item_group(node.name, "liquid") ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.node_is_liquid = node_is_liquid
|
flowlib.node_is_liquid = node_is_liquid
|
||||||
|
|
||||||
--This code is more efficient
|
--This code is more efficient
|
||||||
local function quick_flow_logic(node,pos_testing,direction)
|
local function quick_flow_logic(node, pos_testing, direction)
|
||||||
local name = node.name
|
local name = node.name
|
||||||
if not minetest.registered_nodes[name] then
|
if not registered_nodes[name] then
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
if minetest.registered_nodes[name].liquidtype == "source" then
|
if registered_nodes[name].liquidtype == "source" then
|
||||||
local node_testing = minetest.get_node(pos_testing)
|
local node_testing = get_node(pos_testing)
|
||||||
local param2_testing = node_testing.param2
|
if not registered_nodes[node_testing.name] then
|
||||||
if not minetest.registered_nodes[node_testing.name] then
|
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
if minetest.registered_nodes[node_testing.name].liquidtype
|
if registered_nodes[node_testing.name].liquidtype ~= "flowing" then
|
||||||
~= "flowing" then
|
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return direction
|
return direction
|
||||||
end
|
end
|
||||||
elseif minetest.registered_nodes[name].liquidtype == "flowing" then
|
elseif registered_nodes[name].liquidtype == "flowing" then
|
||||||
local node_testing = minetest.get_node(pos_testing)
|
local node_testing = get_node(pos_testing)
|
||||||
local param2_testing = node_testing.param2
|
local param2_testing = node_testing.param2
|
||||||
if not minetest.registered_nodes[node_testing.name] then
|
if not registered_nodes[node_testing.name] then
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
if minetest.registered_nodes[node_testing.name].liquidtype
|
if registered_nodes[node_testing.name].liquidtype == "source" then
|
||||||
== "source" then
|
|
||||||
return -direction
|
return -direction
|
||||||
elseif minetest.registered_nodes[node_testing.name].liquidtype
|
elseif registered_nodes[node_testing.name].liquidtype == "flowing" then
|
||||||
== "flowing" then
|
|
||||||
if param2_testing < node.param2 then
|
if param2_testing < node.param2 then
|
||||||
if (node.param2 - param2_testing) > 6 then
|
if (node.param2 - param2_testing) > 6 then
|
||||||
return -direction
|
return -direction
|
||||||
|
@ -108,48 +113,41 @@ local function quick_flow_logic(node,pos_testing,direction)
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local quick_flow = function(pos,node)
|
local function quick_flow(pos, node)
|
||||||
local x = 0
|
|
||||||
local z = 0
|
|
||||||
|
|
||||||
if not node_is_liquid(node) then
|
if not node_is_liquid(node) then
|
||||||
return {x=0,y=0,z=0}
|
return {x = 0, y = 0, z = 0}
|
||||||
end
|
end
|
||||||
|
local x = quick_flow_logic(node,{x = pos.x-1, y = pos.y, z = pos.z},-1) + quick_flow_logic(node,{x = pos.x+1, y = pos.y, z = pos.z}, 1)
|
||||||
x = x + quick_flow_logic(node,{x=pos.x-1,y=pos.y,z=pos.z},-1)
|
local z = quick_flow_logic(node,{x = pos.x, y = pos.y, z = pos.z-1},-1) + quick_flow_logic(node,{x = pos.x, y = pos.y, z = pos.z+1}, 1)
|
||||||
x = x + quick_flow_logic(node,{x=pos.x+1,y=pos.y,z=pos.z}, 1)
|
return to_unit_vector({x = x, y = 0, z = z})
|
||||||
z = z + quick_flow_logic(node,{x=pos.x,y=pos.y,z=pos.z-1},-1)
|
|
||||||
z = z + quick_flow_logic(node,{x=pos.x,y=pos.y,z=pos.z+1}, 1)
|
|
||||||
|
|
||||||
return to_unit_vector({x=x,y=0,z=z})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.quick_flow = quick_flow
|
flowlib.quick_flow = quick_flow
|
||||||
|
|
||||||
|
--if not in water but touching, move centre to touching block
|
||||||
|
--x has higher precedence than z
|
||||||
|
--if pos changes with x, it affects z
|
||||||
|
|
||||||
--if not in water but touching, move centre to touching block
|
local function move_centre(pos, realpos, node, radius)
|
||||||
--x has higher precedence than z
|
if is_touching(realpos.x, pos.x, radius) then
|
||||||
--if pos changes with x, it affects z
|
if is_liquid({x = pos.x-1, y = pos.y, z = pos.z}) then
|
||||||
local move_centre = function(pos,realpos,node,radius)
|
node = get_node({x=pos.x-1, y = pos.y, z = pos.z})
|
||||||
if is_touching(realpos.x,pos.x,radius) then
|
pos = {x = pos.x-1, y = pos.y, z = pos.z}
|
||||||
if is_liquid({x=pos.x-1,y=pos.y,z=pos.z}) then
|
elseif is_liquid({x = pos.x+1, y = pos.y, z = pos.z}) then
|
||||||
node = minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z})
|
node = get_node({x = pos.x+1, y = pos.y, z = pos.z})
|
||||||
pos = {x=pos.x-1,y=pos.y,z=pos.z}
|
pos = {x = pos.x+1, y = pos.y, z = pos.z}
|
||||||
elseif is_liquid({x=pos.x+1,y=pos.y,z=pos.z}) then
|
|
||||||
node = minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z})
|
|
||||||
pos = {x=pos.x+1,y=pos.y,z=pos.z}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if is_touching(realpos.z,pos.z,radius) then
|
if is_touching(realpos.z, pos.z, radius) then
|
||||||
if is_liquid({x=pos.x,y=pos.y,z=pos.z-1}) then
|
if is_liquid({x = pos.x, y = pos.y, z = pos.z - 1}) then
|
||||||
node = minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1})
|
node = get_node({x = pos.x, y = pos.y, z = pos.z - 1})
|
||||||
pos = {x=pos.x,y=pos.y,z=pos.z-1}
|
pos = {x = pos.x, y = pos.y, z = pos.z - 1}
|
||||||
elseif is_liquid({x=pos.x,y=pos.y,z=pos.z+1}) then
|
elseif is_liquid({x = pos.x, y = pos.y, z = pos.z + 1}) then
|
||||||
node = minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1})
|
node = get_node({x = pos.x, y = pos.y, z = pos.z + 1})
|
||||||
pos = {x=pos.x,y=pos.y,z=pos.z+1}
|
pos = {x = pos.x, y = pos.y, z = pos.z + 1}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return pos,node
|
return pos, node
|
||||||
end
|
end
|
||||||
|
|
||||||
flowlib.move_centre = move_centre
|
flowlib.move_centre = move_centre
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
name = flowlib
|
name = flowlib
|
||||||
|
author = Qwertymine3
|
||||||
|
description = Simple flow functions for use in Minetest mods by Qwertymine3
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Adds additional ways for nodes to be attached.
|
|
|
@ -1,17 +1,21 @@
|
||||||
|
local vector = vector
|
||||||
|
|
||||||
|
local facedir_to_dir = minetest.facedir_to_dir
|
||||||
|
local get_item_group = minetest.get_item_group
|
||||||
|
local remove_node = minetest.remove_node
|
||||||
|
local get_node = minetest.get_node
|
||||||
|
|
||||||
local original_function = minetest.check_single_for_falling
|
local original_function = minetest.check_single_for_falling
|
||||||
|
|
||||||
minetest.check_single_for_falling = function(pos)
|
function minetest.check_single_for_falling(pos)
|
||||||
local ret_o = original_function(pos)
|
local ret_o = original_function(pos)
|
||||||
|
|
||||||
local ret = false
|
local ret = false
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
if minetest.get_item_group(node.name, "attached_node_facedir") ~= 0 then
|
if get_item_group(node.name, "attached_node_facedir") ~= 0 then
|
||||||
local dir = minetest.facedir_to_dir(node.param2)
|
local dir = facedir_to_dir(node.param2)
|
||||||
if dir then
|
if dir then
|
||||||
local cpos = vector.add(pos, dir)
|
if get_item_group(get_node(vector.add(pos, dir)).name, "solid") == 0 then
|
||||||
local cnode = minetest.get_node(cpos)
|
remove_node(pos)
|
||||||
if minetest.get_item_group(cnode.name, "solid") == 0 then
|
|
||||||
minetest.remove_node(pos)
|
|
||||||
local drops = minetest.get_node_drops(node.name, "")
|
local drops = minetest.get_node_drops(node.name, "")
|
||||||
for dr=1, #drops do
|
for dr=1, #drops do
|
||||||
minetest.add_item(pos, drops[dr])
|
minetest.add_item(pos, drops[dr])
|
||||||
|
@ -20,7 +24,6 @@ minetest.check_single_for_falling = function(pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return ret_o or ret
|
return ret_o or ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_attached
|
||||||
|
author = Wuzzy
|
||||||
|
description = Adds additional ways for nodes to be attached.
|
|
@ -0,0 +1,27 @@
|
||||||
|
# mcl_autogroup
|
||||||
|
This mod emulate digging times from mc.
|
||||||
|
|
||||||
|
## mcl_autogroup.can_harvest(nodename, toolname)
|
||||||
|
Return true if <nodename> can be dig with <toolname>.
|
||||||
|
* nodename: string, valid nodename
|
||||||
|
* toolname: (optional) string, valid toolname
|
||||||
|
|
||||||
|
## mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||||
|
This function is used to calculate diggroups for tools.
|
||||||
|
WARNING: This function can only be called after mod initialization.
|
||||||
|
* toolname: string, name of the tool being enchanted (like "mcl_tools:diamond_pickaxe")
|
||||||
|
* efficiency: (optional) integer, the efficiency level the tool is enchanted with (default 0)
|
||||||
|
|
||||||
|
## mcl_autogroup.get_wear(toolname, diggroup)
|
||||||
|
Return the max wear of <toolname> with <diggroup>
|
||||||
|
WARNING: This function can only be called after mod initialization.
|
||||||
|
* toolname: string, name of the tool used
|
||||||
|
* diggroup: string, the name of the diggroup the tool is used on
|
||||||
|
|
||||||
|
## mcl_autogroup.register_diggroup(group, def)
|
||||||
|
* group: string, name of the group to register as a digging group
|
||||||
|
* def: (optional) table, table with information about the diggroup (defaults to {} if unspecified)
|
||||||
|
* level: (optional) string, if specified it is an array containing the names of the different digging levels the digging group supports
|
||||||
|
|
||||||
|
## mcl_autogroup.registered_diggroups
|
||||||
|
List of registered diggroups, indexed by name.
|
|
@ -0,0 +1,28 @@
|
||||||
|
--[[
|
||||||
|
This is one part of a mod to replicate the digging times from Minecraft. This
|
||||||
|
part only exposes a function to register digging groups. The rest of the mod is
|
||||||
|
implemented and documented in the _mcl_autogroup.
|
||||||
|
|
||||||
|
The mod is split up into two parts, mcl_autogroup and _mcl_autogroup.
|
||||||
|
mcl_autogroup contains the API functions used to register custom digging groups.
|
||||||
|
_mcl_autogroup contains most of the code. The leading underscore in the name
|
||||||
|
"_mcl_autogroup" is used to force Minetest to load that part of the mod as late
|
||||||
|
as possible. Minetest loads mods in reverse alphabetical order.
|
||||||
|
--]]
|
||||||
|
mcl_autogroup = {}
|
||||||
|
mcl_autogroup.registered_diggroups = {}
|
||||||
|
|
||||||
|
assert(minetest.get_modpath("_mcl_autogroup"), "This mod requires the mod _mcl_autogroup to function")
|
||||||
|
|
||||||
|
-- Register a group as a digging group.
|
||||||
|
--
|
||||||
|
-- Parameters:
|
||||||
|
-- group - Name of the group to register as a digging group
|
||||||
|
-- def - Table with information about the diggroup (defaults to {} if unspecified)
|
||||||
|
--
|
||||||
|
-- Values in def:
|
||||||
|
-- level - If specified it is an array containing the names of the different
|
||||||
|
-- digging levels the digging group supports.
|
||||||
|
function mcl_autogroup.register_diggroup(group, def)
|
||||||
|
mcl_autogroup.registered_diggroups[group] = def or {}
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_autogroup
|
||||||
|
author = ryvnf
|
||||||
|
description = MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.
|
|
@ -0,0 +1,8 @@
|
||||||
|
# mcl_colors
|
||||||
|
Mod providing global table containing legacity minecraft colors to be used in mods.
|
||||||
|
|
||||||
|
## mcl_colors.*
|
||||||
|
Colors by upper name, in hex value.
|
||||||
|
|
||||||
|
## mcl_colors.background.*
|
||||||
|
Background colors by upper name, in hex value.
|
|
@ -0,0 +1,36 @@
|
||||||
|
mcl_colors = {
|
||||||
|
BLACK = "#000000",
|
||||||
|
DARK_BLUE = "#0000AA",
|
||||||
|
DARK_GREEN = "#00AA00",
|
||||||
|
DARK_AQUA = "#00AAAA",
|
||||||
|
DARK_RED = "#AA0000",
|
||||||
|
DARK_PURPLE = "#AA00AA",
|
||||||
|
GOLD = "#FFAA00",
|
||||||
|
GRAY = "#AAAAAA",
|
||||||
|
DARK_GRAY = "#555555",
|
||||||
|
BLUE = "#5555FF",
|
||||||
|
GREEN = "#55FF55",
|
||||||
|
AQUA = "#55FFFF",
|
||||||
|
RED = "#FF5555",
|
||||||
|
LIGHT_PURPLE = "#FF55FF",
|
||||||
|
YELLOW = "#FFFF55",
|
||||||
|
WHITE = "#FFFFFF",
|
||||||
|
background = {
|
||||||
|
BLACK = "#000000",
|
||||||
|
DARK_BLUE = "#00002A",
|
||||||
|
DARK_GREEN = "#002A00",
|
||||||
|
DARK_AQUA = "#002A2A",
|
||||||
|
DARK_RED = "#2A0000",
|
||||||
|
DARK_PURPLE = "#2A002A",
|
||||||
|
GOLD = "#2A2A00",
|
||||||
|
GRAY = "#2A2A2A",
|
||||||
|
DARK_GRAY = "#151515",
|
||||||
|
BLUE = "#15153F",
|
||||||
|
GREEN = "#153F15",
|
||||||
|
AQUA = "#153F3F",
|
||||||
|
RED = "#3F1515",
|
||||||
|
LIGHT_PURPLE = "#3F153F",
|
||||||
|
YELLOW = "#3F3F15",
|
||||||
|
WHITE = "#373501",
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_colors
|
||||||
|
author = Fleckenstein
|
||||||
|
description = The HTML sequences for the minecraft colors
|
|
@ -0,0 +1,16 @@
|
||||||
|
# mcl_damage
|
||||||
|
This mod provide damage handling.
|
||||||
|
|
||||||
|
## mcl_damage.register_modifier(func, priority)
|
||||||
|
Register damage modifier.
|
||||||
|
* func: function, called with (obj, damage, reason)
|
||||||
|
|
||||||
|
This function can modify damage, based on mcl reason.
|
||||||
|
|
||||||
|
* priority: int, define call order of registered functions
|
||||||
|
|
||||||
|
You should make use higher values for important or most used functions.
|
||||||
|
|
||||||
|
## mcl_damage.from_mt(mt_reason)
|
||||||
|
Convert mt damage reason (nil, fall, drown, punch, node_damage) to mc like reason.
|
||||||
|
* mt_reason: table, mt damage reason
|
|
@ -0,0 +1,169 @@
|
||||||
|
mcl_damage = {
|
||||||
|
modifiers = {},
|
||||||
|
damage_callbacks = {},
|
||||||
|
death_callbacks = {},
|
||||||
|
types = {
|
||||||
|
in_fire = {is_fire = true},
|
||||||
|
lightning_bolt = {is_lightning = true},
|
||||||
|
on_fire = {is_fire = true, bypasses_armor = true},
|
||||||
|
lava = {is_fire = true},
|
||||||
|
hot_floor = {is_fire = true},
|
||||||
|
in_wall = {bypasses_armor = true},
|
||||||
|
drown = {bypasses_armor = true},
|
||||||
|
starve = {bypasses_armor = true, bypasses_magic = true},
|
||||||
|
cactus = {},
|
||||||
|
fall = {bypasses_armor = true},
|
||||||
|
fly_into_wall = {bypasses_armor = true}, -- unused
|
||||||
|
out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true},
|
||||||
|
generic = {bypasses_armor = true},
|
||||||
|
magic = {is_magic = true, bypasses_armor = true},
|
||||||
|
dragon_breath = {is_magic = true, bypasses_armor = true}, -- this is only used for dragon fireball; dragon fireball does not actually deal impact damage tho, so this is unreachable
|
||||||
|
wither = {bypasses_armor = true}, -- unused
|
||||||
|
wither_skull = {is_magic = true, is_explosion = true}, -- this is non-MC but a workaround to get the proper death message
|
||||||
|
anvil = {},
|
||||||
|
falling_node = {}, -- this is falling_block in MC
|
||||||
|
mob = {},
|
||||||
|
player = {},
|
||||||
|
arrow = {is_projectile = true},
|
||||||
|
fireball = {is_projectile = true, is_fire = true},
|
||||||
|
thorns = {is_magic = true},
|
||||||
|
explosion = {is_explosion = true},
|
||||||
|
cramming = {bypasses_armor = true}, -- unused
|
||||||
|
fireworks = {is_explosion = true}, -- unused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mcl_damage.register_modifier(func, priority)
|
||||||
|
table.insert(mcl_damage.modifiers, {func = func, priority = priority or 0})
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.register_on_damage(func)
|
||||||
|
table.insert(mcl_damage.damage_callbacks, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.register_on_death(func)
|
||||||
|
table.insert(mcl_damage.death_callbacks, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.run_modifiers(obj, damage, reason)
|
||||||
|
for _, modf in ipairs(mcl_damage.modifiers) do
|
||||||
|
damage = modf.func(obj, damage, reason) or damage
|
||||||
|
if damage == 0 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return damage
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run_callbacks(funcs, ...)
|
||||||
|
for _, func in pairs(funcs) do
|
||||||
|
func(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.run_damage_callbacks(obj, damage, reason)
|
||||||
|
run_callbacks(mcl_damage.damage_callbacks, obj, damage, reason)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.run_death_callbacks(obj, reason)
|
||||||
|
run_callbacks(mcl_damage.death_callbacks, obj, reason)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.from_punch(mcl_reason, object)
|
||||||
|
mcl_reason.direct = object
|
||||||
|
local luaentity = mcl_reason.direct:get_luaentity()
|
||||||
|
if luaentity then
|
||||||
|
if luaentity._is_arrow then
|
||||||
|
mcl_reason.type = "arrow"
|
||||||
|
elseif luaentity._is_fireball then
|
||||||
|
mcl_reason.type = "fireball"
|
||||||
|
elseif luaentity._cmi_is_mob then
|
||||||
|
mcl_reason.type = "mob"
|
||||||
|
end
|
||||||
|
mcl_reason.source = mcl_reason.source or luaentity._source_object
|
||||||
|
else
|
||||||
|
mcl_reason.type = "player"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.finish_reason(mcl_reason)
|
||||||
|
mcl_reason.source = mcl_reason.source or mcl_reason.direct
|
||||||
|
mcl_reason.flags = mcl_damage.types[mcl_reason.type]
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.from_mt(mt_reason)
|
||||||
|
if mt_reason._mcl_chached_reason then
|
||||||
|
return mt_reason._mcl_chached_reason
|
||||||
|
end
|
||||||
|
|
||||||
|
local mcl_reason
|
||||||
|
|
||||||
|
if mt_reason._mcl_reason then
|
||||||
|
mcl_reason = mt_reason._mcl_reason
|
||||||
|
else
|
||||||
|
mcl_reason = {type = "generic"}
|
||||||
|
|
||||||
|
if mt_reason._mcl_type then
|
||||||
|
mcl_reason.type = mt_reason._mcl_type
|
||||||
|
elseif mt_reason.type == "fall" then
|
||||||
|
mcl_reason.type = "fall"
|
||||||
|
elseif mt_reason.type == "drown" then
|
||||||
|
mcl_reason.type = "drown"
|
||||||
|
elseif mt_reason.type == "punch" then
|
||||||
|
mcl_damage.from_punch(mcl_reason, mt_reason.object)
|
||||||
|
elseif mt_reason.type == "node_damage" and mt_reason.node then
|
||||||
|
if minetest.get_item_group(mt_reason.node, "fire") > 0 then
|
||||||
|
mcl_reason.type = "in_fire"
|
||||||
|
end
|
||||||
|
if minetest.get_item_group(mt_reason.node, "lava") > 0 then
|
||||||
|
mcl_reason.type = "lava"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, value in pairs(mt_reason) do
|
||||||
|
if key:find("_mcl_") == 1 then
|
||||||
|
mcl_reason[key:sub(6, #key)] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_damage.finish_reason(mcl_reason)
|
||||||
|
mt_reason._mcl_cached_reason = mcl_reason
|
||||||
|
|
||||||
|
return mcl_reason
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_damage.register_type(name, def)
|
||||||
|
mcl_damage.types[name] = def
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
||||||
|
if hp_change < 0 then
|
||||||
|
if player:get_hp() <= 0 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
hp_change = -mcl_damage.run_modifiers(player, -hp_change, mcl_damage.from_mt(mt_reason))
|
||||||
|
end
|
||||||
|
return hp_change
|
||||||
|
end, true)
|
||||||
|
|
||||||
|
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
||||||
|
if player:get_hp() > 0 then
|
||||||
|
mt_reason.approved = true
|
||||||
|
if hp_change < 0 then
|
||||||
|
mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end, false)
|
||||||
|
|
||||||
|
minetest.register_on_dieplayer(function(player, mt_reason)
|
||||||
|
if mt_reason.approved then
|
||||||
|
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_mods_loaded(function()
|
||||||
|
table.sort(mcl_damage.modifiers, function(a, b) return a.priority < b.priority end)
|
||||||
|
end)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_damage
|
||||||
|
author = Fleckenstein
|
||||||
|
description = Minecraft-like damage reason system
|
|
@ -0,0 +1,15 @@
|
||||||
|
# mcl_explosions
|
||||||
|
This mod provide helper functions to create explosions.
|
||||||
|
|
||||||
|
## mcl_explosions.explode(pos, strength, info, puncher)
|
||||||
|
* pos: position, initial position of the explosion
|
||||||
|
* strenght: number, radius of the explosion
|
||||||
|
* info: table, explosion informations:
|
||||||
|
* drop_chance: number, if specified becomes the drop chance of all nodes in the explosion (default: 1.0 / strength)
|
||||||
|
* max_blast_resistance: int, if specified the explosion will treat all non-indestructible nodes as having a blast resistance of no more than this value
|
||||||
|
* sound: bool, if true, the explosion will play a sound (default: true)
|
||||||
|
* particles: bool, if true, the explosion will create particles (default: true)
|
||||||
|
* fire: bool, if true, 1/3 nodes become fire (default: false)
|
||||||
|
* griefing: bool, if true, the explosion will destroy nodes (default: true)
|
||||||
|
* grief_protected: bool, if true, the explosion will also destroy nodes which have been protected (default: false)
|
||||||
|
* puncher: (optional) entity, will be used as source for damage done by the explosion
|
|
@ -12,11 +12,18 @@ under the LGPLv2.1 license.
|
||||||
|
|
||||||
mcl_explosions = {}
|
mcl_explosions = {}
|
||||||
|
|
||||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages") ~= nil
|
|
||||||
local mod_fire = minetest.get_modpath("mcl_fire") ~= nil
|
local mod_fire = minetest.get_modpath("mcl_fire") ~= nil
|
||||||
local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
|
--local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
|
||||||
|
|
||||||
local S = minetest.get_translator("mcl_explosions")
|
local hash_node_position = minetest.hash_node_position
|
||||||
|
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||||
|
local get_position_from_hash = minetest.get_position_from_hash
|
||||||
|
local get_node_drops = minetest.get_node_drops
|
||||||
|
local get_name_from_content_id = minetest.get_name_from_content_id
|
||||||
|
local get_voxel_manip = minetest.get_voxel_manip
|
||||||
|
local bulk_set_node = minetest.bulk_set_node
|
||||||
|
local check_for_falling = minetest.check_for_falling
|
||||||
|
local add_item = minetest.add_item
|
||||||
|
|
||||||
-- Saved sphere explosion shapes for various radiuses
|
-- Saved sphere explosion shapes for various radiuses
|
||||||
local sphere_shapes = {}
|
local sphere_shapes = {}
|
||||||
|
@ -57,46 +64,44 @@ local function compute_sphere_rays(radius)
|
||||||
local rays = {}
|
local rays = {}
|
||||||
local sphere = {}
|
local sphere = {}
|
||||||
|
|
||||||
for i=1, 2 do
|
local function add_ray(pos)
|
||||||
|
sphere[hash_node_position(pos)] = pos
|
||||||
|
end
|
||||||
|
|
||||||
|
for y = -radius, radius do
|
||||||
|
for z = -radius, radius do
|
||||||
|
for x = -radius, 0 do
|
||||||
|
local d = x * x + y * y + z * z
|
||||||
|
if d <= radius * radius then
|
||||||
|
add_ray(vector.new(x, y, z))
|
||||||
|
add_ray(vector.new(-x, y, z))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for x = -radius, radius do
|
||||||
|
for z = -radius, radius do
|
||||||
|
for y = -radius, 0 do
|
||||||
|
local d = x * x + y * y + z * z
|
||||||
|
if d <= radius * radius then
|
||||||
|
add_ray(vector.new(x, y, z))
|
||||||
|
add_ray(vector.new(x, -y, z))
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for x = -radius, radius do
|
||||||
for y = -radius, radius do
|
for y = -radius, radius do
|
||||||
for z = -radius, radius do
|
for z = -radius, 0 do
|
||||||
for x = -radius, 0, 1 do
|
local d = x * x + y * y + z * z
|
||||||
local d = x * x + y * y + z * z
|
if d <= radius * radius then
|
||||||
if d <= radius * radius then
|
add_ray(vector.new(x, y, z))
|
||||||
local pos = { x = x, y = y, z = z }
|
add_ray(vector.new(x, y, -z))
|
||||||
sphere[minetest.hash_node_position(pos)] = pos
|
break
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i=1,2 do
|
|
||||||
for x = -radius, radius do
|
|
||||||
for z = -radius, radius do
|
|
||||||
for y = -radius, 0, 1 do
|
|
||||||
local d = x * x + y * y + z * z
|
|
||||||
if d <= radius * radius then
|
|
||||||
local pos = { x = x, y = y, z = z }
|
|
||||||
sphere[minetest.hash_node_position(pos)] = pos
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i=1,2 do
|
|
||||||
for x = -radius, radius do
|
|
||||||
for y = -radius, radius do
|
|
||||||
for z = -radius, 0, 1 do
|
|
||||||
local d = x * x + y * y + z * z
|
|
||||||
if d <= radius * radius then
|
|
||||||
local pos = { x = x, y = y, z = z }
|
|
||||||
sphere[minetest.hash_node_position(pos)] = pos
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -140,7 +145,8 @@ end
|
||||||
-- raydirs - The directions for each ray
|
-- raydirs - The directions for each ray
|
||||||
-- radius - The maximum distance each ray will go
|
-- radius - The maximum distance each ray will go
|
||||||
-- info - Table containing information about explosion
|
-- info - Table containing information about explosion
|
||||||
-- puncher - object that punches other objects (optional)
|
-- direct - direct source object of the damage (optional)
|
||||||
|
-- source - indirect source object of the damage (optional)
|
||||||
--
|
--
|
||||||
-- Values in info:
|
-- Values in info:
|
||||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
-- drop_chance - The chance that destroyed nodes will drop their items
|
||||||
|
@ -155,8 +161,8 @@ end
|
||||||
-- Note that this function has been optimized, it contains code which has been
|
-- Note that this function has been optimized, it contains code which has been
|
||||||
-- inlined to avoid function calls and unnecessary table creation. This was
|
-- inlined to avoid function calls and unnecessary table creation. This was
|
||||||
-- measured to give a significant performance increase.
|
-- measured to give a significant performance increase.
|
||||||
local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
local function trace_explode(pos, strength, raydirs, radius, info, direct, source)
|
||||||
local vm = minetest.get_voxel_manip()
|
local vm = get_voxel_manip()
|
||||||
|
|
||||||
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
||||||
vector.add(pos, radius))
|
vector.add(pos, radius))
|
||||||
|
@ -166,14 +172,11 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
|
|
||||||
local ystride = (emax.x - emin_x + 1)
|
local ystride = (emax.x - emin_x + 1)
|
||||||
local zstride = ystride * (emax.y - emin_y + 1)
|
local zstride = ystride * (emax.y - emin_y + 1)
|
||||||
local pos_x = pos.x
|
|
||||||
local pos_y = pos.y
|
|
||||||
local pos_z = pos.z
|
|
||||||
|
|
||||||
local area = VoxelArea:new {
|
--[[local area = VoxelArea:new {
|
||||||
MinEdge = emin,
|
MinEdge = emin,
|
||||||
MaxEdge = emax
|
MaxEdge = emax
|
||||||
}
|
}]]
|
||||||
local data = vm:get_data()
|
local data = vm:get_data()
|
||||||
local destroy = {}
|
local destroy = {}
|
||||||
|
|
||||||
|
@ -202,12 +205,12 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
npos_x - emin_x + 1
|
npos_x - emin_x + 1
|
||||||
|
|
||||||
local cid = data[idx]
|
local cid = data[idx]
|
||||||
local br = node_blastres[cid]
|
local br = node_blastres[cid] or INDESTRUCT_BLASTRES
|
||||||
if br < INDESTRUCT_BLASTRES and br > max_blast_resistance then
|
if br < INDESTRUCT_BLASTRES and br > max_blast_resistance then
|
||||||
br = max_blast_resistance
|
br = max_blast_resistance
|
||||||
end
|
end
|
||||||
|
|
||||||
local hash = minetest.hash_node_position(npos)
|
local hash = hash_node_position(npos)
|
||||||
|
|
||||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||||
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
||||||
|
@ -230,14 +233,14 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
|
|
||||||
-- Entities in radius of explosion
|
-- Entities in radius of explosion
|
||||||
local punch_radius = 2 * strength
|
local punch_radius = 2 * strength
|
||||||
local objs = minetest.get_objects_inside_radius(pos, punch_radius)
|
local objs = get_objects_inside_radius(pos, punch_radius)
|
||||||
|
|
||||||
-- Trace rays for entity damage
|
-- Trace rays for entity damage
|
||||||
for _, obj in pairs(objs) do
|
for _, obj in pairs(objs) do
|
||||||
local ent = obj:get_luaentity()
|
local ent = obj:get_luaentity()
|
||||||
|
|
||||||
-- Ignore items to lower lag
|
-- Ignore items to lower lag
|
||||||
if obj:is_player() or (ent and ent.name ~= '__builtin.item') then
|
if (obj:is_player() or (ent and ent.name ~= '__builtin.item')) and obj:get_hp() > 0 then
|
||||||
local opos = obj:get_pos()
|
local opos = obj:get_pos()
|
||||||
local collisionbox = nil
|
local collisionbox = nil
|
||||||
|
|
||||||
|
@ -250,12 +253,12 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
|
|
||||||
if collisionbox then
|
if collisionbox then
|
||||||
-- Create rays from random points in the collision box
|
-- Create rays from random points in the collision box
|
||||||
local x1 = collisionbox[1] * 2
|
local x1 = collisionbox[1]
|
||||||
local y1 = collisionbox[2] * 2
|
local y1 = collisionbox[2]
|
||||||
local z1 = collisionbox[3] * 2
|
local z1 = collisionbox[3]
|
||||||
local x2 = collisionbox[4] * 2
|
local x2 = collisionbox[4]
|
||||||
local y2 = collisionbox[5] * 2
|
local y2 = collisionbox[5]
|
||||||
local z2 = collisionbox[6] * 2
|
local z2 = collisionbox[6]
|
||||||
local x_len = math.abs(x2 - x1)
|
local x_len = math.abs(x2 - x1)
|
||||||
local y_len = math.abs(y2 - y1)
|
local y_len = math.abs(y2 - y1)
|
||||||
local z_len = math.abs(z2 - z1)
|
local z_len = math.abs(z2 - z1)
|
||||||
|
@ -311,7 +314,6 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
impact = 0
|
impact = 0
|
||||||
end
|
end
|
||||||
local damage = math.floor((impact * impact + impact) * 7 * strength + 1)
|
local damage = math.floor((impact * impact + impact) * 7 * strength + 1)
|
||||||
local source = puncher or obj
|
|
||||||
|
|
||||||
local sleep_formspec_doesnt_close_mt53 = false
|
local sleep_formspec_doesnt_close_mt53 = false
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
|
@ -323,26 +325,22 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
sleep_formspec_doesnt_close_mt53 = true
|
sleep_formspec_doesnt_close_mt53 = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if mod_death_messages then
|
|
||||||
mcl_death_messages.player_damage(obj, S("@1 was caught in an explosion.", name))
|
|
||||||
end
|
|
||||||
if rawget(_G, "armor") and armor.last_damage_types then
|
|
||||||
armor.last_damage_types[name] = "explosion"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if sleep_formspec_doesnt_close_mt53 then
|
if sleep_formspec_doesnt_close_mt53 then
|
||||||
minetest.after(0.3, function(obj, damage, impact, punch_dir) -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
|
minetest.after(0.3, function() -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
|
||||||
if not obj then return end
|
if not obj:is_player() then
|
||||||
obj:punch(obj, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
return
|
||||||
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
end
|
||||||
end, obj, damage, impact, vector.new(punch_dir))
|
|
||||||
else
|
|
||||||
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
|
||||||
|
|
||||||
if obj:is_player() then
|
mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source})
|
||||||
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
|
|
||||||
elseif ent.tnt_knockback then
|
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source})
|
||||||
|
|
||||||
|
if obj:is_player() or ent.tnt_knockback then
|
||||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -359,46 +357,46 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||||
local remove = true
|
local remove = true
|
||||||
|
|
||||||
if do_drop or on_blast ~= nil then
|
if do_drop or on_blast ~= nil then
|
||||||
local npos = minetest.get_position_from_hash(hash)
|
local npos = get_position_from_hash(hash)
|
||||||
if on_blast ~= nil then
|
if on_blast ~= nil then
|
||||||
on_blast(npos, 1.0, do_drop)
|
on_blast(npos, 1.0, do_drop)
|
||||||
remove = false
|
remove = false
|
||||||
else
|
else
|
||||||
local name = minetest.get_name_from_content_id(data[idx])
|
local name = get_name_from_content_id(data[idx])
|
||||||
local drop = minetest.get_node_drops(name, "")
|
local drop = get_node_drops(name, "")
|
||||||
|
|
||||||
for _, item in ipairs(drop) do
|
for _, item in ipairs(drop) do
|
||||||
if type(item) ~= "string" then
|
if type(item) ~= "string" then
|
||||||
item = item:get_name() .. item:get_count()
|
item = item:get_name() .. item:get_count()
|
||||||
end
|
end
|
||||||
minetest.add_item(npos, item)
|
add_item(npos, item)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if remove then
|
if remove then
|
||||||
if mod_fire and fire and math.random(1, 3) == 1 then
|
if mod_fire and fire and math.random(1, 3) == 1 then
|
||||||
table.insert(fires, minetest.get_position_from_hash(hash))
|
table.insert(fires, get_position_from_hash(hash))
|
||||||
else
|
else
|
||||||
table.insert(airs, minetest.get_position_from_hash(hash))
|
table.insert(airs, get_position_from_hash(hash))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- We use bulk_set_node instead of LVM because we want to have on_destruct and
|
-- We use bulk_set_node instead of LVM because we want to have on_destruct and
|
||||||
-- on_construct being called
|
-- on_construct being called
|
||||||
if #airs > 0 then
|
if #airs > 0 then
|
||||||
minetest.bulk_set_node(airs, {name="air"})
|
bulk_set_node(airs, {name="air"})
|
||||||
end
|
end
|
||||||
if #fires > 0 then
|
if #fires > 0 then
|
||||||
minetest.bulk_set_node(fires, {name="mcl_fire:fire"})
|
bulk_set_node(fires, {name="mcl_fire:fire"})
|
||||||
end
|
end
|
||||||
-- Update falling nodes
|
-- Update falling nodes
|
||||||
for a=1, #airs do
|
for a=1, #airs do
|
||||||
local p = airs[a]
|
local p = airs[a]
|
||||||
minetest.check_for_falling({x=p.x, y=p.y+1, z=p.z})
|
check_for_falling({x=p.x, y=p.y+1, z=p.z})
|
||||||
end
|
end
|
||||||
for f=1, #fires do
|
for f=1, #fires do
|
||||||
local p = fires[f]
|
local p = fires[f]
|
||||||
minetest.check_for_falling({x=p.x, y=p.y+1, z=p.z})
|
check_for_falling({x=p.x, y=p.y+1, z=p.z})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Log explosion
|
-- Log explosion
|
||||||
|
@ -412,7 +410,8 @@ end
|
||||||
-- pos - The position where the explosion originates from
|
-- pos - The position where the explosion originates from
|
||||||
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
||||||
-- info - Table containing information about explosion
|
-- info - Table containing information about explosion
|
||||||
-- puncher - object that is reported as source of punches/damage (optional)
|
-- direct - direct source object of the damage (optional)
|
||||||
|
-- source - indirect source object of the damage (optional)
|
||||||
--
|
--
|
||||||
-- Values in info:
|
-- Values in info:
|
||||||
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
||||||
|
@ -426,7 +425,7 @@ end
|
||||||
-- griefing - If true, the explosion will destroy nodes (default: true)
|
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||||
-- grief_protected - If true, the explosion will also destroy nodes which have
|
-- grief_protected - If true, the explosion will also destroy nodes which have
|
||||||
-- been protected (default: false)
|
-- been protected (default: false)
|
||||||
function mcl_explosions.explode(pos, strength, info, puncher)
|
function mcl_explosions.explode(pos, strength, info, direct, source)
|
||||||
if info == nil then
|
if info == nil then
|
||||||
info = {}
|
info = {}
|
||||||
end
|
end
|
||||||
|
@ -455,7 +454,7 @@ function mcl_explosions.explode(pos, strength, info, puncher)
|
||||||
info.drop_chance = 0
|
info.drop_chance = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
trace_explode(pos, strength, shape, radius, info, puncher)
|
trace_explode(pos, strength, shape, radius, info, direct, source)
|
||||||
|
|
||||||
if info.particles then
|
if info.particles then
|
||||||
add_particles(pos, radius)
|
add_particles(pos, radius)
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
# textdomain:mcl_explosions
|
|
||||||
@1 was caught in an explosion.=@1 wurde Opfer einer Explosion.
|
|
|
@ -1,2 +0,0 @@
|
||||||
# textdomain:mcl_explosions
|
|
||||||
@1 was caught in an explosion.=@1 a été pris dans une explosion.
|
|
|
@ -1,2 +0,0 @@
|
||||||
# textdomain:mcl_explosions
|
|
||||||
@1 was caught in an explosion.=@1 не удалось пережить взрыва.
|
|
|
@ -1,2 +0,0 @@
|
||||||
# textdomain:mcl_explosions
|
|
||||||
@1 was caught in an explosion.=
|
|
|
@ -1,4 +1,5 @@
|
||||||
name = mcl_explosions
|
name = mcl_explosions
|
||||||
|
author = ryvnf
|
||||||
description = A common API to create explosions.
|
description = A common API to create explosions.
|
||||||
depends = mcl_particles
|
depends = mcl_particles
|
||||||
optional_depends = mcl_fire
|
optional_depends = mcl_fire
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Initialization mod of MineClone 2. Defines some common shared variables and sets up initial default settings which have to be set at the beginning.
|
|
|
@ -21,6 +21,9 @@ mcl_vars.gui_bg_img = "background9[1,1;1,1;mcl_base_textures_background9.png;tru
|
||||||
-- Legacy
|
-- Legacy
|
||||||
mcl_vars.inventory_header = ""
|
mcl_vars.inventory_header = ""
|
||||||
|
|
||||||
|
-- Tool wield size
|
||||||
|
mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
|
||||||
|
|
||||||
-- Mapgen variables
|
-- Mapgen variables
|
||||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||||
local minecraft_height_limit = 256
|
local minecraft_height_limit = 256
|
||||||
|
@ -33,25 +36,26 @@ mcl_vars.MAP_BLOCKSIZE = math.max(1, core.MAP_BLOCKSIZE or 16)
|
||||||
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000)
|
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||||
local chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||||
|
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||||
local central_chunk_max_pos = central_chunk_min_pos + chunk_size_in_nodes - 1
|
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
||||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
||||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
||||||
|
|
||||||
local function coordinate_to_block(x)
|
local function coordinate_to_block(x)
|
||||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function coordinate_to_chunk(x)
|
local function coordinate_to_chunk(x)
|
||||||
return math.floor((coordinate_to_block(x) + central_chunk_offset) / mcl_vars.chunksize)
|
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_vars.pos_to_block(pos)
|
function mcl_vars.pos_to_block(pos)
|
||||||
|
@ -70,7 +74,7 @@ function mcl_vars.pos_to_chunk(pos)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / chunk_size_in_nodes)
|
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||||
local k_positive_z = k_positive * 2
|
local k_positive_z = k_positive * 2
|
||||||
local k_positive_y = k_positive_z * k_positive_z
|
local k_positive_y = k_positive_z * k_positive_z
|
||||||
|
|
||||||
|
@ -174,3 +178,86 @@ minetest.craftitemdef_default.stack_max = 64
|
||||||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
|
|
||||||
|
local chunks = {} -- intervals of chunks generated
|
||||||
|
function mcl_vars.add_chunk(pos)
|
||||||
|
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||||
|
local prev
|
||||||
|
for i, d in pairs(chunks) do
|
||||||
|
if n <= d[2] then -- we've found it
|
||||||
|
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||||
|
if n == d[1]-1 then -- right before:
|
||||||
|
if prev and (prev[2] == n-1) then
|
||||||
|
prev[2] = d[2]
|
||||||
|
table.remove(chunks, i)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
d[1] = n
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if prev and (prev[2] == n-1) then --join to previous
|
||||||
|
prev[2] = n
|
||||||
|
return
|
||||||
|
end
|
||||||
|
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||||
|
return
|
||||||
|
end
|
||||||
|
prev = d
|
||||||
|
end
|
||||||
|
chunks[#chunks+1] = {n, n}
|
||||||
|
end
|
||||||
|
function mcl_vars.is_generated(pos)
|
||||||
|
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||||
|
for i, d in pairs(chunks) do
|
||||||
|
if n <= d[2] then
|
||||||
|
return (n >= d[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||||
|
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||||
|
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||||
|
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||||
|
--
|
||||||
|
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||||
|
function mcl_vars.get_node(p, force, us_timeout)
|
||||||
|
-- check initial circumstances
|
||||||
|
if not p or not p.x or not p.y or not p.z then return {name="error"} end
|
||||||
|
|
||||||
|
-- try common way
|
||||||
|
local node = minetest.get_node(p)
|
||||||
|
if node.name ~= "ignore" then
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
-- copy table to get sure it won't changed by other threads
|
||||||
|
local pos = {x=p.x,y=p.y,z=p.z}
|
||||||
|
|
||||||
|
-- try LVM
|
||||||
|
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||||
|
node = minetest.get_node(pos)
|
||||||
|
if node.name ~= "ignore" or not force then
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
-- all ways failed - need to emerge (or forceload if generated)
|
||||||
|
local us_timeout = us_timeout or 244
|
||||||
|
if mcl_vars.is_generated(pos) then
|
||||||
|
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
|
||||||
|
minetest.forceload_block(pos)
|
||||||
|
else
|
||||||
|
minetest.emerge_area(pos, pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = minetest.get_us_time()
|
||||||
|
|
||||||
|
node = minetest.get_node(pos)
|
||||||
|
|
||||||
|
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||||
|
node = minetest.get_node(pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
return node
|
||||||
|
-- it still can return "ignore", LOL, even if force = true, but only after time out
|
||||||
|
end
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
name = mcl_init
|
name = mcl_init
|
||||||
|
author = Wuzzy
|
||||||
|
description = Initialization mod of MineClone 2. Defines some common shared variables and sets up initial default settings which have to be set at the beginning.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
API for filling a chest with random treasures.
|
|
|
@ -40,10 +40,9 @@ function mcl_loot.get_loot(loot_definitions, pr)
|
||||||
total_weight = total_weight + (loot_definitions.items[i].weight or 1)
|
total_weight = total_weight + (loot_definitions.items[i].weight or 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
local stacks_min = loot_definitions.stacks_min
|
--local stacks_min = loot_definitions.stacks_min or 1
|
||||||
local stacks_max = loot_definitions.stacks_max
|
--local stacks_max = loot_definitions.stacks_max or 1
|
||||||
if not stacks_min then stacks_min = 1 end
|
|
||||||
if not stacks_max then stacks_max = 1 end
|
|
||||||
local stacks = pr:next(loot_definitions.stacks_min, loot_definitions.stacks_max)
|
local stacks = pr:next(loot_definitions.stacks_min, loot_definitions.stacks_max)
|
||||||
for s=1, stacks do
|
for s=1, stacks do
|
||||||
local r = pr:next(1, total_weight)
|
local r = pr:next(1, total_weight)
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
name = mcl_loot
|
name = mcl_loot
|
||||||
|
author = Wuzzy
|
||||||
|
description = API for filling a chest with random treasures.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Contains particle images of MineClone 2. No code.
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
local vector = vector
|
||||||
|
local table = table
|
||||||
|
|
||||||
|
local hash_node_position = minetest.hash_node_position
|
||||||
|
local add_particlespawner = minetest.add_particlespawner
|
||||||
|
local delete_particlespawner = minetest.delete_particlespawner
|
||||||
|
|
||||||
|
local ipairs = ipairs
|
||||||
|
|
||||||
mcl_particles = {}
|
mcl_particles = {}
|
||||||
|
|
||||||
-- Table of particlespawner IDs on a per-node hash basis
|
-- Table of particlespawner IDs on a per-node hash basis
|
||||||
|
@ -32,11 +41,11 @@ function mcl_particles.add_node_particlespawner(pos, particlespawner_definition,
|
||||||
if allowed_level == 0 or levels[level] > allowed_level then
|
if allowed_level == 0 or levels[level] > allowed_level then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local poshash = minetest.hash_node_position(pos)
|
local poshash = hash_node_position(pos)
|
||||||
if not poshash then
|
if not poshash then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local id = minetest.add_particlespawner(particlespawner_definition)
|
local id = add_particlespawner(particlespawner_definition)
|
||||||
if id == -1 then
|
if id == -1 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -47,6 +56,8 @@ function mcl_particles.add_node_particlespawner(pos, particlespawner_definition,
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local add_node_particlespawner = mcl_particles.add_node_particlespawner
|
||||||
|
|
||||||
-- Deletes all particlespawners that are assigned to a node position.
|
-- Deletes all particlespawners that are assigned to a node position.
|
||||||
-- If no particlespawners exist for this position, nothing happens.
|
-- If no particlespawners exist for this position, nothing happens.
|
||||||
-- pos: Node positon. MUST use integer values!
|
-- pos: Node positon. MUST use integer values!
|
||||||
|
@ -55,14 +66,66 @@ function mcl_particles.delete_node_particlespawners(pos)
|
||||||
if allowed_level == 0 then
|
if allowed_level == 0 then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local poshash = minetest.hash_node_position(pos)
|
local poshash = hash_node_position(pos)
|
||||||
local ids = particle_nodes[poshash]
|
local ids = particle_nodes[poshash]
|
||||||
if ids then
|
if ids then
|
||||||
for i=1, #ids do
|
for i=1, #ids do
|
||||||
minetest.delete_particlespawner(ids[i])
|
delete_particlespawner(ids[i])
|
||||||
end
|
end
|
||||||
particle_nodes[poshash] = nil
|
particle_nodes[poshash] = nil
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- 3 exptime variants because the animation is not tied to particle expiration time.
|
||||||
|
-- 3 colorized variants to imitate minecraft's
|
||||||
|
local smoke_pdef_cached = {}
|
||||||
|
|
||||||
|
function mcl_particles.spawn_smoke(pos, name, smoke_pdef_base)
|
||||||
|
local new_minpos = vector.add(pos, smoke_pdef_base.minrelpos)
|
||||||
|
local new_maxpos = vector.add(pos, smoke_pdef_base.maxrelpos)
|
||||||
|
|
||||||
|
-- populate the cache
|
||||||
|
if smoke_pdef_cached[name] then
|
||||||
|
for i, smoke_pdef in ipairs(smoke_pdef_cached[name]) do
|
||||||
|
smoke_pdef.minpos = new_minpos
|
||||||
|
smoke_pdef.maxpos = new_maxpos
|
||||||
|
add_node_particlespawner(pos, smoke_pdef, "high")
|
||||||
|
end
|
||||||
|
-- cache already populated
|
||||||
|
else
|
||||||
|
smoke_pdef_cached[name] = {}
|
||||||
|
|
||||||
|
local smoke_pdef = table.copy(smoke_pdef_base)
|
||||||
|
smoke_pdef.amount = smoke_pdef_base.amount / 9
|
||||||
|
smoke_pdef.time = 0
|
||||||
|
smoke_pdef.animation = {
|
||||||
|
type = "vertical_frames",
|
||||||
|
aspect_w = 8,
|
||||||
|
aspect_h = 8,
|
||||||
|
-- length = 3 exptime variants
|
||||||
|
}
|
||||||
|
smoke_pdef.collisiondetection = true
|
||||||
|
smoke_pdef.minpos = new_minpos
|
||||||
|
smoke_pdef.maxpos = new_maxpos
|
||||||
|
|
||||||
|
-- the last frame plays for 1/8 * N seconds, so we can take advantage of it
|
||||||
|
-- to have varying exptime for each variant.
|
||||||
|
local exptimes = { 0.175, 0.375, 1.0 }
|
||||||
|
local colorizes = { "199", "209", "243" } -- round(78%, 82%, 90% of 256) - 1
|
||||||
|
|
||||||
|
for _,exptime in ipairs(exptimes) do
|
||||||
|
for _,colorize in ipairs(colorizes) do
|
||||||
|
smoke_pdef.maxexptime = exptime * smoke_pdef_base.maxexptime
|
||||||
|
smoke_pdef.animation.length = exptime + 0.1
|
||||||
|
-- minexptime must be set such that the last frame is actully rendered,
|
||||||
|
-- even if its very short. Larger exptime -> larger range
|
||||||
|
smoke_pdef.minexptime = math.min(exptime, (7.0/8.0 * (exptime + 0.1) + 0.1))
|
||||||
|
smoke_pdef.texture = "mcl_particles_smoke_anim.png^[colorize:#000000:" ..colorize
|
||||||
|
add_node_particlespawner(pos, smoke_pdef, "high")
|
||||||
|
table.insert(smoke_pdef_cached[name], table.copy(smoke_pdef))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1 +1,3 @@
|
||||||
name = mcl_particles
|
name = mcl_particles
|
||||||
|
author = Wuzzy
|
||||||
|
description = Contains particle images of MineClone 2. No code.
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -1 +0,0 @@
|
||||||
This mod contains the core sounds of MineClone 2 as well as helper function for mods to access them.
|
|
|
@ -1 +1,3 @@
|
||||||
name = mcl_sounds
|
name = mcl_sounds
|
||||||
|
author = Wuzzy
|
||||||
|
description = This mod contains the core sounds of MineClone 2 as well as helper function for mods to access them.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
mcl_init
|
|
|
@ -1 +0,0 @@
|
||||||
Helper functions for MineClone 2.
|
|
|
@ -150,7 +150,7 @@ function mcl_util.get_eligible_transfer_item_slot(src_inventory, src_list, dst_i
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns true if itemstack is a shulker box
|
-- Returns true if itemstack is a shulker box
|
||||||
local is_not_shulker_box = function(itemstack)
|
local function is_not_shulker_box(itemstack)
|
||||||
local g = minetest.get_item_group(itemstack:get_name(), "shulker_box")
|
local g = minetest.get_item_group(itemstack:get_name(), "shulker_box")
|
||||||
return g == 0 or g == nil
|
return g == 0 or g == nil
|
||||||
end
|
end
|
||||||
|
@ -212,7 +212,7 @@ function mcl_util.move_item_container(source_pos, destination_pos, source_list,
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Normalize double container by forcing to always use the left segment first
|
-- Normalize double container by forcing to always use the left segment first
|
||||||
local normalize_double_container = function(pos, node, ctype)
|
local function normalize_double_container(pos, node, ctype)
|
||||||
if ctype == 6 then
|
if ctype == 6 then
|
||||||
pos = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
pos = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
|
||||||
if not pos then
|
if not pos then
|
||||||
|
@ -405,3 +405,136 @@ function mcl_util.get_object_center(obj)
|
||||||
pos.y = pos.y + (ymax - ymin) / 2.0
|
pos.y = pos.y + (ymax - ymin) / 2.0
|
||||||
return pos
|
return pos
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mcl_util.get_color(colorstr)
|
||||||
|
local mc_color = mcl_colors[colorstr:upper()]
|
||||||
|
if mc_color then
|
||||||
|
colorstr = mc_color
|
||||||
|
elseif #colorstr ~= 7 or colorstr:sub(1, 1) ~= "#" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local hex = tonumber(colorstr:sub(2, 7), 16)
|
||||||
|
if hex then
|
||||||
|
return colorstr, hex
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.call_on_rightclick(itemstack, player, pointed_thing)
|
||||||
|
-- Call on_rightclick if the pointed node defines it
|
||||||
|
if pointed_thing and pointed_thing.type == "node" then
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if player and not player:get_player_control().sneak then
|
||||||
|
local nodedef = minetest.registered_nodes[node.name]
|
||||||
|
local on_rightclick = nodedef and nodedef.on_rightclick
|
||||||
|
if on_rightclick then
|
||||||
|
return on_rightclick(pos, node, player, itemstack, pointed_thing) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.calculate_durability(itemstack)
|
||||||
|
local unbreaking_level = mcl_enchanting.get_enchantment(itemstack, "unbreaking")
|
||||||
|
local armor_uses = minetest.get_item_group(itemstack:get_name(), "mcl_armor_uses")
|
||||||
|
|
||||||
|
local uses
|
||||||
|
|
||||||
|
if armor_uses > 0 then
|
||||||
|
uses = armor_uses
|
||||||
|
if unbreaking_level > 0 then
|
||||||
|
uses = uses / (0.6 + 0.4 / (unbreaking_level + 1))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local def = itemstack:get_definition()
|
||||||
|
if def then
|
||||||
|
local fixed_uses = def._mcl_uses
|
||||||
|
if fixed_uses then
|
||||||
|
uses = fixed_uses
|
||||||
|
if unbreaking_level > 0 then
|
||||||
|
uses = uses * (unbreaking_level + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
uses = uses or (next(itemstack:get_tool_capabilities().groupcaps) or {}).uses
|
||||||
|
end
|
||||||
|
|
||||||
|
return uses or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.use_item_durability(itemstack, n)
|
||||||
|
local uses = mcl_util.calculate_durability(itemstack)
|
||||||
|
itemstack:add_wear(65535 / uses * n)
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.deal_damage(target, damage, mcl_reason)
|
||||||
|
local luaentity = target:get_luaentity()
|
||||||
|
|
||||||
|
if luaentity then
|
||||||
|
if luaentity.deal_damage then
|
||||||
|
luaentity:deal_damage(damage, mcl_reason or {type = "generic"})
|
||||||
|
return
|
||||||
|
elseif luaentity._cmi_is_mob then
|
||||||
|
-- local puncher = mcl_reason and mcl_reason.direct or target
|
||||||
|
-- target:punch(puncher, 1.0, {full_punch_interval = 1.0, damage_groups = {fleshy = damage}}, vector.direction(puncher:get_pos(), target:get_pos()), damage)
|
||||||
|
if luaentity.health > 0 then
|
||||||
|
luaentity.health = luaentity.health - damage
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local hp = target:get_hp()
|
||||||
|
|
||||||
|
if hp > 0 then
|
||||||
|
target:set_hp(hp - damage, {_mcl_reason = mcl_reason})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.get_hp(obj)
|
||||||
|
local luaentity = obj:get_luaentity()
|
||||||
|
|
||||||
|
if luaentity and luaentity._cmi_is_mob then
|
||||||
|
return luaentity.health
|
||||||
|
else
|
||||||
|
return obj:get_hp()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.get_inventory(object, create)
|
||||||
|
if object:is_player() then
|
||||||
|
return object:get_inventory()
|
||||||
|
else
|
||||||
|
local luaentity = object:get_luaentity()
|
||||||
|
local inventory = luaentity.inventory
|
||||||
|
|
||||||
|
if create and not inventory and luaentity.create_inventory then
|
||||||
|
inventory = luaentity:create_inventory()
|
||||||
|
end
|
||||||
|
|
||||||
|
return inventory
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.get_wielded_item(object)
|
||||||
|
if object:is_player() then
|
||||||
|
return object:get_wielded_item()
|
||||||
|
else
|
||||||
|
-- ToDo: implement getting wielditems from mobs as soon as mobs have wielditems
|
||||||
|
return ItemStack()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.get_object_name(object)
|
||||||
|
if object:is_player() then
|
||||||
|
return object:get_player_name()
|
||||||
|
else
|
||||||
|
local luaentity = object:get_luaentity()
|
||||||
|
|
||||||
|
if not luaentity then
|
||||||
|
return tostring(object)
|
||||||
|
end
|
||||||
|
|
||||||
|
return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
name = mcl_util
|
name = mcl_util
|
||||||
|
author = Wuzzy
|
||||||
|
description = Helper functions for MineClone 2.
|
||||||
|
depends = mcl_init
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
# mcl_worlds
|
||||||
|
This mod provides utility functions about positions and dimensions.
|
||||||
|
|
||||||
|
## mcl_worlds.is_in_void(pos)
|
||||||
|
This function returns:
|
||||||
|
|
||||||
|
* true, true: if pos is in deep void (deadly)
|
||||||
|
* true, false: if the pos is in void (non deadly)
|
||||||
|
* false, false: owerwise
|
||||||
|
|
||||||
|
Params:
|
||||||
|
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## mcl_worlds.y_to_layer(y)
|
||||||
|
This function is used to calculate the minetest y layer and dimension of the given <y> minecraft layer.
|
||||||
|
Mainly used for ore generation.
|
||||||
|
Takes an Y coordinate as input and returns:
|
||||||
|
|
||||||
|
* The corresponding Minecraft layer (can be nil if void)
|
||||||
|
* The corresponding Minecraft dimension ("overworld", "nether" or "end") or "void" if <y> is in the void
|
||||||
|
If the Y coordinate is not located in any dimension, it will return: nil, "void"
|
||||||
|
|
||||||
|
Params:
|
||||||
|
|
||||||
|
* y: int
|
||||||
|
|
||||||
|
## mcl_worlds.pos_to_dimension(pos)
|
||||||
|
This function return the Minecraft dimension of <pos> ("overworld", "nether" or "end") or "void" if <y> is in the void.
|
||||||
|
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## mcl_worlds.layer_to_y(layer, mc_dimension)
|
||||||
|
Takes a Minecraft layer and a “dimension” name and returns the corresponding Y coordinate for MineClone 2.
|
||||||
|
mc_dimension can be "overworld", "nether", "end" (default: "overworld").
|
||||||
|
|
||||||
|
* layer: int
|
||||||
|
* mc_dimension: string
|
||||||
|
|
||||||
|
## mcl_worlds.has_weather(pos)
|
||||||
|
Returns true if <pos> can have weather, false owerwise.
|
||||||
|
Weather can be only in the overworld.
|
||||||
|
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## mcl_worlds.has_dust(pos)
|
||||||
|
Returns true if <pos> can have nether dust, false owerwise.
|
||||||
|
Nether dust can be only in the nether.
|
||||||
|
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## mcl_worlds.compass_works(pos)
|
||||||
|
Returns true if compasses are working at <pos>, false owerwise.
|
||||||
|
In mc, you cant use compass in the nether and the end.
|
||||||
|
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## mcl_worlds.compass_works(pos)
|
||||||
|
Returns true if clock are working at <pos>, false owerwise.
|
||||||
|
In mc, you cant use clock in the nether and the end.
|
||||||
|
|
||||||
|
* pos: position
|
||||||
|
|
||||||
|
## mcl_worlds.register_on_dimension_change(function(player, dimension, last_dimension))
|
||||||
|
Register a callback function func(player, dimension).
|
||||||
|
It will be called whenever a player changes between dimensions.
|
||||||
|
The void counts as dimension.
|
||||||
|
|
||||||
|
* player: player, the player who changed of dimension
|
||||||
|
* dimension: string, The new dimension of the player ("overworld", "nether", "end", "void").
|
||||||
|
* last_dimension: string, The dimension where the player was ("overworld", "nether", "end", "void").
|
||||||
|
|
||||||
|
|
||||||
|
## mcl_worlds.registered_on_dimension_change
|
||||||
|
Table containing all function registered with mcl_worlds.register_on_dimension_change()
|
||||||
|
|
||||||
|
## mcl_worlds.dimension_change(player, dimension)
|
||||||
|
Notify this mod of a dimension change of <player> to <dimension>
|
||||||
|
|
||||||
|
* player: player, player who changed the dimension
|
||||||
|
* dimension: string, new dimension ("overworld", "nether", "end", "void")
|
|
@ -1 +0,0 @@
|
||||||
mcl_init
|
|
|
@ -1 +0,0 @@
|
||||||
Utility functions for worlds and the “dimensions”.
|
|
|
@ -6,7 +6,7 @@ mcl_worlds = {}
|
||||||
function mcl_worlds.is_in_void(pos)
|
function mcl_worlds.is_in_void(pos)
|
||||||
local void =
|
local void =
|
||||||
not ((pos.y < mcl_vars.mg_overworld_max and pos.y > mcl_vars.mg_overworld_min) or
|
not ((pos.y < mcl_vars.mg_overworld_max and pos.y > mcl_vars.mg_overworld_min) or
|
||||||
(pos.y < mcl_vars.mg_nether_max and pos.y > mcl_vars.mg_nether_min) or
|
(pos.y < mcl_vars.mg_nether_max+128 and pos.y > mcl_vars.mg_nether_min) or
|
||||||
(pos.y < mcl_vars.mg_end_max and pos.y > mcl_vars.mg_end_min))
|
(pos.y < mcl_vars.mg_end_max and pos.y > mcl_vars.mg_end_min))
|
||||||
|
|
||||||
local void_deadly = false
|
local void_deadly = false
|
||||||
|
@ -15,11 +15,11 @@ function mcl_worlds.is_in_void(pos)
|
||||||
-- Overworld → Void → End → Void → Nether → Void
|
-- Overworld → Void → End → Void → Nether → Void
|
||||||
if pos.y < mcl_vars.mg_overworld_min and pos.y > mcl_vars.mg_end_max then
|
if pos.y < mcl_vars.mg_overworld_min and pos.y > mcl_vars.mg_end_max then
|
||||||
void_deadly = pos.y < mcl_vars.mg_overworld_min - deadly_tolerance
|
void_deadly = pos.y < mcl_vars.mg_overworld_min - deadly_tolerance
|
||||||
elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max then
|
elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max+128 then
|
||||||
-- The void between End and Nether. Like usual, but here, the void
|
-- The void between End and Nether. Like usual, but here, the void
|
||||||
-- *above* the Nether also has a small tolerance area, so player
|
-- *above* the Nether also has a small tolerance area, so player
|
||||||
-- can fly above the Nether without getting hurt instantly.
|
-- can fly above the Nether without getting hurt instantly.
|
||||||
void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max + deadly_tolerance)
|
void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max+128 + deadly_tolerance)
|
||||||
elseif pos.y < mcl_vars.mg_nether_min then
|
elseif pos.y < mcl_vars.mg_nether_min then
|
||||||
void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance
|
void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance
|
||||||
end
|
end
|
||||||
|
@ -33,15 +33,15 @@ end
|
||||||
-- If the Y coordinate is not located in any dimension, it will return:
|
-- If the Y coordinate is not located in any dimension, it will return:
|
||||||
-- nil, "void"
|
-- nil, "void"
|
||||||
function mcl_worlds.y_to_layer(y)
|
function mcl_worlds.y_to_layer(y)
|
||||||
if y >= mcl_vars.mg_overworld_min then
|
if y >= mcl_vars.mg_overworld_min then
|
||||||
return y - mcl_vars.mg_overworld_min, "overworld"
|
return y - mcl_vars.mg_overworld_min, "overworld"
|
||||||
elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max then
|
elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then
|
||||||
return y - mcl_vars.mg_nether_min, "nether"
|
return y - mcl_vars.mg_nether_min, "nether"
|
||||||
elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then
|
elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then
|
||||||
return y - mcl_vars.mg_end_min, "end"
|
return y - mcl_vars.mg_end_min, "end"
|
||||||
else
|
else
|
||||||
return nil, "void"
|
return nil, "void"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Takes a pos and returns the dimension it belongs to (same as above)
|
-- Takes a pos and returns the dimension it belongs to (same as above)
|
||||||
|
@ -55,38 +55,38 @@ end
|
||||||
-- MineClone 2.
|
-- MineClone 2.
|
||||||
-- mc_dimension is one of "overworld", "nether", "end" (default: "overworld").
|
-- mc_dimension is one of "overworld", "nether", "end" (default: "overworld").
|
||||||
function mcl_worlds.layer_to_y(layer, mc_dimension)
|
function mcl_worlds.layer_to_y(layer, mc_dimension)
|
||||||
if mc_dimension == "overworld" or mc_dimension == nil then
|
if mc_dimension == "overworld" or mc_dimension == nil then
|
||||||
return layer + mcl_vars.mg_overworld_min
|
return layer + mcl_vars.mg_overworld_min
|
||||||
elseif mc_dimension == "nether" then
|
elseif mc_dimension == "nether" then
|
||||||
return layer + mcl_vars.mg_nether_min
|
return layer + mcl_vars.mg_nether_min
|
||||||
elseif mc_dimension == "end" then
|
elseif mc_dimension == "end" then
|
||||||
return layer + mcl_vars.mg_end_min
|
return layer + mcl_vars.mg_end_min
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Takes a position and returns true if this position can have weather
|
-- Takes a position and returns true if this position can have weather
|
||||||
function mcl_worlds.has_weather(pos)
|
function mcl_worlds.has_weather(pos)
|
||||||
-- Weather in the Overworld and the high part of the void below
|
-- Weather in the Overworld and the high part of the void below
|
||||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Takes a position and returns true if this position can have Nether dust
|
-- Takes a position and returns true if this position can have Nether dust
|
||||||
function mcl_worlds.has_dust(pos)
|
function mcl_worlds.has_dust(pos)
|
||||||
-- Weather in the Overworld and the high part of the void below
|
-- Weather in the Overworld and the high part of the void below
|
||||||
return pos.y <= mcl_vars.mg_nether_max + 64 and pos.y >= mcl_vars.mg_nether_min - 64
|
return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Takes a position (pos) and returns true if compasses are working here
|
-- Takes a position (pos) and returns true if compasses are working here
|
||||||
function mcl_worlds.compass_works(pos)
|
function mcl_worlds.compass_works(pos)
|
||||||
-- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below
|
-- It doesn't work in Nether and the End, but it works in the Overworld and in the high part of the void below
|
||||||
local _, dim = mcl_worlds.y_to_layer(pos.y)
|
local _, dim = mcl_worlds.y_to_layer(pos.y)
|
||||||
if dim == "nether" or dim == "end" then
|
if dim == "nether" or dim == "end" then
|
||||||
return false
|
return false
|
||||||
elseif dim == "void" then
|
elseif dim == "void" then
|
||||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||||
else
|
else
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Takes a position (pos) and returns true if clocks are working here
|
-- Takes a position (pos) and returns true if clocks are working here
|
||||||
|
@ -112,10 +112,11 @@ local last_dimension = {}
|
||||||
-- * player: Player who changed the dimension
|
-- * player: Player who changed the dimension
|
||||||
-- * dimension: New dimension ("overworld", "nether", "end", "void")
|
-- * dimension: New dimension ("overworld", "nether", "end", "void")
|
||||||
function mcl_worlds.dimension_change(player, dimension)
|
function mcl_worlds.dimension_change(player, dimension)
|
||||||
|
local playername = player:get_player_name()
|
||||||
for i=1, #mcl_worlds.registered_on_dimension_change do
|
for i=1, #mcl_worlds.registered_on_dimension_change do
|
||||||
mcl_worlds.registered_on_dimension_change[i](player, dimension)
|
mcl_worlds.registered_on_dimension_change[i](player, dimension, last_dimension[playername])
|
||||||
last_dimension[player:get_player_name()] = dimension
|
|
||||||
end
|
end
|
||||||
|
last_dimension[playername] = dimension
|
||||||
end
|
end
|
||||||
|
|
||||||
----------------------- INTERNAL STUFF ----------------------
|
----------------------- INTERNAL STUFF ----------------------
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
name = mcl_worlds
|
||||||
|
author = Wuzzy
|
||||||
|
description = Utility functions for worlds and the “dimensions”.
|
||||||
|
depends = mcl_init
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# tga_encoder
|
||||||
|
A TGA Encoder written in Lua without the use of external Libraries.
|
||||||
|
|
||||||
|
May be used as a Minetest mod.
|
|
@ -0,0 +1,78 @@
|
||||||
|
tga_encoder = {}
|
||||||
|
|
||||||
|
local image = setmetatable({}, {
|
||||||
|
__call = function(self, ...)
|
||||||
|
local t = setmetatable({}, {__index = self})
|
||||||
|
t:constructor(...)
|
||||||
|
return t
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
function image:constructor(pixels)
|
||||||
|
self.data = ""
|
||||||
|
self.pixels = pixels
|
||||||
|
self.width = #pixels[1]
|
||||||
|
self.height = #pixels
|
||||||
|
|
||||||
|
self:encode()
|
||||||
|
end
|
||||||
|
|
||||||
|
function image:encode_colormap_spec()
|
||||||
|
self.data = self.data
|
||||||
|
.. string.char(0, 0) -- first entry index
|
||||||
|
.. string.char(0, 0) -- number of entries
|
||||||
|
.. string.char(0) -- bits per pixel
|
||||||
|
end
|
||||||
|
|
||||||
|
function image:encode_image_spec()
|
||||||
|
self.data = self.data
|
||||||
|
.. string.char(0, 0) -- X-origin
|
||||||
|
.. string.char(0, 0) -- Y-origin
|
||||||
|
.. string.char(self.width % 256, math.floor(self.width / 256)) -- width
|
||||||
|
.. string.char(self.height % 256, math.floor(self.height / 256)) -- height
|
||||||
|
.. string.char(24) -- pixel depth (RGB = 3 bytes = 24 bits)
|
||||||
|
.. string.char(0) -- image descriptor
|
||||||
|
end
|
||||||
|
|
||||||
|
function image:encode_header()
|
||||||
|
self.data = self.data
|
||||||
|
.. string.char(0) -- image id
|
||||||
|
.. string.char(0) -- color map type
|
||||||
|
.. string.char(2) -- image type (uncompressed true-color image = 2)
|
||||||
|
self:encode_colormap_spec() -- color map specification
|
||||||
|
self:encode_image_spec() -- image specification
|
||||||
|
end
|
||||||
|
|
||||||
|
function image:encode_data()
|
||||||
|
for _, row in ipairs(self.pixels) do
|
||||||
|
for _, pixel in ipairs(row) do
|
||||||
|
self.data = self.data
|
||||||
|
.. string.char(pixel[3], pixel[2], pixel[1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function image:encode_footer()
|
||||||
|
self.data = self.data
|
||||||
|
.. string.char(0, 0, 0, 0) -- extension area offset
|
||||||
|
.. string.char(0, 0, 0, 0) -- developer area offset
|
||||||
|
.. "TRUEVISION-XFILE"
|
||||||
|
.. "."
|
||||||
|
.. string.char(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function image:encode()
|
||||||
|
self:encode_header() -- header
|
||||||
|
-- no color map and image id data
|
||||||
|
self:encode_data() -- encode data
|
||||||
|
-- no extension or developer area
|
||||||
|
self:encode_footer() -- footer
|
||||||
|
end
|
||||||
|
|
||||||
|
function image:save(filename)
|
||||||
|
local f = assert(io.open(filename, "w"))
|
||||||
|
f:write(self.data)
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
tga_encoder.image = image
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = tga_encoder
|
||||||
|
author = Fleckenstein
|
||||||
|
description = A TGA Encoder written in Lua without the use of external Libraries.
|
|
@ -1,4 +1,10 @@
|
||||||
-- register extra flavours of a base nodedef
|
-- register extra flavours of a base nodedef
|
||||||
|
|
||||||
|
local get_connected_players = minetest.get_connected_players
|
||||||
|
local get_node = minetest.get_node
|
||||||
|
local vector_add = vector.add
|
||||||
|
local ceil = math.ceil
|
||||||
|
|
||||||
walkover = {}
|
walkover = {}
|
||||||
walkover.registered_globals = {}
|
walkover.registered_globals = {}
|
||||||
|
|
||||||
|
@ -6,30 +12,40 @@ function walkover.register_global(func)
|
||||||
table.insert(walkover.registered_globals, func)
|
table.insert(walkover.registered_globals, func)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local on_walk = {}
|
||||||
|
local registered_globals = {}
|
||||||
|
|
||||||
|
minetest.register_on_mods_loaded(function()
|
||||||
|
for name,def in pairs(minetest.registered_nodes) do
|
||||||
|
if def.on_walk_over then
|
||||||
|
on_walk[name] = def.on_walk_over
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _,func in ipairs(walkover.registered_globals) do --cache registered globals
|
||||||
|
table.insert(registered_globals, func)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
local timer = 0
|
local timer = 0
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
timer = timer + dtime;
|
timer = timer + dtime;
|
||||||
if timer >= 0.3 then
|
if timer >= 0.3 then
|
||||||
for _,player in pairs(minetest.get_connected_players()) do
|
for _,player in pairs(get_connected_players()) do
|
||||||
local pp = player:get_pos()
|
local pp = player:get_pos()
|
||||||
pp.y = math.ceil(pp.y)
|
pp.y = ceil(pp.y)
|
||||||
local loc = vector.add(pp, {x=0,y=-1,z=0})
|
local loc = vector_add(pp, {x=0,y=-1,z=0})
|
||||||
if loc ~= nil then
|
if loc ~= nil then
|
||||||
|
local nodeiamon = get_node(loc)
|
||||||
local nodeiamon = minetest.get_node(loc)
|
if nodeiamon ~= nil then
|
||||||
|
if on_walk[nodeiamon.name] then
|
||||||
if nodeiamon ~= nil then
|
on_walk[nodeiamon.name](loc, nodeiamon, player)
|
||||||
local def = minetest.registered_nodes[nodeiamon.name]
|
end
|
||||||
if def ~= nil and def.on_walk_over ~= nil then
|
for i = 1, #registered_globals do
|
||||||
def.on_walk_over(loc, nodeiamon, player)
|
registered_globals[i](loc, nodeiamon, player)
|
||||||
end
|
end
|
||||||
for _, func in ipairs(walkover.registered_globals) do
|
end
|
||||||
func(loc, nodeiamon, player)
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
timer = 0
|
timer = 0
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
name = walkover
|
||||||
|
author = lordfingle
|
||||||
|
description = Some mode developers have shown an interest in having an `on_walk_over` event. This is useful for pressure-plates and the like.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
mcl_core
|
|
|
@ -1,6 +1,8 @@
|
||||||
--Dripping Water Mod
|
--Dripping Water Mod
|
||||||
--by kddekadenz
|
--by kddekadenz
|
||||||
|
|
||||||
|
local math = math
|
||||||
|
|
||||||
-- License of code, textures & sounds: CC0
|
-- License of code, textures & sounds: CC0
|
||||||
|
|
||||||
--Drop entities
|
--Drop entities
|
||||||
|
@ -20,26 +22,21 @@ minetest.register_entity("drippingwater:drop_water", {
|
||||||
spritediv = {x=1, y=1},
|
spritediv = {x=1, y=1},
|
||||||
initial_sprite_basepos = {x=0, y=0},
|
initial_sprite_basepos = {x=0, y=0},
|
||||||
static_save = false,
|
static_save = false,
|
||||||
|
|
||||||
on_activate = function(self, staticdata)
|
on_activate = function(self, staticdata)
|
||||||
self.object:set_sprite({x=0,y=0}, 1, 1, true)
|
self.object:set_sprite({x=0,y=0}, 1, 1, true)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_step = function(self, dtime)
|
on_step = function(self, dtime)
|
||||||
local k = math.random(1,222)
|
local k = math.random(1,222)
|
||||||
local ownpos = self.object:get_pos()
|
local ownpos = self.object:get_pos()
|
||||||
|
if k==1 then
|
||||||
if k==1 then
|
self.object:set_acceleration({x=0, y=-5, z=0})
|
||||||
self.object:set_acceleration({x=0, y=-5, z=0})
|
end
|
||||||
end
|
if minetest.get_node({x=ownpos.x, y=ownpos.y +0.5, z=ownpos.z}).name == "air" then
|
||||||
|
self.object:set_acceleration({x=0, y=-5, z=0})
|
||||||
if minetest.get_node({x=ownpos.x, y=ownpos.y +0.5, z=ownpos.z}).name == "air" then
|
end
|
||||||
self.object:set_acceleration({x=0, y=-5, z=0})
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_node({x=ownpos.x, y=ownpos.y -0.5, z=ownpos.z}).name ~= "air" then
|
if minetest.get_node({x=ownpos.x, y=ownpos.y -0.5, z=ownpos.z}).name ~= "air" then
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
minetest.sound_play({name="drippingwater_drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
|
minetest.sound_play({name="drippingwater_drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
@ -61,27 +58,21 @@ minetest.register_entity("drippingwater:drop_lava", {
|
||||||
spritediv = {x=1, y=1},
|
spritediv = {x=1, y=1},
|
||||||
initial_sprite_basepos = {x=0, y=0},
|
initial_sprite_basepos = {x=0, y=0},
|
||||||
static_save = false,
|
static_save = false,
|
||||||
|
|
||||||
on_activate = function(self, staticdata)
|
on_activate = function(self, staticdata)
|
||||||
self.object:set_sprite({x=0,y=0}, 1, 0, true)
|
self.object:set_sprite({x=0,y=0}, 1, 0, true)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_step = function(self, dtime)
|
on_step = function(self, dtime)
|
||||||
local k = math.random(1,222)
|
local k = math.random(1,222)
|
||||||
local ownpos = self.object:get_pos()
|
local ownpos = self.object:get_pos()
|
||||||
|
if k == 1 then
|
||||||
if k==1 then
|
self.object:set_acceleration({x=0, y=-5, z=0})
|
||||||
self.object:set_acceleration({x=0, y=-5, z=0})
|
end
|
||||||
end
|
if minetest.get_node({x=ownpos.x, y=ownpos.y +0.5, z=ownpos.z}).name == "air" then
|
||||||
|
self.object:set_acceleration({x=0, y=-5, z=0})
|
||||||
if minetest.get_node({x=ownpos.x, y=ownpos.y +0.5, z=ownpos.z}).name == "air" then
|
end
|
||||||
self.object:set_acceleration({x=0, y=-5, z=0})
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
if minetest.get_node({x=ownpos.x, y=ownpos.y -0.5, z=ownpos.z}).name ~= "air" then
|
if minetest.get_node({x=ownpos.x, y=ownpos.y -0.5, z=ownpos.z}).name ~= "air" then
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
minetest.sound_play({name="drippingwater_lavadrip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
|
minetest.sound_play({name="drippingwater_lavadrip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
@ -90,36 +81,34 @@ minetest.register_entity("drippingwater:drop_lava", {
|
||||||
|
|
||||||
--Create drop
|
--Create drop
|
||||||
|
|
||||||
minetest.register_abm(
|
minetest.register_abm({
|
||||||
{
|
|
||||||
label = "Create water drops",
|
label = "Create water drops",
|
||||||
nodenames = {"group:opaque", "group:leaves"},
|
nodenames = {"group:opaque", "group:leaves"},
|
||||||
neighbors = {"group:water"},
|
neighbors = {"group:water"},
|
||||||
interval = 2,
|
interval = 2,
|
||||||
chance = 22,
|
chance = 22,
|
||||||
action = function(pos)
|
action = function(pos)
|
||||||
if minetest.get_item_group(minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name, "water") ~= 0 and
|
if minetest.get_item_group(minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name, "water") ~= 0
|
||||||
minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
|
and minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
|
||||||
local i = math.random(-45,45) / 100
|
local i = math.random(-45,45) / 100
|
||||||
minetest.add_entity({x=pos.x + i, y=pos.y - 0.501, z=pos.z + i}, "drippingwater:drop_water")
|
minetest.add_entity({x=pos.x + i, y=pos.y - 0.501, z=pos.z + i}, "drippingwater:drop_water")
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
--Create lava drop
|
--Create lava drop
|
||||||
|
|
||||||
minetest.register_abm(
|
minetest.register_abm({
|
||||||
{
|
|
||||||
label = "Create lava drops",
|
label = "Create lava drops",
|
||||||
nodenames = {"group:opaque"},
|
nodenames = {"group:opaque"},
|
||||||
neighbors = {"group:lava"},
|
neighbors = {"group:lava"},
|
||||||
interval = 2,
|
interval = 2,
|
||||||
chance = 22,
|
chance = 22,
|
||||||
action = function(pos)
|
action = function(pos)
|
||||||
if minetest.get_item_group(minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name, "lava") ~= 0 and
|
if minetest.get_item_group(minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name, "lava") ~= 0
|
||||||
minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
|
and minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
|
||||||
local i = math.random(-45,45) / 100
|
local i = math.random(-45,45) / 100
|
||||||
minetest.add_entity({x=pos.x + i, y=pos.y - 0.501, z=pos.z + i}, "drippingwater:drop_lava")
|
minetest.add_entity({x=pos.x + i, y=pos.y - 0.501, z=pos.z + i}, "drippingwater:drop_lava")
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
|
@ -0,0 +1,4 @@
|
||||||
|
name = drippingwater
|
||||||
|
author = kddekadenz
|
||||||
|
description = Drops are generated rarely under solid nodes
|
||||||
|
depends = mcl_core
|
|
@ -20,4 +20,4 @@ Authors include:
|
||||||
* Various Minetest / Minetest Game developers and contributors (2012-2016)
|
* Various Minetest / Minetest Game developers and contributors (2012-2016)
|
||||||
* maikerumine (2017)
|
* maikerumine (2017)
|
||||||
* Wuzzy (2017)
|
* Wuzzy (2017)
|
||||||
|
* Fleckenstein (2020-2021)
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
mcl_player
|
|
||||||
mcl_core?
|
|
||||||
doc_identifier?
|
|
|
@ -1 +0,0 @@
|
||||||
Adds drivable boats.
|
|
|
@ -1,6 +1,6 @@
|
||||||
local S = minetest.get_translator("mcl_boats")
|
local S = minetest.get_translator("mcl_boats")
|
||||||
|
|
||||||
local boat_visual_size = {x = 3, y = 3, z = 3}
|
local boat_visual_size = {x = 1, y = 1, z = 1}
|
||||||
local paddling_speed = 22
|
local paddling_speed = 22
|
||||||
local boat_y_offset = 0.35
|
local boat_y_offset = 0.35
|
||||||
local boat_y_offset_ground = boat_y_offset + 0.6
|
local boat_y_offset_ground = boat_y_offset + 0.6
|
||||||
|
@ -12,9 +12,7 @@ local function is_group(pos, group)
|
||||||
return minetest.get_item_group(nn, group) ~= 0
|
return minetest.get_item_group(nn, group) ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function is_water(pos)
|
local is_water = flowlib.is_water
|
||||||
return is_group(pos, "water")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function is_ice(pos)
|
local function is_ice(pos)
|
||||||
return is_group(pos, "ice")
|
return is_group(pos, "ice")
|
||||||
|
@ -163,6 +161,8 @@ function boat.get_staticdata(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
function boat.on_death(self, killer)
|
function boat.on_death(self, killer)
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
|
|
||||||
if killer and killer:is_player() and minetest.is_creative_enabled(killer:get_player_name()) then
|
if killer and killer:is_player() and minetest.is_creative_enabled(killer:get_player_name()) then
|
||||||
local inv = killer:get_inventory()
|
local inv = killer:get_inventory()
|
||||||
if not inv:contains_item("main", self._itemstring) then
|
if not inv:contains_item("main", self._itemstring) then
|
||||||
|
@ -188,6 +188,8 @@ function boat.on_punch(self, puncher, time_from_last_punch, tool_capabilities, d
|
||||||
end
|
end
|
||||||
|
|
||||||
function boat.on_step(self, dtime, moveresult)
|
function boat.on_step(self, dtime, moveresult)
|
||||||
|
mcl_burning.tick(self.object, dtime, self)
|
||||||
|
|
||||||
self._v = get_v(self.object:get_velocity()) * get_sign(self._v)
|
self._v = get_v(self.object:get_velocity()) * get_sign(self._v)
|
||||||
local v_factor = 1
|
local v_factor = 1
|
||||||
local v_slowdown = 0.02
|
local v_slowdown = 0.02
|
||||||
|
@ -223,7 +225,7 @@ function boat.on_step(self, dtime, moveresult)
|
||||||
self._regen_timer = regen_timer
|
self._regen_timer = regen_timer
|
||||||
|
|
||||||
if moveresult and moveresult.collides then
|
if moveresult and moveresult.collides then
|
||||||
for _, collision in ipairs(moveresult.collisions) do
|
for _, collision in pairs(moveresult.collisions) do
|
||||||
local pos = collision.node_pos
|
local pos = collision.node_pos
|
||||||
if collision.type == "node" and minetest.get_item_group(minetest.get_node(pos).name, "dig_by_boat") > 0 then
|
if collision.type == "node" and minetest.get_item_group(minetest.get_node(pos).name, "dig_by_boat") > 0 then
|
||||||
minetest.dig_node(pos)
|
minetest.dig_node(pos)
|
||||||
|
@ -243,7 +245,7 @@ function boat.on_step(self, dtime, moveresult)
|
||||||
else
|
else
|
||||||
local ctrl = self._passenger:get_player_control()
|
local ctrl = self._passenger:get_player_control()
|
||||||
if ctrl and ctrl.sneak then
|
if ctrl and ctrl.sneak then
|
||||||
detach_player(self._passenger, true)
|
detach_object(self._passenger, true)
|
||||||
self._passenger = nil
|
self._passenger = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -305,7 +307,7 @@ function boat.on_step(self, dtime, moveresult)
|
||||||
self._animation = 0
|
self._animation = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, obj in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 1.3)) do
|
for _, obj in pairs(minetest.get_objects_inside_radius(self.object:get_pos(), 1.3)) do
|
||||||
local entity = obj:get_luaentity()
|
local entity = obj:get_luaentity()
|
||||||
if entity and entity._cmi_is_mob then
|
if entity and entity._cmi_is_mob then
|
||||||
attach_object(self, obj)
|
attach_object(self, obj)
|
||||||
|
@ -326,10 +328,10 @@ function boat.on_step(self, dtime, moveresult)
|
||||||
|
|
||||||
p.y = p.y - boat_y_offset
|
p.y = p.y - boat_y_offset
|
||||||
local new_velo
|
local new_velo
|
||||||
local new_acce = {x = 0, y = 0, z = 0}
|
local new_acce
|
||||||
if not is_water(p) and not on_ice then
|
if not is_water(p) and not on_ice then
|
||||||
-- Not on water or inside water: Free fall
|
-- Not on water or inside water: Free fall
|
||||||
local nodedef = minetest.registered_nodes[minetest.get_node(p).name]
|
--local nodedef = minetest.registered_nodes[minetest.get_node(p).name]
|
||||||
new_acce = {x = 0, y = -9.8, z = 0}
|
new_acce = {x = 0, y = -9.8, z = 0}
|
||||||
new_velo = get_velocity(self._v, self.object:get_yaw(),
|
new_velo = get_velocity(self._v, self.object:get_yaw(),
|
||||||
self.object:get_velocity().y)
|
self.object:get_velocity().y)
|
||||||
|
@ -392,7 +394,7 @@ for b=1, #boat_ids do
|
||||||
if b == 1 then
|
if b == 1 then
|
||||||
help = true
|
help = true
|
||||||
longdesc = S("Boats are used to travel on the surface of water.")
|
longdesc = S("Boats are used to travel on the surface of water.")
|
||||||
usagehelp = S("Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.")
|
usagehelp = S("Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.")
|
||||||
helpname = S("Boat")
|
helpname = S("Boat")
|
||||||
end
|
end
|
||||||
tt_help = S("Water vehicle")
|
tt_help = S("Water vehicle")
|
||||||
|
|
|
@ -6,6 +6,7 @@ Boats are used to travel on the surface of water.=Boote werden benutzt, um sich
|
||||||
Dark Oak Boat=Schwarzeichenboot
|
Dark Oak Boat=Schwarzeichenboot
|
||||||
Jungle Boat=Dschungelboot
|
Jungle Boat=Dschungelboot
|
||||||
Oak Boat=Eichenboot
|
Oak Boat=Eichenboot
|
||||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.=Rechtsklicken Sie auf eine Wasserquelle, um das Boot zu platzieren. Rechtsklicken Sie auf das Boot, um es zu betreten. Mit [Links] und [Rechts] lenken, mit [Vorwärts] und [Rückwärts] Geschwindigkeit regeln oder rückwärts fahren. Rechtsklicken Sie erneut auf das Boot, um es zu verlassen, schlagen Sie das Boot, um es als Gegenstand fallen zu lassen.
|
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=Rechtsklicken Sie auf eine Wasserquelle, um das Boot zu platzieren. Rechtsklicken Sie auf das Boot, um es zu betreten. Mit [Links] und [Rechts] lenken, mit [Vorwärts] und [Rückwärts] Geschwindigkeit regeln oder rückwärts fahren. Nutzen sie [Schleichen], um das Boot zu verlassen, schlagen Sie das Boot, um es als Gegenstand fallen zu lassen.
|
||||||
Spruce Boat=Fichtenboot
|
Spruce Boat=Fichtenboot
|
||||||
Water vehicle=Wasserfahrzeug
|
Water vehicle=Wasserfahrzeug
|
||||||
|
Sneak to dismount=Zum Aussteigen schleichen
|
||||||
|
|
|
@ -6,6 +6,7 @@ Boats are used to travel on the surface of water.=
|
||||||
Dark Oak Boat=
|
Dark Oak Boat=
|
||||||
Jungle Boat=
|
Jungle Boat=
|
||||||
Oak Boat=
|
Oak Boat=
|
||||||
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.=
|
Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Use [Sneak] to leave the boat, punch the boat to make it drop as an item.=
|
||||||
Spruce Boat=
|
Spruce Boat=
|
||||||
Water vehicle=
|
Water vehicle=
|
||||||
|
Sneak to dismount=
|
||||||
|
|
|
@ -1 +1,7 @@
|
||||||
name = mcl_boats
|
name = mcl_boats
|
||||||
|
author = PilzAdam
|
||||||
|
description = Adds drivable boats.
|
||||||
|
depends = mcl_player, flowlib
|
||||||
|
optional_depends = mcl_core, doc_identifier
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,180 +1,86 @@
|
||||||
local S = minetest.get_translator("mcl_burning")
|
function mcl_burning.get_storage(obj)
|
||||||
|
return obj:is_player() and mcl_burning.storage[obj] or obj:get_luaentity()
|
||||||
function mcl_burning.get_default(datatype)
|
|
||||||
local default_table = {string = "", float = 0.0, int = 0, bool = false}
|
|
||||||
return default_table[datatype]
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_burning.get(obj, datatype, name)
|
|
||||||
local key
|
|
||||||
if obj:is_player() then
|
|
||||||
local meta = obj:get_meta()
|
|
||||||
return meta["get_" .. datatype](meta, "mcl_burning:" .. name)
|
|
||||||
else
|
|
||||||
local luaentity = obj:get_luaentity()
|
|
||||||
return luaentity and luaentity["mcl_burning_" .. name] or mcl_burning.get_default(datatype)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_burning.set(obj, datatype, name, value)
|
|
||||||
if obj:is_player() then
|
|
||||||
local meta = obj:get_meta()
|
|
||||||
meta["set_" .. datatype](meta, "mcl_burning:" .. name, value or mcl_burning.get_default(datatype))
|
|
||||||
else
|
|
||||||
local luaentity = obj:get_luaentity()
|
|
||||||
if mcl_burning.get_default(datatype) == value then
|
|
||||||
value = nil
|
|
||||||
end
|
|
||||||
luaentity["mcl_burning_" .. name] = value
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.is_burning(obj)
|
function mcl_burning.is_burning(obj)
|
||||||
return mcl_burning.get(obj, "float", "burn_time") > 0
|
return mcl_burning.get_storage(obj).burn_time
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.is_affected_by_rain(obj)
|
function mcl_burning.is_affected_by_rain(obj)
|
||||||
return mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos())
|
return mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos())
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.get_collisionbox(obj, smaller)
|
function mcl_burning.get_collisionbox(obj, smaller, storage)
|
||||||
local box = obj:get_properties().collisionbox
|
local cache = storage.collisionbox_cache
|
||||||
local minp, maxp = vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6])
|
if cache then
|
||||||
if smaller then
|
local box = cache[smaller and 2 or 1]
|
||||||
|
return box[1], box[2]
|
||||||
|
else
|
||||||
|
local box = obj:get_properties().collisionbox
|
||||||
|
local minp, maxp = vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6])
|
||||||
local s_vec = vector.new(0.1, 0.1, 0.1)
|
local s_vec = vector.new(0.1, 0.1, 0.1)
|
||||||
minp = vector.add(minp, s_vec)
|
local s_minp = vector.add(minp, s_vec)
|
||||||
maxp = vector.subtract(maxp, s_vec)
|
local s_maxp = vector.subtract(maxp, s_vec)
|
||||||
|
storage.collisionbox_cache = {{minp, maxp}, {s_minp, s_maxp}}
|
||||||
|
return minp, maxp
|
||||||
end
|
end
|
||||||
return minp, maxp
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.get_touching_nodes(obj, nodenames)
|
function mcl_burning.get_touching_nodes(obj, nodenames, storage)
|
||||||
local pos = obj:get_pos()
|
local pos = obj:get_pos()
|
||||||
local box = obj:get_properties().collisionbox
|
local minp, maxp = mcl_burning.get_collisionbox(obj, true, storage)
|
||||||
local minp, maxp = mcl_burning.get_collisionbox(obj, true)
|
|
||||||
local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames)
|
||||||
return nodes
|
return nodes
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.get_highest_group_value(obj, groupname)
|
function mcl_burning.set_on_fire(obj, burn_time)
|
||||||
local nodes = mcl_burning.get_touching_nodes(obj, "group:" .. groupname, true)
|
if obj:get_hp() < 0 then
|
||||||
local highest_group_value = 0
|
|
||||||
|
|
||||||
for _, pos in pairs(nodes) do
|
|
||||||
local node = minetest.get_node(pos)
|
|
||||||
local group_value = minetest.get_item_group(node.name, groupname)
|
|
||||||
if group_value > highest_group_value then
|
|
||||||
highest_group_value = group_value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return highest_group_value
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_burning.damage(obj)
|
|
||||||
local luaentity = obj:get_luaentity()
|
|
||||||
local health
|
|
||||||
|
|
||||||
if luaentity then
|
|
||||||
health = luaentity.health
|
|
||||||
end
|
|
||||||
|
|
||||||
local hp = health or obj:get_hp()
|
|
||||||
|
|
||||||
if hp <= 0 then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local do_damage = true
|
local storage = mcl_burning.get_storage(obj)
|
||||||
|
|
||||||
if obj:is_player() then
|
|
||||||
if mcl_potions.player_has_effect(obj, "fire_proof") then
|
|
||||||
do_damage = false
|
|
||||||
else
|
|
||||||
local name = obj:get_player_name()
|
|
||||||
armor.last_damage_types[name] = "fire"
|
|
||||||
local deathmsg = S("@1 burned to death.", name)
|
|
||||||
local reason = mcl_burning.get(obj, "string", "reason")
|
|
||||||
if reason ~= "" then
|
|
||||||
deathmsg = S("@1 was burned by @2.", name, reason)
|
|
||||||
end
|
|
||||||
mcl_death_messages.player_damage(obj, deathmsg)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if luaentity.fire_damage_resistant then
|
|
||||||
do_damage = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if do_damage then
|
|
||||||
local new_hp = hp - 1
|
|
||||||
if health then
|
|
||||||
luaentity.health = new_hp
|
|
||||||
else
|
|
||||||
obj:set_hp(new_hp)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_burning.set_on_fire(obj, burn_time, reason)
|
|
||||||
local luaentity = obj:get_luaentity()
|
local luaentity = obj:get_luaentity()
|
||||||
if luaentity and luaentity.fire_resistant then
|
if luaentity and luaentity.fire_resistant then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local old_burn_time = mcl_burning.get(obj, "float", "burn_time")
|
if obj:is_player() and minetest.is_creative_enabled(obj:get_player_name()) then
|
||||||
local max_fire_prot_lvl = 0
|
burn_time = 0
|
||||||
|
else
|
||||||
|
local max_fire_prot_lvl = 0
|
||||||
|
local inv = mcl_util.get_inventory(obj)
|
||||||
|
local armor_list = inv and inv:get_list("armor")
|
||||||
|
|
||||||
if obj:is_player() then
|
if armor_list then
|
||||||
if minetest.is_creative_enabled(obj:get_player_name()) then
|
for _, stack in pairs(armor_list) do
|
||||||
burn_time = burn_time / 100
|
local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
|
||||||
end
|
if fire_prot_lvl > max_fire_prot_lvl then
|
||||||
|
max_fire_prot_lvl = fire_prot_lvl
|
||||||
local inv = obj:get_inventory()
|
end
|
||||||
|
|
||||||
for i = 2, 5 do
|
|
||||||
local stack = inv:get_stack("armor", i)
|
|
||||||
|
|
||||||
local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
|
|
||||||
max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if max_fire_prot_lvl > 0 then
|
|
||||||
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
|
||||||
end
|
|
||||||
|
|
||||||
if old_burn_time <= burn_time then
|
|
||||||
local sound_id = mcl_burning.get(obj, "int", "sound_id")
|
|
||||||
if sound_id == 0 then
|
|
||||||
sound_id = minetest.sound_play("fire_fire", {
|
|
||||||
object = obj,
|
|
||||||
gain = 0.18,
|
|
||||||
max_hear_distance = 16,
|
|
||||||
loop = true,
|
|
||||||
}) + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local hud_id
|
|
||||||
if obj:is_player() then
|
|
||||||
hud_id = mcl_burning.get(obj, "int", "hud_id")
|
|
||||||
if hud_id == 0 then
|
|
||||||
hud_id = obj:hud_add({
|
|
||||||
hud_elem_type = "image",
|
|
||||||
position = {x = 0.5, y = 0.5},
|
|
||||||
scale = {x = -100, y = -100},
|
|
||||||
text = "fire_basic_flame.png",
|
|
||||||
z_index = 1000,
|
|
||||||
}) + 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
mcl_burning.set(obj, "float", "burn_time", burn_time)
|
|
||||||
mcl_burning.set(obj, "string", "reason", reason)
|
if max_fire_prot_lvl > 0 then
|
||||||
mcl_burning.set(obj, "int", "hud_id", hud_id)
|
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
||||||
mcl_burning.set(obj, "int", "sound_id", sound_id)
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not storage.burn_time or burn_time >= storage.burn_time then
|
||||||
|
if obj:is_player() and not storage.fire_hud_id then
|
||||||
|
storage.fire_hud_id = obj:hud_add({
|
||||||
|
hud_elem_type = "image",
|
||||||
|
position = {x = 0.5, y = 0.5},
|
||||||
|
scale = {x = -100, y = -100},
|
||||||
|
text = "mcl_burning_entity_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. 1,
|
||||||
|
z_index = 1000,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
storage.burn_time = burn_time
|
||||||
|
storage.fire_damage_timer = 0
|
||||||
|
|
||||||
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||||
local minp, maxp = mcl_burning.get_collisionbox(obj)
|
local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage)
|
||||||
local obj_size = obj:get_properties().visual_size
|
local obj_size = obj:get_properties().visual_size
|
||||||
|
|
||||||
local vertical_grow_factor = 1.2
|
local vertical_grow_factor = 1.2
|
||||||
|
@ -188,111 +94,53 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
|
||||||
|
|
||||||
fire_entity:set_properties({visual_size = size})
|
fire_entity:set_properties({visual_size = size})
|
||||||
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0})
|
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0})
|
||||||
mcl_burning.update_animation_frame(obj, fire_entity, 0)
|
local fire_luaentity = fire_entity:get_luaentity()
|
||||||
|
fire_luaentity:update_frame(obj, storage)
|
||||||
|
|
||||||
|
for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do
|
||||||
|
local other_luaentity = other:get_luaentity()
|
||||||
|
if other_luaentity and other_luaentity.name == "mcl_burning:fire" and other_luaentity ~= fire_luaentity then
|
||||||
|
other:remove()
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.extinguish(obj)
|
function mcl_burning.extinguish(obj)
|
||||||
if mcl_burning.is_burning(obj) then
|
if mcl_burning.is_burning(obj) then
|
||||||
local sound_id = mcl_burning.get(obj, "int", "sound_id") - 1
|
local storage = mcl_burning.get_storage(obj)
|
||||||
minetest.sound_stop(sound_id)
|
|
||||||
|
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1
|
if storage.fire_hud_id then
|
||||||
obj:hud_remove(hud_id)
|
obj:hud_remove(storage.fire_hud_id)
|
||||||
end
|
end
|
||||||
|
mcl_burning.storage[obj] = {}
|
||||||
mcl_burning.set(obj, "string", "reason")
|
else
|
||||||
mcl_burning.set(obj, "float", "burn_time")
|
storage.burn_time = nil
|
||||||
mcl_burning.set(obj, "float", "damage_timer")
|
storage.fire_damage_timer = nil
|
||||||
mcl_burning.set(obj, "int", "hud_id")
|
|
||||||
mcl_burning.set(obj, "int", "sound_id")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_burning.catch_fire_tick(obj, dtime)
|
|
||||||
if mcl_burning.is_affected_by_rain(obj) or #mcl_burning.get_touching_nodes(obj, "group:puts_out_fire") > 0 then
|
|
||||||
mcl_burning.extinguish(obj)
|
|
||||||
else
|
|
||||||
local set_on_fire_value = mcl_burning.get_highest_group_value(obj, "set_on_fire")
|
|
||||||
|
|
||||||
if set_on_fire_value > 0 then
|
|
||||||
mcl_burning.set_on_fire(obj, set_on_fire_value)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_burning.tick(obj, dtime)
|
function mcl_burning.tick(obj, dtime, storage)
|
||||||
local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime
|
if storage.burn_time then
|
||||||
|
storage.burn_time = storage.burn_time - dtime
|
||||||
|
|
||||||
if burn_time <= 0 then
|
if storage.burn_time <= 0 or mcl_burning.is_affected_by_rain(obj) or #mcl_burning.get_touching_nodes(obj, "group:puts_out_fire", storage) > 0 then
|
||||||
mcl_burning.extinguish(obj)
|
mcl_burning.extinguish(obj)
|
||||||
else
|
return true
|
||||||
mcl_burning.set(obj, "float", "burn_time", burn_time)
|
else
|
||||||
|
storage.fire_damage_timer = storage.fire_damage_timer + dtime
|
||||||
|
|
||||||
local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime
|
if storage.fire_damage_timer >= 1 then
|
||||||
|
storage.fire_damage_timer = 0
|
||||||
|
|
||||||
if damage_timer >= 1 then
|
local luaentity = obj:get_luaentity()
|
||||||
damage_timer = 0
|
|
||||||
mcl_burning.damage(obj)
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_burning.set(obj, "float", "damage_timer", damage_timer)
|
if not luaentity or not luaentity.fire_damage_resistant then
|
||||||
end
|
mcl_util.deal_damage(obj, 1, {type = "on_fire"})
|
||||||
|
end
|
||||||
mcl_burning.catch_fire_tick(obj, dtime)
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_burning.update_animation_frame(obj, fire_entity, animation_frame)
|
|
||||||
local fire_texture = "mcl_burning_entity_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. animation_frame
|
|
||||||
local fire_HUD_texture = "mcl_burning_hud_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. animation_frame
|
|
||||||
fire_entity:set_properties({textures = {"blank.png", "blank.png", fire_texture, fire_texture, fire_texture, fire_texture}})
|
|
||||||
if obj:is_player() then
|
|
||||||
local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1
|
|
||||||
obj:hud_change(hud_id, "text", fire_HUD_texture)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function mcl_burning.fire_entity_step(self, dtime)
|
|
||||||
if self.removed then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local obj = self.object
|
|
||||||
local parent = obj:get_attach()
|
|
||||||
local do_remove
|
|
||||||
|
|
||||||
self.doing_step = true
|
|
||||||
|
|
||||||
if not parent or not mcl_burning.is_burning(parent) then
|
|
||||||
do_remove = true
|
|
||||||
else
|
|
||||||
for _, other in ipairs(minetest.get_objects_inside_radius(obj:get_pos(), 0)) do
|
|
||||||
local luaentity = obj:get_luaentity()
|
|
||||||
if luaentity and luaentity.name == "mcl_burning:fire" and not luaentity.doing_step and not luaentity.removed then
|
|
||||||
do_remove = true
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
self.doing_step = false
|
|
||||||
|
|
||||||
if do_remove then
|
|
||||||
self.removed = true
|
|
||||||
obj:remove()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local animation_timer = self.animation_timer + dtime
|
|
||||||
if animation_timer >= 0.015 then
|
|
||||||
animation_timer = 0
|
|
||||||
local animation_frame = self.animation_frame + 1
|
|
||||||
if animation_frame > mcl_burning.animation_frames - 1 then
|
|
||||||
animation_frame = 0
|
|
||||||
end
|
|
||||||
mcl_burning.update_animation_frame(parent, obj, animation_frame)
|
|
||||||
self.animation_frame = animation_frame
|
|
||||||
end
|
|
||||||
self.animation_timer = animation_timer
|
|
||||||
end
|
|
|
@ -1,12 +1,64 @@
|
||||||
local S = minetest.get_translator("mcl_burning")
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
local modpath = minetest.get_modpath("mcl_burning")
|
|
||||||
|
|
||||||
mcl_burning = {
|
mcl_burning = {
|
||||||
|
storage = {},
|
||||||
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
|
||||||
}
|
}
|
||||||
|
|
||||||
dofile(modpath .. "/api.lua")
|
dofile(modpath .. "/api.lua")
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for _, player in pairs(minetest.get_connected_players()) do
|
||||||
|
local storage = mcl_burning.storage[player]
|
||||||
|
if not mcl_burning.tick(player, dtime, storage) and not mcl_burning.is_affected_by_rain(player) then
|
||||||
|
local nodes = mcl_burning.get_touching_nodes(player, {"group:puts_out_fire", "group:set_on_fire"}, storage)
|
||||||
|
local burn_time = 0
|
||||||
|
|
||||||
|
for _, pos in pairs(nodes) do
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if minetest.get_item_group(node.name, "puts_out_fire") > 0 then
|
||||||
|
burn_time = 0
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local value = minetest.get_item_group(node.name, "set_on_fire")
|
||||||
|
if value > burn_time then
|
||||||
|
burn_time = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if burn_time > 0 then
|
||||||
|
mcl_burning.set_on_fire(player, burn_time)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_respawnplayer(function(player)
|
||||||
|
mcl_burning.extinguish(player)
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_joinplayer(function(player)
|
||||||
|
local storage
|
||||||
|
|
||||||
|
local burn_data = player:get_meta():get_string("mcl_burning:data")
|
||||||
|
if burn_data == "" then
|
||||||
|
storage = {}
|
||||||
|
else
|
||||||
|
storage = minetest.deserialize(burn_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_burning.storage[player] = storage
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
local storage = mcl_burning.storage[player]
|
||||||
|
storage.fire_hud_id = nil
|
||||||
|
player:get_meta():set_string("mcl_burning:data", minetest.serialize(storage))
|
||||||
|
mcl_burning.storage[player] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
minetest.register_entity("mcl_burning:fire", {
|
minetest.register_entity("mcl_burning:fire", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
physical = false,
|
physical = false,
|
||||||
|
@ -14,23 +66,48 @@ minetest.register_entity("mcl_burning:fire", {
|
||||||
visual = "cube",
|
visual = "cube",
|
||||||
pointable = false,
|
pointable = false,
|
||||||
glow = -1,
|
glow = -1,
|
||||||
|
backface_culling = false,
|
||||||
},
|
},
|
||||||
|
|
||||||
animation_frame = 0,
|
animation_frame = 0,
|
||||||
animation_timer = 0,
|
animation_timer = 0,
|
||||||
on_step = mcl_burning.fire_entity_step,
|
on_step = function(self, dtime)
|
||||||
|
local parent, storage = self:sanity_check()
|
||||||
|
|
||||||
|
if parent then
|
||||||
|
self.animation_timer = self.animation_timer + dtime
|
||||||
|
if self.animation_timer >= 0.1 then
|
||||||
|
self.animation_timer = 0
|
||||||
|
self.animation_frame = self.animation_frame + 1
|
||||||
|
if self.animation_frame > mcl_burning.animation_frames - 1 then
|
||||||
|
self.animation_frame = 0
|
||||||
|
end
|
||||||
|
self:update_frame(parent, storage)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
sanity_check = function(self)
|
||||||
|
local parent = self.object:get_attach()
|
||||||
|
|
||||||
|
if not parent then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local storage = mcl_burning.get_storage(parent)
|
||||||
|
|
||||||
|
if not storage or not storage.burn_time then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
return parent, storage
|
||||||
|
end,
|
||||||
|
update_frame = function(self, parent, storage)
|
||||||
|
local frame_overlay = "^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. self.animation_frame
|
||||||
|
local fire_texture = "mcl_burning_entity_flame_animated.png" .. frame_overlay
|
||||||
|
self.object:set_properties({textures = {"blank.png", "blank.png", fire_texture, fire_texture, fire_texture, fire_texture}})
|
||||||
|
if parent:is_player() then
|
||||||
|
parent:hud_change(storage.fire_hud_id, "text", "mcl_burning_hud_flame_animated.png" .. frame_overlay)
|
||||||
|
end
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
|
||||||
mcl_burning.tick(player, dtime)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
minetest.register_on_respawnplayer(function(player)
|
|
||||||
mcl_burning.extinguish(player)
|
|
||||||
end)
|
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
|
||||||
mcl_burning.set(player, "int", "hud_id")
|
|
||||||
end)
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Falling node entities, Minecraft-style
|
|
|
@ -1,7 +1,4 @@
|
||||||
local S = minetest.get_translator("mcl_falling_nodes")
|
local function get_falling_depth(self)
|
||||||
local dmes = minetest.get_modpath("mcl_death_messages") ~= nil
|
|
||||||
|
|
||||||
local get_falling_depth = function(self)
|
|
||||||
if not self._startpos then
|
if not self._startpos then
|
||||||
-- Fallback
|
-- Fallback
|
||||||
self._startpos = self.object:get_pos()
|
self._startpos = self.object:get_pos()
|
||||||
|
@ -9,56 +6,42 @@ local get_falling_depth = function(self)
|
||||||
return self._startpos.y - vector.round(self.object:get_pos()).y
|
return self._startpos.y - vector.round(self.object:get_pos()).y
|
||||||
end
|
end
|
||||||
|
|
||||||
local deal_falling_damage = function(self, dtime)
|
local function deal_falling_damage(self, dtime)
|
||||||
if minetest.get_item_group(self.node.name, "falling_node_damage") == 0 then
|
if minetest.get_item_group(self.node.name, "falling_node_damage") == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- Cause damage to any player it hits.
|
-- Cause damage to any entity it hits.
|
||||||
-- Algorithm based on MC anvils.
|
-- Algorithm based on MC anvils.
|
||||||
-- TODO: Support smashing other objects, too.
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
if not self._startpos then
|
if not self._startpos then
|
||||||
-- Fallback
|
-- Fallback
|
||||||
self._startpos = pos
|
self._startpos = pos
|
||||||
end
|
end
|
||||||
local objs = minetest.get_objects_inside_radius(pos, 1)
|
self._hit = self._hit or {}
|
||||||
for _,v in ipairs(objs) do
|
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
|
||||||
local hp = v:get_hp()
|
if mcl_util.get_hp(obj) > 0 and not self._hit[obj] then
|
||||||
if v:is_player() and hp ~= 0 then
|
self._hit[obj] = true
|
||||||
if not self._hit_players then
|
local way = self._startpos.y - pos.y
|
||||||
self._hit_players = {}
|
local damage = (way - 1) * 2
|
||||||
end
|
damage = math.min(40, math.max(0, damage))
|
||||||
local name = v:get_player_name()
|
if damage >= 1 then
|
||||||
local hit = false
|
-- Reduce damage if wearing a helmet
|
||||||
for _,v in ipairs(self._hit_players) do
|
local inv = mcl_util.get_inventory(obj)
|
||||||
if name == v then
|
if inv then
|
||||||
hit = true
|
local helmet = inv:get_stack("armor", 2)
|
||||||
end
|
if minetest.get_item_group(helmet:get_name(), "combat_armor") > 0 then
|
||||||
end
|
damage = damage / 4 * 3
|
||||||
if not hit then
|
mcl_util.use_item_durability(helmet, 1)
|
||||||
table.insert(self._hit_players, name)
|
inv:set_stack("armor", 2, helmet)
|
||||||
local way = self._startpos.y - pos.y
|
|
||||||
local damage = (way - 1) * 2
|
|
||||||
damage = math.min(40, math.max(0, damage))
|
|
||||||
if damage >= 1 then
|
|
||||||
hp = hp - damage
|
|
||||||
if hp < 0 then
|
|
||||||
hp = 0
|
|
||||||
end
|
end
|
||||||
if v:is_player() then
|
|
||||||
-- TODO: Reduce damage if wearing a helmet
|
|
||||||
local msg
|
|
||||||
if minetest.get_item_group(self.node.name, "anvil") ~= 0 then
|
|
||||||
msg = S("@1 was smashed by a falling anvil.", v:get_player_name())
|
|
||||||
else
|
|
||||||
msg = S("@1 was smashed by a falling block.", v:get_player_name())
|
|
||||||
end
|
|
||||||
if dmes then
|
|
||||||
mcl_death_messages.player_damage(v, msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
v:set_hp(hp, { type = "punch", from = "mod" })
|
|
||||||
end
|
end
|
||||||
|
local dmg_type
|
||||||
|
if minetest.get_item_group(self.node.name, "anvil") ~= 0 then
|
||||||
|
dmg_type = "anvil"
|
||||||
|
else
|
||||||
|
dmg_type = "falling_node"
|
||||||
|
end
|
||||||
|
mcl_util.deal_damage(obj, damage, {type = dmg_type})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -74,10 +57,8 @@ minetest.register_entity(":__builtin:falling_node", {
|
||||||
collide_with_objects = false,
|
collide_with_objects = false,
|
||||||
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||||
},
|
},
|
||||||
|
|
||||||
node = {},
|
node = {},
|
||||||
meta = {},
|
meta = {},
|
||||||
|
|
||||||
set_node = function(self, node, meta)
|
set_node = function(self, node, meta)
|
||||||
local def = minetest.registered_nodes[node.name]
|
local def = minetest.registered_nodes[node.name]
|
||||||
-- Change falling node if definition tells us to
|
-- Change falling node if definition tells us to
|
||||||
|
@ -104,7 +85,6 @@ minetest.register_entity(":__builtin:falling_node", {
|
||||||
glow = glow,
|
glow = glow,
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
|
|
||||||
get_staticdata = function(self)
|
get_staticdata = function(self)
|
||||||
local meta = self.meta
|
local meta = self.meta
|
||||||
-- Workaround: Save inventory seperately from metadata.
|
-- Workaround: Save inventory seperately from metadata.
|
||||||
|
@ -125,10 +105,9 @@ minetest.register_entity(":__builtin:falling_node", {
|
||||||
}
|
}
|
||||||
return minetest.serialize(ds)
|
return minetest.serialize(ds)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_activate = function(self, staticdata)
|
on_activate = function(self, staticdata)
|
||||||
self.object:set_armor_groups({immortal = 1})
|
self.object:set_armor_groups({immortal = 1})
|
||||||
|
|
||||||
local ds = minetest.deserialize(staticdata)
|
local ds = minetest.deserialize(staticdata)
|
||||||
if ds then
|
if ds then
|
||||||
self._startpos = ds._startpos
|
self._startpos = ds._startpos
|
||||||
|
@ -148,7 +127,6 @@ minetest.register_entity(":__builtin:falling_node", {
|
||||||
end
|
end
|
||||||
self._startpos = vector.round(self._startpos)
|
self._startpos = vector.round(self._startpos)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_step = function(self, dtime)
|
on_step = function(self, dtime)
|
||||||
-- Set gravity
|
-- Set gravity
|
||||||
local acceleration = self.object:get_acceleration()
|
local acceleration = self.object:get_acceleration()
|
||||||
|
@ -162,7 +140,7 @@ minetest.register_entity(":__builtin:falling_node", {
|
||||||
local np = {x = pos.x, y = pos.y + 0.3, z = pos.z}
|
local np = {x = pos.x, y = pos.y + 0.3, z = pos.z}
|
||||||
local n2 = minetest.get_node(np)
|
local n2 = minetest.get_node(np)
|
||||||
if n2.name == "mcl_portals:portal_end" then
|
if n2.name == "mcl_portals:portal_end" then
|
||||||
-- TODO: Teleport falling node.
|
-- TODO: Teleport falling node.
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -200,10 +178,9 @@ minetest.register_entity(":__builtin:falling_node", {
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local nd = minetest.registered_nodes[n2.name]
|
local nd = minetest.registered_nodes[n2.name]
|
||||||
if n2.name == "mcl_portals:portal_end" then
|
--if n2.name == "mcl_portals:portal_end" then
|
||||||
-- TODO: Teleport falling node.
|
-- TODO: Teleport falling node.
|
||||||
|
if (nd and nd.buildable_to == true) or minetest.get_item_group(self.node.name, "crush_after_fall") ~= 0 then
|
||||||
elseif (nd and nd.buildable_to == true) or minetest.get_item_group(self.node.name, "crush_after_fall") ~= 0 then
|
|
||||||
-- Replace destination node if it's buildable to
|
-- Replace destination node if it's buildable to
|
||||||
minetest.remove_node(np)
|
minetest.remove_node(np)
|
||||||
-- Run script hook
|
-- Run script hook
|
||||||
|
@ -270,7 +247,6 @@ minetest.register_entity(":__builtin:falling_node", {
|
||||||
self.object:set_pos(npos)
|
self.object:set_pos(npos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
deal_falling_damage(self, dtime)
|
deal_falling_damage(self, dtime)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 wurde von einem fallenden Amboss zerschmettert.
|
|
||||||
@1 was smashed by a falling block.=@1 wurde von einem fallenden Block zerschmettert.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 fue aplastado por la caída de un yunque.
|
|
||||||
@1 was smashed by a falling block.=@1 fue aplastado por la caída de un bloque.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 a été écrasé par une enclume qui tombait.
|
|
||||||
@1 was smashed by a falling block.=@1 a été écrasé par un bloc qui tombait.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=@1 придавило падающей наковальней.
|
|
||||||
@1 was smashed by a falling block.=@1 раздавило падающим блоком.
|
|
|
@ -1,3 +0,0 @@
|
||||||
# textdomain: mcl_falling_nodes
|
|
||||||
@1 was smashed by a falling anvil.=
|
|
||||||
@1 was smashed by a falling block.=
|
|
|
@ -1 +1,3 @@
|
||||||
name = mcl_falling_nodes
|
name = mcl_falling_nodes
|
||||||
|
author = Wuzzy
|
||||||
|
description = Falling node entities, Minecraft-style
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
flowlib
|
|
||||||
mcl_enchanting
|
|
|
@ -1 +0,0 @@
|
||||||
Dropped items will be attracted to the player like a magnet.
|
|
|
@ -1,10 +1,36 @@
|
||||||
|
--these are lua locals, used for higher performance
|
||||||
|
local minetest, math, vector, ipairs = minetest, math, vector, ipairs
|
||||||
|
|
||||||
|
--this is used for the player pool in the sound buffer
|
||||||
|
local pool = {}
|
||||||
|
|
||||||
|
local tick = false
|
||||||
|
|
||||||
|
minetest.register_on_joinplayer(function(player)
|
||||||
|
local name
|
||||||
|
name = player:get_player_name()
|
||||||
|
pool[name] = 0
|
||||||
|
end)
|
||||||
|
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
local name
|
||||||
|
name = player:get_player_name()
|
||||||
|
pool[name] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
local has_awards = minetest.get_modpath("awards")
|
||||||
|
|
||||||
|
local mcl_item_entity = {}
|
||||||
|
|
||||||
--basic settings
|
--basic settings
|
||||||
local item_drop_settings = {} --settings table
|
local item_drop_settings = {} --settings table
|
||||||
|
item_drop_settings.dug_buffer = 0.65 -- the warm up period before a dug item can be collected
|
||||||
item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting
|
item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting
|
||||||
item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect!
|
item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect!
|
||||||
item_drop_settings.xp_radius_magnet = 7.25 --radius of xp magnet. MUST BE LARGER THAN radius_collect!
|
item_drop_settings.xp_radius_magnet = 7.25 --radius of xp magnet. MUST BE LARGER THAN radius_collect!
|
||||||
item_drop_settings.radius_collect = 0.2 --radius of collection
|
item_drop_settings.radius_collect = 0.2 --radius of collection
|
||||||
item_drop_settings.player_collect_height = 1.0 --added to their pos y value
|
item_drop_settings.player_collect_height = 0.8 --added to their pos y value
|
||||||
item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers
|
item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers
|
||||||
item_drop_settings.random_item_velocity = true --this sets random item velocity if velocity is 0
|
item_drop_settings.random_item_velocity = true --this sets random item velocity if velocity is 0
|
||||||
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
|
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
|
||||||
|
@ -12,24 +38,41 @@ item_drop_settings.drop_single_item = false --if true, the drop control dro
|
||||||
|
|
||||||
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
item_drop_settings.magnet_time = 0.75 -- how many seconds an item follows the player before giving up
|
||||||
|
|
||||||
local get_gravity = function()
|
local function get_gravity()
|
||||||
return tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
return tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
||||||
end
|
end
|
||||||
|
|
||||||
local check_pickup_achievements = function(object, player)
|
local registered_pickup_achievement = {}
|
||||||
local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
|
|
||||||
if minetest.get_item_group(itemname, "tree") ~= 0 then
|
--TODO: remove limitation of 1 award per itemname
|
||||||
awards.unlock(player:get_player_name(), "mcl:mineWood")
|
function mcl_item_entity.register_pickup_achievement(itemname, award)
|
||||||
elseif itemname == "mcl_mobitems:blaze_rod" then
|
if not has_awards then
|
||||||
awards.unlock(player:get_player_name(), "mcl:blazeRod")
|
minetest.log("warning", "[mcl_item_entity] Trying to register pickup achievement ["..award.."] for ["..itemname.."] while awards missing")
|
||||||
elseif itemname == "mcl_mobitems:leather" then
|
elseif registered_pickup_achievement[itemname] then
|
||||||
awards.unlock(player:get_player_name(), "mcl:killCow")
|
minetest.log("error", "[mcl_item_entity] Trying to register already existing pickup achievement ["..award.."] for ["..itemname.."]")
|
||||||
elseif itemname == "mcl_core:diamond" then
|
else
|
||||||
awards.unlock(player:get_player_name(), "mcl:diamonds")
|
registered_pickup_achievement[itemname] = award
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local enable_physics = function(object, luaentity, ignore_check)
|
mcl_item_entity.register_pickup_achievement("tree", "mcl:mineWood")
|
||||||
|
mcl_item_entity.register_pickup_achievement("mcl_mobitems:blaze_rod", "mcl:blazeRod")
|
||||||
|
mcl_item_entity.register_pickup_achievement("mcl_mobitems:leather", "mcl:killCow")
|
||||||
|
mcl_item_entity.register_pickup_achievement("mcl_core:diamond", "mcl:diamonds")
|
||||||
|
|
||||||
|
local function check_pickup_achievements(object, player)
|
||||||
|
if has_awards then
|
||||||
|
local itemname = ItemStack(object:get_luaentity().itemstring):get_name()
|
||||||
|
local playername = player:get_player_name()
|
||||||
|
for name,award in pairs(registered_pickup_achievement) do
|
||||||
|
if itemname == name or minetest.get_item_group(itemname, name) ~= 0 then
|
||||||
|
awards.unlock(playername, award)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function enable_physics(object, luaentity, ignore_check)
|
||||||
if luaentity.physical_state == false or ignore_check == true then
|
if luaentity.physical_state == false or ignore_check == true then
|
||||||
luaentity.physical_state = true
|
luaentity.physical_state = true
|
||||||
object:set_properties({
|
object:set_properties({
|
||||||
|
@ -40,7 +83,7 @@ local enable_physics = function(object, luaentity, ignore_check)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local disable_physics = function(object, luaentity, ignore_check, reset_movement)
|
local function disable_physics(object, luaentity, ignore_check, reset_movement)
|
||||||
if luaentity.physical_state == true or ignore_check == true then
|
if luaentity.physical_state == true or ignore_check == true then
|
||||||
luaentity.physical_state = false
|
luaentity.physical_state = false
|
||||||
object:set_properties({
|
object:set_properties({
|
||||||
|
@ -53,103 +96,69 @@ local disable_physics = function(object, luaentity, ignore_check, reset_movement
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
for _,player in ipairs(minetest.get_connected_players()) do
|
tick = not tick
|
||||||
|
|
||||||
|
for _,player in pairs(minetest.get_connected_players()) do
|
||||||
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
|
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
|
||||||
|
|
||||||
|
local name = player:get_player_name()
|
||||||
|
|
||||||
local pos = player:get_pos()
|
local pos = player:get_pos()
|
||||||
|
|
||||||
|
if tick == true and pool[name] > 0 then
|
||||||
|
minetest.sound_play("item_drop_pickup", {
|
||||||
|
pos = pos,
|
||||||
|
gain = 0.7,
|
||||||
|
max_hear_distance = 16,
|
||||||
|
pitch = math.random(70,110)/100
|
||||||
|
})
|
||||||
|
if pool[name] > 6 then
|
||||||
|
pool[name] = 6
|
||||||
|
else
|
||||||
|
pool[name] = pool[name] - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
|
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
|
||||||
|
|
||||||
--magnet and collection
|
--magnet and collection
|
||||||
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
|
||||||
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
|
||||||
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
|
|
||||||
local collected = false
|
|
||||||
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
||||||
|
|
||||||
-- Collection
|
-- Collection
|
||||||
if vector.distance(checkpos, object:get_pos()) <= item_drop_settings.radius_collect and not object:get_luaentity()._removed then
|
if not object:get_luaentity()._removed then
|
||||||
-- Ignore if itemstring is not set yet
|
-- Ignore if itemstring is not set yet
|
||||||
if object:get_luaentity().itemstring ~= "" then
|
if object:get_luaentity().itemstring ~= "" then
|
||||||
inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
|
inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
|
||||||
minetest.sound_play("item_drop_pickup", {
|
|
||||||
pos = pos,
|
|
||||||
max_hear_distance = 16,
|
|
||||||
gain = 1.0,
|
|
||||||
}, true)
|
|
||||||
check_pickup_achievements(object, player)
|
|
||||||
|
|
||||||
|
check_pickup_achievements(object, player)
|
||||||
|
|
||||||
-- Destroy entity
|
-- Destroy entity
|
||||||
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
|
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
|
||||||
|
object:get_luaentity().target = checkpos
|
||||||
object:get_luaentity()._removed = true
|
object:get_luaentity()._removed = true
|
||||||
object:remove()
|
|
||||||
collected = true
|
object:set_velocity({x=0,y=0,z=0})
|
||||||
|
object:set_acceleration({x=0,y=0,z=0})
|
||||||
|
|
||||||
|
object:move_to(checkpos)
|
||||||
|
|
||||||
|
pool[name] = pool[name] + 1
|
||||||
|
|
||||||
|
minetest.after(0.25, function()
|
||||||
|
--safety check
|
||||||
|
if object and object:get_luaentity() then
|
||||||
|
object:remove()
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Magnet
|
|
||||||
else
|
|
||||||
|
|
||||||
object:get_luaentity()._magnet_active = true
|
|
||||||
object:get_luaentity()._collector_timer = 0
|
|
||||||
|
|
||||||
-- Move object to player
|
|
||||||
disable_physics(object, object:get_luaentity())
|
|
||||||
|
|
||||||
local opos = object:get_pos()
|
|
||||||
local vec = vector.subtract(checkpos, opos)
|
|
||||||
vec = vector.add(opos, vector.divide(vec, 2))
|
|
||||||
object:move_to(vec)
|
|
||||||
|
|
||||||
|
|
||||||
--fix eternally falling items
|
|
||||||
minetest.after(0, function(object)
|
|
||||||
local lua = object:get_luaentity()
|
|
||||||
if lua then
|
|
||||||
object:set_acceleration({x=0, y=0, z=0})
|
|
||||||
end
|
|
||||||
end, object)
|
|
||||||
|
|
||||||
|
|
||||||
--this is a safety to prevent items flying away on laggy servers
|
|
||||||
if item_drop_settings.collection_safety == true then
|
|
||||||
if object:get_luaentity().init ~= true then
|
|
||||||
object:get_luaentity().init = true
|
|
||||||
minetest.after(1, function(args)
|
|
||||||
local playername = args[1]
|
|
||||||
local player = minetest.get_player_by_name(playername)
|
|
||||||
local object = args[2]
|
|
||||||
local lua = object:get_luaentity()
|
|
||||||
if player == nil or not player:is_player() or object == nil or lua == nil or lua.itemstring == nil then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
|
|
||||||
inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
|
|
||||||
if not object:get_luaentity()._removed then
|
|
||||||
minetest.sound_play("item_drop_pickup", {
|
|
||||||
pos = pos,
|
|
||||||
max_hear_distance = 16,
|
|
||||||
gain = 1.0,
|
|
||||||
}, true)
|
|
||||||
end
|
|
||||||
check_pickup_achievements(object, player)
|
|
||||||
object:get_luaentity()._removed = true
|
|
||||||
object:remove()
|
|
||||||
else
|
|
||||||
enable_physics(object, object:get_luaentity())
|
|
||||||
end
|
|
||||||
end, {player:get_player_name(), object})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not collected then
|
|
||||||
if object:get_luaentity()._magnet_timer > 1 then
|
|
||||||
object:get_luaentity()._magnet_timer = -item_drop_settings.magnet_time
|
|
||||||
object:get_luaentity()._magnet_active = false
|
|
||||||
elseif object:get_luaentity()._magnet_timer < 0 then
|
|
||||||
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -165,66 +174,6 @@ minetest.register_globalstep(function(dtime)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local minigroups = { "shearsy", "swordy", "shearsy_wool", "swordy_cobweb" }
|
|
||||||
local basegroups = { "pickaxey", "axey", "shovely" }
|
|
||||||
local materials = { "wood", "gold", "stone", "iron", "diamond" }
|
|
||||||
|
|
||||||
-- Checks if the given node would drop its useful drop if dug by a tool
|
|
||||||
-- with the given tool capabilities. Returns true if it will yield its useful
|
|
||||||
-- drop, false otherwise.
|
|
||||||
local check_can_drop = function(node_name, tool_capabilities)
|
|
||||||
local handy = minetest.get_item_group(node_name, "handy")
|
|
||||||
local dig_immediate = minetest.get_item_group(node_name, "dig_immediate")
|
|
||||||
if handy == 1 or dig_immediate == 2 or dig_immediate == 3 then
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
local toolgroupcaps
|
|
||||||
if tool_capabilities then
|
|
||||||
toolgroupcaps = tool_capabilities.groupcaps
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Compare node groups with tool capabilities
|
|
||||||
for m=1, #minigroups do
|
|
||||||
local minigroup = minigroups[m]
|
|
||||||
local g = minetest.get_item_group(node_name, minigroup)
|
|
||||||
if g ~= 0 then
|
|
||||||
local plus = minigroup .. "_dig"
|
|
||||||
if toolgroupcaps[plus] then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
for e=1,5 do
|
|
||||||
local effplus = plus .. "_efficiency_" .. e
|
|
||||||
if toolgroupcaps[effplus] then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for b=1, #basegroups do
|
|
||||||
local basegroup = basegroups[b]
|
|
||||||
local g = minetest.get_item_group(node_name, basegroup)
|
|
||||||
if g ~= 0 then
|
|
||||||
for m=g, #materials do
|
|
||||||
local plus = basegroup .. "_dig_"..materials[m]
|
|
||||||
if toolgroupcaps[plus] then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
for e=1,5 do
|
|
||||||
local effplus = plus .. "_efficiency_" .. e
|
|
||||||
if toolgroupcaps[effplus] then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Stupid workaround to get drops from a drop table:
|
-- Stupid workaround to get drops from a drop table:
|
||||||
-- Create a temporary table in minetest.registered_nodes that contains the proper drops,
|
-- Create a temporary table in minetest.registered_nodes that contains the proper drops,
|
||||||
-- because unfortunately minetest.get_node_drops needs the drop table to be inside a registered node definition
|
-- because unfortunately minetest.get_node_drops needs the drop table to be inside a registered node definition
|
||||||
|
@ -269,29 +218,33 @@ local function get_fortune_drops(fortune_drops, fortune_level)
|
||||||
return drop or {}
|
return drop or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true)
|
||||||
|
|
||||||
function minetest.handle_node_drops(pos, drops, digger)
|
function minetest.handle_node_drops(pos, drops, digger)
|
||||||
-- NOTE: This function override allows digger to be nil.
|
-- NOTE: This function override allows digger to be nil.
|
||||||
-- This means there is no digger. This is a special case which allows this function to be called
|
-- This means there is no digger. This is a special case which allows this function to be called
|
||||||
-- by hand. Creative Mode is intentionally ignored in this case.
|
-- by hand. Creative Mode is intentionally ignored in this case.
|
||||||
|
|
||||||
local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true)
|
|
||||||
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if node will yield its useful drop by the digger's tool
|
-- Check if node will yield its useful drop by the digger's tool
|
||||||
local dug_node = minetest.get_node(pos)
|
local dug_node = minetest.get_node(pos)
|
||||||
local toolcaps
|
local tooldef
|
||||||
local tool
|
local tool
|
||||||
if digger ~= nil then
|
if digger ~= nil then
|
||||||
tool = digger:get_wielded_item()
|
tool = digger:get_wielded_item()
|
||||||
toolcaps = tool:get_tool_capabilities()
|
tooldef = minetest.registered_tools[tool:get_name()]
|
||||||
|
|
||||||
if not check_can_drop(dug_node.name, toolcaps) then
|
if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name()) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local diggroups = tooldef and tooldef._mcl_diggroups
|
||||||
|
local shearsy_level = diggroups and diggroups.shearsy and diggroups.shearsy.level
|
||||||
|
|
||||||
--[[ Special node drops when dug by shears by reading _mcl_shears_drop or with a silk touch tool reading _mcl_silk_touch_drop
|
--[[ Special node drops when dug by shears by reading _mcl_shears_drop or with a silk touch tool reading _mcl_silk_touch_drop
|
||||||
from the node definition.
|
from the node definition.
|
||||||
Definition of _mcl_shears_drop / _mcl_silk_touch_drop:
|
Definition of _mcl_shears_drop / _mcl_silk_touch_drop:
|
||||||
|
@ -303,7 +256,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
|
|
||||||
local silk_touch_drop = false
|
local silk_touch_drop = false
|
||||||
local nodedef = minetest.registered_nodes[dug_node.name]
|
local nodedef = minetest.registered_nodes[dug_node.name]
|
||||||
if toolcaps ~= nil and toolcaps.groupcaps and toolcaps.groupcaps.shearsy_dig and nodedef._mcl_shears_drop then
|
if shearsy_level and shearsy_level > 0 and nodedef._mcl_shears_drop then
|
||||||
if nodedef._mcl_shears_drop == true then
|
if nodedef._mcl_shears_drop == true then
|
||||||
drops = { dug_node.name }
|
drops = { dug_node.name }
|
||||||
else
|
else
|
||||||
|
@ -371,6 +324,10 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
z = -z
|
z = -z
|
||||||
end
|
end
|
||||||
obj:set_velocity({x=1/x, y=obj:get_velocity().y, z=1/z})
|
obj:set_velocity({x=1/x, y=obj:get_velocity().y, z=1/z})
|
||||||
|
|
||||||
|
obj:get_luaentity().age = item_drop_settings.dug_buffer
|
||||||
|
|
||||||
|
obj:get_luaentity()._insta_collect = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -437,6 +394,9 @@ minetest.register_entity(":__builtin:item", {
|
||||||
-- Number of seconds this item entity has existed so far
|
-- Number of seconds this item entity has existed so far
|
||||||
age = 0,
|
age = 0,
|
||||||
|
|
||||||
|
-- How old it has become in the collection animation
|
||||||
|
collection_age = 0,
|
||||||
|
|
||||||
set_item = function(self, itemstring)
|
set_item = function(self, itemstring)
|
||||||
self.itemstring = itemstring
|
self.itemstring = itemstring
|
||||||
if self.itemstring == "" then
|
if self.itemstring == "" then
|
||||||
|
@ -444,6 +404,14 @@ minetest.register_entity(":__builtin:item", {
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local stack = ItemStack(itemstring)
|
local stack = ItemStack(itemstring)
|
||||||
|
if minetest.get_item_group(stack:get_name(), "compass") > 0 then
|
||||||
|
stack:set_name("mcl_compass:16")
|
||||||
|
itemstring = stack:to_string()
|
||||||
|
self.itemstring = itemstring
|
||||||
|
end
|
||||||
|
if minetest.get_item_group(stack:get_name(), "clock") > 0 then
|
||||||
|
self.is_clock = true
|
||||||
|
end
|
||||||
local count = stack:get_count()
|
local count = stack:get_count()
|
||||||
local max_count = stack:get_stack_max()
|
local max_count = stack:get_stack_max()
|
||||||
if count > max_count then
|
if count > max_count then
|
||||||
|
@ -456,13 +424,9 @@ minetest.register_entity(":__builtin:item", {
|
||||||
if itemtable then
|
if itemtable then
|
||||||
itemname = stack:to_table().name
|
itemname = stack:to_table().name
|
||||||
end
|
end
|
||||||
local item_texture = nil
|
|
||||||
local item_type = ""
|
|
||||||
local glow
|
local glow
|
||||||
local def = minetest.registered_items[itemname]
|
local def = minetest.registered_items[itemname]
|
||||||
if def then
|
if def then
|
||||||
item_texture = def.inventory_image
|
|
||||||
item_type = def.type
|
|
||||||
description = def.description
|
description = def.description
|
||||||
glow = def.light_source
|
glow = def.light_source
|
||||||
end
|
end
|
||||||
|
@ -602,6 +566,11 @@ minetest.register_entity(":__builtin:item", {
|
||||||
|
|
||||||
on_step = function(self, dtime)
|
on_step = function(self, dtime)
|
||||||
if self._removed then
|
if self._removed then
|
||||||
|
self.object:set_properties({
|
||||||
|
physical = false
|
||||||
|
})
|
||||||
|
self.object:set_velocity({x=0,y=0,z=0})
|
||||||
|
self.object:set_acceleration({x=0,y=0,z=0})
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self.age = self.age + dtime
|
self.age = self.age + dtime
|
||||||
|
@ -626,6 +595,12 @@ minetest.register_entity(":__builtin:item", {
|
||||||
local node = minetest.get_node_or_nil(p)
|
local node = minetest.get_node_or_nil(p)
|
||||||
local in_unloaded = (node == nil)
|
local in_unloaded = (node == nil)
|
||||||
|
|
||||||
|
if self.is_clock then
|
||||||
|
self.object:set_properties({
|
||||||
|
textures = {"mcl_clock:clock_" .. (mcl_worlds.clock_works(p) and mcl_clock.old_time or mcl_clock.random_frame)}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
-- If no collector was found for a long enough time, declare the magnet as disabled
|
-- If no collector was found for a long enough time, declare the magnet as disabled
|
||||||
if self._magnet_active and (self._collector_timer == nil or (self._collector_timer > item_drop_settings.magnet_time)) then
|
if self._magnet_active and (self._collector_timer == nil or (self._collector_timer > item_drop_settings.magnet_time)) then
|
||||||
self._magnet_active = false
|
self._magnet_active = false
|
||||||
|
@ -785,7 +760,7 @@ minetest.register_entity(":__builtin:item", {
|
||||||
if self.physical_state then
|
if self.physical_state then
|
||||||
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
|
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
|
||||||
-- Merge with close entities of the same item
|
-- Merge with close entities of the same item
|
||||||
for _, object in ipairs(minetest.get_objects_inside_radius(p, 0.8)) do
|
for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do
|
||||||
local obj = object:get_luaentity()
|
local obj = object:get_luaentity()
|
||||||
if obj and obj.name == "__builtin:item"
|
if obj and obj.name == "__builtin:item"
|
||||||
and obj.physical_state == false then
|
and obj.physical_state == false then
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
name = mcl_item_entity
|
name = mcl_item_entity
|
||||||
|
author = PilzAdam
|
||||||
|
description = Dropped items will be attracted to the player like a magnet.
|
||||||
|
depends = flowlib, mcl_enchanting
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Item_Drop_Pickup - https://freesound.org/people/benniknop/sounds/317848/ (License: CC0)
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue