Compare commits

...

365 Commits

Author SHA1 Message Date
Lizzy Fleckenstein a8b974266c Merge pull request 'Add 1024x1024 logo (basic and small versions)' (#1947) from AFCMS/MineClone2:new_logo into master
Reviewed-on: MineClone2/MineClone2#1947
2022-01-03 17:49:54 +00:00
AFCMS 11f3ad15ba add logo 2022-01-02 18:50:15 +01:00
NO11 627c37cd97 Fix pumpkin hud 2022-01-02 12:37:20 +00:00
NO11 7cc7fb1331 Make removing of arrow entities also work with mobs, remove arrows on respawn 2022-01-02 11:06:29 +00:00
NO11 7b46225176 Remove arrow entities when the player joins to prevent killing on startup (working fix) 2022-01-01 22:59:21 +00:00
NO411 7b47a15e34 Remove arrow entities when the player leaves to prevent killing on startup 2021-12-30 14:04:53 +01:00
AFCMS e3129b057f Merge pull request 'Optional connected glass support' (#1939) from AFCMS/MineClone2:connected_glass into master
Reviewed-on: MineClone2/MineClone2#1939
2021-12-23 20:18:19 +00:00
AFCMS a7e471de62 framed stained glass 2021-12-23 18:02:43 +01:00
AFCMS 12830781f8 Merge branch 'master' into connected_glass 2021-12-23 17:29:53 +01:00
Lizzy Fleckenstein bfd1fd69d1
Fix potential crash when falling onto unknown node 2021-12-19 18:59:09 +01:00
Lizzy Fleckenstein e2360204a7
Revert "fixed daylightsensor's register_abms"
This reverts commit 5a4abcbcb7.
2021-12-12 15:55:52 +01:00
Lizzy Fleckenstein 14295cc4d7 Merge pull request 'Fixed daylightsensors' (#1928) from chmodsayshello/MineClone2:daylightsensorfix into master
Reviewed-on: MineClone2/MineClone2#1928
2021-12-10 18:31:38 +00:00
chmodsayshello 5a4abcbcb7 fixed daylightsensor's register_abms
By changing the check if a normal/inverted daylightsensor should update by turning on and off, I made them workling again
2021-12-10 13:59:31 +00:00
kay27 0c8e5dc7a4 Disable Nether portal node rotation by screwdriver 2021-12-10 03:52:14 +04:00
Lizzy Fleckenstein e4feb233e0
Fix hopper dupe 2021-12-09 18:20:24 +01:00
Lizzy Fleckenstein b945975427
Slime splitting: nil check child to prevent crash (that happened on oysterity-mcl2) 2021-12-09 18:11:05 +01:00
Lizzy Fleckenstein 0e9a56fa35
Add stacks to enchant_uniform_randomly 2021-12-07 18:19:41 +01:00
Lizzy Fleckenstein ec7e245b9d
Various fixes to the enchanting and loot system
- enchanted loot generated by mapgen now uses PseudoRandom for randomness
- prevent fishing loot from generating loot 32767 times (!!!) when only 1 is needed
- bows and fishing rods obtained from the treasure section of fishing loot are now enchanted
- there is now a function to uniform enchant items other than books
2021-12-07 17:57:18 +01:00
Lizzy Fleckenstein b3958a956d
Refactor random enchantment selection code 2021-12-07 16:16:07 +01:00
Lizzy Fleckenstein 882db9f873
Remove unused and completely unlogical enchantment_level paramenter from get_possible_enchantments 2021-12-07 15:49:12 +01:00
Lizzy Fleckenstein 261faafb7c
Fix get_possible_enchantments to not return incompatible enchantments, even if treasure enchantments are allowed 2021-12-07 15:47:23 +01:00
Lizzy Fleckenstein 92686e5412
Fix broken mcl_util.calculate_durability 2021-12-02 17:28:19 +01:00
Lizzy Fleckenstein e6b200aaf3
Fix access to ender inventory without an ender chest 2021-12-02 16:19:59 +01:00
Lizzy Fleckenstein d3015edeb9
Fix reference dupes for droppers and dispensers 2021-11-29 19:12:49 +01:00
NO11 2127bb3ef1 Merge pull request 'Fix mobs spawner count' (#1915) from TioBlocos/MineClone2:fix-mobs-spawn into master
Reviewed-on: MineClone2/MineClone2#1915
2021-11-22 12:06:12 +00:00
Glaucos Ginez 9edf277905 Fix mobs spawn count 2021-11-21 22:13:24 -03:00
Nils Dagsson Moskopp 46394e7e1f
Add obsidian boat that always sinks 2021-11-20 09:06:48 +01:00
Lizzy Fleckenstein b0aceae73d
Fix reference dupe glitches 2021-11-19 15:22:40 +01:00
NO11 9200c3fe44 Merge branch 'master' of https://git.minetest.land/MineClone2/MineClone2 2021-11-18 17:42:19 +01:00
NO11 903d1777be Use set_count instead of creating a new item and checking for enchanted books 2021-11-18 17:40:32 +01:00
Lizzy Fleckenstein 6ca5799565
Merge branch 'master' of https://git.minetest.land/MineClone2/MineClone2 2021-11-17 18:25:19 +01:00
Lizzy Fleckenstein 30528b0a2c
Fix crash when opening a chest with an unknown node on top 2021-11-17 18:25:12 +01:00
NO11 9919011aca Fix enchanted books losing their enchantments in creative inventory 2021-11-17 16:43:48 +01:00
NO11 c757e98b4f Fix #1911, error in lightning callback 2021-11-17 00:37:11 +01:00
NO11 e2b22a62ce Merge pull request 'Make dripping particles MC-like (rework drippingwater)' (#1898) from NO11/MineClone2:dripping into master
Reviewed-on: MineClone2/MineClone2#1898
2021-11-15 20:55:47 +00:00
NO11 a9804879e2 Rename drippingwater to mcl_dripping in mod.conf and readme.txt 2021-11-15 21:54:16 +01:00
NO11 d2a03ec0b9 Rename entity ids 2021-11-15 21:44:23 +01:00
NO11 7ef6613f09 Rename drippingwater mod to mcl_dripping 2021-11-15 21:39:43 +01:00
NO11 d27109d807 Merge branch 'master' into dripping 2021-11-13 19:15:49 +00:00
iliekprogrammar 79e1e2fa8f Merge pull request 'Add 64 items to inventory when creative is on' (#1899) from NO11/MineClone2:inventory into master
Reviewed-on: MineClone2/MineClone2#1899
2021-11-13 19:12:26 +00:00
NO11 fdaaf0ec49 Use on_joinplayer instead of on_newplayer 2021-11-13 18:56:52 +00:00
NO11 add97d39a6 delete overlay texture 2021-11-13 17:28:13 +00:00
NO11 bcb6251d20 Use label instead of extra texture 2021-11-13 17:26:17 +00:00
NO11 1483c45cc9 Merge branch 'master' into inventory 2021-11-13 15:28:13 +00:00
NO11 642b9db035 localize wielditem in crossbow.lua (Fix #1901) 2021-11-13 15:19:34 +00:00
NO11 d7e59f6a35 Add switch stack size overlay texture 2021-11-13 12:26:01 +00:00
NO11 d4da855570 Add button to switch between max stack size and just one item 2021-11-13 12:25:10 +00:00
NO11 30dd505985 Merge branch 'master' into inventory 2021-11-13 11:18:47 +00:00
NO11 ae8068cca6 Use stack_max instead of 64 for all items 2021-11-13 11:17:46 +00:00
iliekprogrammar bd14918543
Reduce defuse reach for charged creeper
5.2 is actually half of the estimated MC creeper defuse range, which is 10.4.
The reason for this change is to balance the creeper in MCL2 where it fuses
whilst moving making it more difficult than MC. In MC, the creeper does not move
while fusing.
2021-11-13 12:12:20 +08:00
iliekprogrammar 66c1b4a95f Merge pull request 'fix_creeper' (#1896) from Dieter44/MineClone2:fix_creeper into master
Reviewed-on: MineClone2/MineClone2#1896
2021-11-13 04:06:55 +00:00
iliekprogrammar 96c4fb60d8
Fix crash on startup during immediate runtime by mcl_burning
The crash occurs if mcl_burning:data is deserialized to nil. The cause of
mcl_burning being set to "return nil" is unknown. Therefore, when it occurs, it
will be logged as warning.
2021-11-13 10:55:24 +08:00
NO11 5515e2baa1 Add 64 items to inventory when creative is on 2021-11-12 21:49:47 +00:00
NO11 be2e4614d0 Merge pull request 'master' (#12) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#12
2021-11-12 21:46:31 +00:00
NO11 7ed964756e local luaentity 2021-11-12 18:00:04 +00:00
NO11 0e5ad8637d Merge branch 'master' into dripping 2021-11-12 17:54:30 +00:00
NO11 0cc0a7e01d Make dripping particles MC-like 2021-11-12 17:49:27 +00:00
NO11 490e40d042 Bone meal particles: add some velocity, correct glow 2021-11-12 15:41:09 +00:00
NO11 f233fb5d30 Merge pull request 'Several fixes for applying bone meal to grass (Fix #900)' (#1894) from NO11/MineClone2:bone_meal into master
Reviewed-on: MineClone2/MineClone2#1894
2021-11-12 15:02:30 +00:00
NO11 9e4e7f0695 Merge branch 'master' into bone_meal 2021-11-12 15:02:13 +00:00
NO11 2a08f31435 Use particlespawners for better performance (sponge particles) 2021-11-12 14:09:59 +00:00
iliekprogrammar 740f7583ef
Add Dieter44 to CREDITS.md 2021-11-12 02:49:18 +08:00
iliekprogrammar 0564121183
Code style for #1890 2021-11-12 02:36:17 +08:00
iliekprogrammar bca5033fb2 Merge pull request 'Implement health regeneration correctly' (#1890) from Dieter44/MineClone2:fixHealthRegen into master
Reviewed-on: MineClone2/MineClone2#1890
2021-11-11 18:33:57 +00:00
Dieter44 03d22852ee Replace mobs:boom with equivalent mcl_explosions.exlode() to fix game crash when creeper is right-clicked with flint and steel. Issue #1753 2021-11-11 16:56:44 +01:00
Dieter44 10a5f8c4bf Adding attribute hostile=true to charged creeper to fix that the charged creeper has no behavior: Issue #1756 2021-11-11 16:50:29 +01:00
Dieter44 68810a2a74 Change creeper fuse range and defuse range according to minecraft wiki: https://minecraft.fandom.com/wiki/Creeper and: https://minecraft.fandom.com/wiki/Explosion. Fix of #1689 2021-11-11 16:47:32 +01:00
Dieter44 0b6467d679 Reduce creeper run_velocity to 2.1, to fix #1691 2021-11-11 16:03:04 +01:00
NO11 8979230c42 Several fixes for applying bone meal to grass 2021-11-10 17:15:27 +00:00
NO11 fafa47d643 Merge pull request 'master' (#11) from MineClone2/MineClone2:master into bone_meal
Reviewed-on: NO11/MineClone2#11
2021-11-10 17:13:54 +00:00
iliekprogrammar f61143758e
Fix small typo in API.md 2021-11-10 12:54:28 +08:00
iliekprogrammar fa22ec4dd0
Add helper functions to update/merge tables. 2021-11-10 02:50:49 +08:00
Dieter44 017bf705e9 Fixing that player can regenerate health in death screen and then respawn without HP being set to maximum 2021-11-09 19:35:32 +01:00
Lizzy Fleckenstein a7bc460fae
Fix boat and enchanting book texture glitches / warnings 2021-11-09 17:39:39 +01:00
Dieter44 e82d21040c minor changes, ipairs() replaced with pairs() 2021-11-08 19:15:56 +01:00
iliekprogrammar 0491b814dd Merge pull request 'Simple bone meal API (Fix #1862)' (#1892) from NO11/MineClone2:bone_meal into master
Reviewed-on: MineClone2/MineClone2#1892
2021-11-08 16:53:01 +00:00
Dieter44 2f05388541 Add one food_tick_timer per player instead of using one for all players. 2021-11-08 15:49:05 +01:00
Dieter44 976f522b9d Combine slowFoodTickTimer and fastFoodTickTimer to a single food_tick_timer 2021-11-08 15:33:53 +01:00
NO11 51dffc6c53 Merge branch 'master' into bone_meal 2021-11-08 13:16:39 +00:00
NO11 30ce6f8a77 Fix typo min -> max 2021-11-08 13:16:20 +00:00
Lizzy Fleckenstein a34ae040c8
Add ContentDB links 2021-11-08 14:02:22 +01:00
Lizzy Fleckenstein a410a7fabe Merge pull request 'Add OpenCollective link and credits' (#1893) from EliasFleckenstein03/MineClone2:opencollective into master
Reviewed-on: MineClone2/MineClone2#1893
2021-11-08 11:48:10 +00:00
Lizzy Fleckenstein ea46c8741b
Add OpenCollective link and credits 2021-11-07 20:29:11 +01:00
NO11 5b52deaa8a Merge branch 'master' into bone_meal 2021-11-06 13:38:20 +00:00
NO11 7bbc1e9951 Add API.md for bone meal API 2021-11-06 13:34:22 +00:00
Lizzy Fleckenstein 0dd780ee2a Merge pull request 'Implement grass palette conversion, Add sugar cane colorisation' (#1889) from EliasFleckenstein03/MineClone2:tint into master
Reviewed-on: MineClone2/MineClone2#1889
2021-11-06 13:29:39 +00:00
NO11 1b259f928b Add simple bone meal API
- callback api
- particle api
2021-11-06 13:12:03 +00:00
Dieter44 d0d60804a3 Implemented health regeneration mechanics as described in minecraft wiki. Saturation values and different regeneration speeds now used. 2021-11-04 21:01:28 +01:00
Dieter44 d1d11f9740 Fixed debug hudbars for player saturation and exhaustion when mcl_hunger_debug=true is set in .config file 2021-11-04 20:58:54 +01:00
Nils Dagsson Moskopp 4926c0560d
Speed up TGA encoding by creating fewer strings 2021-11-04 15:38:56 +01:00
Nils Dagsson Moskopp 23ca11c8e1
Use RLE compression in tga_encoder 2021-11-04 15:38:26 +01:00
Elias Fleckenstein 88e084cbca Merge pull request 'Rework XP API' (#1888) from EliasFleckenstein03/MineClone2:xp into master
Reviewed-on: MineClone2/MineClone2#1888
2021-11-04 13:36:13 +00:00
Lizzy Fleckenstein be86b603f8
Update README.md to reflect new contribution guidelines 2021-11-04 13:14:35 +01:00
iliekprogrammar f4803a35c4 Merge pull request 'Update contribution guidelines' (#1881) from EliasFleckenstein03/MineClone2:guidelines into master
Reviewed-on: MineClone2/MineClone2#1881
2021-11-04 12:06:32 +00:00
Lizzy Fleckenstein ce4c0ed4c1
free -> free/libre 2021-11-04 12:56:34 +01:00
Lizzy Fleckenstein 4a3a8841cd
Add ingame credits script to release process 2021-11-04 12:31:13 +01:00
Lizzy Fleckenstein 649f481b51
provide example for non-descriptive title 2021-11-04 12:28:36 +01:00
Lizzy Fleckenstein b937b38b1c
Separate translations and assets 2021-11-04 12:26:14 +01:00
Lizzy Fleckenstein f9e7f58492
Reword necessary PR feedback section 2021-11-04 12:21:06 +01:00
Lizzy Fleckenstein a77e79d985
where the real troublespots are -> places to investigate optimization issues 2021-11-03 21:15:20 +01:00
Lizzy Fleckenstein 24ca8252a9
community wants -> community feedback 2021-11-03 21:14:22 +01:00
Lizzy Fleckenstein c6e9d763d6
repo -> repository (in release process documentation) 2021-11-03 21:09:57 +01:00
Lizzy Fleckenstein 61d0dc8182
intrested -> interested 2021-11-03 21:09:13 +01:00
Lizzy Fleckenstein 46d1dd42d4
recieved -> received 2021-11-03 21:08:47 +01:00
Lizzy Fleckenstein 39f66eb4a0
repo -> repository 2021-11-03 21:08:11 +01:00
Lizzy Fleckenstein 18dd1cabd0
everytime -> every time 2021-11-03 21:07:28 +01:00
Lizzy Fleckenstein e70161501f
alreay -> already 2021-11-03 21:06:58 +01:00
Lizzy Fleckenstein bb6fe65aa5
inadequeate -> inadequate 2021-11-03 21:06:35 +01:00
Lizzy Fleckenstein cdf6533e0a
regulary -> regularly 2021-11-03 21:06:08 +01:00
Lizzy Fleckenstein d690797011
commited -> committed 2021-11-03 21:05:38 +01:00
Lizzy Fleckenstein 6000c29171
ressource -> resource 2021-11-03 21:04:52 +01:00
Lizzy Fleckenstein faff9316e0
minecraft -> Minecraft 2021-11-03 21:03:58 +01:00
Lizzy Fleckenstein 7c1777c53a
minetest -> Minetest 2021-11-03 21:03:17 +01:00
Lizzy Fleckenstein c2f0f0297b
Optifine -> OptiFine 2021-11-03 21:02:15 +01:00
Lizzy Fleckenstein 6473494cbc
prioritised -> prioritized 2021-11-03 21:01:43 +01:00
Lizzy Fleckenstein 4d93e13f80
Reword developer presence in public discussion rooms rule 2021-11-03 20:59:27 +01:00
Lizzy Fleckenstein 47340386e2
Turn parethesized sentence about voluntary work into normal one 2021-11-03 20:55:33 +01:00
Lizzy Fleckenstein 25f467c8ab
Merge branch 'master' into xp 2021-11-03 20:18:49 +01:00
Elias Fleckenstein c17fc81d1f Merge pull request 'Break minecart if it's near a cactus' (#1886) from NO11/MineClone2:minecart into master
Reviewed-on: MineClone2/MineClone2#1886
2021-11-03 19:18:01 +00:00
Lizzy Fleckenstein 8f9f5cc936
Merge branch 'master' into xp 2021-11-03 20:14:08 +01:00
Elias Fleckenstein 4af5d8e5e8 Merge pull request '[cherry pick from MCL5] Add missing call for on_die function' (#1887) from iliekprogrammar/MineClone2:quickfix_slime into master
Reviewed-on: MineClone2/MineClone2#1887
2021-11-03 19:11:53 +00:00
Lizzy Fleckenstein 643ded06da
Merge branch 'master' into guidelines 2021-11-03 20:04:08 +01:00
Lizzy Fleckenstein 970988cb39
Add sugar cane colorisation 2021-11-03 19:58:50 +01:00
Lizzy Fleckenstein 34f329a9d5
TextureConverter: Implement grass palette conversion
Source: https://minecraft.fandom.com/wiki/Tint
Since the MineClone2 biomes do not entirely match with the Minecraft ones I picked the Minecraft biomes that seem to match them best.
This also changes the palette index of the nether to match the desert instead of the mesa biome
and changes the color of grass blocks in item form to the default minecraft one.
2021-11-03 19:57:21 +01:00
Lizzy Fleckenstein a4e73886d5
Rework XP API 2021-11-03 19:36:57 +01:00
Lizzy Fleckenstein 148575a05b
Remove unused hud_manager.hud_exists function 2021-11-03 16:28:13 +01:00
iliekprogrammar 0baffeced3 Merge branch 'master' into quickfix_slime 2021-11-03 07:01:37 +00:00
Nils Dagsson Moskopp 2607d40f1f
Add script to show packets count from debug logs
Mineclonia has inherited mods from MineClone 2 that send a lot of network
packets. This behaviour wastes bandwith and is most likely a major reason
for the unusually high amount of lag that MineClone2 and Mineclonia have.

Many network packets that are sent by Mineclonia are entirely useless.
Analyzing minetest log files to figure out what kind of packets are
sent and how often is a first step in getting rid of useless traffic.
2021-11-03 14:57:18 +08:00
Artem Arbatsky db696d0e2b
Add missing call for on_die function 2021-11-03 10:11:06 +08:00
NO11 f09923ded9 Merge branch 'master' into minecart 2021-11-02 22:01:54 +00:00
NO11 0b9cbdb20a Merge branch 'minecart' of https://git.minetest.land/NO11/MineClone2 into minecart 2021-11-02 22:58:34 +01:00
NO11 c52fda154b Break minecart if it's near a cactus (Fix #924) 2021-11-02 22:58:03 +01:00
NO11 28b7304211 Break minecart it's near a cactus (Fix #924) 2021-11-02 22:55:49 +01:00
NO11 1518eb81cb Merge pull request 'Remove small gray border of buttons in creative inventory pages' (#1883) from NO11/MineClone2:inventory into master
Reviewed-on: MineClone2/MineClone2#1883
2021-10-30 12:22:45 +00:00
NO11 4e0bb0d120 Merge branch 'master' into inventory 2021-10-28 09:47:39 +00:00
NO11 5b37f56005 Remove small gray border of buttons in creative inventory pages 2021-10-28 09:43:14 +00:00
NO11 aaee3b6de7 Merge pull request 'Totem particles (Fix #1745)' (#1768) from totem_particles into master
Reviewed-on: MineClone2/MineClone2#1768
2021-10-28 09:08:17 +00:00
NO11 6025a3d7d4 Merge branch 'master' into totem_particles 2021-10-28 09:06:09 +00:00
Lizzy Fleckenstein bbdd8f55eb
Reword 'reporting issues' part in 'testing pull requests' section 2021-10-28 09:34:39 +02:00
Lizzy Fleckenstein 6fd8ff8865
testing -> test 2021-10-27 18:54:39 +02:00
Lizzy Fleckenstein 11e364b3ec
Give development target it's own headline 2021-10-27 18:52:26 +02:00
Lizzy Fleckenstein 4db9952a84
if -> only when 2021-10-27 18:48:38 +02:00
Lizzy Fleckenstein fb2a501a9c
Keep our guidelines -> Stick to our guidelines 2021-10-27 18:47:38 +02:00
Lizzy Fleckenstein 938911e7e3
even help using -> assist you use 2021-10-27 18:46:58 +02:00
Lizzy Fleckenstein c1934c4f3a
Reword feature request alignment with development goals guideline 2021-10-27 18:45:37 +02:00
Lizzy Fleckenstein 61dccfb9e5
Reword up to date guideline for feature requests 2021-10-27 18:44:10 +02:00
Lizzy Fleckenstein 90796ec7b4
can unfortunately not -> unfortunately cannot 2021-10-27 18:42:11 +02:00
Lizzy Fleckenstein d30e014233
Mineclone2 -> MineClone2 2021-10-27 18:40:45 +02:00
NO11 19689dd857 Use enchanted golden apple for thing banner 2021-10-26 16:50:10 +00:00
NO11 b78e7b3e4d Merge branch 'master' into totem_particles 2021-10-26 14:48:07 +00:00
Lizzy Fleckenstein 835076ea4b
Document asset contributions 2021-10-26 14:28:40 +02:00
Lizzy Fleckenstein 797da20fa7
Add script to automatically generate ingame credits from CREDITS.md 2021-10-26 13:08:07 +02:00
Lizzy Fleckenstein c315d155e1
Update CREDITS.md 2021-10-26 12:35:19 +02:00
Lizzy Fleckenstein 0c567c7921
Update maintainer section in CREDITS.md (leave kay27 in, but remove jordan since he never did any maintainance work) 2021-10-26 12:22:21 +02:00
Lizzy Fleckenstein 64ebdd0f18
Update line length in licensing section 2021-10-26 12:16:00 +02:00
Lizzy Fleckenstein 1bd972bff7
Split maintainer responsibilities into list 2021-10-26 12:11:18 +02:00
Lizzy Fleckenstein ea0f52763c
Split developer responsibilities into a list 2021-10-26 12:04:16 +02:00
Lizzy Fleckenstein 70425e9f30
Split profiling section 2021-10-26 11:59:32 +02:00
Lizzy Fleckenstein a0789e72f0
Move licensing down, just before crediting 2021-10-26 11:57:17 +02:00
Lizzy Fleckenstein e341b2a6fe
Split code contributor section 2021-10-26 11:55:08 +02:00
Lizzy Fleckenstein 4e8e6fbb51
Update development target section 2021-10-26 11:42:33 +02:00
Lizzy Fleckenstein efbe3c93b4
Merge branch 'master' into guidelines 2021-10-26 11:37:45 +02:00
Lizzy Fleckenstein 0369465630
Add todoporlalibertad to translation credits 2021-10-25 22:59:21 +02:00
Lizzy Fleckenstein 30f7c638f3
mcl_enchanting: Add spanish translations and update template
Credit to: todoporlalibertad <todoporlalibertad@riseup.net>
Reviewed by j45
2021-10-25 22:55:48 +02:00
NO11 eccba76732 Use math.floor instead of math.round 2021-10-25 20:25:34 +00:00
Lizzy Fleckenstein f3d16d264c
Add notice about Minetest not supporting capital letters in modnames 2021-10-25 20:41:09 +02:00
Lizzy Fleckenstein da5e703675
Clarify that 'make atomic commits' is just an advise 2021-10-25 20:36:29 +02:00
Lizzy Fleckenstein 6466061796
Add back function declaration guideline, provide examples for code style guidelines 2021-10-25 20:33:45 +02:00
Lizzy Fleckenstein a80438d58e
Advice about atomic commits 2021-10-25 20:21:45 +02:00
Lizzy Fleckenstein 47fbb0c176
Mod naming convention, snake case convention 2021-10-25 20:18:03 +02:00
Lizzy Fleckenstein fba30eccd6
Add rule about double quotes for strings 2021-10-25 20:04:51 +02:00
Lizzy Fleckenstein 6e7827902c
Use the wording 'reproduce a problem' in the reporting bugs section 2021-10-25 20:04:08 +02:00
Lizzy Fleckenstein a877c615a5
Clarify tabs usage: Use spaces for alignment 2021-10-25 20:01:12 +02:00
Lizzy Fleckenstein 7f43ba6e36
Clarify rule about merging upstream 2021-10-25 19:56:03 +02:00
Lizzy Fleckenstein 5edf27ac88
Reword 'bug responsibility' section 2021-10-25 19:54:10 +02:00
Lizzy Fleckenstein c998788435
Reword 'help for junior devs' section 2021-10-25 19:48:14 +02:00
Lizzy Fleckenstein 7707c3132c
Fix duplicate and forgotten word in 'helping as a programmer' section 2021-10-25 19:46:13 +02:00
Lizzy Fleckenstein 756d28e2c6
Use iliekprogrammar's wording in the begging rule 2021-10-25 19:31:07 +02:00
Lizzy Fleckenstein 3a422e3afc
Reword 'understandable English' rule 2021-10-25 19:25:48 +02:00
Lizzy Fleckenstein 362de4c920
Add minecraft wiki link 2021-10-25 19:16:24 +02:00
Lizzy Fleckenstein 6580bcab5a
Add info about Minestorm and add links for MCP and Minestorm 2021-10-25 19:15:26 +02:00
Lizzy Fleckenstein a6def5e9bb
Remove guideline about localizing variables 2021-10-25 19:14:53 +02:00
NO11 6d22262c53 Merge branch 'master' into totem_particles 2021-10-25 17:09:24 +00:00
NO11 7489010152 Use particlespawners instead of single particles 2021-10-25 17:08:38 +00:00
Lizzy Fleckenstein d224236388
Consistency about line length (not a convention, just something applied to this file) 2021-10-25 18:58:30 +02:00
Lizzy Fleckenstein 27f35fe422
Add info about discord server in 'Let us know your opinion' section 2021-10-25 18:48:11 +02:00
Lizzy Fleckenstein 4b1606eaee
Update 'git for non-programmers' section 2021-10-25 18:26:31 +02:00
Lizzy Fleckenstein 4776487f83
Merge branch 'guidelines' of https://git.minetest.land/EliasFleckenstein03/MineClone2 into guidelines 2021-10-25 17:21:09 +02:00
Lizzy Fleckenstein 664244d25c
Make sure PRs are tested at least twice before being merged 2021-10-25 17:20:58 +02:00
Lizzy Fleckenstein b9999195ec
Add publishing releases to my responsibility field 2021-10-25 16:52:56 +02:00
Elias Fleckenstein b18e077ba3 Markdown fix to development target info
Signed-off-by: Elias Fleckenstein <eliasfleckenstein03@noreply.git.minetest.land>
2021-10-25 08:47:56 +00:00
Elias Fleckenstein f3693138c8 Use proper English
Signed-off-by: Elias Fleckenstein <eliasfleckenstein03@noreply.git.minetest.land>
2021-10-25 08:46:33 +00:00
Elias Fleckenstein 6e94550a12 Clarification about tab indent
Signed-off-by: Elias Fleckenstein <eliasfleckenstein03@noreply.git.minetest.land>
2021-10-25 08:44:12 +00:00
NO11 d85f143fde Merge pull request 'Add crossbows' (#10) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#10
2021-10-24 19:36:45 +00:00
NO11 dafe860e56 simple totem particles 2021-10-24 19:31:51 +00:00
Lizzy Fleckenstein 832e634e3b
Use tabs instead of spaces, spaces are braindead 2021-10-24 20:44:37 +02:00
Lizzy Fleckenstein 5c55ddff1e
Delete merge artifact 2021-10-24 20:21:54 +02:00
Lizzy Fleckenstein a28bfebb9b
Merge branch 'master' into guidelines 2021-10-24 20:19:04 +02:00
Lizzy Fleckenstein e5c5a78553
Update contribution guidelines 2021-10-24 20:13:34 +02:00
epCode 1c458a2e72 Add crossbows 2021-10-15 12:00:37 -07:00
NO11 94e1d82b45 Merge pull request 'master' (#9) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#9
2021-10-09 21:19:43 +00:00
NO11 9ccf8de606 Fix crash on startup if mcl_playersSleepingPercentage is not defined (#1874) 2021-10-09 14:41:56 +00:00
NO11 19b5a5aac7 Merge pull request 'Add playersSleepingPercentage server setting (Fix #920)' (#1861) from NO11/MineClone2:beds into master
Reviewed-on: MineClone2/MineClone2#1861
2021-10-07 15:14:03 +00:00
NO11 6803d22dbd Merge pull request 'Give players fly priv when creative is enabled' (#1865) from NO11/MineClone2:privs into master
Reviewed-on: MineClone2/MineClone2#1865
2021-10-07 15:13:04 +00:00
NO11 0584d16569 add lightning API support for mobs 2021-10-05 04:15:48 +00:00
NO11 03829dd518 fix typo 2021-10-05 04:15:48 +00:00
NO11 72ea9069bd correct lightning API.md a bit 2021-10-05 04:15:48 +00:00
NO11 9188467a6a add API.md for lightning mod 2021-10-05 04:15:48 +00:00
NO11 fe91d7f3e0 use mcl_util.replace_mob function to simplify dispenser code 2021-10-05 04:15:48 +00:00
NO11 463fe2af5f use mcl_util.replace_mob function to simplify lightning code 2021-10-05 04:15:48 +00:00
NO11 e4af02ea52 Add function to replace mobs 2021-10-05 04:15:48 +00:00
NO11 8e3f9d2169 add basic lightning API 2021-10-05 04:15:48 +00:00
NO11 a410d17306 Fix that all of new players' default_privs are removed 2021-09-30 20:14:13 +00:00
AFCMS e9437e9e1e fix crash then using function in `_mcl_armor_[texture, preview]` tool field 2021-09-29 21:06:51 +02:00
AFCMS e40ed91674 Merge branch 'master' of ssh://git.minetest.land:29418/MineClone2/MineClone2 2021-09-29 19:59:33 +02:00
NO11 16c73c1cb6 Add forgotten `=` 2021-09-28 13:16:19 +00:00
NO11 03be736566 Dont skip night if no players are in bed 2021-09-27 20:13:12 +00:00
NO11 8697b38d60 Remove on_newplayer ... 2021-09-27 20:00:11 +00:00
NO11 e83438e42c Update mcl_bed README.txt 2021-09-21 18:19:07 +00:00
NO11 71f448537c Remove unused setting from settingtypes.txt 2021-09-21 18:14:24 +00:00
NO11 df1d8077e6 Some fixes for mcl_beds
- remove enable_bed_night_skip setting (mcl_playersSleepingPercentage setting can be used to enable disable night skip)
- make it possible to change mcl_playersSleepingPercentage ingame
- fix weird bug which allowed only numbers <= 0
2021-09-21 18:07:36 +00:00
NO11 89e90b13eb Use on_newplayer 2021-09-20 14:16:59 +00:00
AFCMS b0cf07a020 Mise à jour de 'mods/ITEMS/mcl_core/locale/mcl_core.ru.tr' 2021-09-20 07:59:00 +00:00
AFCMS e36a8c5acf Mise à jour de 'mods/ITEMS/mcl_core/locale/mcl_core.pl.tr' 2021-09-20 07:58:25 +00:00
AFCMS b2af00db22 Mise à jour de 'mods/ITEMS/mcl_core/locale/mcl_core.es.tr' 2021-09-20 07:57:04 +00:00
AFCMS e8134345d4 Mise à jour de 'mods/ITEMS/mcl_core/locale/mcl_core.de.tr' 2021-09-20 07:56:25 +00:00
AFCMS e0c7e938de Mise à jour de 'mods/ITEMS/mcl_core/locale/mcl_core.fr.tr' 2021-09-20 07:55:51 +00:00
AFCMS 3e54acce9d fix emerald help text translation 2021-09-20 09:51:37 +02:00
AFCMS 47fff66a41 Merge pull request 'Update description of emerald' (#1866) from ztianyang/MineClone2:emerald-desc into master
Reviewed-on: MineClone2/MineClone2#1866
2021-09-20 07:36:36 +00:00
ztianyang ac8383dd4b Merge branch 'master' into emerald-desc 2021-09-20 01:54:00 +00:00
NO11 c6003398b5 Remove chain armor recipes, because villagers spawn now 2021-09-19 13:14:36 +00:00
NO11 f10d579d9c Only change fly priv on join if it wasn't revoked or granted 2021-09-19 12:07:21 +00:00
NO11 fed43586f2 fix typo 2021-09-19 11:28:07 +00:00
NO11 18a83fa5d7 Fix typo 2021-09-19 11:18:09 +00:00
NO11 0e15accada Enable fly in creative mode 2021-09-19 11:15:19 +00:00
NO11 4194a76db0 Merge pull request 'master' (#8) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#8
2021-09-19 09:15:43 +00:00
Lizzy Fleckenstein 27e4bd6d09 Fix burning entity packet spam
- Use upright_sprite for 3rd person flame display, which is both closer to minecraft and allows for client side texture animation
- Take care of flame HUD in the MineClone2Client
2021-09-18 22:28:20 +02:00
Nils Dagsson Moskopp 256de2bc36 Log warning for non-serializable item entity fix 2021-09-15 18:10:40 +02:00
sfan5 693a5317ef Fix non-serializable item entity unload crash
Some items, like shulkers or books, can have so much metadata that the
corresponding item entity can not be serialized by the Minetest engine.

Without this patch, dropping such an item and then moving away crashes
Minetest, as it can not serialize the entity with serializeString16()
when unloading a map block.

The patch resets the overlong metadata of non-serializable item entities.
This avoids a crash and makes it possible to retrieve a “sanitized” item
without metadata when the mapblock containing the item entity is reloaded.

Originally sfan5 guessed the maximum possible item entity serialization size
that would not lead to a crash as 65530 bytes, but anon5 calculated it to be
actually 65487 bytes. This has been experimentally verified by erlehmann.
2021-09-15 18:10:32 +02:00
Nils Dagsson Moskopp 95c4d6472b Send FOV packets only when necessary
Before this change, about 10 to 30 FOV packets were sent from the server
to each connected client each second. This patch only sends FOV packets
when the FOV actually needs to be changed, i.e. when the player starts
or stops sprinting.
2021-09-15 18:08:58 +02:00
Wuzzy 1c192f4fbb Do not send useless HUDCHANGE packets
Several mods set or unset the visibility of a HUD bar way too often (e.g.
in a globalstep handler), causing the server to send a lot of superfluous
HUDCHANGE packets to each client. Returning from hb.hide_hudbar() early
if HUD bar visibility would not change prevents sending these packets.
2021-09-15 17:47:35 +02:00
NO11 c22c2063ad Merge branch 'master' into beds 2021-09-12 12:53:01 +00:00
NO11 410b7c7844 Update german translation for mcl_beds 2021-09-12 12:52:26 +00:00
NO11 9f9799d96e Update template.txt in mcl_beds 2021-09-12 12:50:54 +00:00
NO11 cd84c472dc Add translation support. 2021-09-12 12:49:39 +00:00
NO11 0bc9ab9233 Add playersSleepingPercentage setting to settingtypes.txt 2021-09-12 12:23:28 +00:00
NO11 89ff666a6a Add playersSleepingPercentage server setting (Fix #920) 2021-09-12 12:21:18 +00:00
NO11 1a5339e907 Only use the shears once in dispenser if there are more mobs in front of the dispenser 2021-09-08 14:22:53 +00:00
NO11 aa930dc2b8 Merge pull request 'Fix strange behaviour when filling end portal with bedrock inside (#1749)' (#1853) from NO11/MineClone2:end_portal into master
Reviewed-on: MineClone2/MineClone2#1853
2021-09-07 18:04:05 +00:00
NO11 79463738f6 Merge pull request 'Make it possible to use shears in the dispenser for mobs (Fix #1233)' (#1854) from NO11/MineClone2:dispenser into master
Reviewed-on: MineClone2/MineClone2#1854
2021-09-07 18:03:19 +00:00
NO11 79d8593d34 Merge pull request 'Destroy objects near cactus faster (make it possible to throw items at a cactus)' (#1856) from NO11/MineClone2:cactus into master
Reviewed-on: MineClone2/MineClone2#1856
2021-09-07 18:00:53 +00:00
NO11 dc8436fdf9 Destroy objects near cactus faster (make it possible to throw items at a cactus) 2021-09-06 14:34:25 +00:00
NO11 f41cea71fd Make it possible to use shears in the dispenser for mobs (Fix #1233) 2021-09-06 13:30:08 +00:00
NO11 5fedd914fb Fix strange behaviour when filling end portal with bedrock inside (#1749) 2021-09-04 19:14:08 +00:00
Elias Fleckenstein a8d09338a9 Merge pull request 'Added spawn egg for killer rabbit' (#1704) from talamh/MineClone2:master into master
Reviewed-on: MineClone2/MineClone2#1704
2021-09-04 10:21:18 +00:00
NO11 872e3e74d3 Merge pull request 'Make cactus mechanisms more MC like (Fix #1741)' (#1851) from NO11/MineClone2:cactus into master
Reviewed-on: MineClone2/MineClone2#1851
2021-09-03 16:20:14 +00:00
NO11 bf62eb33fa Change label of cactus abm 2021-09-03 14:06:21 +00:00
NO11 0da7b3fbda Make cactus mechanisms more MC like (Fix #1741) 2021-09-02 20:38:01 +00:00
Elias Fleckenstein 3669321828 Merge pull request 'Support tables for `_repair_material`' (#1850) from NO11/MineClone2:anvils into master
Reviewed-on: MineClone2/MineClone2#1850
2021-09-01 11:04:46 +00:00
NO11 ca086109bf support tables for `_repair_material` 2021-08-31 21:04:57 +00:00
NO11 6c6d40eb9d Merge pull request 'master' (#7) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#7
2021-08-31 21:02:39 +00:00
NO11 2b322a451f remove space 2021-08-26 10:17:15 +00:00
NO11 f0af15fcd8 Make anvil selection/collision box more MC like 2021-08-26 10:14:57 +00:00
AFCMS af8e88f44c fix error in `mcl_title` documentation 2021-08-24 08:25:42 +02:00
AFCMS 2d1a43396f Merge pull request 'Title HUD API' (#1778) from title-API into master
Reviewed-on: MineClone2/MineClone2#1778
2021-08-20 12:31:54 +00:00
AFCMS df4b8e64cc finish `mcl_title` API + doc 2021-08-19 19:21:33 +02:00
AFCMS 40898d3e9d WIP bold and italic support 2021-08-16 14:19:50 +02:00
AFCMS 58a292a4f3 fix inconsistency 2021-08-16 13:48:08 +02:00
AFCMS fe62189019 Update French translation (part 1) 2021-08-13 11:35:18 +02:00
NO11 4802b610c3 Merge pull request 'Add MC like nodebox for anvils' (#1848) from NO11/MineClone2:anvil_nodebox into master
Reviewed-on: MineClone2/MineClone2#1848
2021-08-11 15:46:57 +00:00
NO11 cb55c36863 Correct the texture of anvils
Because of the new node_nox, the textures have to be a little bit bigger.
2021-08-11 15:44:43 +00:00
NO11 f8dcf05670 Add MC like nodebox for anvils 2021-08-11 15:41:45 +00:00
NO11 7e0bb036f4 Merge pull request 'master' (#5) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#5
2021-08-11 15:38:44 +00:00
NO11 664c238137 Add german translation for the bow/fishing rod desc 2021-08-06 10:52:55 +00:00
Elias Fleckenstein efab5a1cf5 Merge pull request 'Fix warning in `mcl_end`' (#1834) from Emojigit/MineClone2:fork-20210710-fixwarn into master
Reviewed-on: MineClone2/MineClone2#1834
2021-08-06 10:45:33 +00:00
NO11 d76a7daf2d Merge pull request 'Make bows and fishing rods show their durability in description (Fixes issue #1773)' (#1847) from Emily2255/MineClone2:fishingroddurability into master
Reviewed-on: MineClone2/MineClone2#1847
2021-08-06 10:41:34 +00:00
Emily 5bb57a81ad Add durability tooltip to translation template 2021-08-06 11:55:27 +02:00
Emily df0c1f1dd1 Make bows and fishing rods show their durability in description (Fixes issue #1773) 2021-08-06 11:14:17 +02:00
NO11 5c563d6ffd Make eating particles much more MC like! 2021-08-02 12:24:34 +00:00
NO11 4aabd7d9e7 Make size/position of potion HUD more MC like 2021-08-01 12:10:00 +00:00
Elias Fleckenstein 88f253bf66 Merge pull request 'raycast based buckets' (#1811) from buckets into master
Reviewed-on: MineClone2/MineClone2#1811
2021-07-26 16:59:15 +00:00
NO11 289ba826ba Merge pull request 'Fix #1842 (several fixes for `mcl_item_id`)' (#1843) from NO11/MineClone2:item_id_fixes into master
Reviewed-on: MineClone2/MineClone2#1843
2021-07-24 19:15:53 +00:00
NO11 4846076c8f `mcl_item_id` simplify code 2021-07-24 19:07:44 +00:00
NO11 5c5c405ccf Add missing check 2021-07-24 15:19:10 +00:00
NO11 65d33b935a Add API-md for `mcl_item_id` 2021-07-24 14:45:55 +00:00
NO11 c05e57efb1 Fix some crashes with set_mod_namespace and bugs 2021-07-24 14:09:47 +00:00
NO11 e44e9eaf62 Fix typo 2021-07-23 21:35:10 +00:00
NO11 09a68443cd Better fix for #1842 (make other mods not using "mineclone" name space for item ids) 2021-07-23 16:12:43 +00:00
NO11 75b425ffd7 Fix #1842 make other mods not using "mineclone" name space for item ids 2021-07-23 12:23:30 +00:00
NO11 0a9ea7e46a Merge pull request 'master' (#4) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#4
2021-07-23 12:18:22 +00:00
NO11 a44d9643ae Fix several problems in `mcl_item_id` 2021-07-22 19:23:48 +00:00
AFCMS a47630035d Merge branch 'master' of ssh://git.minetest.land:29418/MineClone2/MineClone2 2021-07-22 13:44:14 +02:00
AFCMS 667ef5cad5 cache doc modpath 2021-07-22 00:46:43 +02:00
AFCMS fef23d0b6f fix missing depend to `mcl_credits` of `mcl_portals` 2021-07-22 00:39:05 +02:00
NO11 a0d52010bf Fix that aliases attemp to register mineclone:book_enchanted again and again 2021-07-21 22:16:37 +00:00
AFCMS 44063bca93 Merge branch 'master' into buckets 2021-07-21 18:21:27 +02:00
AFCMS e58bb6d859 Merge branch 'master' into title-API 2021-07-21 18:21:16 +02:00
NO11 31d3ea8a87 Fix #1801 (add better texture for golden boots) 2021-07-20 20:09:43 +00:00
AFCMS 13536baed8 Merge branch 'master' into title-API 2021-07-20 20:47:08 +02:00
AFCMS 6069bb4a38 Merge branch 'master' of ssh://git.minetest.land:29418/MineClone2/MineClone2 2021-07-20 19:26:04 +02:00
AFCMS c31c852a6e add documentation 2021-07-20 16:14:34 +02:00
AFCMS b5f7ae5458 working implementation + support of other mods 2021-07-20 15:47:26 +02:00
AFCMS 9254bab971 Merge branch 'master' into title-API 2021-07-20 15:23:15 +02:00
AFCMS 999b82c94a small documentation graphical improvement 2021-07-20 15:21:07 +02:00
NO11 a83dd8548f Merge pull request 'Add item IDs to the description of items' (#1841) from NO11/MineClone2:item_id into master
Reviewed-on: MineClone2/MineClone2#1841
2021-07-20 11:57:33 +00:00
Tianyang Zhang 559cf85c94 Improve description of emerald 2021-07-19 09:12:39 -07:00
NO11 96e8e6a86f Use mineclone: instead of mineclone2: for item IDs 2021-07-19 12:21:30 +00:00
NO11 801d9a2571 Remove some spaces 2021-07-18 18:01:55 +00:00
NO11 f2a4d6bd56 Add item id setting 2021-07-18 17:23:12 +00:00
NO11 48166625d4 Add mcl_item_id mod 2021-07-18 17:21:53 +00:00
NO11 a2e0cf83bc Merge pull request 'master' (#2) from MineClone2/MineClone2:master into master
Reviewed-on: NO11/MineClone2#2
2021-07-18 17:19:54 +00:00
AFCMS b364faa7c7 make bucket use 5 lenght raycast 2021-07-17 16:22:46 +02:00
Tianyang Zhang 60fcafeee4 Update description of emerald 2021-07-15 19:25:32 -07:00
SmallJoker 9d9e213012 Fix some implicit hard and soft-dependencies
These issues were found while testing minetest#8603 and are caused by relying on the undefined mod loading order
2021-07-16 06:18:54 +04:00
AFCMS 49bde37a5e rewrite README to markdown 2021-07-15 01:03:50 +02:00
AFCMS dc17cc91a3 make raycast start from player head 2021-07-15 00:01:56 +02:00
AFCMS 873a1e73dc fix documentation 2021-07-14 15:22:27 +02:00
AFCMS 8fff20eec9 fix misleading API 2021-07-14 15:18:12 +02:00
AFCMS ec6086d8e6 cleanup 2021-07-14 15:14:23 +02:00
AFCMS 6d7aafe0d4 Revert "more mt like API (improved readability)"
This reverts commit 88e59d3592.
2021-07-14 15:13:40 +02:00
AFCMS 91adfcbb1d Merge branch 'master' into buckets 2021-07-14 15:13:20 +02:00
AFCMS 8958aa7b12 Merge branch 'master' into buckets 2021-07-14 15:12:53 +02:00
AFCMS cf5703d528 fix luacheck warnings 2021-07-14 11:53:37 +02:00
AFCMS 88e59d3592 more mt like API (improved readability) 2021-07-14 11:52:27 +02:00
AFCMS cd08df175c add better documentation 2021-07-14 11:41:09 +02:00
AFCMS ca277b6769 mcl_bucket code refactoring + fix extra_check noot working 2021-07-14 11:29:15 +02:00
AFCMS b0127fc1c3 fix bucket dispense function 2021-07-14 09:18:15 +02:00
AFCMS d26b1b1402 use mcl_util.call_on_rightclick insteed of current implementation 2021-07-14 09:10:01 +02:00
NO11 549bdeb6e9 Remove object:is_player 2021-07-12 21:41:57 +00:00
NO11 ecfb615c89 Merge branch 'master' into totem_particles 2021-07-12 19:02:02 +00:00
NO11 5ceb48fcb1 Faster rgb to hex 2021-07-12 18:05:52 +00:00
1F616EMO d2f7d31360
Fix warning in `mcl_end`
This fixes:
```
2021-07-10 10:00:58: WARNING[Main]: get_mapgen_params is deprecated; use get_mapgen_setting instead (at .../../games/MineClone2/mods/ITEMS/mcl_end/chorus_plant.lua:456)
```
2021-07-10 10:16:55 +08:00
AFCMS 8e931e92f5 refactor mcl_title to be more efficient 2021-07-09 11:34:23 +02:00
AFCMS cbfec5c5c8 Merge branch 'master' into title-API 2021-07-08 22:36:56 +02:00
NO11 509568b4b0 Use real Minecraft colors for totem particles! 2021-07-08 16:49:19 +00:00
NO11 1471521709 Merge branch 'master' into totem_particles 2021-07-07 09:49:33 +00:00
AFCMS 6bef350be4 baisc glass support 2021-06-19 00:58:05 +02:00
AFCMS 2624343c30 Merge branch 'master' into buckets 2021-06-14 14:36:41 +02:00
AFCMS 30e2e0d70a test values 2021-06-14 14:36:17 +02:00
AFCMS 40f4287ff2 new buckets fixes 2021-06-12 12:21:01 +02:00
AFCMS f70dbb8cfa Merge branch 'master' into buckets 2021-06-12 10:12:51 +02:00
NO11 ee2fa60cae local totem particle position 2021-06-09 14:47:42 +00:00
NO11 0795862c5c Merge branch 'master' into totem_particles 2021-06-08 19:00:43 +00:00
NO11 99ccd9ea4c Fix possible crash 2021-06-08 15:13:00 +00:00
AFCMS 2603c4768b mcl_title: basic mc like layout (collide with other mods) 2021-06-07 22:32:05 +02:00
AFCMS c642f9e2f7 Merge branch 'master' into title-API 2021-06-07 20:09:11 +02:00
NO11 1e0ffed26b Merge branch 'master' into totem_particles 2021-06-07 17:16:41 +00:00
NO11 ee21a24fb6 Don't register a separate entity for every particle 2021-06-07 17:13:50 +00:00
AFCMS 881f0b0a71 Merge branch 'master' into title-API 2021-06-04 19:10:52 +02:00
AFCMS a21b14e707 Merge branch 'master' into title-API 2021-06-02 17:59:05 +02:00
AFCMS b9fd1ac227 credit digminecraft for the tutorial 2021-06-02 11:12:15 +02:00
AFCMS 7e64470f70 fix future API usage of bold+italic pr 2021-06-02 11:07:31 +02:00
AFCMS c8102838cb add missing TODO entry (bold+italic) 2021-06-02 00:26:10 +02:00
AFCMS 6b53dda79b add todo list 2021-06-02 00:25:15 +02:00
AFCMS 640b0dc485 basic title API working (testing needed) 2021-06-02 00:23:11 +02:00
NO11 75e263debc Add code for totem partciles 2021-05-29 19:24:16 +00:00
NO11 a65db15b5c Totem particle textures 2021-05-29 19:21:15 +00:00
AFCMS 0119793d7a Merge branch 'master' into buckets 2021-05-27 09:10:35 +02:00
AFCMS 91ac70cf28 Merge branch 'master' into buckets 2021-05-23 16:22:53 +02:00
AFCMS 17202115fa cache general functions 2021-05-22 18:58:58 +02:00
AFCMS 5d65c8a3aa Working empty bucket 2021-05-22 18:57:51 +02:00
AFCMS e9f38c6b90 WIP raycast base buckets 2021-05-22 10:47:28 +02:00
talamh 2c434495c1 Merge branch 'master' into master 2021-05-03 23:46:44 +00:00
talamh e6b61a1551 Update 'mods/ENTITIES/mobs_mc/rabbit.lua' 2021-05-02 02:00:21 +00:00
talamh f1229c5401 Added spawn egg for killer rabbitt 2021-05-02 01:58:40 +00:00
194 changed files with 6341 additions and 2537 deletions

128
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
eliasfleckenstein@web.de.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@ -1,105 +1,414 @@
# Contributing to MineClone 2
So you want to contribute to MineClone 2?
# Contributing to MineClone2
So you want to contribute to MineClone2?
Wow, thank you! :-)
But first, some things to note:
MineClone2 is maintained by Nicu and Fleckenstein. If you have any
problems or questions, contact us (See Links section below).
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 ***.
You can help with MineClone2's development in many different ways,
whether you're a programmer or not.
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 #mineclone2
channel on irc.freenode.net. And finally, you can send e-mails to
<eliasfleckenstein@web.de> or <kay27@bk.ru>.
## MineClone2's development target is to...
- Crucially, create a stable, moddable, free/libre clone of Minecraft
based on the Minetest engine with polished features, usable in both
singleplayer and multiplayer. Currently, most of **Minecraft Java
Edition 1.12.2** features are already implemented and polishing existing
features are prioritized over new feature requests.
- With lessened priority yet strictly, implement features targetting
**Minecraft version 1.17 + OptiFine** (OptiFine only as far as supported
by the Minetest Engine). This means features in parity with the listed
Minecraft experiences are prioritized over those that don't fulfill this
scope.
- Optionally, create a performant experience that will run relatively
well on really low spec computers. Unfortunately, due to Minecraft's
mechanisms and Minetest engine's limitations along with a very small
playerbase on low spec computers, optimizations are hard to investigate.
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
means they will become part of a free software.
## Links
* [Mesehub](https://git.minetest.land/MineClone2/MineClone2)
* [Discord](https://discord.gg/xE4z8EEpDC)
* [YouTube](https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A)
* [IRC](https://web.libera.chat/#mineclone2)
* [Matrix](https://app.element.io/#/room/#mc2:matrix.org)
* [Reddit](https://www.reddit.com/r/MineClone2/)
* [Minetest forums](https://forum.minetest.net/viewtopic.php?f=50&t=16407)
* [ContentDB](https://content.minetest.net/packages/wuzzy/mineclone2/)
* [OpenCollective](https://opencollective.com/mineclone2)
## The suggested workflow
We don't **dictate** your workflow, but in order to work with us in an efficient
way, you can follow these suggestions:
## Using git
MineClone2 is developed using the version control system
[git](https://git-scm.com/). If you want to contribute code to the
project, it is **highly recommended** that you learn the git basics.
For non-programmers and people who do not plan to contribute code to
MineClone2, git is not required. However, git is a tool that will be
referenced frequently because of its usefulness. As such, it is valuable
in learning how git works and its terminology. It can also help you
keeping your game updated, and easily test pull requests.
For small and medium changes:
## How you can help as a non-programmer
* Fork the repository
As someone who does not know how to write programs in Lua or does not
know how to use the Minetest API, you can still help us out a lot. For
example, by opening an issue in the
[Issue tracker](https://git.minetest.land/MineClone2/MineClone2/issues),
you can report a bug or request a feature.
### Rules about both bugs and feature requests
* Stay polite towards the developers and anyone else involved in the
discussion.
* Choose a descriptive title (e.g. not just "crash", "bug" or "question"
).
* Please write in plain, understandable English. It will be easier to
communicate.
* Please start the issue title with a capital letter.
* Always check the currently opened issues before creating a new one.
Don't report bugs that have already been reported or request features
that already have been requested.
* If you know about Minetest's inner workings, please think about
whether the bug / the feature that you are reporting / requesting is
actually an issue with Minetest itself, and if it is, head to the
[Minetest issue tracker](https://github.com/minetest/minetest/issues)
instead.
* If you need any help regarding creating a Mesehub account or opening
an issue, feel free to ask on the Discord / Matrix server or the IRC
channel.
### Reporting bugs
* A bug is an unintended behavior or, in the worst case, a crash.
However, it is not a bug if you believe something is missing in the
game. In this case, please read "Requesting features"
* If you report a crash, always include the error message. If you play
in singleplayer, post a screenshot of the message that Minetest showed
when the crash happened (or copy the message into your issue). If you
are a server admin, you can find error messages in the log file of the
server.
* Tell us which MineClone2 and Minetest versions you are using.
* Tell us how to reproduce the problem: What you were doing to trigger
the bug, e.g. before the crash happened or what causes the faulty
behavior.
### Requesting features
* Ensure the requested feature fulfills our development targets and
goals.
* Begging or excessive attention seeking does not help us in the
slightest, and may very well disrupt MineClone2 development. It's better
to put that energy into helping or researching the feature in question.
After all, we're just volunteers working on our spare time.
* Ensure the requested feature has not been implemented in MineClone2
latest or development versions.
### Testing code
If you want to help us with speeding up MineClone2 development and
making the game more stable, a great way to do that is by testing out
new features from contributors. For most new things that get into the
game, a pull request is created. A pull request is essentially a
programmer saying "Look, I modified the game, please apply my changes
to the upstream version of the game". However, every programmer makes
mistakes sometimes, some of which are hard to spot. You can help by
downloading this modified version of the game and trying it out - then
tell us if the code works as expected without any issues. Ideally, you
would report issues will pull requests similar to when you were
reporting bugs that are the mainline (See Reporting bugs section). You
can find currently open pull requests here:
<https://git.minetest.land/MineClone2/MineClone2/pulls>. Note that pull
requests that start with a `WIP:` are not done yet, and therefore might
not work, so it's not very useful to try them out yet.
### Contributing assets
Due to license problems, MineClone2 unfortunately cannot use
Minecraft's assets, therefore we are always looking for asset
contributions. To contribute assets, it can be useful to learn git
basics and read the section for Programmers of this document, however
this is not required. It's also a good idea to join the Discord server
(or alternatively IRC or Matrix).
#### Textures
For textures we use the Pixel Perfection texture pack. This is mostly
enough; however in some cases - e.g. for newer Minecraft features, it's
useful to have texture artists around. If you want to make such
contributions, join our Discord server. Demands for textures will be
communicated there.
#### Sounds
MineClone2 currently does not have a consistent way to handle sounds.
The sounds in the game come from different sources, like the SnowZone
resource pack or minetest_game. Unfortunately, MineClone2 does not play
a sound in every situation you would get one in Minecraft. Any help with
sounds is greatly appreciated, however if you add new sounds you should
probably work together with a programmer, to write the code to actually
play these sounds in game.
#### 3D Models
Most of the 3D Models in MineClone2 come from
[22i's repository](https://github.com/22i/minecraft-voxel-blender-models).
Similar to the textures, we need people that can make 3D Models with
Blender on demand. Many of the models have to be patched, some new
animations have to be added etc.
#### Crediting
Asset contributions will be credited in their own respective sections in
CREDITS.md. If you have commited the results yourself, you will also be
credited in the Contributors section.
### Contributing Translations
#### Workflow
To add/update support for your language to MineClone2, you should take
the steps documented in the section for Programmers, add/update the
translation files of the mods that you want to update. You can add
support for all mods, just some of them or only one mod; you can update
the translation file entirely or only partly; basically any effort is
valued. If your changes are small, you can also send them to developers
via E-Mail, Discord, IRC or Matrix - they will credit you appropriately.
#### Things to note
You can use the script at `tools/check_translate_files.py` to compare
the translation files for the language you are working on with the
template files, to see what is missing and what is out of date with
the template file. However, template files are often incomplete and/or
out of date, sometimes they don't match the code. You can update the
translation files if that is required, you can also modify the code in
your translation PR if it's related to translation. You can also work on
multiple languages at the same time in one PR.
#### Crediting
Translation contributions will be credited in their own in CREDITS.md.
If you have commited the results yourself, you will also be credited in
the Contributors section.
### Profiling
If you own a server, a great way to help us improve MineClone2's code
is by giving us profiler results. Profiler results give us detailed
information about the game's performance and let us know places to
investigate optimization issues. This way we can make the game faster.
#### Using Minetest's profiler
Minetest has a built in profiler. Simply set `profiler.load = true` in
your configuration file and restart the server. After running the server
for some time, just run `/profiler save` in chat - then you will find a
file in the world directory containing the results. Open a new issue and
upload the file. You can name the issue "<Server name> profiler
results".
### Let us know your opinion
It is always encouraged to actively contribute to issue discussions on
MeseHub, let us know what you think about a topic and help us make
decisions. Also, note that a lot of discussion takes place on the
Discord server, so it's definitely worth checking it out.
### Funding
You can help pay for our infrastructure (Mesehub) by donating to our
OpenCollective link (See Links section).
### Crediting
If you opened or have contributed to an issue, you receive the
`Community` role on our Discord (after asking for it).
OpenCollective Funders are credited in their own section in
`CREDITS.md` and receive a special role "Funder" on our discord (unless
they have made their donation Incognito).
## How you can help as a programmer
(Almost) all the MineClone2 development is done using pull requests.
### Recommended workflow
* Fork the repository (in case you have not already)
* Do your change in a new branch
* Create a pull request to get your changes merged into master
* Keep your pull request up to date by regularly merging upstream. It is
imperative that conflicts are resolved prior to merging the pull
request.
* After the pull request got merged, you can delete the branch
For small changes, sending us a patch is also good.
### Discuss first
If you feel like a problem needs to fixed or you want to make a new
feature, you could start writing the code right away and notifying us
when you're done, but it never hurts to discuss things first. If there
is no issue on the topic, open one. If there is an issue, tell us that
you'd like to take care of it, to avoid duplicate work.
For big changes: Same as above, but consider notifying us first to avoid
duplicate work and possible tears of rejection. ;-)
### Don't hesitate to ask for help
We appreciate any contributing effort to MineClone2. If you are a
relatively new programmer, you can reach us on Discord, Matrix or IRC
for questions about git, Lua, Minetest API, MineClone2 codebase or
anything related to MineClone2. We can help you avoid writing code that
would be deemed inadequate, or help you become familiar with MineClone2
better, or assist you use development tools.
For trusted people, we might give them direct commit access to this
repository. In this case, you obviously don't need to fork, but you still
need to show your contributions align with the project goals. We still
reserve the right to revert everything that we don't like.
For bigger changes, we strongly recommend to use feature branches and
discuss with me first.
### Maintain your own code, even if already got merged
Sometimes, your code may cause crashes or bugs - we try to avoid such
scenarios by testing every time before merging it, but if your merged
work causes problems, we ask you fix the issues as soon as possible.
If your code causes bugs and crashes, it is your responsibility to fix them as soon as possible.
### Changing Gameplay
Pull Requests that change gameplay have to be properly researched and
need to state their sources. These PRs also need Fleckenstein's approval
before they are merged.
You can use these sources:
We mostly use plain merging rather than rebasing or squash merging.
* Minecraft code (Name the source file and line, however DONT post any
proprietary code). You can use
[MCP](https://minecraft.fandom.com/wiki/Programs_and_editors/Mod_Coder_Pack)
to decompile Minecraft or look at
[Minestorm](https://github.com/Minestom/Minestom) code.
* Testing things inside of Minecraft (Attach screenshots / video footage
of the results)
* [Official Minecraft Wiki](https://minecraft.fandom.com/wiki/Minecraft_Wiki)
(Include a link to the specific page you used)
Your commit names should be relatively descriptive, e.g. when saying "Fix #issueid", the commit message should also contain the title of the issue.
### Stick to our guidelines
Contributors will be credited in `CREDITS.md`.
#### Git Guidelines
* We use merge rather than rebase or squash merge
* We don't use git submodules.
* Your commit names should be relatively descriptive, e.g. when saying
"Fix #issueid", the commit message should also contain the title of the
issue.
* Try to keep your commits as atomic as possible (advise, but completely
optional)
## Code Style
#### Code Guidelines
* Each mod must provide `mod.conf`.
* Mod names are snake case, and newly added mods start with `mcl_`, e.g.
`mcl_core`, `mcl_farming`, `mcl_monster_eggs`. Keep in mind Minetest
does not support capital letters in mod names.
* To export functions, store them inside a global table named like the
mod, e.g.
Each mod must provide `mod.conf`.
Each mod which add API functions should store functions inside a global table named like the mod.
Public functions should not use self references but rather just access the table directly.
Functions should be defined in this way:
```
function mcl_xyz.stuff(param) end
```
Insteed of this way:
```
mcl_xyz.stuff = function(param) end
```
Indentation must be unified, more likely with tabs.
```lua
mcl_example = {}
function mcl_example.do_something()
-- ...
end
Time sensitive mods should make a local copy of most used API functions to improve performances.
```
local vector = vector
local get_node = minetest.get_node
```
* Public functions should not use self references but rather just access
the table directly, e.g.
## Features > 1.12
```lua
-- bad
function mcl_example:do_something()
end
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.
-- good
function mcl_example.do_something()
end
```
## What we accept
* Use modern Minetest API, e.g. no usage of `minetest.env`
* Tabs should be used for indent, spaces for alignment, e.g.
* 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.
```lua
## What we reject
-- use tabs for indent
* 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.
for i = 1, 10 do
if i % 3 == 0 then
print(i)
end
end
## Reporting bugs
Report all bugs and missing Minecraft features here:
-- use tabs for indent and spaces to align things
<https://git.minetest.land/MineClone2/MineClone2/issues>
some_table = {
{"a string", 5},
{"a very much longer string", 10},
}
```
## Direct discussion
We have an IRC channel! Join us on #mineclone2 in freenode.net.
* Use double quotes for strings, e.g. `"asdf"` rather than `'asdf'`
* Use snake_case rather than CamelCase, e.g. `my_function` rather than
`MyFunction`
* Don't declare functions as an assignment, e.g.
<ircs://irc.freenode.net:6697/#mineclone2>
```lua
-- bad
local some_local_func = function()
-- ...
end
## Creating releases
my_mod.some_func = function()
-- ...
end
-- good
local function some_local_func()
-- ...
end
function my_mod.some_func()
-- ...
end
```
### Developer status
Active and trusted contributors are often granted write access to the
MineClone2 repository.
#### Developer responsibilities
- You should not push things directly to
MineClone2 master - rather, do your work on a branch on your private
repository, then create a pull request. This way other people can review
your changes and make sure they work before they get merged.
- Merge PRs only when they have recieved the necessary feedback and have
been tested by at least two different people (including the author of
the pull request), to avoid crashes or the introduction of new bugs.
- You may also be assigned to issues or pull
requests as a developer. In this case it is your responsibility to fix
the issue / review and merge the pull request when it is ready. You can
also unassign yourself from the issue / PR if you have no time or don't
want to take care of it for some other reason. After all, everyone is a
volunteer and we can't expect you to do work that you are not interested
in. **The important thing is that you make sure to inform us if you
won't take care of something that has been assigned to you.**
- Please assign yourself to something that you want to work on to avoid
duplicate work.
- As a developer, it should be easy to reach you about your work. You
should be in at least one of the public MineClone2 discussion rooms -
preferrably Discord, but if you really don't like Discord, Matrix
or IRC are fine too.
### Maintainer status
Maintainers carry the main responsibility for the project.
#### Maintainer responsibilities
- Making sure issues are addressed and pull requests are reviewed and
merged, by assigning either themselves or Developers to issues / PRs
- Making releases
- Making sure guidelines are kept
- Making project decisions based on community feedback
- Granting/revoking developer access
- Enforcing the code of conduct (See CODE_OF_CONDUCT.md)
- Moderating official community spaces (See Links section)
- Resolving conflicts and problems within the community
#### Current maintainers
* Fleckenstein - responsible for gameplay review, publishing releases,
technical guidelines and issue/PR delegation
* Nicu - responsible for community related issues
#### Release process
* Run `tools/generate_ingame_credits.lua` to update the ingame credits
from `CREDITS.md` and commit the result (if anything changed)
* Launch MineClone2 to make sure it still runs
* Update the version number in README.md
* Use `git tag <version number>` to tag the latest commit with the version number
* Push to repo (don't forget `--tags`!)
* Update ContentDB (https://content.minetest.net/packages/Wuzzy/mineclone2/)
* Update first post in forum thread (https://forum.minetest.net/viewtopic.php?f=50&t=16407)
* Use `git tag <version number>` to tag the latest commit with the
version number
* Push to repository (don't forget `--tags`!)
* Update ContentDB
(https://content.minetest.net/packages/Wuzzy/mineclone2/)
* Update first post in forum thread
(https://forum.minetest.net/viewtopic.php?f=50&t=16407)
* Post release announcement and changelog in forums
### Licensing
By asking us to include your changes in this game, you agree that they
fall under the terms of the GPLv3, which basically means they will
become part of a free/libre software.
### Crediting
Contributors, Developers and Maintainers will be credited in
`CREDITS.md`. If you make your first time contribution, please add
yourself to this file. There are also Discord roles for Contributors,
Developers and Maintainers.

View File

@ -8,8 +8,8 @@
## Maintainers
* Fleckenstein
* Nicu
* kay27
* jordan4ibanez
## Developers
* bzoss
@ -19,10 +19,11 @@
* iliekprogrammar
* MysticTempest
* Rootyjr
* Nicu
* aligator
* Code-Sploit
* NO11
* cora
* jordan4ibanez
## Contributors
* Laurent Rocher
@ -48,8 +49,25 @@
* dBeans
* nickolas360
* yutyo
* ztianyang
* Tianyang Zhang
* j45
* Marcin Serwin
* erlehmann
* E
* Benjamin Schötz
* Doloment
* Sydney Gems
* talamh
* Emily2255
* Emojigit
* FinishedFragment
* sfan5
* Blue Blancmange
* Jared Moody
* SmallJoker
* Sven792
* aldum
* Dieter44
## MineClone5
* kay27
@ -74,7 +92,6 @@
* Rochambeau
* rubenwardy
* stu
* jordan4ibanez
* 4aiman
* Kahrl
* Krock
@ -103,6 +120,7 @@
* xMrVizzy
* yutyo
* NO11
* kay27
## Translations
* Wuzzy
@ -110,6 +128,11 @@
* wuniversales
* kay27
* pitchum
* todoporlalibertad
* Marcin Serwin
## Funders
* 40W
## Special thanks
* celeron55 for creating Minetest

View File

@ -1,4 +1,4 @@
# MineClone 2
# MineClone2
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB.
@ -69,9 +69,9 @@ an explanation.
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
are officially supported.
There is no support for running MineClone 2 in development versions of Minetest.
There is no support for running MineClone2 in development versions of Minetest.
To install MineClone 2 (if you haven't already), move this directory into the
To install MineClone2 (if you haven't already), move this directory into the
“games” directory of your Minetest data directory. Consult the help of
Minetest to learn more.
@ -85,21 +85,24 @@ The MineClone2 repository is hosted at Mesehub. To contribute or report issues,
* Matrix: <https://app.element.io/#/room/#mc2:matrix.org>
* Reddit: <https://www.reddit.com/r/MineClone2/>
* Minetest forums: <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
* ContentDB: <https://content.minetest.net/packages/wuzzy/mineclone2/>
* OpenCollective: <https://opencollective.com/mineclone2>
## Project description
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”)
* MineClone2 also includes Optifine features supported by the Minetest
* In general, Minecraft is aimed to be cloned as good as possible
* Cloning the gameplay has highest priority
* MineClone 2 will use different assets, but with a similar style
* Limitations found in Minetest will be documented 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
## Target
- Crucially, create a stable, moddable, free/libre clone of Minecraft
based on the Minetest engine with polished features, usable in both
singleplayer and multiplayer. Currently, most of **Minecraft Java
Edition 1.12.2** features are already implemented and polishing existing
features are prioritized over new feature requests.
- With lessened priority yet strictly, implement features targetting
**Minecraft version 1.17 + OptiFine** (OptiFine only as far as supported
by the Minetest Engine). This means features in parity with the listed
Minecraft experiences are prioritized over those that don't fulfill this
scope.
- Optionally, create a performant experience that will run relatively
well on really low spec computers. Unfortunately, due to Minecraft's
mechanisms and Minetest engine's limitations along with a very small
playerbase on low spec computers, optimizations are hard to investigate.
## Completion status
This game is currently in **beta** stage.
@ -186,7 +189,7 @@ Technical differences from Minecraft:
* Different engine (Minetest)
* Different easter eggs
… and finally, MineClone 2 is free software (“free” as in “freedom”)!
… and finally, MineClone2 is free software (“free” as in “freedom”)!
## Other readme files

BIN
menu/Logo.blend Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 547 KiB

BIN
menu/icon_small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

View File

@ -58,26 +58,27 @@ function mcl_loot.get_loot(loot_definitions, pr)
end
if item then
local itemstring = item.itemstring
local itemstack = item.itemstack
if itemstring then
local stack = ItemStack(itemstring)
if item.amount_min and item.amount_max then
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max)
stack:set_count(pr:next(item.amount_min, item.amount_max))
end
if item.wear_min and item.wear_max then
-- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10
local wear_min = math.floor(item.wear_min / 10)
local wear_max = math.floor(item.wear_max / 10)
local wear = pr:next(wear_min, wear_max) * 10
if not item.amount_min and not item.amount_max then
itemstring = itemstring .. " 1"
end
itemstring = itemstring .. " " .. tostring(wear)
stack:set_wear(pr:next(wear_min, wear_max) * 10)
end
table.insert(items, itemstring)
elseif itemstack then
table.insert(items, itemstack)
if item.func then
item.func(stack, pr)
end
table.insert(items, stack)
else
minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!")
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

View File

@ -1,5 +1,27 @@
mcl_util = {}
-- Updates all values in t using values from to*.
function table.update(t, ...)
for _, to in ipairs{...} do
for k,v in pairs(to) do
t[k] = v
end
end
return t
end
-- Updates nil values in t using values from to*.
function table.update_nil(t, ...)
for _, to in ipairs{...} do
for k,v in pairs(to) do
if t[k] == nil then
t[k] = v
end
end
end
return t
end
-- Based on minetest.rotate_and_place
--[[
@ -456,7 +478,9 @@ function mcl_util.calculate_durability(itemstack)
end
end
end
uses = uses or (next(itemstack:get_tool_capabilities().groupcaps) or {}).uses
local _, groupcap = next(itemstack:get_tool_capabilities().groupcaps)
uses = uses or (groupcap or {}).uses
end
return uses or 0
@ -538,3 +562,12 @@ function mcl_util.get_object_name(object)
return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name
end
end
function mcl_util.replace_mob(obj, mob)
local rot = obj:get_yaw()
local pos = obj:get_pos()
obj:remove()
obj = minetest.add_entity(pos, mob)
obj:set_yaw(rot)
return obj
end

View File

@ -12,7 +12,7 @@ Params:
* pos: position
## mcl_worlds.y_to_layer(y)
## 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:
@ -78,4 +78,4 @@ Table containing all function registered with mcl_worlds.register_on_dimension_c
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")
* dimension: string, new dimension ("overworld", "nether", "end", "void")

View File

@ -38,18 +38,32 @@ 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)
.. string.char(10) -- image type (RLE RGB = 10)
self:encode_colormap_spec() -- color map specification
self:encode_image_spec() -- image specification
end
function image:encode_data()
local current_pixel = ''
local previous_pixel = ''
local count = 1
local packets = {}
local rle_packet = ''
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])
current_pixel = string.char(pixel[3], pixel[2], pixel[1])
if current_pixel ~= previous_pixel or count == 128 then
packets[#packets +1] = rle_packet
count = 1
previous_pixel = current_pixel
else
count = count + 1
end
rle_packet = string.char(128 + count - 1) .. current_pixel
end
end
packets[#packets +1] = rle_packet
self.data = self.data .. table.concat(packets)
end
function image:encode_footer()

View File

@ -1,114 +0,0 @@
--Dripping Water Mod
--by kddekadenz
local math = math
-- License of code, textures & sounds: CC0
--Drop entities
--water
local water_tex = "default_water_source_animated.png^[verticalframe:16:0"
minetest.register_entity("drippingwater:drop_water", {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.025,-0.05,-0.025,0.025,-0.01,0.025},
pointable = false,
visual = "cube",
visual_size = {x=0.05, y=0.1},
textures = {water_tex, water_tex, water_tex, water_tex, water_tex, water_tex},
spritediv = {x=1, y=1},
initial_sprite_basepos = {x=0, y=0},
static_save = false,
on_activate = function(self, staticdata)
self.object:set_sprite({x=0,y=0}, 1, 1, true)
end,
on_step = function(self, dtime)
local k = math.random(1,222)
local ownpos = self.object:get_pos()
if k==1 then
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
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
self.object:remove()
minetest.sound_play({name="drippingwater_drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end
end,
})
--lava
local lava_tex = "default_lava_source_animated.png^[verticalframe:16:0"
minetest.register_entity("drippingwater:drop_lava", {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.025,-0.05,-0.025,0.025,-0.01,0.025},
glow = math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3),
pointable = false,
visual = "cube",
visual_size = {x=0.05, y=0.1},
textures = {lava_tex, lava_tex, lava_tex, lava_tex, lava_tex, lava_tex},
spritediv = {x=1, y=1},
initial_sprite_basepos = {x=0, y=0},
static_save = false,
on_activate = function(self, staticdata)
self.object:set_sprite({x=0,y=0}, 1, 0, true)
end,
on_step = function(self, dtime)
local k = math.random(1,222)
local ownpos = self.object:get_pos()
if k == 1 then
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
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
self.object:remove()
minetest.sound_play({name="drippingwater_lavadrip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end
end,
})
--Create drop
minetest.register_abm({
label = "Create water drops",
nodenames = {"group:opaque", "group:leaves"},
neighbors = {"group:water"},
interval = 2,
chance = 22,
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 minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
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")
end
end,
})
--Create lava drop
minetest.register_abm({
label = "Create lava drops",
nodenames = {"group:opaque"},
neighbors = {"group:lava"},
interval = 2,
chance = 22,
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 minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}).name == "air" then
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")
end
end,
})

View File

@ -84,7 +84,7 @@ local function attach_object(self, obj)
end
end, name)
obj:set_look_horizontal(yaw)
mcl_tmp_message.message(obj, S("Sneak to dismount"))
mcl_title.set(obj, "actionbar", {text=S("Sneak to dismount"), color="white", stay=60})
else
obj:get_luaentity()._old_visual_size = visual_size
end
@ -115,7 +115,7 @@ local boat = {
collisionbox = {-0.5, -0.35, -0.5, 0.5, 0.3, 0.5},
visual = "mesh",
mesh = "mcl_boats_boat.b3d",
textures = {"mcl_boats_texture_oak_boat.png"},
textures = {"mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png", "mcl_boats_texture_oak_boat.png"},
visual_size = boat_visual_size,
hp_max = boat_max_hp,
damage_texture_modifier = "^[colorize:white:0",
@ -148,6 +148,11 @@ function boat.on_activate(self, staticdata, dtime_s)
self._v = data.v
self._last_v = self._v
self._itemstring = data.itemstring
while #data.textures < 5 do
table.insert(data.textures, data.textures[1])
end
self.object:set_properties({textures = data.textures})
end
end
@ -337,7 +342,8 @@ function boat.on_step(self, dtime, moveresult)
self.object:get_velocity().y)
else
p.y = p.y + 1
if is_water(p) then
local is_obsidian_boat = self.object:get_luaentity()._itemstring == "mcl_boats:boat_obsidian"
if is_water(p) or is_obsidian_boat then
-- Inside water: Slowly sink
local y = self.object:get_velocity().y
y = y - 0.01
@ -377,13 +383,13 @@ end
-- Register one entity for all boat types
minetest.register_entity("mcl_boats:boat", boat)
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak" }
local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat") }
local boat_ids = { "boat", "boat_spruce", "boat_birch", "boat_jungle", "boat_acacia", "boat_dark_oak", "boat_obsidian" }
local names = { S("Oak Boat"), S("Spruce Boat"), S("Birch Boat"), S("Jungle Boat"), S("Acacia Boat"), S("Dark Oak Boat"), S("Obsidian Boat") }
local craftstuffs = {}
if minetest.get_modpath("mcl_core") then
craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood" }
craftstuffs = { "mcl_core:wood", "mcl_core:sprucewood", "mcl_core:birchwood", "mcl_core:junglewood", "mcl_core:acaciawood", "mcl_core:darkwood", "mcl_core:obsidian" }
end
local images = { "oak", "spruce", "birch", "jungle", "acacia", "dark_oak" }
local images = { "oak", "spruce", "birch", "jungle", "acacia", "dark_oak", "obsidian" }
for b=1, #boat_ids do
local itemstring = "mcl_boats:"..boat_ids[b]
@ -434,8 +440,9 @@ for b=1, #boat_ids do
pos = vector.add(pos, vector.multiply(dir, boat_y_offset_ground))
end
local boat = minetest.add_entity(pos, "mcl_boats:boat")
local texture = "mcl_boats_texture_"..images[b].."_boat.png"
boat:get_luaentity()._itemstring = itemstring
boat:set_properties({textures = { "mcl_boats_texture_"..images[b].."_boat.png" }})
boat:set_properties({textures = { texture, texture, texture, texture, texture }})
boat:set_yaw(placer:get_look_horizontal())
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()

View File

@ -6,6 +6,7 @@ Boats are used to travel on the surface of water.=Les bateaux sont utilisés pou
Dark Oak Boat=Bateau en Chêne Noir
Jungle Boat=Bateau en Acajou
Oak Boat=Bateau en Chêne
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.=Faites un clic droit sur une source d'eau pour placer le bateau. Faites un clic droit sur le bateau pour y entrer. Utilisez [Gauche] et [Droite] pour diriger, [Avant] pour accélérer et [Arrière] pour ralentir ou reculer. Cliquez de nouveau avec le bouton droit sur le bateau pour le quitter, frappez le bateau pour le faire tomber en tant qu'objet.
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.=Faites un clic droit sur une source d'eau pour placer le bateau. Faites un clic droit sur le bateau pour y entrer. Utilisez [Gauche] et [Droite] pour diriger, [Avant] pour accélérer et [Arrière] pour ralentir ou reculer. Utilisez [Sneak] pour le quitter, frappez le bateau pour le faire tomber en tant qu'objet.
Spruce Boat=Bateau en Sapin
Water vehicle=Véhicule aquatique
Water vehicle=Véhicule aquatique
Sneak to dismount=

View File

@ -1,7 +1,7 @@
name = mcl_boats
author = PilzAdam
description = Adds drivable boats.
depends = mcl_player, flowlib
depends = mcl_player, flowlib, mcl_title
optional_depends = mcl_core, doc_identifier

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

View File

@ -67,14 +67,9 @@ function mcl_burning.set_on_fire(obj, burn_time)
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,
})
if obj:is_player() then
mcl_burning.channels[obj]:send_all(tostring(mcl_burning.animation_frames))
mcl_burning.channels[obj]:send_all("start")
end
storage.burn_time = burn_time
storage.fire_damage_timer = 0
@ -95,7 +90,6 @@ function mcl_burning.set_on_fire(obj, burn_time)
fire_entity:set_properties({visual_size = size})
fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 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()
@ -111,9 +105,7 @@ function mcl_burning.extinguish(obj)
if mcl_burning.is_burning(obj) then
local storage = mcl_burning.get_storage(obj)
if obj:is_player() then
if storage.fire_hud_id then
obj:hud_remove(storage.fire_hud_id)
end
mcl_burning.channels[obj]:send_all("stop")
mcl_burning.storage[obj] = {}
else
storage.burn_time = nil
@ -143,4 +135,4 @@ function mcl_burning.tick(obj, dtime, storage)
end
end
end
end
end

View File

@ -7,6 +7,7 @@ local get_item_group = minetest.get_item_group
mcl_burning = {
storage = {},
channels = {},
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
}
@ -43,23 +44,22 @@ 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)
function mcl_burning.init_player(player)
local meta = player:get_meta()
-- NOTE: mcl_burning:data may be "return nil" (which deserialize into nil) for reasons unknown.
if meta:get_string("mcl_burning:data"):find("return nil", 1, true) then
minetest.log("warning", "[mcl_burning] 'mcl_burning:data' player meta field is invalid! Please report this bug")
end
mcl_burning.storage[player] = meta:contains("mcl_burning:data") and minetest.deserialize(meta:get_string("mcl_burning:data")) or {}
mcl_burning.channels[player] = minetest.mod_channel_join("mcl_burning:" .. player:get_player_name())
end
mcl_burning.storage[player] = storage
minetest.register_on_joinplayer(function(player)
mcl_burning.init_player(player)
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))
player:get_meta():set_string("mcl_burning:data", minetest.serialize(mcl_burning.storage[player]))
mcl_burning.storage[player] = nil
end)
@ -68,27 +68,28 @@ minetest.register_entity("mcl_burning:fire", {
initial_properties = {
physical = false,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "cube",
visual = "upright_sprite",
textures = {
name = "mcl_burning_entity_flame_animated.png",
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0,
},
},
spritediv = {x = 1, y = mcl_burning.animation_frames},
pointable = false,
glow = -1,
backface_culling = false,
},
animation_frame = 0,
animation_timer = 0,
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
on_activate = function(self)
self.object:set_sprite({x = 0, y = 0}, mcl_burning.animation_frames, 1.0 / mcl_burning.animation_frames)
end,
on_step = function(self)
if not self:sanity_check() then
self.object:remove()
end
end,
@ -96,23 +97,15 @@ minetest.register_entity("mcl_burning:fire", {
local parent = self.object:get_attach()
if not parent then
return
return false
end
local storage = mcl_burning.get_storage(parent)
if not storage or not storage.burn_time then
return
return false
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
return true
end,
})

View File

@ -0,0 +1,66 @@
-- Dripping Water Mod
-- by kddekadenz
local math = math
-- License of code, textures & sounds: CC0
local function register_drop(liquid, glow, sound, nodes)
minetest.register_entity("mcl_dripping:drop_" .. liquid, {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.01, 0.01, -0.01, 0.01, 0.01, 0.01},
glow = glow,
pointable = false,
visual = "sprite",
visual_size = {x = 0.1, y = 0.1},
textures = {""},
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
static_save = false,
_dropped = false,
on_activate = function(self)
self.object:set_properties({
textures = {"[combine:2x2:" .. -math.random(1, 16) .. "," .. -math.random(1, 16) .. "=default_" .. liquid .. "_source_animated.png"}
})
end,
on_step = function(self, dtime)
local k = math.random(1, 222)
local ownpos = self.object:get_pos()
if k == 1 then
self.object:set_acceleration(vector.new(0, -5, 0))
end
if minetest.get_node(vector.offset(ownpos, 0, 0.5, 0)).name == "air" then
self.object:set_acceleration(vector.new(0, -5, 0))
end
if minetest.get_node(vector.offset(ownpos, 0, -0.1, 0)).name ~= "air" then
local ent = self.object:get_luaentity()
if not ent._dropped then
ent._dropped = true
minetest.sound_play({name = "drippingwater_" .. sound .. "drip"}, {pos = ownpos, gain = 0.5, max_hear_distance = 8}, true)
end
if k < 3 then
self.object:remove()
end
end
end,
})
minetest.register_abm({
label = "Create drops",
nodenames = nodes,
neighbors = {"group:" .. liquid},
interval = 2,
chance = 22,
action = function(pos)
if minetest.get_item_group(minetest.get_node(vector.offset(pos, 0, 1, 0)).name, liquid) ~= 0
and minetest.get_node(vector.offset(pos, 0, -1, 0)).name == "air" then
local x, z = math.random(-45, 45) / 100, math.random(-45, 45) / 100
minetest.add_entity(vector.offset(pos, x, -0.520, z), "mcl_dripping:drop_" .. liquid)
end
end,
})
end
register_drop("water", 1, "", {"group:opaque", "group:leaves"})
register_drop("lava", math.max(7, minetest.registered_nodes["mcl_core:lava_source"].light_source - 3), "lava", {"group:opaque"})

View File

@ -1,4 +1,4 @@
name = drippingwater
name = mcl_dripping
author = kddekadenz
description = Drops are generated rarely under solid nodes
depends = mcl_core

View File

@ -1,12 +1,12 @@
Dripping Water Mod
Dripping Mod
by kddekadenz
modified for MineClone 2 by Wuzzy
modified for MineClone 2 by Wuzzy and NO11
Installing instructions:
1. Copy the drippingwater mod folder into games/gamemode/mods
1. Copy the mcl_dripping mod folder into games/gamemode/mods
2. Start game and enjoy :)

View File

@ -290,10 +290,10 @@ function minetest.handle_node_drops(pos, drops, digger)
end
end
if digger and mcl_experience.throw_experience and not silk_touch_drop then
if digger and mcl_experience.throw_xp and not silk_touch_drop then
local experience_amount = minetest.get_item_group(dug_node.name,"xp")
if experience_amount > 0 then
mcl_experience.throw_experience(pos, experience_amount)
mcl_experience.throw_xp(pos, experience_amount)
end
end
@ -480,7 +480,7 @@ minetest.register_entity(":__builtin:item", {
end,
get_staticdata = function(self)
return minetest.serialize({
local data = minetest.serialize({
itemstring = self.itemstring,
always_collect = self.always_collect,
age = self.age,
@ -488,6 +488,39 @@ minetest.register_entity(":__builtin:item", {
_flowing = self._flowing,
_removed = self._removed,
})
-- sfan5 guessed that the biggest serializable item
-- entity would have a size of 65530 bytes. This has
-- been experimentally verified to be still too large.
--
-- anon5 has calculated that the biggest serializable
-- item entity has a size of exactly 65487 bytes:
--
-- 1. serializeString16 can handle max. 65535 bytes.
-- 2. The following engine metadata is always saved:
-- • 1 byte (version)
-- • 2 byte (length prefix)
-- • 14 byte “__builtin:item”
-- • 4 byte (length prefix)
-- • 2 byte (health)
-- • 3 × 4 byte = 12 byte (position)
-- • 4 byte (yaw)
-- • 1 byte (version 2)
-- • 2 × 4 byte = 8 byte (pitch and roll)
-- 3. This leaves 65487 bytes for the serialization.
if #data > 65487 then -- would crash the engine
local stack = ItemStack(self.itemstring)
stack:get_meta():from_table(nil)
self.itemstring = stack:to_string()
minetest.log(
"warning",
"Overlong item entity metadata removed: “" ..
self.itemstring ..
"” had serialized length of " ..
#data
)
return self:get_staticdata()
end
return data
end,
on_activate = function(self, staticdata, dtime_s)
@ -575,7 +608,7 @@ minetest.register_entity(":__builtin:item", {
return true
end,
on_step = function(self, dtime)
on_step = function(self, dtime, moveresult)
if self._removed then
self.object:set_properties({
physical = false
@ -642,6 +675,18 @@ minetest.register_entity(":__builtin:item", {
end
end
-- Destroy item when it collides with a cactus
if moveresult and moveresult.collides then
for _, collision in pairs(moveresult.collisions) do
local pos = collision.node_pos
if collision.type == "node" and minetest.get_node(pos).name == "mcl_core:cactus" then
self._removed = true
self.object:remove()
return
end
end
end
-- Push item out when stuck inside solid opaque node
if def and def.walkable and def.groups and def.groups.opaque == 1 then
local shootdir

View File

@ -198,7 +198,20 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
else
self._last_float_check = self._last_float_check + dtime
end
local pos, rou_pos, node
local pos, rou_pos, node = self.object:get_pos()
local r = 0.6
for _, node_pos in pairs({{r, 0}, {0, r}, {-r, 0}, {0, -r}}) do
if minetest.get_node(vector.offset(pos, node_pos[1], 0, node_pos[2])).name == "mcl_core:cactus" then
detach_driver(self)
for d = 1, #drop do
minetest.add_item(pos, drop[d])
end
self.object:remove()
return
end
end
-- Drop minecart if it isn't on a rail anymore
if self._last_float_check >= mcl_minecarts.check_float_time then
pos = self.object:get_pos()
@ -646,7 +659,7 @@ register_minecart(
if player then
mcl_player.player_set_animation(player, "sit" , 30)
player:set_eye_offset({x=0, y=-5.5, z=0},{x=0, y=-4, z=0})
mcl_tmp_message.message(clicker, S("Sneak to dismount"))
mcl_title.set(clicker, "actionbar", {text=S("Sneak to dismount"), color="white", stay=60})
end
end, name)
end

View File

@ -33,3 +33,4 @@ Activates minecarts when powered=Active les wagonnets lorsqu'il est alimenté
Emits redstone power when a minecart is detected=Émet de l'énergie redstone lorsqu'un wagonnet est détecté
Vehicle for fast travel on rails=Véhicule pour voyager rapidement sur rails
Can be ignited by tools or powered activator rail=Peut être allumé par des outils ou un rail d'activation motorisé
Sneak to dismount=

View File

@ -1,6 +1,6 @@
name = mcl_minecarts
author = Krock
description = Minecarts are vehicles to move players quickly on rails.
depends = mcl_explosions, mcl_core, mcl_sounds, mcl_player, mcl_achievements, mcl_chests, mcl_furnaces, mesecons_commandblock, mcl_hoppers, mcl_tnt, mesecons
depends = mcl_title, mcl_explosions, mcl_core, mcl_sounds, mcl_player, mcl_achievements, mcl_chests, mcl_furnaces, mesecons_commandblock, mcl_hoppers, mcl_tnt, mesecons
optional_depends = doc_identifier, mcl_wip

View File

@ -122,7 +122,10 @@ mobs.death_logic = function(self, dtime)
if self.death_animation_timer >= 1.25 then
item_drop(self,false,1)
mobs.death_effect(self)
mcl_experience.throw_experience(self.object:get_pos(), math_random(self.xp_min, self.xp_max))
mcl_experience.throw_xp(self.object:get_pos(), math_random(self.xp_min, self.xp_max))
if self.on_die then
self.on_die(self, self.object:get_pos())
end
self.object:remove()
return
end
@ -155,4 +158,4 @@ mobs.death_logic = function(self, dtime)
if self.pause_timer <= 0 then
mobs.set_velocity(self,0)
end
end
end

View File

@ -37,7 +37,7 @@ mobs:register_mob("mobs_mc:creeper", {
},
makes_footstep_sound = false,
walk_velocity = 1.05,
run_velocity = 3.25,
run_velocity = 2.1,
runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" },
attack_type = "explode",
eye_height = 1.25,
@ -47,8 +47,8 @@ mobs:register_mob("mobs_mc:creeper", {
--explosion_radius = 3,
--explosion_damage_radius = 6,
--explosiontimer_reset_radius = 6,
reach = 1.5,
defuse_reach = 4,
reach = 3,
defuse_reach = 5.2,
explosion_timer = 0.3,
allow_fuse_reset = true,
stop_to_explode = true,
@ -95,7 +95,8 @@ mobs:register_mob("mobs_mc:creeper", {
if self._forced_explosion_countdown_timer then
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
if self._forced_explosion_countdown_timer <= 0 then
mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { griefing = mobs_griefing, drop_chance = 1.0}, self.object)
end
end
end,
@ -151,6 +152,7 @@ mobs:register_mob("mobs_mc:creeper_charged", {
description = S("Charged Creeper"),
type = "monster",
spawn_class = "hostile",
hostile = true,
hp_min = 20,
hp_max = 20,
xp_min = 5,
@ -186,8 +188,8 @@ mobs:register_mob("mobs_mc:creeper_charged", {
--explosion_radius = 3,
--explosion_damage_radius = 6,
--explosiontimer_reset_radius = 3,
reach = 1.5,
defuse_reach = 4,
reach = 3,
defuse_reach = 5.2,
explosion_timer = 0.3,
allow_fuse_reset = true,
stop_to_explode = true,
@ -219,7 +221,8 @@ mobs:register_mob("mobs_mc:creeper_charged", {
if self._forced_explosion_countdown_timer then
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
if self._forced_explosion_countdown_timer <= 0 then
mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { griefing = mobs_griefing, drop_chance = 1.0}, self.object)
end
end
end,

View File

@ -103,7 +103,7 @@ mobs:register_mob("mobs_mc:enderdragon", {
mcl_portals.spawn_gateway_portal()
mcl_structures.call_struct(self._portal_pos, "end_exit_portal_open")
if self._initial then
mcl_experience.throw_experience(pos, 11500) -- 500 + 11500 = 12000
mcl_experience.throw_xp(pos, 11500) -- 500 + 11500 = 12000
minetest.set_node(vector.add(self._portal_pos, vector.new(3, 5, 3)), {name = mobs_mc.items.dragon_egg})
end
end

View File

@ -28,6 +28,7 @@ Pig=
Polar Bear=
Rabbit=
Killer Bunny=
The Killer Bunny=
Sheep=
Shulker=
Silverfish=

View File

@ -233,4 +233,4 @@ mobs:spawn(spawn_grass)
mobs:register_egg("mobs_mc:rabbit", S("Rabbit"), "mobs_mc_spawn_icon_rabbit.png", 0)
-- Note: This spawn egg does not exist in Minecraft
mobs:register_egg("mobs_mc:killer_bunny", S("Killer Bunny"), "mobs_mc_spawn_icon_rabbit.png^[colorize:#FF0000:192", 0) -- TODO: Update inventory image
mobs:register_egg("mobs_mc:killer_bunny", S("Killer Bunny"), "mobs_mc_spawn_icon_rabbit_caerbannog.png", 0)

View File

@ -31,12 +31,14 @@ local spawn_children_on_die = function(child_mob, children_count, spawn_distance
speed_penalty = 0.5
end
local mob = minetest.add_entity(newpos, child_mob)
if (not mother_stuck) then
mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty))
if mob then
if (not mother_stuck) then
mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty))
end
mob:set_yaw(angle - math.pi/2)
table.insert(children, mob)
angle = angle + (math.pi*2)/children_count
end
mob:set_yaw(angle - math.pi/2)
table.insert(children, mob)
angle = angle + (math.pi*2)/children_count
end
-- If mother was murdered, children attack the killer after 1 second
if self.state == "attack" then

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -409,7 +409,7 @@ local init_trades = function(self, inv)
local offered_stack = ItemStack({name = offered_item, count = offered_count})
if mcl_enchanting.is_enchanted(offered_item) then
if mcl_enchanting.is_book(offered_item) then
offered_stack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"})
mcl_enchanting.enchant_uniform_randomly(offered_stack, {"soul_speed"})
else
mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true)
mcl_enchanting.unload_enchantments(offered_stack)

View File

@ -0,0 +1,31 @@
# lightning
Lightning mod for MineClone2 with the following API:
## lightning.register_on_strike(function(pos, pos2, objects))
Custom function called when a lightning strikes.
* `pos`: impact position
* `pos2`: rounded node position where fire is placed
* `objects`: table with ObjectRefs of all objects within a radius of 3.5 around pos2
## lightning.strike(pos)
Let a lightning strike.
* `pos`: optional, if not given a random pos will be chosen
* `returns`: bool - success if a strike happened
### Examples:
```
lightning.register_on_strike(function(pos, pos2, objects)
for _, obj in pairs(objects) do
obj:remove()
end
minetest.add_entity(pos, "mobs_mc:sheep")
end)
minetest.register_on_respawnplayer(function(player)
lightning.strike(player:get_pos())
end)
```

View File

@ -24,13 +24,14 @@ local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_item_group = minetest.get_item_group
lightning = {
interval_low = 17,
interval_high = 503,
range_h = 100,
range_v = 50,
size = 100,
-- disable this to stop lightning mod from striking
auto = true,
interval_low = 17,
interval_high = 503,
range_h = 100,
range_v = 50,
size = 100,
-- disable this to stop lightning mod from striking
auto = true,
on_strike_functions = {},
}
local rng = PcgRandom(32321123312123)
@ -54,6 +55,18 @@ end
minetest.register_globalstep(revertsky)
-- lightning strike API
-- See API.md
--[[
lightning.register_on_strike(function(pos, pos2, objects)
-- code
end)
]]
function lightning.register_on_strike(func)
table.insert(lightning.on_strike_functions, func)
end
-- select a random strike point, midpoint
local function choose_pos(pos)
if not pos then
@ -79,14 +92,14 @@ local function choose_pos(pos)
pos.z = math.floor(pos.z - (lightning.range_h / 2) + rng:next(1, lightning.range_h))
end
local b, pos2 = line_of_sight(pos, {x = pos.x, y = pos.y - lightning.range_v, z = pos.z}, 1)
local b, pos2 = line_of_sight(pos, { x = pos.x, y = pos.y - lightning.range_v, z = pos.z }, 1)
-- nothing but air found
if b then
return nil, nil
end
local n = get_node({x = pos2.x, y = pos2.y - 1/2, z = pos2.z})
local n = get_node({ x = pos2.x, y = pos2.y - 1/2, z = pos2.z })
if n.name == "air" or n.name == "ignore" then
return nil, nil
end
@ -94,7 +107,6 @@ local function choose_pos(pos)
return pos, pos2
end
-- lightning strike API
-- * pos: optional, if not given a random pos will be chosen
-- * returns: bool - success if a strike happened
function lightning.strike(pos)
@ -108,21 +120,28 @@ function lightning.strike(pos)
if not pos then
return false
end
local objects = get_objects_inside_radius(pos2, 3.5)
if lightning.on_strike_functions then
for _, func in pairs(lightning.on_strike_functions) do
func(pos, pos2, objects)
end
end
end
lightning.register_on_strike(function(pos, pos2, objects)
local particle_pos = vector.offset(pos2, 0, (lightning.size / 2) + 0.5, 0)
local particle_size = lightning.size * 10
local time = 0.2
add_particlespawner({
amount = 1,
time = 0.2,
time = time,
-- make it hit the top of a block exactly with the bottom
minpos = {x = pos2.x, y = pos2.y + (lightning.size / 2) + 1/2, z = pos2.z },
maxpos = {x = pos2.x, y = pos2.y + (lightning.size / 2) + 1/2, z = pos2.z },
minvel = {x = 0, y = 0, z = 0},
maxvel = {x = 0, y = 0, z = 0},
minacc = {x = 0, y = 0, z = 0},
maxacc = {x = 0, y = 0, z = 0},
minexptime = 0.2,
maxexptime = 0.2,
minsize = lightning.size * 10,
maxsize = lightning.size * 10,
minpos = particle_pos,
maxpos = particle_pos,
minexptime = time,
maxexptime = time,
minsize = particle_size,
maxsize = particle_size,
collisiondetection = true,
vertical = true,
-- to make it appear hitting the node that will get set on fire, make sure
@ -135,44 +154,27 @@ function lightning.strike(pos)
sound_play({ name = "lightning_thunder", gain = 10 }, { pos = pos, max_hear_distance = 500 }, true)
-- damage nearby objects, transform mobs
-- TODO: use an API insteed of hardcoding this behaviour
local objs = get_objects_inside_radius(pos2, 3.5)
for o=1, #objs do
local obj = objs[o]
for _, obj in pairs(objects) do
local lua = obj:get_luaentity()
-- pig → zombie pigman (no damage)
if lua and lua._on_strike then
lua._on_strike(lua, pos, pos2, objects)
end
-- remove this when mob API is done
if lua and lua.name == "mobs_mc:pig" then
local rot = obj:get_yaw()
obj:remove()
obj = add_entity(pos2, "mobs_mc:pigman")
obj:set_yaw(rot)
-- mooshroom: toggle color red/brown (no damage)
mcl_util.replace_mob(obj, "mobs_mc:pigman")
elseif lua and lua.name == "mobs_mc:mooshroom" then
if lua.base_texture[1] == "mobs_mc_mooshroom.png" then
lua.base_texture = { "mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" }
else
lua.base_texture = { "mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png" }
end
obj:set_properties({textures = lua.base_texture})
-- villager → witch (no damage)
--elseif lua and lua.name == "mobs_mc:villager" then
-- Witches are incomplete, this code is unused
-- TODO: Enable this code when witches are working.
--[[
local rot = obj:get_yaw()
obj:remove()
obj = minetest.add_entity(pos2, "mobs_mc:witch")
obj:set_yaw(rot)
]]
-- charged creeper
obj:set_properties({ textures = lua.base_texture })
elseif lua and lua.name == "mobs_mc:villager" then
mcl_util.replace_mob(obj, "mobs_mc:witch")
elseif lua and lua.name == "mobs_mc:creeper" then
local rot = obj:get_yaw()
obj:remove()
obj = add_entity(pos2, "mobs_mc:creeper_charged")
obj:set_yaw(rot)
-- Other objects: Just damage
mcl_util.replace_mob(obj, "mobs_mc:creeper_charged")
else
mcl_util.deal_damage(obj, 5, {type = "lightning_bolt"})
mcl_util.deal_damage(obj, 5, { type = "lightning_bolt" })
end
end
@ -186,7 +188,7 @@ function lightning.strike(pos)
local name = player:get_player_name()
if ps[name] == nil then
ps[name] = {p = player, sky = sky}
mcl_weather.skycolor.add_layer("lightning", {{r=255,g=255,b=255}}, true)
mcl_weather.skycolor.add_layer("lightning", { { r = 255, g = 255, b = 255 } }, true)
mcl_weather.skycolor.active = true
end
end
@ -201,7 +203,7 @@ function lightning.strike(pos)
if rng:next(1,100) <= 3 then
skeleton_lightning = true
end
if get_item_group(get_node({x = pos2.x, y = pos2.y - 1, z = pos2.z}).name, "liquid") < 1 then
if get_item_group(get_node({ x = pos2.x, y = pos2.y - 1, z = pos2.z }).name, "liquid") < 1 then
if get_node(pos2).name == "air" then
-- Low chance for a lightning to spawn skeleton horse + skeletons
if skeleton_lightning then
@ -210,21 +212,22 @@ function lightning.strike(pos)
local angle, posadd
angle = math.random(0, math.pi*2)
for i=1,3 do
posadd = {x=math.cos(angle),y=0,z=math.sin(angle)}
posadd = { x=math.cos(angle),y=0,z=math.sin(angle) }
posadd = vector.normalize(posadd)
local mob = add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
mob:set_yaw(angle-math.pi/2)
if mob then
mob:set_yaw(angle-math.pi/2)
end
angle = angle + (math.pi*2) / 3
end
-- Cause a fire
else
set_node(pos2, {name = "mcl_fire:fire"})
set_node(pos2, { name = "mcl_fire:fire" })
end
end
end
end
end)
-- if other mods disable auto lightning during initialization, don't trigger the first lightning.
after(5, function(dtime)

View File

@ -2,7 +2,7 @@
Using it as fuel turns it into: @1.=L'utiliser comme combustible le transforme en : @1.
@1 seconds=@1 secondes
# Item count times item name
%@1×@2=%@1×@
@1×@2=@1×@
# Itemname (25%)
@1 (@2%)=@1 (@2%)
# Itemname (<0.5%)

View File

@ -0,0 +1,24 @@
# mcl_item_id
Show the item ID of an item in the description.
With this API, you can register a different name space than "mineclone" for your mod.
## mcl_item_id.set_mod_namespace(modname, namespace)
Set a name space for all items in a mod.
* param1: the modname
* param2: (optional) string of the desired name space, if nil, it is the name of the mod
## mcl_item_id.get_mod_namespace(modname)
Get the name space of a mod registered with mcl_item_id.set_mod_namespace(modname, namespace).
* param1: the modname
### Examples:
The name of the mod is "mod" which registered an item called "mod:itemname".
* mcl_item_id.set_mod_namespace("mod", "mymod") will show "mymod:itemname" in the description of "mod:itemname"
* mcl_item_id.set_mod_namespace(minetest.get_current_modname()) will show "mod:itemname" in the description of "mod:itemname"
* mcl_item_id.get_mod_namespace(minetest.get_current_modname()) will return "mod"
(If no namespace is set by a mod, mcl_item_id.get_mod_namespace(minetest.get_current_modname()) will return "mineclone")

View File

@ -0,0 +1,62 @@
mcl_item_id = {
mod_namespaces = {},
}
local game = "mineclone"
function mcl_item_id.set_mod_namespace(modname, namespace)
local namespace = namespace or modname
mcl_item_id.mod_namespaces[modname] = namespace
end
function mcl_item_id.get_mod_namespace(modname)
local namespace = mcl_item_id.mod_namespaces[modname]
if namespace then
return namespace
else
return game
end
end
local same_id = {
enchanting = { "table" },
experience = { "bottle" },
heads = { "skeleton", "zombie", "creeper", "wither_skeleton" },
mobitems = { "rabbit", "chicken" },
walls = {
"andesite", "brick", "cobble", "diorite", "endbricks",
"granite", "mossycobble", "netherbrick", "prismarine",
"rednetherbrick", "redsandstone", "sandstone",
"stonebrick", "stonebrickmossy",
},
wool = {
"black", "blue", "brown", "cyan", "green",
"grey", "light_blue", "lime", "magenta", "orange",
"pink", "purple", "red", "silver", "white", "yellow",
},
}
tt.register_snippet(function(itemstring)
local def = minetest.registered_items[itemstring]
local item_split = itemstring:find(":")
local id_string = itemstring:sub(item_split)
local id_modname = itemstring:sub(1, item_split - 1)
local new_id = game .. id_string
local mod_namespace = mcl_item_id.get_mod_namespace(id_modname)
for mod, ids in pairs(same_id) do
for _, id in pairs(ids) do
if itemstring == "mcl_" .. mod .. ":" .. id then
new_id = game .. ":" .. id .. "_" .. mod:gsub("s", "")
end
end
end
if mod_namespace ~= game then
new_id = mod_namespace .. id_string
end
if mod_namespace ~= id_modname then
minetest.register_alias_force(new_id, itemstring)
end
if minetest.settings:get_bool("mcl_item_id_debug", false) then
return new_id, "#555555"
end
end)

View File

@ -0,0 +1,3 @@
name = mcl_item_id
author = NO11
depends = tt

View File

@ -45,3 +45,4 @@ Mining durability: @1=Grabehaltbarkeit: @1
Block breaking strength: @1=Blockbruchstärke: @1
@1 uses=@1 Verwendungen
Unlimited uses=Unbegrenzte Verwendungen
Durability: @1=Haltbarkeit: @1

View File

@ -45,3 +45,4 @@ Mining durability: @1=
Block breaking strength: @1=
@1 uses=
Unlimited uses=
Durability: @1=

View File

@ -107,3 +107,8 @@ tt.register_snippet(function(itemstring)
end
end)
tt.register_snippet(function(itemstring, _, itemstack)
if itemstring:sub(1, 23) == "mcl_fishing:fishing_rod" or itemstring:sub(1, 12) == "mcl_bows:bow" then
return S("Durability: @1", S("@1 uses", mcl_util.calculate_durability(itemstack or ItemStack(itemstring))))
end
end)

View File

@ -425,6 +425,7 @@ function hb.hide_hudbar(player, identifier)
local name = player:get_player_name()
local hudtable = hb.get_hudtable(identifier)
if hudtable == nil then return false end
if hudtable.hudstate[name].hidden == true then return true end
if hb.settings.bar_type == "progress_bar" then
if hudtable.hudids[name].icon then
player:hud_change(hudtable.hudids[name].icon, "scale", {x=0,y=0})
@ -443,6 +444,7 @@ function hb.unhide_hudbar(player, identifier)
local name = player:get_player_name()
local hudtable = hb.get_hudtable(identifier)
if hudtable == nil then return false end
if hudtable.hudstate[name].hidden == false then return true end
local value = hudtable.hudstate[name].value
local max = hudtable.hudstate[name].max
if hb.settings.bar_type == "progress_bar" then

View File

@ -3,123 +3,8 @@ local S = minetest.get_translator(modname)
mcl_credits = {
players = {},
}
mcl_credits.description = S("A faithful Open Source clone of Minecraft")
-- Sub-lists are sorted by number of commits, but the list should not be rearranged (-> new contributors are just added at the end of the list)
mcl_credits.people = {
{ S("Creator of MineClone"), 0x0A9400, {
"davedevils",
}},
{ S("Creator of MineClone2"), 0xFBF837, {
"Wuzzy",
}},
{ S("Maintainers"), 0xFF51D5, {
"Fleckenstein",
"kay27",
"oilboi",
}},
{ S("Developers"), 0xF84355, {
"bzoss",
"AFCMS",
"epCode",
"ryvnf",
"iliekprogrammar",
"MysticTempest",
"Rootyjr",
"Nicu",
"aligator",
"Code-Sploit",
"NO11",
}},
{ S("Contributors"), 0x52FF00, {
"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", 0xA60014, {
"kay27",
"Debiankaios",
"epCode",
"NO11",
"j45",
}},
{ S("Original Mod Authors"), 0x343434, {
"Wuzzy",
"Fleckenstein",
"BlockMen",
"TenPlus1",
"PilzAdam",
"ryvnf",
"stujones11",
"Arcelmi",
"celeron55",
"maikerumine",
"GunshipPenguin",
"Qwertymine3",
"Rochambeau",
"rubenwardy",
"stu",
"oilboi",
"4aiman",
"Kahrl",
"Krock",
"UgnilJoZ",
"lordfingle",
"22i",
"bzoss",
"kilbith",
"xeranas",
"kddekadenz",
"sofar",
"4Evergreen4",
"jordan4ibanez",
"paramat",
}},
{ S("3D Models"), 0x0019FF, {
"22i",
"tobyplowy",
"epCode",
}},
{ S("Textures"), 0xFF9705, {
"XSSheep",
"Wuzzy",
"kingoscargames",
"leorockway",
"xMrVizzy",
"yutyo",
"NO11",
}},
{ S("Translations"), 0x00FF60, {
"Wuzzy",
"Rocher Laurent",
"wuniversales",
"kay27",
"pitchum",
}},
description = S("A faithful Open Source clone of Minecraft"),
people = dofile(minetest.get_modpath(modname) .. "/people.lua"),
}
local function add_hud_element(def, huds, y)
@ -243,7 +128,7 @@ minetest.register_globalstep(function(dtime)
y = y - 5
end
end
if y > -100 then
if id == huds.icon then
y = math.max(400, y)

View File

@ -7,6 +7,7 @@ Creator of MineClone2=Schöpfer von MineClone2
Developers=Entwickler
Jump to speed up (additionally sprint)=Springen, um zu beschleunigen (zusätzlich sprinten)
Maintainers=Betreuer
MineClone5=MineClone5
Original Mod Authors=Original-Mod-Autoren
Sneak to skip=Schleichen zum Überspringen
Textures=Texturen

View File

@ -0,0 +1,14 @@
# textdomain: mcl_credits
3D Models=
A faithful Open Source clone of Minecraft=
Contributors=
Creator of MineClone=
Creator of MineClone2=
Developers=
Jump to speed up (additionally sprint)=
Maintainers=
MineClone5=
Original Mod Authors=
Sneak to skip=
Textures=
Translations=

View File

@ -0,0 +1,14 @@
# textdomain: mcl_credits
3D Models=Modèles 3D
A faithful Open Source clone of Minecraft=Un clone open source de Minecraft
Contributors=Contributeurs
Creator of MineClone=Créateur de MineClone
Creator of MineClone2=Créateur de MineClone2
Developers=Développeurs
Jump to speed up (additionally sprint)=Saut pour accélérer (peut être combiné avec sprint)
Maintainers=Mainteneurs
MineClone5=MineClone5
Original Mod Authors=Auteurs des mods originaux
Sneak to skip=Shift pour passer
Textures=Textures
Translations=Traductions

View File

@ -0,0 +1,14 @@
# textdomain: mcl_credits
3D Models=
A faithful Open Source clone of Minecraft=
Contributors=
Creator of MineClone=
Creator of MineClone2=
Developers=
Jump to speed up (additionally sprint)=
Maintainers=
MineClone5=
Original Mod Authors=
Sneak to skip=
Textures=
Translations=

View File

@ -0,0 +1,14 @@
# textdomain: mcl_credits
3D Models=
A faithful Open Source clone of Minecraft=
Contributors=
Creator of MineClone=
Creator of MineClone2=
Developers=
Jump to speed up (additionally sprint)=
Maintainers=
MineClone5=
Original Mod Authors=
Sneak to skip=
Textures=
Translations=

View File

@ -0,0 +1,144 @@
local modname = minetest.get_current_modname()
local S = minetest.get_translator(modname)
return {
{S("Creator of MineClone"), 0x0A9400, {
"davedevils",
}},
{S("Creator of MineClone2"), 0xFBF837, {
"Wuzzy",
}},
{S("Maintainers"), 0xFF51D5, {
"Fleckenstein",
"Nicu",
"kay27",
}},
{S("Developers"), 0xF84355, {
"bzoss",
"AFCMS",
"epCode",
"ryvnf",
"iliekprogrammar",
"MysticTempest",
"Rootyjr",
"aligator",
"Code-Sploit",
"NO11",
"cora",
"jordan4ibanez",
}},
{S("Contributors"), 0x52FF00, {
"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",
"Tianyang Zhang",
"j45",
"Marcin Serwin",
"erlehmann",
"E",
"Benjamin Schötz",
"Doloment",
"Sydney Gems",
"talamh",
"Emily2255",
"Emojigit",
"FinishedFragment",
"sfan5",
"Blue Blancmange",
"Jared Moody",
"SmallJoker",
"Sven792",
"aldum",
}},
{S("MineClone5"), 0xA60014, {
"kay27",
"Debiankaios",
"epCode",
"NO11",
"j45",
}},
{S("Original Mod Authors"), 0x343434, {
"Wuzzy",
"Fleckenstein",
"BlockMen",
"TenPlus1",
"PilzAdam",
"ryvnf",
"stujones11",
"Arcelmi",
"celeron55",
"maikerumine",
"GunshipPenguin",
"Qwertymine3",
"Rochambeau",
"rubenwardy",
"stu",
"4aiman",
"Kahrl",
"Krock",
"UgnilJoZ",
"lordfingle",
"22i",
"bzoss",
"kilbith",
"xeranas",
"kddekadenz",
"sofar",
"4Evergreen4",
"jordan4ibanez",
"paramat",
}},
{S("3D Models"), 0x0019FF, {
"22i",
"tobyplowy",
"epCode",
}},
{S("Textures"), 0xFF9705, {
"XSSheep",
"Wuzzy",
"kingoscargames",
"leorockway",
"xMrVizzy",
"yutyo",
"NO11",
"kay27",
}},
{S("Translations"), 0x00FF60, {
"Wuzzy",
"Rocher Laurent",
"wuniversales",
"kay27",
"pitchum",
"todoporlalibertad",
"Marcin Serwin",
}},
{S("Funders"), 0xF7FF00, {
"40W",
}},
{S("Special thanks"), 0x00E9FF, {
"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",
}},
}

View File

@ -0,0 +1,63 @@
local S = minetest.get_translator(minetest.get_current_modname())
minetest.register_entity("mcl_experience:bottle",{
textures = {"mcl_experience_bottle.png"},
hp_max = 1,
visual_size = {x = 0.35, y = 0.35},
collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
pointable = false,
on_step = function(self, dtime)
local pos = self.object:get_pos()
local node = minetest.get_node(pos)
local n = node.name
if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and minetest.get_item_group(n, "liquid") == 0 then
minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1})
mcl_experience.throw_xp(pos, math.random(3, 11))
minetest.add_particlespawner({
amount = 50,
time = 0.1,
minpos = vector.add(pos, vector.new(-0.1, 0.5, -0.1)),
maxpos = vector.add(pos, vector.new( 0.1, 0.6, 0.1)),
minvel = vector.new(-2, 0, -2),
maxvel = vector.new( 2, 2, 2),
minacc = vector.new(0, 0, 0),
maxacc = vector.new(0, 0, 0),
minexptime = 0.5,
maxexptime = 1.25,
minsize = 1,
maxsize = 2,
collisiondetection = true,
vertical = false,
texture = "mcl_particles_effect.png^[colorize:blue:127",
})
self.object:remove()
end
end,
})
local function throw_xp_bottle(pos, dir, velocity)
minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true)
local obj = minetest.add_entity(pos, "mcl_experience:bottle")
obj:set_velocity(vector.multiply(dir, velocity))
local acceleration = vector.multiply(dir, -3)
acceleration.y = -9.81
obj:set_acceleration(acceleration)
end
minetest.register_craftitem("mcl_experience:bottle", {
description = "Bottle o' Enchanting",
inventory_image = "mcl_experience_bottle.png",
wield_image = "mcl_experience_bottle.png",
stack_max = 64,
on_use = function(itemstack, placer, pointed_thing)
throw_xp_bottle(vector.add(placer:get_pos(), vector.new(0, 1.5, 0)), placer:get_look_dir(), 10)
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end,
_on_dispense = function(_, pos, _, _, dir)
throw_xp_bottle(vector.add(pos, vector.multiply(dir, 0.51)), dir, 10)
end
})

View File

@ -0,0 +1,39 @@
local S = minetest.get_translator(minetest.get_current_modname())
minetest.register_chatcommand("xp", {
params = S("[[<player>] <xp>]"),
description = S("Gives a player some XP"),
privs = {server=true},
func = function(name, params)
local player, xp = nil, 1000
local P, i = {}, 0
for str in string.gmatch(params, "([^ ]+)") do
i = i + 1
P[i] = str
end
if i > 2 then
return false, S("Error: Too many parameters!")
end
if i > 0 then
xp = tonumber(P[i])
end
if i < 2 then
player = minetest.get_player_by_name(name)
end
if i == 2 then
player = minetest.get_player_by_name(P[1])
end
if not xp then
return false, S("Error: Incorrect value of XP")
end
if not player then
return false, S("Error: Player not found")
end
mcl_experience.add_xp(player, xp)
return true, S("Added @1 XP to @2, total: @3, experience level: @4", tostring(xp), player:get_player_name(), tostring(mcl_experience.get_xp(player)), tostring(mcl_experience.get_level(player)))
end,
})

View File

@ -1,641 +1,227 @@
local S = minetest.get_translator(minetest.get_current_modname())
mcl_experience = {}
local vector = vector
local math = math
local string = string
local pool = {}
local registered_nodes
local max_xp = 2^31-1
local max_orb_age = 300 -- seconds
local gravity = {x = 0, y = -((tonumber(minetest.settings:get("movement_gravity"))) or 9.81), z = 0}
local size_min, size_max = 20, 59 -- percents
local delta_size = size_max - size_min
local size_to_xp = {
{-32768, 2}, -- 1
{ 3, 6}, -- 2
{ 7, 16}, -- 3
{ 17, 36}, -- 4
{ 37, 72}, -- 5
{ 73, 148}, -- 6
{ 149, 306}, -- 7
{ 307, 616}, -- 8
{ 617, 1236}, -- 9
{ 1237, 2476}, --10
{ 2477, 32767} --11
mcl_experience = {
on_add_xp = {},
}
local function xp_to_size(xp)
local i, l = 1, #size_to_xp
while (xp > size_to_xp[i][1]) and (i < l) do
i = i + 1
end
return ((i-1) / (l-1) * delta_size + size_min)/100
end
local modpath = minetest.get_modpath(minetest.get_current_modname())
minetest.register_on_mods_loaded(function()
registered_nodes = minetest.registered_nodes
end)
dofile(modpath .. "/command.lua")
dofile(modpath .. "/orb.lua")
dofile(modpath .. "/bottle.lua")
local function load_data(player)
local name = player:get_player_name()
pool[name] = {}
local temp_pool = pool[name]
local meta = player:get_meta()
temp_pool.xp = meta:get_int("xp") or 0
temp_pool.level = mcl_experience.xp_to_level(temp_pool.xp)
temp_pool.bar, temp_pool.bar_step, temp_pool.xp_next_level = mcl_experience.xp_to_bar(temp_pool.xp, temp_pool.level)
temp_pool.last_time= minetest.get_us_time()/1000000
end
-- local storage
-- saves data to be utilized on next login
local function save_data(player)
local name = player:get_player_name()
local temp_pool = pool[name]
local meta = player:get_meta()
meta:set_int("xp", temp_pool.xp)
pool[name] = nil
end
local hud_bars = {}
local hud_levels = {}
local caches = {}
local player_huds = {} -- the list of players hud lists (3d array)
hud_manager = {} -- hud manager class
-- helpers
-- terminate the player's list on leave
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
player_huds[name] = nil
end)
-- create instance of new hud
function hud_manager.add_hud(player,hud_name,def)
local name = player:get_player_name()
if minetest.is_creative_enabled(name) then
return
end
local local_hud = player:hud_add({
hud_elem_type = def.hud_elem_type,
position = def.position,
text = def.text,
text2 = def.text2,
number = def.number,
item = def.item,
direction = def.direction,
size = def.size,
offset = def.offset,
z_index = def.z_index,
alignment = def.alignment,
scale = def.scale,
})
-- create new 3d array here
-- depends.txt is not needed
-- with it here
if not player_huds[name] then
player_huds[name] = {}
end
player_huds[name][hud_name] = local_hud
end
-- delete instance of hud
function hud_manager.remove_hud(player,hud_name)
local name = player:get_player_name()
if player_huds[name] and player_huds[name][hud_name] then
player:hud_remove(player_huds[name][hud_name])
player_huds[name][hud_name] = nil
end
end
-- change element of hud
function hud_manager.change_hud(data)
local name = data.player:get_player_name()
if player_huds[name] and player_huds[name][data.hud_name] then
data.player:hud_change(player_huds[name][data.hud_name], data.element, data.data)
end
end
-- gets if hud exists
function hud_manager.hud_exists(player,hud_name)
local name = player:get_player_name()
if player_huds[name] and player_huds[name][hud_name] then
return true
else
return false
end
end
-------------------
-- saves specific users data for when they relog
minetest.register_on_leaveplayer(function(player)
save_data(player)
end)
-- is used for shutdowns to save all data
local function save_all()
for name,_ in pairs(pool) do
local player = minetest.get_player_by_name(name)
if player then
save_data(player)
end
end
end
-- save all data to mod storage on shutdown
minetest.register_on_shutdown(function()
save_all()
end)
function mcl_experience.get_player_xp_level(player)
local name = player:get_player_name()
return pool[name].level
end
function mcl_experience.set_player_xp_level(player,level)
local name = player:get_player_name()
if level == pool[name].level then
return
end
pool[name].level = level
pool[name].xp, pool[name].bar_step, pool[name].xp_next_level = mcl_experience.bar_to_xp(pool[name].bar, level)
hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(level)})
-- we may don't update the bar
end
local name
local temp_pool
minetest.register_on_joinplayer(function(player)
load_data(player)
name = player:get_player_name()
temp_pool = pool[name]
hud_manager.add_hud(player,"experience_bar",
{
hud_elem_type = "image",
name = "experience bar",
text = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",
position = {x=0.5, y=1},
offset = {x = (-9 * 28) - 3, y = -(48 + 24 + 16 - 5)},
scale = {x = 2.8, y = 3.0},
alignment = { x = 1, y = 1 },
z_index = 11,
})
hud_manager.add_hud(player,"xp_level",
{
hud_elem_type = "text", position = {x=0.5, y=1},
name = "xp_level", text = tostring(temp_pool.level),
number = 0x80FF20,
offset = {x = 0, y = -(48 + 24 + 24)},
z_index = 12,
})
end)
function mcl_experience.xp_to_level(xp)
local function xp_to_level(xp)
local xp = xp or 0
local a, b, c, D
if xp > 1507 then
a, b, c = 4.5, -162.5, 2220-xp
a, b, c = 4.5, -162.5, 2220 - xp
elseif xp > 352 then
a, b, c = 2.5, -40.5, 360-xp
a, b, c = 2.5, -40.5, 360 - xp
else
a, b, c = 1, 6, -xp
end
D = b*b-4*a*c
D = b * b - 4 * a * c
if D == 0 then
return math.floor(-b/2/a)
elseif D > 0 then
local v1, v2 = -b/2/a, math.sqrt(D)/2/a
return math.floor((math.max(v1-v2, v1+v2)))
return math.floor(-b / 2 / a)
elseif D > 0 then
local v1, v2 = -b / 2 / a, math.sqrt(D) / 2 / a
return math.floor(math.max(v1 - v2, v1 + v2))
end
return 0
end
function mcl_experience.level_to_xp(level)
if (level >= 1 and level <= 16) then
local function level_to_xp(level)
if level >= 1 and level <= 16 then
return math.floor(math.pow(level, 2) + 6 * level)
elseif (level >= 17 and level <= 31) then
elseif level >= 17 and level <= 31 then
return math.floor(2.5 * math.pow(level, 2) - 40.5 * level + 360)
elseif level >= 32 then
return math.floor(4.5 * math.pow(level, 2) - 162.5 * level + 2220);
return math.floor(4.5 * math.pow(level, 2) - 162.5 * level + 2220)
end
return 0
end
function mcl_experience.xp_to_bar(xp, level)
local level = level or mcl_experience.xp_to_level(xp)
local xp_this_level = mcl_experience.level_to_xp(level)
local xp_next_level = mcl_experience.level_to_xp(level+1)
local bar_step = 36 / (xp_next_level-xp_this_level)
local bar = (xp-xp_this_level) * bar_step
return bar, bar_step, xp_next_level
local function calculate_bounds(level)
return level_to_xp(level), level_to_xp(level + 1)
end
function mcl_experience.bar_to_xp(bar, level)
local xp_this_level = mcl_experience.level_to_xp(level)
local xp_next_level = mcl_experience.level_to_xp(level+1)
local bar_step = 36 / (xp_next_level-xp_this_level)
local xp = xp_this_level + math.floor(bar/36*(xp_next_level-xp_this_level))
return xp, bar_step, xp_next_level
local function xp_to_bar(xp, level)
local xp_min, xp_max = calculate_bounds(level)
return (xp - xp_min) / (xp_max - xp_min)
end
function mcl_experience.add_experience(player, experience)
local name = player:get_player_name()
local temp_pool = pool[name]
local function bar_to_xp(bar, level)
local xp_min, xp_max = calculate_bounds(level)
local inv = player:get_inventory()
local candidates = {
{list = "main", index = player:get_wield_index()},
{list = "armor", index = 2},
{list = "armor", index = 3},
{list = "armor", index = 4},
{list = "armor", index = 5},
}
local final_candidates = {}
for _, can in ipairs(candidates) do
local stack = inv:get_stack(can.list, can.index)
local wear = stack:get_wear()
if mcl_enchanting.has_enchantment(stack, "mending") and wear > 0 then
can.stack = stack
can.wear = wear
table.insert(final_candidates, can)
end
end
if #final_candidates > 0 then
local can = final_candidates[math.random(#final_candidates)]
local stack, list, index, wear = can.stack, can.list, can.index, can.wear
local uses = mcl_util.calculate_durability(stack)
local multiplier = 2 * 65535 / uses
local repair = experience * multiplier
local new_wear = wear - repair
if new_wear < 0 then
experience = math.floor(-new_wear / multiplier + 0.5)
new_wear = 0
else
experience = 0
end
stack:set_wear(math.floor(new_wear))
inv:set_stack(list, index, stack)
end
return xp_min + bar * (xp_max - xp_min)
end
local old_bar, old_xp, old_level = temp_pool.bar, temp_pool.xp, temp_pool.level
temp_pool.xp = math.min(math.max(temp_pool.xp + experience, 0), max_xp)
local function get_time()
return minetest.get_us_time() / 1000000
end
if (temp_pool.xp < temp_pool.xp_next_level) and (temp_pool.xp >= old_xp) then
temp_pool.bar = temp_pool.bar + temp_pool.bar_step * experience
else
temp_pool.level = mcl_experience.xp_to_level(temp_pool.xp)
temp_pool.bar, temp_pool.bar_step, temp_pool.xp_next_level = mcl_experience.xp_to_bar(temp_pool.xp, temp_pool.level)
end
-- api
if old_bar ~= temp_pool.bar then
hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "text", data = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",})
end
function mcl_experience.get_level(player)
return caches[player].level
end
if experience > 0 and minetest.get_us_time()/1000000 - temp_pool.last_time > 0.01 then
if old_level ~= temp_pool.level then
minetest.sound_play("level_up",{gain=0.2,to_player = name})
temp_pool.last_time = minetest.get_us_time()/1000000 + 0.2
else
minetest.sound_play("experience",{gain=0.1,to_player = name,pitch=math.random(75,99)/100})
temp_pool.last_time = minetest.get_us_time()/1000000
end
end
function mcl_experience.set_level(player, level)
local cache = caches[player]
if old_level ~= temp_pool.level then
hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(temp_pool.level)})
if level ~= cache.level then
mcl_experience.set_xp(player, math.floor(bar_to_xp(xp_to_bar(mcl_experience.get_xp(player), cache.level), level)))
end
end
--reset player level
local name
local temp_pool
local xp_amount
minetest.register_on_dieplayer(function(player)
if minetest.settings:get_bool("mcl_keepInventory", false) then
return
end
function mcl_experience.get_xp(player)
return player:get_meta():get_int("xp")
end
name = player:get_player_name()
temp_pool = pool[name]
xp_amount = temp_pool.xp
function mcl_experience.set_xp(player, xp)
player:get_meta():set_int("xp", xp)
temp_pool.xp = 0
temp_pool.level = 0
temp_pool.bar, temp_pool.bar_step, temp_pool.xp_next_level = mcl_experience.xp_to_bar(temp_pool.xp, temp_pool.level)
mcl_experience.update(player)
end
hud_manager.change_hud({player = player, hud_name = "xp_level", element = "text", data = tostring(temp_pool.level)})
hud_manager.change_hud({player = player, hud_name = "experience_bar", element = "text", data = "experience_bar_background.png^[lowpart:" .. math.floor(temp_pool.bar / 36 * 100) .. ":experience_bar.png^[transformR270",})
function mcl_experience.add_xp(player, xp)
for _, cb in ipairs(mcl_experience.on_add_xp) do
xp = cb.func(player, xp) or xp
mcl_experience.throw_experience(player:get_pos(), xp_amount)
end)
local collector, pos, pos2
local direction, distance, player_velocity, goal
local currentvel, acceleration, multiplier, velocity
local node, vel, def
local is_moving, is_slippery, slippery, slip_factor
local size
local function xp_step(self, dtime)
--if item set to be collected then only execute go to player
if self.collected == true then
if not self.collector then
self.collected = false
return
end
collector = minetest.get_player_by_name(self.collector)
if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 7.25 then
self.object:set_acceleration(vector.new(0,0,0))
self.disable_physics(self)
--get the variables
pos = self.object:get_pos()
pos2 = collector:get_pos()
player_velocity = collector:get_velocity() or collector:get_player_velocity()
pos2.y = pos2.y + 0.8
direction = vector.direction(pos,pos2)
distance = vector.distance(pos2,pos)
multiplier = distance
if multiplier < 1 then
multiplier = 1
end
goal = vector.multiply(direction,multiplier)
currentvel = self.object:get_velocity()
if distance > 1 then
multiplier = 20 - distance
velocity = vector.multiply(direction,multiplier)
goal = velocity
acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
self.object:add_velocity(vector.add(acceleration,player_velocity))
elseif distance < 0.8 then
mcl_experience.add_experience(collector, self._xp)
self.object:remove()
end
return
else
self.collector = nil
self.enable_physics(self)
if xp == 0 then
break
end
end
local cache = caches[player]
local old_level = cache.level
self.age = self.age + dtime
if self.age > max_orb_age then
self.object:remove()
return
end
mcl_experience.set_xp(player, mcl_experience.get_xp(player) + xp)
pos = self.object:get_pos()
local current_time = get_time()
if pos then
node = minetest.get_node_or_nil({
x = pos.x,
y = pos.y -0.25,
z = pos.z
})
else
return
end
if current_time - cache.last_time > 0.01 then
local name = player:get_player_name()
-- Remove nodes in 'ignore'
if node and node.name == "ignore" then
self.object:remove()
return
end
if not self.physical_state then
return -- Don't do anything
end
-- Slide on slippery nodes
vel = self.object:get_velocity()
def = node and registered_nodes[node.name]
is_moving = (def and not def.walkable) or
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
is_slippery = false
if def and def.walkable then
slippery = minetest.get_item_group(node.name, "slippery")
is_slippery = slippery ~= 0
if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
-- Horizontal deceleration
slip_factor = 4.0 / (slippery + 4)
self.object:set_acceleration({
x = -vel.x * slip_factor,
y = 0,
z = -vel.z * slip_factor
if old_level == cache.level then
minetest.sound_play("mcl_experience", {
to_player = name,
gain = 0.1,
pitch = math.random(75, 99) / 100,
})
elseif vel.y == 0 then
is_moving = false
cache.last_time = current_time
else
minetest.sound_play("mcl_experience_level_up", {
to_player = name,
gain = 0.2,
})
cache.last_time = current_time + 0.2
end
end
if self.moving_state == is_moving and self.slippery_state == is_slippery then
-- Do not update anything until the moving state changes
return
end
self.moving_state = is_moving
self.slippery_state = is_slippery
if is_moving then
self.object:set_acceleration(gravity)
else
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity({x = 0, y = 0, z = 0})
end
end
minetest.register_entity("mcl_experience:orb", {
initial_properties = {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
visual = "sprite",
visual_size = {x = 0.4, y = 0.4},
textures = {name="experience_orb.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}},
spritediv = {x = 1, y = 14},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = true,
pointable = false,
static_save = false,
},
moving_state = true,
slippery_state = false,
physical_state = true,
-- Item expiry
age = 0,
-- Pushing item out of solid nodes
force_out = nil,
force_out_start = nil,
--Collection Variables
collectable = false,
try_timer = 0,
collected = false,
delete_timer = 0,
radius = 4,
on_activate = function(self, staticdata, dtime_s)
self.object:set_velocity(vector.new(
math.random(-2,2)*math.random(),
math.random(2,5),
math.random(-2,2)*math.random()
))
self.object:set_armor_groups({immortal = 1})
self.object:set_velocity({x = 0, y = 2, z = 0})
self.object:set_acceleration(gravity)
local xp = tonumber(staticdata)
self._xp = xp
size = xp_to_size(xp)
self.object:set_properties({
visual_size = {x = size, y = size},
glow = 14,
})
self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
end,
enable_physics = function(self)
if not self.physical_state then
self.physical_state = true
self.object:set_properties({physical = true})
self.object:set_velocity({x=0, y=0, z=0})
self.object:set_acceleration(gravity)
end
end,
disable_physics = function(self)
if self.physical_state then
self.physical_state = false
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})
end
end,
on_step = function(self, dtime)
xp_step(self, dtime)
end,
})
minetest.register_chatcommand("xp", {
params = S("[[<player>] <xp>]"),
description = S("Gives a player some XP"),
privs = {server=true},
func = function(name, params)
local player, xp = nil, 1000
local P, i = {}, 0
for str in string.gmatch(params, "([^ ]+)") do
i = i + 1
P[i] = str
end
if i > 2 then
return false, S("Error: Too many parameters!")
end
if i > 0 then
xp = tonumber(P[i])
end
if i < 2 then
player = minetest.get_player_by_name(name)
end
if i == 2 then
player = minetest.get_player_by_name(P[1])
end
if not xp then
return false, S("Error: Incorrect value of XP")
end
if not player then
return false, S("Error: Player not found")
end
mcl_experience.add_experience(player, xp)
local playername = player:get_player_name()
minetest.chat_send_player(name, S("Added @1 XP to @2, total: @3, experience level: @4", tostring(xp), playername, tostring(pool[playername].xp), tostring(pool[playername].level)))
end,
})
function mcl_experience.throw_experience(pos, amount)
function mcl_experience.throw_xp(pos, total_xp)
local i, j = 0, 0
local obj, xp
while i < amount and j < 100 do
xp = math.min(math.random(1, math.min(32767, amount-math.floor(i/2))), amount-i)
obj = minetest.add_entity(pos, "mcl_experience:orb", tostring(xp))
while i < total_xp and j < 100 do
local xp = math.min(math.random(1, math.min(32767, total_xp - math.floor(i / 2))), total_xp - i)
local obj = minetest.add_entity(pos, "mcl_experience:orb", tostring(xp))
if not obj then
return false
end
obj:set_velocity({
x=math.random(-2,2)*math.random(),
y=math.random(2,5),
z=math.random(-2,2)*math.random()
})
obj:set_velocity(vector.new(
math.random(-2, 2) * math.random(),
math.random( 2, 5),
math.random(-2, 2) * math.random()
))
i = i + xp
j = j + 1
end
end
minetest.register_entity("mcl_experience:bottle",{
textures = {"mcl_experience_bottle.png"},
hp_max = 1,
visual_size = {x = 0.35, y = 0.35},
collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
pointable = false,
on_step = function(self, dtime)
local pos = self.object:get_pos()
local node = minetest.get_node(pos)
local n = node.name
if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and minetest.get_item_group(n, "liquid") == 0 then
minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1})
mcl_experience.throw_experience(pos, math.random(3, 11))
minetest.add_particlespawner({
amount = 50,
time = 0.1,
minpos = vector.add(pos, vector.new(-0.1, 0.5, -0.1)),
maxpos = vector.add(pos, vector.new( 0.1, 0.6, 0.1)),
minvel = vector.new(-2, 0, -2),
maxvel = vector.new( 2, 2, 2),
minacc = vector.new(0, 0, 0),
maxacc = vector.new(0, 0, 0),
minexptime = 0.5,
maxexptime = 1.25,
minsize = 1,
maxsize = 2,
collisiondetection = true,
vertical = false,
texture = "mcl_particles_effect.png^[colorize:blue:127",
})
self.object:remove()
end
end,
})
function mcl_experience.update(player)
local xp = mcl_experience.get_xp(player)
local cache = caches[player]
local function throw_xp_bottle(pos, dir, velocity)
minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true)
local obj = minetest.add_entity(pos, "mcl_experience:bottle")
obj:set_velocity(vector.multiply(dir, velocity))
local acceleration = vector.multiply(dir, -3)
acceleration.y = -9.81
obj:set_acceleration(acceleration)
cache.level = xp_to_level(xp)
if not minetest.is_creative_enabled(player:get_player_name()) then
player:hud_change(hud_bars[player], "text", "mcl_experience_bar_background.png^[lowpart:"
.. math.floor(math.floor(xp_to_bar(xp, cache.level) * 18) / 18 * 100)
.. ":mcl_experience_bar.png^[transformR270"
)
if cache.level == 0 then
player:hud_change(hud_levels[player], "text", "")
else
player:hud_change(hud_levels[player], "text", tostring(cache.level))
end
end
end
minetest.register_craftitem("mcl_experience:bottle", {
description = "Bottle o' Enchanting",
inventory_image = "mcl_experience_bottle.png",
wield_image = "mcl_experience_bottle.png",
stack_max = 64,
on_use = function(itemstack, placer, pointed_thing)
throw_xp_bottle(vector.add(placer:get_pos(), vector.new(0, 1.5, 0)), placer:get_look_dir(), 10)
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end,
_on_dispense = function(_, pos, _, _, dir)
throw_xp_bottle(vector.add(pos, vector.multiply(dir, 0.51)), dir, 10)
function mcl_experience.register_on_add_xp(func, priority)
table.insert(mcl_experience.on_add_xp, {func = func, priority = priority or 0})
end
-- callbacks
minetest.register_on_joinplayer(function(player)
caches[player] = {
last_time = get_time(),
}
if not minetest.is_creative_enabled(player:get_player_name()) then
hud_bars[player] = player:hud_add({
hud_elem_type = "image",
position = {x = 0.5, y = 1},
offset = {x = (-9 * 28) - 3, y = -(48 + 24 + 16 - 5)},
scale = {x = 2.8, y = 3.0},
alignment = {x = 1, y = 1},
z_index = 11,
})
hud_levels[player] = player:hud_add({
hud_elem_type = "text",
position = {x = 0.5, y = 1},
number = 0x80FF20,
offset = {x = 0, y = -(48 + 24 + 24)},
z_index = 12,
})
end
})
mcl_experience.update(player)
end)
minetest.register_on_leaveplayer(function(player)
hud_bars[player] = nil
hud_levels[player] = nil
caches[player] = nil
end)
minetest.register_on_dieplayer(function(player)
if not minetest.settings:get_bool("mcl_keepInventory", false) then
mcl_experience.throw_xp(player:get_pos(), mcl_experience.get_xp(player))
mcl_experience.set_xp(player, 0)
end
end)
minetest.register_on_mods_loaded(function()
table.sort(mcl_experience.on_add_xp, function(a, b) return a.priority < b.priority end)
end)

View File

@ -0,0 +1,220 @@
local size_min, size_max = 20, 59
local delta_size = size_max - size_min
local size_to_xp = {
{-32768, 2}, -- 1
{ 3, 6}, -- 2
{ 7, 16}, -- 3
{ 17, 36}, -- 4
{ 37, 72}, -- 5
{ 73, 148}, -- 6
{ 149, 306}, -- 7
{ 307, 616}, -- 8
{ 617, 1236}, -- 9
{ 1237, 2476}, -- 10
{ 2477, 32767} -- 11
}
local function xp_to_size(xp)
local i, l = 1, #size_to_xp
while xp > size_to_xp[i][1] and i < l do
i = i + 1
end
return ((i - 1) / (l - 1) * delta_size + size_min) / 100
end
local max_orb_age = 300 -- seconds
local gravity = vector.new(0, -((tonumber(minetest.settings:get("movement_gravity"))) or 9.81), 0)
local collector, pos, pos2
local direction, distance, player_velocity, goal
local currentvel, acceleration, multiplier, velocity
local node, vel, def
local is_moving, is_slippery, slippery, slip_factor
local size
local function xp_step(self, dtime)
--if item set to be collected then only execute go to player
if self.collected == true then
if not self.collector then
self.collected = false
return
end
collector = minetest.get_player_by_name(self.collector)
if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 7.25 then
self.object:set_acceleration(vector.new(0,0,0))
self.disable_physics(self)
--get the variables
pos = self.object:get_pos()
pos2 = collector:get_pos()
player_velocity = collector:get_velocity() or collector:get_player_velocity()
pos2.y = pos2.y + 0.8
direction = vector.direction(pos,pos2)
distance = vector.distance(pos2,pos)
multiplier = distance
if multiplier < 1 then
multiplier = 1
end
goal = vector.multiply(direction,multiplier)
currentvel = self.object:get_velocity()
if distance > 1 then
multiplier = 20 - distance
velocity = vector.multiply(direction,multiplier)
goal = velocity
acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
self.object:add_velocity(vector.add(acceleration,player_velocity))
elseif distance < 0.8 then
mcl_experience.add_xp(collector, self._xp)
self.object:remove()
end
return
else
self.collector = nil
self.enable_physics(self)
end
end
self.age = self.age + dtime
if self.age > max_orb_age then
self.object:remove()
return
end
pos = self.object:get_pos()
if pos then
node = minetest.get_node_or_nil({
x = pos.x,
y = pos.y -0.25,
z = pos.z
})
else
return
end
-- Remove nodes in 'ignore'
if node and node.name == "ignore" then
self.object:remove()
return
end
if not self.physical_state then
return -- Don't do anything
end
-- Slide on slippery nodes
vel = self.object:get_velocity()
def = node and minetest.registered_nodes[node.name]
is_moving = (def and not def.walkable) or
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
is_slippery = false
if def and def.walkable then
slippery = minetest.get_item_group(node.name, "slippery")
is_slippery = slippery ~= 0
if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
-- Horizontal deceleration
slip_factor = 4.0 / (slippery + 4)
self.object:set_acceleration({
x = -vel.x * slip_factor,
y = 0,
z = -vel.z * slip_factor
})
elseif vel.y == 0 then
is_moving = false
end
end
if self.moving_state == is_moving and self.slippery_state == is_slippery then
-- Do not update anything until the moving state changes
return
end
self.moving_state = is_moving
self.slippery_state = is_slippery
if is_moving then
self.object:set_acceleration(gravity)
else
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity({x = 0, y = 0, z = 0})
end
end
minetest.register_entity("mcl_experience:orb", {
initial_properties = {
hp_max = 1,
physical = true,
collide_with_objects = false,
collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
visual = "sprite",
visual_size = {x = 0.4, y = 0.4},
textures = {name="mcl_experience_orb.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}},
spritediv = {x = 1, y = 14},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = true,
pointable = false,
static_save = false,
},
moving_state = true,
slippery_state = false,
physical_state = true,
-- Item expiry
age = 0,
-- Pushing item out of solid nodes
force_out = nil,
force_out_start = nil,
--Collection Variables
collectable = false,
try_timer = 0,
collected = false,
delete_timer = 0,
radius = 4,
on_activate = function(self, staticdata, dtime_s)
self.object:set_velocity(vector.new(
math.random(-2,2)*math.random(),
math.random(2,5),
math.random(-2,2)*math.random()
))
self.object:set_armor_groups({immortal = 1})
self.object:set_velocity({x = 0, y = 2, z = 0})
self.object:set_acceleration(gravity)
local xp = tonumber(staticdata)
self._xp = xp
size = xp_to_size(xp)
self.object:set_properties({
visual_size = {x = size, y = size},
glow = 14,
})
self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
end,
enable_physics = function(self)
if not self.physical_state then
self.physical_state = true
self.object:set_properties({physical = true})
self.object:set_velocity({x=0, y=0, z=0})
self.object:set_acceleration(gravity)
end
end,
disable_physics = function(self)
if self.physical_state then
self.physical_state = false
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})
end
end,
on_step = function(self, dtime)
xp_step(self, dtime)
end,
})

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 891 B

After

Width:  |  Height:  |  Size: 891 B

File diff suppressed because it is too large Load Diff

50
mods/HUD/mcl_title/API.md Normal file
View File

@ -0,0 +1,50 @@
# mcl_title
Allow mods to show messages in the hud of players.
## mcl_title.set(player, type, data)
Show a hud message of `type` to player `player` with `data` as params.
The element will stay for the per-player param `stay` or `data.stay` (in gametick which is 1/20 second).
Here is a usage exemple:
```lua
--show a title in the HUD with minecraft color "gold"
mcl_title.set(player, "title", {text="dummy text", color="gold"})
--show a subtitle in the HUD with hex color "#612D2D"
mcl_title.set(player, "subtitle", {text="dummy subtitle", color="#612D2D"})
--show an actionbar in the HUD (above the hotbar) with minecraft color "red"
mcl_title.set(player, "subtitle", {text="dummy actionbar", color="red"})
--show a title in the HUD with minecraft color "gold" staying for 3 seconds (override stay setting)
mcl_title.set(player, "title", {text="dummy text", color="gold", stay=60})
```
## mcl_title.remove(player, type)
Hide HUD element of type `type` for player `player`.
## mcl_title.clear(player)
Remove every title/subtitle/actionbar from a player.
Basicaly run `mcl_title.remove(player, type)` for every type.
## mcl_title.params_set(player, params)
Allow mods to set `stay` and upcomming `fadeIn`/`fadeOut` params.
```lua
mcl_title.params_set(player, {stay = 600}) --elements with no 'data.stay' field will stay during 30s (600/20)
```
## mcl_title.params_get(player)
Get `stay` and upcomming `fadeIn` and `fadeOut` params of a player as a table.
```lua
mcl_title.params_get(player)
```

236
mods/HUD/mcl_title/init.lua Normal file
View File

@ -0,0 +1,236 @@
--Based on:
--https://www.digminecraft.com/game_commands/title_command.php
--https://youtu.be/oVrtQRO2hpY
--TODO: use SSCSM to reduce lag and network trafic (just send modchannel messages)
--TODO: fadeIn and fadeOut animation (needs engine change: SSCSM or native support)
--TODO: allow obfuscating text (needs engine change: SSCSM or native support)
--TODO: allow colorizing and styling of part of the text (NEEDS ENGINE CHANGE!!!)
--TODO: exactly mc like layout
--Note that the table storing timeouts use playername as index insteed of player objects (faster)
--This is intended in order to speedup the process of removing HUD elements the the timeout is up
local huds_idx = {}
local hud_hide_timeouts = {}
hud_hide_timeouts.title = {}
hud_hide_timeouts.subtitle = {}
hud_hide_timeouts.actionbar = {}
huds_idx.title = {}
huds_idx.subtitle = {}
huds_idx.actionbar = {}
mcl_title = {}
mcl_title.defaults = {fadein = 10, stay = 70, fadeout = 20}
mcl_title.layout = {}
mcl_title.layout.title = {position = {x = 0.5, y = 0.5}, alignment = {x = 0, y = -1.3}, size = 7}
mcl_title.layout.subtitle = {position = {x = 0.5, y = 0.5}, alignment = {x = 0, y = 1.7}, size = 4}
mcl_title.layout.actionbar = {position = {x = 0.5, y = 1}, alignment = {x = 0, y = 0}, size = 1}
local get_color = mcl_util.get_color
--local string = string
local pairs = pairs
local function gametick_to_secondes(gametick)
if gametick then
return gametick / 20
else
return nil
end
end
--https://github.com/minetest/minetest/blob/b3b075ea02034306256b486dd45410aa765f035a/doc/lua_api.txt#L8477
--[[
local function style_to_bits(bold, italic)
if bold then
if italic then
return 3
else
return 1
end
else
if italic then
return 2
else
return 0
end
end
end
]]
--PARAMS SYSTEM
local player_params = {}
minetest.register_on_joinplayer(function(player)
--local playername = player:get_player_name()
player_params[player] = {
stay = mcl_title.defaults.stay,
--fadeIn = mcl_title.defaults.fadein,
--fadeOut = mcl_title.defaults.fadeout,
}
local _, hex_color = get_color("white")
huds_idx.title[player] = player:hud_add({
hud_elem_type = "text",
position = mcl_title.layout.title.position,
alignment = mcl_title.layout.title.alignment,
text = "",
--style = 0,
size = {x = mcl_title.layout.title.size},
number = hex_color,
z_index = 100,
})
huds_idx.subtitle[player] = player:hud_add({
hud_elem_type = "text",
position = mcl_title.layout.subtitle.position,
alignment = mcl_title.layout.subtitle.alignment,
text = "",
--style = 0,
size = {x = mcl_title.layout.subtitle.size},
number = hex_color,
z_index = 100,
})
huds_idx.actionbar[player] = player:hud_add({
hud_elem_type = "text",
position = mcl_title.layout.actionbar.position,
offset = {x = 0, y = -210},
alignment = mcl_title.layout.actionbar.alignment,
--style = 0,
text = "",
size = {x = mcl_title.layout.actionbar.size},
number = hex_color,
z_index = 100,
})
end)
minetest.register_on_leaveplayer(function(player)
local playername = player:get_player_name()
--remove player params from the list
player_params[player] = nil
--remove HUD idx from the list (HUD elements are removed by the engine)
huds_idx.title[player] = nil
huds_idx.subtitle[player] = nil
huds_idx.actionbar[player] = nil
--remove timers from list
hud_hide_timeouts.title[playername] = nil
hud_hide_timeouts.subtitle[playername] = nil
hud_hide_timeouts.actionbar[playername] = nil
end)
function mcl_title.params_set(player, data)
player_params[player] = {
stay = data.stay or mcl_title.defaults.stay,
--fadeIn = data.fadeIn or mcl_title.defaults.fadein,
--fadeOut = data.fadeOut or mcl_title.defaults.fadeout,
}
end
function mcl_title.params_get(player)
return player_params[player]
end
--API FUNCTIONS
function mcl_title.set(player, type, data)
if not data.color then
data.color = "white"
end
local _, hex_color = get_color(data.color)
if not hex_color then
return false
end
player:hud_change(huds_idx[type][player], "text", data.text)
player:hud_change(huds_idx[type][player], "number", hex_color)
--apply bold and italic
--player:hud_change(huds_idx[type][player], "style", style_to_bits(data.bold, data.italic))
hud_hide_timeouts[type][player:get_player_name()] = gametick_to_secondes(data.stay) or gametick_to_secondes(mcl_title.params_get(player).stay)
return true
end
function mcl_title.remove(player, type)
if player then
player:hud_change(huds_idx[type][player], "text", "")
--player:hud_change(huds_idx[type][player], "style", 0) --no styling
end
end
function mcl_title.clear(player)
mcl_title.remove(player, "title")
mcl_title.remove(player, "subtitle")
mcl_title.remove(player, "actionbar")
end
minetest.register_on_dieplayer(function(player)
mcl_title.clear(player)
end)
minetest.register_globalstep(function(dtime)
local new_timeouts = {
title = {},
subtitle = {},
actionbar = {},
}
for element, content in pairs(hud_hide_timeouts) do
for name, timeout in pairs(content) do
timeout = timeout - dtime
if timeout <= 0 then
local player = minetest.get_player_by_name(name)
mcl_title.remove(player, element)
else
new_timeouts[element][name] = timeout
end
end
end
hud_hide_timeouts = new_timeouts
end)
--DEBUG STUFF!!
--[[
minetest.register_chatcommand("title", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
mcl_title.set(player, "title", {text=param, color="gold", bold=true, italic=true})
end,
})
minetest.register_chatcommand("subtitle", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
mcl_title.set(player, "subtitle", {text=param, color="gold"})
end,
})
minetest.register_chatcommand("actionbar", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
mcl_title.set(player, "actionbar", {text=param, color="gold"})
end,
})
minetest.register_chatcommand("timeout", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
mcl_title.params_set(player, {stay = 600})
end,
})
minetest.register_chatcommand("all", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
mcl_title.params_set(player, {stay = 600})
mcl_title.set(player, "title", {text=param, color="gold"})
mcl_title.set(player, "subtitle", {text=param, color="gold"})
mcl_title.set(player, "actionbar", {text=param, color="gold"})
end,
})
]]

View File

@ -0,0 +1,4 @@
name = mcl_title
description = Add an API to add in HUD title
depends = mcl_colors
author = AFCMS

View File

@ -1,7 +0,0 @@
# mcl_temp_message
Allow mods to show short messages in the hud of players.
## mcl_tmp_message.message(player, message)
Show above the hotbar a hud message <message> to player <player>.

View File

@ -1,44 +0,0 @@
mcl_tmp_message = {}
local huds = {}
local hud_hide_timeouts = {}
function mcl_tmp_message.message(player, message)
local name = player:get_player_name()
player:hud_change(huds[name], "text", message)
hud_hide_timeouts[name] = 3
end
minetest.register_on_joinplayer(function(player)
huds[player:get_player_name()] = player:hud_add({
hud_elem_type = "text",
position = {x=0.5, y=1},
offset = {x = 0, y = -210},
alignment = {x=0, y=0},
number = 0xFFFFFF ,
text = "",
z_index = 100,
})
end)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
huds[name] = nil
hud_hide_timeouts[name] = nil
end)
minetest.register_globalstep(function(dtime)
local new_timeouts = {}
for name, timeout in pairs(hud_hide_timeouts) do
timeout = timeout - dtime
if timeout <= 0 then
local player = minetest.get_player_by_name(name)
if player then
player:hud_change(huds[name], "text", "")
end
else
new_timeouts[name] = timeout
end
end
hud_hide_timeouts = new_timeouts
end)

View File

@ -1,3 +0,0 @@
name = mcl_tmp_message
author = Fleckenstein
description = A simple API to show a temporary message to a player

View File

@ -82,7 +82,7 @@ local dispenserdef = {
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for i=1, inv:get_size("main") do
@ -92,7 +92,7 @@ local dispenserdef = {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
_mcl_blast_resistance = 3.5,
_mcl_hardness = 3.5,
@ -168,6 +168,56 @@ local dispenserdef = {
end
inv:set_stack("main", stack_id, stack)
-- Use shears on sheeps
elseif igroups.shears then
for _, obj in pairs(minetest.get_objects_inside_radius(droppos, 1)) do
local entity = obj:get_luaentity()
if entity and not entity.child and not entity.gotten then
local entname = entity.name
local pos = obj:get_pos()
local used, texture = false
if entname == "mobs_mc:sheep" then
minetest.add_item(pos, entity.drops[2].name .. " " .. math.random(1, 3))
if not entity.color then
entity.color = "unicolor_white"
end
entity.base_texture = { "blank.png", "mobs_mc_sheep.png" }
texture = entity.base_texture
entity.drops = {
{ name = mobs_mc.items.mutton_raw, chance = 1, min = 1, max = 2 },
}
used = true
elseif entname == "mobs_mc:snowman" then
texture = {
"mobs_mc_snowman.png",
"blank.png", "blank.png",
"blank.png", "blank.png",
"blank.png", "blank.png",
}
used = true
elseif entname == "mobs_mc:mooshroom" then
local droppos = vector.offset(pos, 0, 1.4, 0)
if entity.base_texture[1] == "mobs_mc_mooshroom_brown.png" then
minetest.add_item(droppos, mobs_mc.items.mushroom_brown .. " 5")
else
minetest.add_item(droppos, mobs_mc.items.mushroom_red .. " 5")
end
obj = mcl_util.replace_mob(obj, "mobs_mc:cow")
entity = obj:get_luaentity()
used = true
end
if used then
obj:set_properties({ textures = texture })
entity.gotten = true
minetest.sound_play("mcl_tools_shears_cut", { pos = pos }, true)
stack:add_wear(65535 / stackdef._mcl_diggroups.shearsy.uses)
inv:set_stack("main", stack_id, stack)
break
end
end
end
-- Spawn Egg
elseif igroups.spawn_egg then
-- Spawn mob

View File

@ -55,7 +55,7 @@ local dropperdef = {
sounds = mcl_sounds.node_sound_stone_defaults(),
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for i=1, inv:get_size("main") do
@ -65,7 +65,7 @@ local dropperdef = {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local name = player:get_player_name()

View File

@ -53,7 +53,7 @@ local dropperdef = {
sounds = mcl_sounds.node_sound_stone_defaults(),
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
local inv = meta:get_inventory()
for i=1, inv:get_size("main") do
@ -63,7 +63,7 @@ local dropperdef = {
minetest.add_item(p, stack)
end
end
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
local name = player:get_player_name()

View File

@ -53,6 +53,15 @@ local function get_consumed_materials(tool, material)
return materials_used
end
local function contains(table, value)
for _, i in pairs(table) do
if i == value then
return true
end
end
return false
end
-- Given 2 input stacks, tells you which is the tool and which is the material.
-- Returns ("tool", input1, input2) if input1 is tool and input2 is material.
-- Returns ("material", input2, input1) if input1 is material and input2 is tool.
@ -60,9 +69,15 @@ end
local function distinguish_tool_and_material(input1, input2)
local def1 = input1:get_definition()
local def2 = input2:get_definition()
if def1.type == "tool" and def1._repair_material then
local r1 = def1._repair_material
local r2 = def2._repair_material
if def1.type == "tool" and r1 and type(r1) == "table" and contains(r1, input2) then
return "tool", input1, input2
elseif def2.type == "tool" and def2._repair_material then
elseif def2.type == "tool" and r2 and type(r2) == "table" and contains(r2, input1) then
return "material", input2, input1
elseif def1.type == "tool" and r1 then
return "tool", input1, input2
elseif def2.type == "tool" and r2 then
return "material", input2, input1
else
return nil
@ -121,11 +136,28 @@ local function update_anvil_slots(meta)
local distinguished, tool, material = distinguish_tool_and_material(input1, input2)
if distinguished then
local tooldef = tool:get_definition()
local repair = tooldef._repair_material
local has_correct_material = false
if string.sub(tooldef._repair_material, 1, 6) == "group:" then
has_correct_material = minetest.get_item_group(material:get_name(), string.sub(tooldef._repair_material, 7)) ~= 0
elseif material:get_name() == tooldef._repair_material then
has_correct_material = true
local material_name = material:get_name()
if type(repair) == "string" then
if string.sub(repair, 1, 6) == "group:" then
has_correct_material = minetest.get_item_group(material_name, string.sub(repair, 7)) ~= 0
elseif material_name == repair then
has_correct_material = true
end
else
if contains(repair, material_name) then
has_correct_material = true
else
for _, r in pairs(repair) do
if string.sub(r, 1, 6) == "group:" then
if minetest.get_item_group(material_name, string.sub(r, 7)) ~= 0 then
has_correct_material = true
end
end
end
end
end
if has_correct_material and tool:get_wear() > 0 then
local materials_used = get_consumed_materials(tool, material)
@ -284,6 +316,12 @@ local function damage_anvil_by_falling(pos, distance)
end
end
local anvilbox = {
type = "fixed",
fixed = {
{ -8 / 16, -8 / 16, -6 / 16, 8 / 16, 8 / 16, 6 / 16 },
},
}
local anvildef = {
groups = {pickaxey=1, falling_node=1, falling_node_damage=1, crush_after_fall=1, deco_block=1, anvil=1},
tiles = {"mcl_anvils_anvil_top_damaged_0.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png"},
@ -297,11 +335,14 @@ local anvildef = {
node_box = {
type = "fixed",
fixed = {
{-8/16, 2/16, -5/16, 8/16, 8/16, 5/16}, -- top
{-5/16, -4/16, -2/16, 5/16, 5/16, 2/16}, -- middle
{-8/16, -8/16, -5/16, 8/16, -4/16, 5/16}, -- base
{ -6 / 16, -8 / 16, -6 / 16, 6 / 16, -4 / 16, 6 / 16 },
{ -5 / 16, -4 / 16, -4 / 16, 5 / 16, -3 / 16, 4 / 16 },
{ -4 / 16, -3 / 16, -2 / 16, 4 / 16, 2 / 16, 2 / 16 },
{ -8 / 16, 2 / 16, -5 / 16, 8 / 16, 8 / 16, 5 / 16 },
}
},
selection_box = anvilbox,
collision_box = anvilbox,
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1200,
_mcl_hardness = 5,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 B

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -1,5 +1,5 @@
name = mcl_armor
author = stu
description = Adds craftable armor that is visible to other players.
depends = mcl_core, mcl_player, mcl_enchanting
depends = mcl_core, mcl_player, mcl_enchanting, mcl_damage
optional_depends = mcl_fire, ethereal, bakedclay

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 B

After

Width:  |  Height:  |  Size: 409 B

View File

@ -119,8 +119,7 @@ local patterns = {
name = N("@1 Thing Charge"),
type = "shapeless",
-- TODO: Replace with enchanted golden apple
{ e, "mcl_core:apple_gold", d },
{ e, "mcl_core:apple_gold_enchanted", d },
},
["rhombus"] = {
name = N("@1 Lozenge"),

View File

@ -12,15 +12,7 @@ Authors of media (textures)
BlockMen (CC BY-SA 3.0)
This mod adds a bed to Minetest which allows to skip the night.
To sleep, rightclick the bed. If playing in singleplayer mode the night gets skipped
immediately. If playing multiplayer you get shown how many other players are in bed too,
if all players are sleeping the night gets skipped. The night skip can be forced if more
than 50% of the players are lying in bed and use this option.
Another feature is a controlled respawning. If you have slept in bed (not just lying in
it) your respawn point is set to the beds location and you will respawn there after
To sleep, rightclick the bed.
Another feature is a controlled respawning. If you have slept in bed your respawn point is set to the beds location and you will respawn there after
death.
You can disable the respawn at beds by setting "enable_bed_respawn = false" in
minetest.conf.
You can disable the night skip feature by setting "enable_bed_night_skip = false" in
minetest.conf or by using the /set command in-game.
Use the mcl_playersSleepingPercentage setting to enable/disable night skipping or set a percentage of how many players need to sleep to skip the night.

View File

@ -14,39 +14,34 @@ local worlds_mod = minetest.get_modpath("mcl_worlds")
local function get_look_yaw(pos)
local n = minetest.get_node(pos)
if n.param2 == 1 then
return math.pi / 2, n.param2
elseif n.param2 == 3 then
return -math.pi / 2, n.param2
elseif n.param2 == 0 then
return math.pi, n.param2
local param = n.param2
if param == 1 then
return math.pi / 2, param
elseif param == 3 then
return -math.pi / 2, param
elseif param == 0 then
return math.pi, param
else
return 0, n.param2
return 0, param
end
end
local function players_in_bed_setting()
return tonumber(minetest.settings:get("mcl_playersSleepingPercentage")) or 100
end
local function is_night_skip_enabled()
local enable_night_skip = minetest.settings:get_bool("enable_bed_night_skip")
if enable_night_skip == nil then
enable_night_skip = true
end
return enable_night_skip
return players_in_bed_setting() <= 100
end
local function check_in_beds(players)
local in_bed = mcl_beds.player
if not players then
players = minetest.get_connected_players()
end
for n, player in pairs(players) do
local name = player:get_player_name()
if not in_bed[name] then
return false
end
if player_in_bed <= 0 then
return false
end
return #players > 0
return players_in_bed_setting() <= (player_in_bed * 100) / #players
end
-- These monsters do not prevent sleep
@ -198,7 +193,7 @@ end
local function update_formspecs(finished, ges)
local ges = ges or #minetest.get_connected_players()
local form_n = "size[12,5;true]"
local all_in_bed = ges == player_in_bed
local all_in_bed = players_in_bed_setting() <= (player_in_bed * 100) / ges
local night_skip = is_night_skip_enabled()
local button_leave = "button_exit[4,3;4,0.75;leave;"..F(S("Leave bed")).."]"
local button_abort = "button_exit[4,3;4,0.75;leave;"..F(S("Abort sleep")).."]"
@ -221,7 +216,13 @@ local function update_formspecs(finished, ges)
form_n = form_n .. bg_sleep
form_n = form_n .. button_abort
else
text = text .. "\n" .. S("You will fall asleep when all players are in bed.")
local comment = "You will fall asleep when "
if players_in_bed_setting() == 100 then
comment = S(comment .. "all players are in bed.")
else
comment = S(comment .. "@1% of all players are in bed.", players_in_bed_setting())
end
text = text .. "\n" .. comment
form_n = form_n .. bg_presleep
form_n = form_n .. button_leave
end
@ -330,7 +331,7 @@ function mcl_beds.on_rightclick(pos, player, is_top)
message = select(2, lay_down(player, ppos, other))
end
if message then
mcl_tmp_message.message(player, message)
mcl_title.set(player, "actionbar", {text=message, color="white", stay=60})
end
else
lay_down(player, nil, nil, false)
@ -349,7 +350,6 @@ function mcl_beds.on_rightclick(pos, player, is_top)
end
end
-- Callbacks
minetest.register_on_joinplayer(function(player)
local meta = player:get_meta()

View File

@ -37,5 +37,6 @@ Players in bed: @1/@2=Spieler im Bett: @1/@2
Note: Night skip is disabled.=Anmerkung: Überspringen der Nacht deaktiviert.
You're sleeping.=Sie schlafen.
You will fall asleep when all players are in bed.=Sie werden einschlafen, wenn alle Spieler im Bett sind.
You will fall asleep when @1% of all players are in bed.=Sie werden einschlafen, wenn @1% der Spieler im Bett sind.
You're in bed.=Sie sind im Bett.
Allows you to sleep=Zum Einschafen

View File

@ -37,5 +37,6 @@ Players in bed: @1/@2=
Note: Night skip is disabled.=
You're sleeping.=
You will fall asleep when all players are in bed.=
You will fall asleep when @1% of all players are in bed.=
You're in bed.=
Allows you to sleep=

View File

@ -43,7 +43,7 @@ S("An arrow fired from a bow has a regular damage of 1-9. At full charge, there'
S("Arrows might get stuck on solid blocks and can be retrieved again. They are also capable of pushing wooden buttons."),
_doc_items_usagehelp = S("To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory. To retrieve an arrow that sticks in a block, simply walk close to it."),
inventory_image = "mcl_bows_arrow_inv.png",
groups = { ammo=1, ammo_bow=1, ammo_bow_regular=1 },
groups = { ammo=1, ammo_bow=1, ammo_bow_regular=1, ammo_crossbow=1 },
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
-- Shoot arrow
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
@ -73,7 +73,7 @@ local ARROW_ENTITY={
_stuckin=nil, --Position of node in which arow is stuck.
_shooter=nil, -- ObjectRef of player or mob who shot it
_is_arrow = true,
_in_player = false,
_viscosity=0, -- Viscosity of node the arrow is currently in
_deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession
}
@ -324,7 +324,9 @@ function ARROW_ENTITY.on_step(self, dtime)
end
if not obj:is_player() then
mcl_burning.extinguish(self.object)
self.object:remove()
if self._piercing == 0 then
self.object:remove()
end
end
return
end
@ -437,6 +439,7 @@ function ARROW_ENTITY.get_staticdata(self)
is_critical = self._is_critical,
stuck = self._stuck,
stuckin = self._stuckin,
stuckin_player = self._in_player,
}
if self._stuck then
-- If _stucktimer is missing for some reason, assume the maximum
@ -453,7 +456,6 @@ end
function ARROW_ENTITY.on_activate(self, staticdata, dtime_s)
self._time_in_air = 1.0
self._in_player = false
local data = minetest.deserialize(staticdata)
if data then
self._stuck = data.stuck
@ -486,10 +488,23 @@ function ARROW_ENTITY.on_activate(self, staticdata, dtime_s)
self._shooter = shooter
end
end
if data.stuckin_player then
self.object:remove()
end
end
self.object:set_armor_groups({ immortal = 1 })
end
minetest.register_on_respawnplayer(function(player)
for _, obj in pairs(player:get_children()) do
local ent = obj:get_luaentity()
if ent and ent.name and string.find(ent.name, "mcl_bows:arrow_entity") then
obj:remove()
end
end
end)
minetest.register_entity("mcl_bows:arrow_entity", ARROW_ENTITY)
if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_mobitems") then

View File

@ -0,0 +1,454 @@
local S = minetest.get_translator(minetest.get_current_modname())
mcl_bows_s = {}
-- local arrows = {
-- ["mcl_bows:arrow"] = "mcl_bows:arrow_entity",
-- }
local GRAVITY = 9.81
local BOW_DURABILITY = 385
-- Charging time in microseconds
local _BOW_CHARGE_TIME_HALF = 350000 -- bow level 1
local _BOW_CHARGE_TIME_FULL = 900000 -- bow level 2 (full charge)
local BOW_CHARGE_TIME_HALF = 350000 -- bow level 1
local BOW_CHARGE_TIME_FULL = 900000 -- bow level 2 (full charge)
-- Factor to multiply with player speed while player uses bow
-- This emulates the sneak speed.
local PLAYER_USE_CROSSBOW_SPEED = tonumber(minetest.settings:get("movement_speed_crouch")) / tonumber(minetest.settings:get("movement_speed_walk"))
-- TODO: Use Minecraft speed (ca. 53 m/s)
-- Currently nerfed because at full speed the arrow would easily get out of the range of the loaded map.
local BOW_MAX_SPEED = 68
local function play_load_sound(id, pos)
minetest.sound_play("mcl_bows_crossbow_drawback_"..id, {pos=pos, max_hear_distance=12}, true)
end
--[[ Store the charging state of each player.
keys: player name
value:
nil = not charging or player not existing
number: currently charging, the number is the time from minetest.get_us_time
in which the charging has started
]]
local bow_load = {}
-- Another player table, this one stores the wield index of the bow being charged
local bow_index = {}
function mcl_bows_s.shoot_arrow_crossbow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, crossbow_stack, collectable)
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
if power == nil then
power = BOW_MAX_SPEED --19
end
if damage == nil then
damage = 3
end
local knockback
if crossbow_stack then
local enchantments = mcl_enchanting.get_enchantments(crossbow_stack)
if enchantments.piercing then
obj:get_luaentity()._piercing = 1 * enchantments.piercing
else
obj:get_luaentity()._piercing = 0
end
end
obj:set_velocity({x=dir.x*power, y=dir.y*power, z=dir.z*power})
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
obj:set_yaw(yaw-math.pi/2)
local le = obj:get_luaentity()
le._shooter = shooter
le._source_object = shooter
le._damage = damage
le._is_critical = is_critical
le._startpos = pos
le._knockback = knockback
le._collectable = collectable
minetest.sound_play("mcl_bows_crossbow_shoot", {pos=pos, max_hear_distance=16}, true)
if shooter and shooter:is_player() then
if obj:get_luaentity().player == "" then
obj:get_luaentity().player = shooter
end
obj:get_luaentity().node = shooter:get_inventory():get_stack("main", 1):get_name()
end
return obj
end
local function get_arrow(player)
local inv = player:get_inventory()
local arrow_stack, arrow_stack_id
for i=1, inv:get_size("main") do
local it = inv:get_stack("main", i)
if not it:is_empty() and minetest.get_item_group(it:get_name(), "ammo_crossbow") ~= 0 then
arrow_stack = it
arrow_stack_id = i
break
end
end
return arrow_stack, arrow_stack_id
end
local function player_shoot_arrow(wielditem, player, power, damage, is_critical)
local has_multishot_enchantment = mcl_enchanting.has_enchantment(player:get_wielded_item(), "multishot")
local arrow_itemstring = wielditem:get_meta():get("arrow")
if not arrow_itemstring then
return false
end
local playerpos = player:get_pos()
local dir = player:get_look_dir()
local yaw = player:get_look_horizontal()
if has_multishot_enchantment then
mcl_bows_s.shoot_arrow_crossbow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, {x=dir.x, y=dir.y, z=dir.z + .2}, yaw, player, power, damage, is_critical, player:get_wielded_item(), false)
mcl_bows_s.shoot_arrow_crossbow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, {x=dir.x, y=dir.y, z=dir.z - .2}, yaw, player, power, damage, is_critical, player:get_wielded_item(), false)
mcl_bows_s.shoot_arrow_crossbow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, dir, yaw, player, power, damage, is_critical, player:get_wielded_item(), true)
else
mcl_bows_s.shoot_arrow_crossbow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, dir, yaw, player, power, damage, is_critical, player:get_wielded_item(), true)
end
return true
end
-- Bow item, uncharged state
minetest.register_tool("mcl_bows:crossbow", {
description = S("Corssbow"),
_tt_help = S("Launches arrows"),
_doc_items_longdesc = S("Bows are ranged weapons to shoot arrows at your foes.").."\n"..
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
_doc_items_usagehelp = S("To use the bow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to shoot."),
_doc_items_durability = BOW_DURABILITY,
inventory_image = "mcl_bows_crossbow.png",
wield_scale = mcl_vars.tool_wield_scale,
stack_max = 1,
range = 4,
-- Trick to disable digging as well
on_use = function() return end,
on_place = function(itemstack, player, pointed_thing)
if pointed_thing and pointed_thing.type == "node" then
-- Call on_rightclick if the pointed node defines it
local node = minetest.get_node(pointed_thing.under)
if player and not player:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, player, itemstack) or itemstack
end
end
end
itemstack:get_meta():set_string("active", "true")
return itemstack
end,
on_secondary_use = function(itemstack)
itemstack:get_meta():set_string("active", "true")
return itemstack
end,
groups = {weapon=1,weapon_ranged=1,crossbow=1,enchantability=1},
_mcl_uses = 326,
})
minetest.register_tool("mcl_bows:crossbow_loaded", {
description = S("Corssbow"),
_tt_help = S("Launches arrows"),
_doc_items_longdesc = S("Corssbow are ranged weapons to shoot arrows at your foes.").."\n"..
S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."),
_doc_items_usagehelp = S("To use the corssbow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to load an arrow into the chamber, then to shoot press left mouse."),
_doc_items_durability = BOW_DURABILITY,
inventory_image = "mcl_bows_crossbow_3.png",
wield_scale = mcl_vars.tool_wield_scale,
stack_max = 1,
range = 4,
-- Trick to disable digging as well
on_use = function() return end,
on_place = function(itemstack, player, pointed_thing)
if pointed_thing and pointed_thing.type == "node" then
-- Call on_rightclick if the pointed node defines it
local node = minetest.get_node(pointed_thing.under)
if player and not player:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, player, itemstack) or itemstack
end
end
end
itemstack:get_meta():set_string("active", "true")
return itemstack
end,
on_secondary_use = function(itemstack)
itemstack:get_meta():set_string("active", "true")
return itemstack
end,
groups = {weapon=1,weapon_ranged=1,crossbow=1,enchantability=1},
_mcl_uses = 326,
})
-- Iterates through player inventory and resets all the bows in "charging" state back to their original stage
local function reset_bows(player)
local inv = player:get_inventory()
local list = inv:get_list("main")
for place, stack in pairs(list) do
if stack:get_name() == "mcl_bows:crossbow" or stack:get_name() == "mcl_bows:crossbow_enchanted" then
stack:get_meta():set_string("active", "")
elseif stack:get_name()=="mcl_bows:crossbow_0" or stack:get_name()=="mcl_bows:crossbow_1" or stack:get_name()=="mcl_bows:crossbow_2" then
stack:set_name("mcl_bows:crossbow")
stack:get_meta():set_string("active", "")
list[place] = stack
elseif stack:get_name()=="mcl_bows:crossbow_0_enchanted" or stack:get_name()=="mcl_bows:crossbow_1_enchanted" or stack:get_name()=="mcl_bows:crossbow_2_enchanted" then
stack:set_name("mcl_bows:crossbow_enchanted")
stack:get_meta():set_string("active", "")
list[place] = stack
end
end
inv:set_list("main", list)
end
-- Resets the bow charging state and player speed. To be used when the player is no longer charging the bow
local function reset_bow_state(player, also_reset_bows)
bow_load[player:get_player_name()] = nil
bow_index[player:get_player_name()] = nil
if minetest.get_modpath("playerphysics") then
playerphysics.remove_physics_factor(player, "speed", "mcl_bows:use_crossbow")
end
if also_reset_bows then
reset_bows(player)
end
end
-- Bow in charging state
for level=0, 2 do
minetest.register_tool("mcl_bows:crossbow_"..level, {
description = S("Crossbow"),
_doc_items_create_entry = false,
inventory_image = "mcl_bows_crossbow_"..level..".png",
wield_scale = mcl_vars.tool_wield_scale,
stack_max = 1,
range = 0, -- Pointing range to 0 to prevent punching with bow :D
groups = {not_in_creative_inventory=1, not_in_craft_guide=1, bow=1, enchantability=1},
-- Trick to disable digging as well
on_use = function() return end,
on_drop = function(itemstack, dropper, pos)
reset_bow_state(dropper)
itemstack:get_meta():set_string("active", "")
if mcl_enchanting.is_enchanted(itemstack:get_name()) then
itemstack:set_name("mcl_bows:crossbow_enchanted")
else
itemstack:set_name("mcl_bows:crossbow")
end
minetest.item_drop(itemstack, dropper, pos)
itemstack:take_item()
return itemstack
end,
-- Prevent accidental interaction with itemframes and other nodes
on_place = function(itemstack)
return itemstack
end,
_mcl_uses = 385,
})
end
controls.register_on_release(function(player, key, time)
if key~="RMB" then return end
--local inv = minetest.get_inventory({type="player", name=player:get_player_name()})
local wielditem = player:get_wielded_item()
if wielditem:get_name()=="mcl_bows:crossbow_2" and get_arrow(player) or wielditem:get_name()=="mcl_bows:crossbow_2" and minetest.is_creative_enabled(player:get_player_name()) or wielditem:get_name()=="mcl_bows:crossbow_2_enchanted" and get_arrow(player) or wielditem:get_name()=="mcl_bows:crossbow_2_enchanted" and minetest.is_creative_enabled(player:get_player_name()) then
local arrow_stack, arrow_stack_id = get_arrow(player)
local arrow_itemstring
if minetest.is_creative_enabled(player:get_player_name()) then
if arrow_stack then
arrow_itemstring = arrow_stack:get_name()
else
arrow_itemstring = "mcl_bows:arrow"
end
else
arrow_itemstring = arrow_stack:get_name()
arrow_stack:take_item()
player:get_inventory():set_stack("main", arrow_stack_id, arrow_stack)
end
wielditem:get_meta():set_string("arrow", arrow_itemstring)
if wielditem:get_name()=="mcl_bows:crossbow_2" then
wielditem:set_name("mcl_bows:crossbow_loaded")
else
wielditem:set_name("mcl_bows:crossbow_loaded_enchanted")
end
player:set_wielded_item(wielditem)
minetest.sound_play("mcl_bows_crossbow_load", {pos=player:get_pos(), max_hear_distance=16}, true)
else
reset_bow_state(player, true)
end
end)
controls.register_on_press(function(player, key, time)
if key~="LMB" then return end
local wielditem = player:get_wielded_item()
if wielditem:get_name()=="mcl_bows:crossbow_loaded" or wielditem:get_name()=="mcl_bows:crossbow_loaded_enchanted" then
local enchanted = mcl_enchanting.is_enchanted(wielditem:get_name())
local speed, damage
local p_load = bow_load[player:get_player_name()]
local charge
-- Type sanity check
if type(p_load) == "number" then
charge = minetest.get_us_time() - p_load
else
-- In case something goes wrong ...
-- Just assume minimum charge.
charge = 0
minetest.log("warning", "[mcl_bows] Player "..player:get_player_name().." fires arrow with non-numeric bow_load!")
end
charge = math.max(math.min(charge, BOW_CHARGE_TIME_FULL), 0)
local charge_ratio = charge / BOW_CHARGE_TIME_FULL
charge_ratio = math.max(math.min(charge_ratio, 1), 0)
-- Calculate damage and speed
-- Fully charged
local is_critical = false
speed = BOW_MAX_SPEED
local r = math.random(1,5)
if r == 1 then
-- 20% chance for critical hit
damage = 10
is_critical = true
else
damage = 9
end
local has_shot = player_shoot_arrow(wielditem, player, speed, damage, is_critical)
if enchanted then
wielditem:set_name("mcl_bows:crossbow_enchanted")
else
wielditem:set_name("mcl_bows:crossbow")
end
if has_shot and not minetest.is_creative_enabled(player:get_player_name()) then
local durability = BOW_DURABILITY
local unbreaking = mcl_enchanting.get_enchantment(wielditem, "unbreaking")
local multishot = mcl_enchanting.get_enchantment(wielditem, "multishot")
if unbreaking > 0 then
durability = durability * (unbreaking + 1)
end
if multishot then
durability = durability / 3
end
wielditem:add_wear(65535/durability)
end
player:set_wielded_item(wielditem)
reset_bow_state(player, true)
end
end)
controls.register_on_hold(function(player, key, time)
local name = player:get_player_name()
local creative = minetest.is_creative_enabled(name)
if key ~= "RMB" then
return
end
--local inv = minetest.get_inventory({type="player", name=name})
local wielditem = player:get_wielded_item()
local enchantments = mcl_enchanting.get_enchantments(wielditem)
if enchantments.quick_charge then
BOW_CHARGE_TIME_HALF = _BOW_CHARGE_TIME_HALF - (enchantments.quick_charge * 0.13 * 1000000 * .5)
BOW_CHARGE_TIME_FULL = _BOW_CHARGE_TIME_FULL - (enchantments.quick_charge * 0.13 * 1000000)
else
BOW_CHARGE_TIME_HALF = _BOW_CHARGE_TIME_HALF
BOW_CHARGE_TIME_FULL = _BOW_CHARGE_TIME_FULL
end
if bow_load[name] == nil and (wielditem:get_name()=="mcl_bows:crossbow" or wielditem:get_name()=="mcl_bows:crossbow_enchanted") and wielditem:get_meta():get("active") and (creative or get_arrow(player)) then
local enchanted = mcl_enchanting.is_enchanted(wielditem:get_name())
if enchanted then
wielditem:set_name("mcl_bows:crossbow_0_enchanted")
play_load_sound(0, player:get_pos())
else
wielditem:set_name("mcl_bows:crossbow_0")
play_load_sound(0, player:get_pos())
end
player:set_wielded_item(wielditem)
if minetest.get_modpath("playerphysics") then
-- Slow player down when using bow
playerphysics.add_physics_factor(player, "speed", "mcl_bows:use_crossbow", PLAYER_USE_CROSSBOW_SPEED)
end
bow_load[name] = minetest.get_us_time()
bow_index[name] = player:get_wield_index()
else
if player:get_wield_index() == bow_index[name] then
if type(bow_load[name]) == "number" then
if wielditem:get_name() == "mcl_bows:crossbow_0" and minetest.get_us_time() - bow_load[name] >= BOW_CHARGE_TIME_HALF then
wielditem:set_name("mcl_bows:crossbow_1")
play_load_sound(1, player:get_pos())
elseif wielditem:get_name() == "mcl_bows:crossbow_0_enchanted" and minetest.get_us_time() - bow_load[name] >= BOW_CHARGE_TIME_HALF then
wielditem:set_name("mcl_bows:crossbow_1_enchanted")
play_load_sound(1, player:get_pos())
elseif wielditem:get_name() == "mcl_bows:crossbow_1" and minetest.get_us_time() - bow_load[name] >= BOW_CHARGE_TIME_FULL then
wielditem:set_name("mcl_bows:crossbow_2")
play_load_sound(2, player:get_pos())
elseif wielditem:get_name() == "mcl_bows:crossbow_1_enchanted" and minetest.get_us_time() - bow_load[name] >= BOW_CHARGE_TIME_FULL then
wielditem:set_name("mcl_bows:crossbow_2_enchanted")
play_load_sound(2, player:get_pos())
end
else
if wielditem:get_name() == "mcl_bows:crossbow_0" or wielditem:get_name() == "mcl_bows:crossbow_1" or wielditem:get_name() == "mcl_bows:crossbow_2" then
wielditem:set_name("mcl_bows:crossbow")
play_load_sound(1, player:get_pos())
elseif wielditem:get_name() == "mcl_bows:crossbow_0_enchanted" or wielditem:get_name() == "mcl_bows:crossbow_1_enchanted" or wielditem:get_name() == "mcl_bows:crossbow_2_enchanted" then
wielditem:set_name("mcl_bows:crossbow_enchanted")
play_load_sound(1, player:get_pos())
end
end
player:set_wielded_item(wielditem)
else
reset_bow_state(player, true)
end
end
end)
minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
local name = player:get_player_name()
local wielditem = player:get_wielded_item()
local wieldindex = player:get_wield_index()
--local controls = player:get_player_control()
if type(bow_load[name]) == "number" and ((wielditem:get_name()~="mcl_bows:crossbow_0" and wielditem:get_name()~="mcl_bows:crossbow_1" and wielditem:get_name()~="mcl_bows:crossbow_2" and wielditem:get_name()~="mcl_bows:crossbow_0_enchanted" and wielditem:get_name()~="mcl_bows:crossbow_1_enchanted" and wielditem:get_name()~="mcl_bows:crossbow_2_enchanted") or wieldindex ~= bow_index[name]) then
reset_bow_state(player, true)
end
end
end)
minetest.register_on_joinplayer(function(player)
reset_bows(player)
end)
minetest.register_on_leaveplayer(function(player)
reset_bow_state(player, true)
end)
if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_mobitems") then
minetest.register_craft({
output = "mcl_bows:crossbow",
recipe = {
{"mcl_core:stick", "mcl_core:iron_ingot", "mcl_core:stick"},
{"mcl_mobitems:string", "mcl_bows:arrow", "mcl_mobitems:string"},
{"", "mcl_core:stick", ""},
}
})
end
minetest.register_craft({
type = "fuel",
recipe = "group:bow",
burntime = 15,
})
-- Add entry aliases for the Help
if minetest.get_modpath("doc") then
doc.add_entry_alias("tools", "mcl_bows:crossbow", "tools", "mcl_bows:crossbow_0")
doc.add_entry_alias("tools", "mcl_bows:crossbow", "tools", "mcl_bows:crossbow_1")
doc.add_entry_alias("tools", "mcl_bows:crossbow", "tools", "mcl_bows:crossbow_2")
end

View File

@ -1,5 +1,11 @@
--Bow
dofile(minetest.get_modpath("mcl_bows") .. "/arrow.lua")
dofile(minetest.get_modpath("mcl_bows") .. "/bow.lua")
dofile(minetest.get_modpath("mcl_bows") .. "/rocket.lua")
--Crossbow
dofile(minetest.get_modpath("mcl_bows") .. "/crossbow.lua")
--Compatiblility with older MineClone worlds
minetest.register_alias("mcl_throwing:bow", "mcl_bows:bow")
minetest.register_alias("mcl_throwing:arrow", "mcl_bows:arrow")

Binary file not shown.

View File

@ -0,0 +1,10 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl None
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,706 @@
local S = minetest.get_translator(minetest.get_current_modname())
local math = math
local vector = vector
-- Time in seconds after which a stuck arrow is deleted
local ARROW_TIMEOUT = 1
-- Time after which stuck arrow is rechecked for being stuck
local STUCK_RECHECK_TIME = 0.1
--local GRAVITY = 9.81
local YAW_OFFSET = -math.pi/2
local function dir_to_pitch(dir)
--local dir2 = vector.normalize(dir)
local xz = math.abs(dir.x) + math.abs(dir.z)
return -math.atan2(-dir.y, xz)
end
local function random_arrow_positions(positions, placement)
if positions == "x" then
return math.random(-4, 4)
elseif positions == "y" then
return math.random(0, 10)
end
if placement == "front" and positions == "z" then
return 3
elseif placement == "back" and positions == "z" then
return -3
end
return 0
end
local function damage_explosion(self, damagemulitplier)
mcl_explosions.explode(self.object:get_pos(), 3, {})
local objects = minetest.get_objects_inside_radius(self.object:get_pos(), 8)
for _,obj in pairs(objects) do
if obj:is_player() then
mcl_util.deal_damage(obj, damagemulitplier - vector.distance(self.object:get_pos(), obj:get_pos()), {type = "explosion"})
elseif obj:get_luaentity()._cmi_is_mob then
obj:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=damagemulitplier - vector.distance(self.object:get_pos(), obj:get_pos())},
}, self.object:get_velocity())
end
end
end
local function particle_explosion(self)
local particle_pattern = math.random(1, 3)
local fpitch = 0
local true_type = ""
local type = math.random(1,2)
local size = math.random(1,3)
local colors = {"red", "yellow", "blue", "green", "white"}
local this_colors = {colors[math.random(#colors)], colors[math.random(#colors)], colors[math.random(#colors)]}
if size == 1 then
fpitch = math.random(200, 300)
elseif size == 2 then
fpitch = math.random(100, 130)
else
fpitch = math.random(60, 70)
end
if type == 1 then
true_type = "Popper"
else
true_type = "Floof"
end
if type == 1 then
minetest.sound_play("mcl_bows_firework", {
pos = self.object:get_pos(),
max_hear_distance = 100,
gain = 3.0,
pitch = fpitch/100
}, true)
else
minetest.sound_play("mcl_bows_firework_soft", {
pos = self.object:get_pos(),
max_hear_distance = 100,
gain = 4.0,
pitch = fpitch/100
}, true)
end
if particle_pattern == 1 then
minetest.add_particlespawner({
amount = 400 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-7 * size,-7 * size,-7 * size),
maxvel = vector.new(7 * size,7 * size,7 * size),
minexptime = .6 * size / 2,
maxexptime = .9 * size / 2,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[1]..".png",
glow = 14,
})
minetest.add_particlespawner({
amount = 400 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-2 * size,-2 * size,-2 * size),
maxvel = vector.new(2 * size,2 * size,2 * size),
minexptime = .6 * size / 2,
maxexptime = .9 * size / 2,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[2]..".png",
glow = 14,
})
minetest.add_particlespawner({
amount = 100 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-14 * size,-14 * size,-14 * size),
maxvel = vector.new(14 * size,14 * size,14 * size),
minexptime = .6 * size / 2,
maxexptime = .9 * size / 2,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[3]..".png",
glow = 14,
})
elseif particle_pattern == 2 then
minetest.add_particlespawner({
amount = 240 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-5 * size,-5 * size,-5 * size),
maxvel = vector.new(5 * size,5 * size,5 * size),
minexptime = .6 * size / 2,
maxexptime = .9 * size / 2,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[1]..".png",
glow = 14,
})
minetest.add_particlespawner({
amount = 500 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-2 * size,-2 * size,-2 * size),
maxvel = vector.new(2 * size,2 * size,2 * size),
minexptime = .6 * size / 2,
maxexptime = .9 * size / 2,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[2]..".png",
glow = 14,
})
minetest.add_particlespawner({
amount = 350 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-3 * size,-3 * size,-3 * size),
maxvel = vector.new(3 * size,3 * size,3 * size),
minexptime = .6 * size / 2,
maxexptime = .9 * size / 2,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[3]..".png",
glow = 14,
})
elseif particle_pattern == 3 then
minetest.add_particlespawner({
amount = 400 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-6 * size,-4 * size,-6 * size),
maxvel = vector.new(6 * size,4 * size,6 * size),
minexptime = .6 * size,
maxexptime = .9 * size,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[1]..".png",
glow = 14,
})
minetest.add_particlespawner({
amount = 120 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-8 * size,6 * size,-8 * size),
maxvel = vector.new(8 * size,6 * size,8 * size),
minexptime = .6 * size,
maxexptime = .9 * size,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[2]..".png",
glow = 14,
})
minetest.add_particlespawner({
amount = 130 * size,
time = 0.0001,
minpos = self.object:get_pos(),
maxpos = self.object:get_pos(),
minvel = vector.new(-3 * size,3 * size,-3 * size),
maxvel = vector.new(3 * size,3 * size,3 * size),
minexptime = .6 * size,
maxexptime = .9 * size,
minsize = 2 * size,
maxsize = 3 * size,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_firework_"..this_colors[3]..".png",
glow = 14,
})
end
return size
end
local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements")
local mod_button = minetest.get_modpath("mesecons_button")
minetest.register_craftitem("mcl_bows:rocket", {
description = S("Arrow"),
_tt_help = S("Ammunition").."\n"..S("Damage from bow: 1-10").."\n"..S("Damage from dispenser: 3"),
_doc_items_longdesc = S("Arrows are ammunition for bows and dispensers.").."\n"..
S("An arrow fired from a bow has a regular damage of 1-9. At full charge, there's a 20% chance of a critical hit dealing 10 damage instead. An arrow fired from a dispenser always deals 3 damage.").."\n"..
S("Arrows might get stuck on solid blocks and can be retrieved again. They are also capable of pushing wooden buttons."),
_doc_items_usagehelp = S("To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory. To retrieve an arrow that sticks in a block, simply walk close to it."),
inventory_image = "mcl_bows_rocket.png",
groups = { ammo=1, ammo_crossbow=1, ammo_bow_regular=1 },
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
-- Shoot arrow
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
local yaw = math.atan2(dropdir.z, dropdir.x) + YAW_OFFSET
mcl_bows.shoot_arrow(itemstack:get_name(), shootpos, dropdir, yaw, nil, 19, 3)
end,
})
local ARROW_ENTITY={
physical = true,
pointable = false,
visual = "mesh",
mesh = "mcl_bows_rocket.obj",
visual_size = {x=2.5, y=2.5},
textures = {"mcl_bows_rocket.png"},
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
collide_with_objects = false,
_fire_damage_resistant = true,
_lastpos={},
_startpos=nil,
_damage=1, -- Damage on impact
_is_critical=false, -- Whether this arrow would deal critical damage
_stuck=false, -- Whether arrow is stuck
_fuse=nil,-- Amount of time (in seconds) the arrow has been stuck so far
_fuserechecktimer=nil,-- An additional timer for periodically re-checking the stuck status of an arrow
_stuckin=nil, --Position of node in which arow is stuck.
_shooter=nil, -- ObjectRef of player or mob who shot it
_is_arrow = true,
_viscosity=0, -- Viscosity of node the arrow is currently in
_deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession
}
-- Destroy arrow entity self at pos and drops it as an item
local function spawn_item(self, pos)
if not minetest.is_creative_enabled("") then
local item = minetest.add_item(pos, "mcl_bows:rocket")
item:set_velocity({x=0, y=0, z=0})
item:set_yaw(self.object:get_yaw())
end
mcl_burning.extinguish(self.object)
self.object:remove()
end
local function damage_particles(pos, is_critical)
if is_critical then
minetest.add_particlespawner({
amount = 15,
time = 0.1,
minpos = {x=pos.x-0.5, y=pos.y-0.5, z=pos.z-0.5},
maxpos = {x=pos.x+0.5, y=pos.y+0.5, z=pos.z+0.5},
minvel = {x=-0.1, y=-0.1, z=-0.1},
maxvel = {x=0.1, y=0.1, z=0.1},
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1,
maxexptime = 2,
minsize = 1.5,
maxsize = 1.5,
collisiondetection = false,
vertical = false,
texture = "mcl_particles_crit.png^[colorize:#bc7a57:127",
})
end
end
function ARROW_ENTITY.on_step(self, dtime)
mcl_burning.tick(self.object, dtime, self)
self._time_in_air = self._time_in_air + .001
local pos = self.object:get_pos()
local dpos = table.copy(pos) -- digital pos
dpos = vector.round(dpos)
local node = minetest.get_node(dpos)
if not self._fuse then
self._fuse = 0
end
if not self._fuserechecktimer then
self._fuserechecktimer = 0
end
self._fuse = self._fuse + dtime
self._fuserechecktimer = self._fuserechecktimer + dtime
if self._fuse > ARROW_TIMEOUT then
self._stuck = true
end
if self._stuck then
if self._fuse > ARROW_TIMEOUT then
local eploded_particle = particle_explosion(self)
damage_explosion(self, eploded_particle * 17)
mcl_burning.extinguish(self.object)
self.object:remove()
return
end
-- Drop arrow as item when it is no longer stuck
-- FIXME: Arrows are a bit slow to react and continue to float in mid air for a few seconds.
if self._fuserechecktimer > STUCK_RECHECK_TIME then
local stuckin_def
if self._stuckin then
stuckin_def = minetest.registered_nodes[minetest.get_node(self._stuckin).name]
end
-- TODO: In MC, arrow just falls down without turning into an item
if stuckin_def and stuckin_def.walkable == false then
spawn_item(self, pos)
return
end
self._fuserechecktimer = 0
end
-- Pickup arrow if player is nearby (not in Creative Mode)
local objects = minetest.get_objects_inside_radius(pos, 1)
for _,obj in ipairs(objects) do
if obj:is_player() then
if self._collectable and not minetest.is_creative_enabled(obj:get_player_name()) then
if obj:get_inventory():room_for_item("main", "mcl_bows:rocket") then
obj:get_inventory():add_item("main", "mcl_bows:rocket")
minetest.sound_play("item_drop_pickup", {
pos = pos,
max_hear_distance = 16,
gain = 1.0,
}, true)
end
end
mcl_burning.extinguish(self.object)
self.object:remove()
return
end
end
-- Check for object "collision". Done every tick (hopefully this is not too stressing)
else
if self._in_player == false then
minetest.add_particlespawner({
amount = 1,
time = .0001,
minpos = pos,
maxpos = pos,
minvel = vector.new(-0.1,-0.1,-0.1),
maxvel = vector.new(0.1,0.1,0.1),
minexptime = 0.5,
maxexptime = 0.5,
minsize = 2,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "mcl_bows_rocket_particle.png",
glow = 1,
})
end
-- We just check for any hurtable objects nearby.
-- The radius of 3 is fairly liberal, but anything lower than than will cause
-- arrow to hilariously go through mobs often.
-- TODO: Implement an ACTUAL collision detection (engine support needed).
local objs = minetest.get_objects_inside_radius(pos, 1.5)
local closest_object
local closest_distance
if self._deflection_cooloff > 0 then
self._deflection_cooloff = self._deflection_cooloff - dtime
end
-- Iterate through all objects and remember the closest attackable object
for k, obj in pairs(objs) do
local ok = false
-- Arrows can only damage players and mobs
if obj:is_player() then
ok = true
elseif obj:get_luaentity() then
if (obj:get_luaentity()._cmi_is_mob or obj:get_luaentity()._hittable_by_projectile) then
ok = true
end
end
if ok then
local dist = vector.distance(pos, obj:get_pos())
if not closest_object or not closest_distance then
closest_object = obj
closest_distance = dist
elseif dist < closest_distance then
closest_object = obj
closest_distance = dist
end
end
end
-- If an attackable object was found, we will damage the closest one only
if closest_object then
local obj = closest_object
local is_player = obj:is_player()
local lua = obj:get_luaentity()
if obj == self._shooter and self._time_in_air > 1.02 or obj ~= self._shooter and (is_player or (lua and (lua._cmi_is_mob or lua._hittable_by_projectile))) then
if obj:get_hp() > 0 then
-- Check if there is no solid node between arrow and object
local ray = minetest.raycast(self.object:get_pos(), obj:get_pos(), true)
for pointed_thing in ray do
if pointed_thing.type == "object" and pointed_thing.ref == closest_object then
-- Target reached! We can proceed now.
break
elseif pointed_thing.type == "node" then
local nn = minetest.get_node(minetest.get_pointed_thing_position(pointed_thing)).name
local def = minetest.registered_nodes[nn]
if (not def) or def.walkable then
-- There's a node in the way. Delete arrow without damage
mcl_burning.extinguish(self.object)
self.object:remove()
return
end
end
end
-- Punch target object but avoid hurting enderman.
if not lua or lua.name ~= "mobs_mc:enderman" then
if self._in_player == false then
damage_particles(self.object:get_pos(), self._is_critical)
end
if mcl_burning.is_burning(self.object) then
mcl_burning.set_on_fire(obj, 5)
end
if self._in_player == false then
obj:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self._damage},
}, self.object:get_velocity())
if obj:is_player() then
local eploded_particle = particle_explosion(self)
damage_explosion(self, eploded_particle * 17)
mcl_burning.extinguish(self.object)
self.object:remove()
end
end
end
if is_player then
if self._shooter and self._shooter:is_player() and self._in_player == false then
-- “Ding” sound for hitting another player
minetest.sound_play({name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true)
end
end
if lua then
local entity_name = lua.name
-- Achievement for hitting skeleton, wither skeleton or stray (TODO) with an arrow at least 50 meters away
-- NOTE: Range has been reduced because mobs unload much earlier than that ... >_>
-- TODO: This achievement should be given for the kill, not just a hit
if self._shooter and self._shooter:is_player() and vector.distance(pos, self._startpos) >= 20 then
if mod_awards and (entity_name == "mobs_mc:skeleton" or entity_name == "mobs_mc:stray" or entity_name == "mobs_mc:witherskeleton") then
awards.unlock(self._shooter:get_player_name(), "mcl:snipeSkeleton")
end
end
end
if self._in_player == false then
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
end
end
if not obj:is_player() then
mcl_burning.extinguish(self.object)
if self._piercing == 0 then
local eploded_particle = particle_explosion(self)
damage_explosion(self, eploded_particle * 17)
self.object:remove()
end
end
return
end
end
end
-- Check for node collision
if self._lastpos.x~=nil and not self._stuck then
local def = minetest.registered_nodes[node.name]
local vel = self.object:get_velocity()
-- Arrow has stopped in one axis, so it probably hit something.
-- This detection is a bit clunky, but sadly, MT does not offer a direct collision detection for us. :-(
if (math.abs(vel.x) < 0.0001) or (math.abs(vel.z) < 0.0001) or (math.abs(vel.y) < 0.00001) then
-- Check for the node to which the arrow is pointing
local dir
if math.abs(vel.y) < 0.00001 then
if self._lastpos.y < pos.y then
dir = {x=0, y=1, z=0}
else
dir = {x=0, y=-1, z=0}
end
else
dir = minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(self.object:get_yaw()-YAW_OFFSET)))
end
self._stuckin = vector.add(dpos, dir)
local snode = minetest.get_node(self._stuckin)
local sdef = minetest.registered_nodes[snode.name]
-- If node is non-walkable, unknown or ignore, don't make arrow stuck.
-- This causes a deflection in the engine.
if not sdef or sdef.walkable == false or snode.name == "ignore" then
self._stuckin = nil
if self._deflection_cooloff <= 0 then
-- Lose 1/3 of velocity on deflection
local newvel = vector.multiply(vel, 0.6667)
self.object:set_velocity(newvel)
-- Reset deflection cooloff timer to prevent many deflections happening in quick succession
self._deflection_cooloff = 1.0
end
else
-- Node was walkable, make arrow stuck
self._stuck = true
self._fuserechecktimer = 0
self.object:set_velocity({x=0, y=0, z=0})
self.object:set_acceleration({x=0, y=0, z=0})
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
if mcl_burning.is_burning(self.object) and snode.name == "mcl_tnt:tnt" then
tnt.ignite(self._stuckin)
end
-- Push the button! Push, push, push the button!
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
local bdir = minetest.wallmounted_to_dir(node.param2)
-- Check the button orientation
if vector.equals(vector.add(dpos, bdir), self._stuckin) then
mesecon.push_button(dpos, node)
end
end
end
elseif (def and def.liquidtype ~= "none") then
-- Slow down arrow in liquids
local v = def.liquid_viscosity
if not v then
v = 0
end
--local old_v = self._viscosity
self._viscosity = v
local vpenalty = math.max(0.1, 0.98 - 0.1 * v)
if math.abs(vel.x) > 0.001 then
vel.x = vel.x * vpenalty
end
if math.abs(vel.z) > 0.001 then
vel.z = vel.z * vpenalty
end
self.object:set_velocity(vel)
end
end
-- Update yaw
if not self._stuck then
local vel = self.object:get_velocity()
local yaw = minetest.dir_to_yaw(vel)+YAW_OFFSET
local pitch = dir_to_pitch(vel)
self.object:set_rotation({ x = 0, y = yaw, z = pitch })
end
-- Update internal variable
self._lastpos={x=pos.x, y=pos.y, z=pos.z}
end
-- Force recheck of stuck arrows when punched.
-- Otherwise, punching has no effect.
function ARROW_ENTITY.on_punch(self)
if self._stuck then
self._fuserechecktimer = STUCK_RECHECK_TIME
end
end
function ARROW_ENTITY.get_staticdata(self)
local out = {
lastpos = self._lastpos,
startpos = self._startpos,
damage = self._damage,
is_critical = self._is_critical,
stuck = self._stuck,
stuckin = self._stuckin,
}
if self._stuck then
-- If _fuse is missing for some reason, assume the maximum
if not self._fuse then
self._fuse = ARROW_TIMEOUT
end
out.stuckstarttime = minetest.get_gametime() - self._fuse
end
if self._shooter and self._shooter:is_player() then
out.shootername = self._shooter:get_player_name()
end
return minetest.serialize(out)
end
function ARROW_ENTITY.on_activate(self, staticdata, dtime_s)
self._time_in_air = 1.0
self._in_player = false
local data = minetest.deserialize(staticdata)
if data then
self._stuck = data.stuck
if data.stuck then
if data.stuckstarttime then
-- First, check if the stuck arrow is aleady past its life timer.
-- If yes, delete it.
self._fuse = minetest.get_gametime() - data.stuckstarttime
if self._fuse > ARROW_TIMEOUT then
mcl_burning.extinguish(self.object)
self.object:remove()
return
end
end
self._fuse = 2
-- Perform a stuck recheck on the next step.
self._fuserechecktimer = STUCK_RECHECK_TIME
self._stuckin = data.stuckin
end
-- Get the remaining arrow state
self._lastpos = data.lastpos
self._startpos = data.startpos
self._damage = data.damage
self._is_critical = data.is_critical
if data.shootername then
local shooter = minetest.get_player_by_name(data.shootername)
if shooter and shooter:is_player() then
self._shooter = shooter
end
end
end
self.object:set_armor_groups({ immortal = 1 })
end
minetest.register_entity("mcl_bows:rocket_entity", ARROW_ENTITY)
if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_mobitems") then
minetest.register_craft({
output = "mcl_bows:rocket 1",
recipe = {
{"mcl_core:paper"},
{"mcl_fireworks:rocket_2"},
{"mcl_bows:arrow"},
}
})
end
if minetest.get_modpath("doc_identifier") then
doc.sub.identifier.register_object("mcl_bows:rocket_entity", "craftitems", "mcl_bows:rocket")
end

Some files were not shown because too many files have changed in this diff Show More