Compare commits

..

187 Commits

Author SHA1 Message Date
teknomunk 01f168a511 Flip powered special T-junction textures to match regular rails 2024-11-10 02:46:38 +01:00
teknomunk d1c4b3ddc2 Add in working curved variants of special rails 2024-11-10 02:46:38 +01:00
teknomunk bceb070849 Make powered rails always accelerate moving carts 2024-11-10 02:46:38 +01:00
teknomunk cd69597c6c Fix detector rail strangeness, prevent crash 2024-11-10 02:46:38 +01:00
teknomunk 4f913f4264 Use correct vectors for look directions east/west 2024-11-10 02:46:38 +01:00
teknomunk 4a88f976f9 Remove debug code 2024-11-10 02:46:38 +01:00
teknomunk 4e923219c7 Fix minecart entity rotation 2024-11-10 02:46:38 +01:00
teknomunk b653fab1ff Fix crash 2024-11-10 02:46:38 +01:00
teknomunk af24855d18 Make straight rails with a free end bend towards newly placed rail and form corners 2024-11-10 02:46:38 +01:00
teknomunk 38e5aada31 Finish restricting 45 degree movement code to horizontal plane 2024-11-10 02:46:38 +01:00
teknomunk 6ccfca2387 Fix vertical movement that was hitting 45 degree curve code, reset pitch on minecarts 2024-11-10 02:46:38 +01:00
teknomunk 1d10fdcac2 Fix friction on slopes, fix cart reversal when timestep is very small or zero 2024-11-10 02:46:38 +01:00
teknomunk a8314b1356 Allow functions for _rail_acceleration, make powered rail only accelerate carts when one side of the rail is a solid block or stairs 2024-11-10 02:46:38 +01:00
teknomunk 4e970a5ea1 Remove instance of debug logging, change movement.lua function export 2024-11-10 02:46:38 +01:00
teknomunk c7a829d59a Fix crash with minecart on activator rail 2024-11-10 02:46:38 +01:00
teknomunk e364722864 Fix cart pitch when detached 2024-11-10 02:46:38 +01:00
teknomunk e204e0fd3e Add workaround to prevent random detached inventory doesn't exist warning when right-clicking entities with inventory 2024-11-10 02:46:38 +01:00
teknomunk b39482fe32 Fix right-clicking nodes while holding rail 2024-11-10 02:46:38 +01:00
teknomunk e0e343d86b Add back shift+punch to immediately drop minecart 2024-11-10 02:46:38 +01:00
teknomunk 6183e71b12 Fix another crash, fix rail tee on texture 2024-11-10 02:46:38 +01:00
teknomunk e44ff54195 Calculate acceleration of trains based on average of acceleration for all carts in the train, make velocity not change on slopes and 45 degree track 2024-11-10 02:46:38 +01:00
teknomunk 517e5765ee Prevent trains from slowing on 45 degree track 2024-11-10 02:46:38 +01:00
teknomunk 08419ccacf Add guard that prevents crash when itemstack is nil 2024-11-10 02:46:38 +01:00
teknomunk 0f1208d7b4 Silence debug prints and logging 2024-11-10 02:46:38 +01:00
teknomunk d1452f44de Prevent removal of old minecarts 2024-11-10 02:46:38 +01:00
teknomunk 63edda42a7 Add legacy node conversion to vl_legacy and update rails.lua to use it 2024-11-10 02:46:38 +01:00
teknomunk 735ef088ce Make activated tnt minecarts glow in the dark, fix crash with lit tnt minecarts 2024-11-10 02:46:38 +01:00
teknomunk f99a3a8e26 Fix a couple of crashes (TNT minecart trying to update orientation after exploding, trying to punch/push a minecart not on track) 2024-11-10 02:46:38 +01:00
teknomunk b964fc3372 Expand mcl_util.hopper_pull() to mcl_util.hopper_pull_to_inventory() 2024-11-10 02:46:38 +01:00
teknomunk 66727aedda Add profiling code to force_get_node() 2024-11-10 02:46:38 +01:00
teknomunk 70bb65ac1c Address additional review comments 2024-11-10 02:46:38 +01:00
teknomunk c33fb223da Update API documentation to always use , add compatibility shim to mcl_minecarts.is_rail() and mcl_minecarts.ge_rail_direction() 2024-11-10 02:46:38 +01:00
teknomunk b6ca0e6af5 Rewrite mcl_util.hopper_pull in terms of mcl_util.hopper_pull_to_inventory 2024-11-10 02:46:38 +01:00
teknomunk 665e8fec52 Correct documentation per review 2024-11-10 02:46:38 +01:00
teknomunk 16889c5d38 Switch over to using vl_legacy for item conversion in player inventories 2024-11-10 02:46:38 +01:00
teknomunk 9615d44332 Fix typo 2024-11-10 02:46:38 +01:00
teknomunk fac22d53d4 Register rail conversions 2024-11-10 02:46:38 +01:00
teknomunk d568adb931 Implement vl_legacy deprecated function and item conversion APIs 2024-11-10 02:46:38 +01:00
teknomunk 45ce26124c Fix crashes 2024-11-10 02:46:38 +01:00
teknomunk 90c6fd9f75 Make old rails have a drawtype, make update lbm always run 2024-11-10 02:46:38 +01:00
teknomunk 8334ccf4aa Move the various rails to their own files, code cleanup 2024-11-10 02:46:38 +01:00
teknomunk 96f6624684 Remove undefined global for optional environmental physics 2024-11-10 02:46:38 +01:00
teknomunk 166c19e8f3 Remove Emerge-0 warning that occurs when placing mineshafts 2024-11-10 02:46:38 +01:00
teknomunk 90f51af90e Restore 45 degree cart movement, remove warning about unknown global 2024-11-10 02:46:38 +01:00
teknomunk f3d2c8b877 Complete rework of curve/tee rail direction functions 2024-11-10 02:46:38 +01:00
teknomunk 6849bcc518 Rework rail_dir_curve to significantly reduce code size 2024-11-10 02:46:38 +01:00
teknomunk b815f82de5 Convert curved rails direction code to use fourdir 2024-11-10 02:46:38 +01:00
teknomunk 3feadcb9f9 Change verticle offset for testing reattaching to rail to 0.55, which is a bit more than the stair step height 2024-11-10 02:46:38 +01:00
teknomunk a389ecebc4 Fix cart detaching without unregistering from everything 2024-11-10 02:46:38 +01:00
teknomunk e8b5c9f9de Fix typo, set use_texture_alpha = clip for all rail 2024-11-10 02:46:38 +01:00
teknomunk 166cd93298 Fix several undefined global warnings, fix cart movement when over maximum speed, fix cart reattachment to sloped track 2024-11-10 02:46:38 +01:00
teknomunk 0b5f6544ce Revert changed made to debug minecart-updates integration into tsm_railcorridors 2024-11-10 02:46:38 +01:00
teknomunk e6a0f01cde Make punch move minecarts a little, comment out more debug prints 2024-11-10 02:46:38 +01:00
teknomunk 2c460d5e30 Fix visual artifacts on the sides of rails 2024-11-10 02:46:38 +01:00
teknomunk c1398b52cc Stop carts from reversing when they stop, make stopped carts try to start moving in the direction the player is facing 2024-11-10 02:46:38 +01:00
teknomunk 125ca644b5 Fix crash after entering a minecart not on rails 2024-11-10 02:46:38 +01:00
teknomunk da5ab60545 Fix placed rail conversion, start automatic inventory rail conversion 2024-11-10 02:46:38 +01:00
teknomunk 7959108245 Fix players repelling carts with new player metadata system 2024-11-10 02:46:38 +01:00
teknomunk fdf673162a Cleanup debug prints 2024-11-10 02:46:38 +01:00
teknomunk 6dc721f9cf Add documentation for newly exposed attach_driver 2024-11-10 02:46:38 +01:00
teknomunk af0e4d12af Add persistent player-specific metadata into mcl_playerinfo, simple cart reattachment (only exists if the luaentity for the cart exists when the player logs in) 2024-11-10 02:46:38 +01:00
teknomunk 46028b1fc0 More fixes for minecart-hopper movement 2024-11-10 02:46:38 +01:00
teknomunk 7be3659fe1 Get rail placement creating corners that lead into a downward sloped rail 2024-11-10 02:46:38 +01:00
teknomunk c6eb2f23d5 Create mcl_util.metadata_timer, fix crashes, add checks to prevent hoppers from pulling from carts that are not in the square above it 2024-11-10 02:46:38 +01:00
teknomunk 578de9c398 Fix hopper-minecart interaction, convert ipairs(table) to use for i=1,#table instead 2024-11-10 02:46:38 +01:00
teknomunk 11d8e46e96 Update mineshafts for new rail and minecarts, add loot to generated chest and hopper minecarts (and remove notes about a hack) 2024-11-10 02:46:38 +01:00
teknomunk 9f8559a642 Give carts a small vertical lift when pushed to allow them to get back on rails 2024-11-10 02:46:38 +01:00
teknomunk 418efda348 Stop rail from being placed directly above rail (floating in air) 2024-11-10 02:46:38 +01:00
teknomunk a65d043e15 Fix sloped power,activator and detector rails, remove debug print 2024-11-10 02:46:38 +01:00
teknomunk ac44d93aa4 Modify mcl_entity_invs to add support for save/load items hooks in entities, add save/load hooks to minecarts to store item list in the minecart data and not in the entity data so that respawn doesn't destroy items 2024-11-10 02:46:38 +01:00
teknomunk 68e7a6e02c Add documentation on the rail 2024-11-10 02:46:38 +01:00
teknomunk 46ec4db298 Add documentation on file structure and overviewes of each file 2024-11-10 02:46:38 +01:00
teknomunk 2b6dba20be Fix crashes, fix link in documentation 2024-11-10 02:46:38 +01:00
teknomunk 2610754ee6 More documentation, add myself to copyright list in README.txt 2024-11-10 02:46:38 +01:00
teknomunk 44875440eb More minor changes to API.md, start overall implementation documentation 2024-11-10 02:46:38 +01:00
teknomunk 60ef68b7c7 Fix table of contents 2024-11-10 02:46:38 +01:00
teknomunk c3c6d2861e Finish writing API documentation, remove drop_railcarts (replaced by try_detach_minecart), rename constants to ALL CAPS for consistency, change mcl_minecarts. to mod. for API function definitions 2024-11-10 02:46:38 +01:00
teknomunk 474eed5e8f Nearly finish API documentation, create mcl_minecarts.add_blocks_to_map() 2024-11-10 02:46:38 +01:00
teknomunk 845d92aef6 Continue writing API documentation, update call signatures for a couple of API functions 2024-11-10 02:46:38 +01:00
teknomunk 17360f42de Change document formatting, finally move cactus cart dropping to node definition for mcl_core:cactus 2024-11-10 02:46:38 +01:00
teknomunk 2447632d57 Correct crashes/item duplication with dropping carts, start API documentation 2024-11-10 02:46:38 +01:00
teknomunk 200f72c2f1 Fix cart controls, cart pushing 2024-11-10 02:46:38 +01:00
teknomunk d8ad11781b Fix typo in rail replacement mapping, fix several crashes 2024-11-10 02:46:38 +01:00
teknomunk 2e20ea21bd Implement movement thru tee rails 2024-11-10 02:46:38 +01:00
teknomunk 0734ce73cd Tune respawn distance limit 2024-11-10 02:46:38 +01:00
teknomunk efd171252f Fix crashes 2024-11-10 02:46:38 +01:00
teknomunk d2f8676df2 Remove memory leak for cart data, check distance to players before respawning distant carts to prevent adding entities that are immediately inactivated 2024-11-10 02:46:38 +01:00
teknomunk f86ff41554 Implement offline/out of range minecart movement and fix minecart respawning, remove railtype tracking 2024-11-10 02:46:38 +01:00
teknomunk 252179c695 Remove do_movement dependency on the existence of a cart luaentity 2024-11-10 02:46:38 +01:00
teknomunk 6cf8c640ca Fix undefined global warning, move player off to the side of a cart when dismounting so trains don't get pushed apart when getting out 2024-11-10 02:46:38 +01:00
teknomunk 12df6f37dc Make trains containing a player in a minecart function, minor cleanup in mcl_playerinfo 2024-11-10 02:46:38 +01:00
teknomunk b7ba0c8607 Fix crashes in train logic, allow breaking apart trains 2024-11-10 02:46:38 +01:00
teknomunk c7fd179a35 Implement train reversing 2024-11-10 02:46:38 +01:00
teknomunk c69ab674d3 Repair vectors in cart data, mostly fix train movement bugs (still possible to have a furnace minecart flip, without the train also flipping) 2024-11-10 02:46:38 +01:00
teknomunk 5f5ec96394 Add cart entity respawn/destroy to match cart data (partially working) 2024-11-10 02:46:38 +01:00
teknomunk 3320fe768b Give furnace minecart minimum velocity when lit, add train separation code, update logging code, add sequence number to entity staticdata to allow respawn/despawn when carts move when the entity is unloaded 2024-11-10 02:46:38 +01:00
teknomunk 4e27774679 Fix rail detach crash, make tnt minecarts explode if they hit something hard (off rails) 2024-11-10 02:46:38 +01:00
teknomunk 4943fff0d5 Make sure carts get detatch if the rail under them is removed 2024-11-10 02:46:38 +01:00
teknomunk 7aa83ac15c Fixish reorganizing, initial train implementation 2024-11-10 02:46:38 +01:00
teknomunk 88ffa84dc0 Major reorganization, start setup for trains 2024-11-10 02:46:38 +01:00
teknomunk a4c60cfa4a Make sure carts that collide move in the same direction the colliding cart was 2024-11-10 02:46:38 +01:00
teknomunk b815253704 Add utilities to convert between an ObjectRef, it's active object id and a 128bit uuid, move minecart data from entity staticdata to mod storage to eventually allow updating carts when out of range of players and also track what carts are alive, implement on-rail cart collisions 2024-11-10 02:46:38 +01:00
teknomunk 233e253a5d Harden against unknown nodes 2024-11-10 02:46:38 +01:00
teknomunk 39f22e3769 Allow players to push minecarts that are not on track 2024-11-10 02:46:38 +01:00
teknomunk 556c29cf0c Fix rails in creative inventory, make minecart with tnt not crash server when exploding, make minecart with tnt slightly more powerful than regular tnt 2024-11-10 02:46:38 +01:00
teknomunk 8702911da8 Fix rail movement regressions 2024-11-10 02:46:38 +01:00
teknomunk b02b68148c Move cart code to its own file, more code cleanup, add aliases for old track items 2024-11-10 02:46:38 +01:00
teknomunk 75304d2e75 Cleanup code, restore uphill/downhill cart movement, completely remove old rail 2024-11-10 02:46:38 +01:00
teknomunk 8478269dd9 Get rail reattachment (especially after jumps) working correctly 2024-11-10 02:46:38 +01:00
teknomunk 35af50bce0 Make legacy rail update apply to all old rail types, add basic detached railcart physics with a stub to use mcl_physics when it gets merged 2024-11-10 02:46:38 +01:00
teknomunk d5c9a56e74 Silence unmaskable print statements 2024-11-10 02:46:38 +01:00
teknomunk 641626e505 Add immortal item entity support, add legacy rail conversion that uses immortal item drops for corners/tees/crosses that are no longer possible 2024-11-10 02:46:38 +01:00
teknomunk 64760f7d9d Fix more rail connection bugs 2024-11-10 02:46:38 +01:00
teknomunk 2259f5249b Get sloped connections working correctly 2024-11-10 02:46:38 +01:00
teknomunk 81c77f039e Re-enable rule for powering rail from underneath, have stairs block minecart movement, fix crash when lightning strikes a minecart 2024-11-10 02:46:38 +01:00
teknomunk 00dccd1823 Fix mcl_util.table_merge where a standard value overwrites a table, fix base definition usage, implement behavior difference when there is a solid block after a straight piece of track (this will eventually allow minecarts to fly off the end of the track) 2024-11-10 02:46:38 +01:00
teknomunk f18bd9b8e7 Update all rail types to new version 2024-11-10 02:46:38 +01:00
teknomunk 8773e515d6 Reorganize 2024-11-10 02:46:38 +01:00
teknomunk d02d1b7b05 Finish reverting 08b41a3b39 2024-11-10 02:46:38 +01:00
teknomunk d7294d156d Enable new track with get_next_dir handlers 2024-11-10 02:46:38 +01:00
teknomunk 0b7a6c444f Change connection rules again to allow building parallel track, tees and crosses), start implementing rail rules callbacks 2024-11-10 02:46:38 +01:00
teknomunk 126b667527 Add sloped rail 2024-11-10 02:46:38 +01:00
teknomunk 95fc97e6b8 Fix rail visuals, add switch operation 2024-11-10 02:46:38 +01:00
teknomunk b8496d1ad3 Implement initial rail connection logic (no vertical track yet), experiment with texture modifiers and gravel underlay for display (not working) 2024-11-10 02:46:38 +01:00
teknomunk fc64ff5c41 Start implementing new rail nodes 2024-11-10 02:46:38 +01:00
teknomunk e9116457bc Implement minecart with command block 2024-11-10 02:46:38 +01:00
teknomunk 70e94d3745 Create mesecons command API and modify commandblock to use it 2024-11-10 02:46:38 +01:00
teknomunk baf58dbf21 Disable punch to move minecarts, implement punch to drop minecart, enable basic cart keyboard controls (accelerate and brake) 2024-11-10 02:46:38 +01:00
teknomunk 8a1170120c Remove cart oscillation when pushed 2024-11-10 02:46:38 +01:00
teknomunk f346b95620 Limit top speed of furnace minecarts to 4 blocks/second, limit total fuel time to 27 minutes 2024-11-10 02:46:38 +01:00
teknomunk 2468acb27b Fix bug with furnace minecart at max velocity (stopped until fuel ran out), move _fueltime into staticdata 2024-11-10 02:46:38 +01:00
teknomunk 44b46b0763 Fix call signature of mcl_util.hopper_pull_to_inventory, move cart-specific behaviors to _mcl_minecarts_on_step handlers, fix typo, change distance used in rail reattach code, move cart_id generation 2024-11-10 02:46:38 +01:00
teknomunk 408d17d2b1 Add groups to minecart entities (for containers), fix cart node watch handling, relocate hopper_push_to_mc in mcl_hopper/init.lua, implement hopper-to-minecart push using enter/leave hooks for both straight and bent hoppers 2024-11-10 02:46:38 +01:00
teknomunk ea6cb325aa Add API function to remove node watch 2024-11-10 02:46:38 +01:00
teknomunk 9365e16a6d Refactor enter/leave hook processing, add node watches for implementing hopper-to-minecart functionality (should properly handle heavy server lag without missing any time), temporarily disable hopper push/pull to minecart in mcl_hoppers, prepare to move minecart-specific on_step behavior out of main on_step function and to a minecart-specific handler 2024-11-10 02:46:38 +01:00
teknomunk 5cc06160fb Start adding hooks for implpementing minecart with command block 2024-11-10 02:46:38 +01:00
teknomunk 09c3c5efe5 Make minecarts solid and add players pushing 2024-11-10 02:46:38 +01:00
teknomunk ed6ef684b2 Fix forwards/backwars tilt in all directions 2024-11-10 02:46:38 +01:00
teknomunk 74345fb555 Prevent players from entering minecarts when sneaking, prevents players from causing MineClone2/MineClone2#3188 2024-11-10 02:46:38 +01:00
teknomunk 8bd7efc25c Increase default track friction, disable right-click to exit minecarts 2024-11-10 02:46:38 +01:00
teknomunk 19a9e9de1b Initial tuning of acceleration/gravity, fix crash when entering an activator rail, detach mobs from cart on active activator rail, remove commented out code no longer needed 2024-11-10 02:46:38 +01:00
teknomunk b6d30919cf Move code that handles below-rail hoppers to handle_cart_enter, implement timestep-independent cart physics (will need tuning punch, power rail and gravityaccelerations to make game fun) 2024-11-10 02:46:38 +01:00
teknomunk 1e621ab0e7 Mostly fix carts stopping between powered rails (there is still some strangeness with acceleration physics) 2024-11-10 02:46:38 +01:00
teknomunk cd32b7865f Fix diagonal movement 2024-11-10 02:46:38 +01:00
teknomunk 0050b2dd62 Add diagonal track movement on zig-zag track, rewrite mcl_minecarts:get_rail_direction 2024-11-10 02:46:38 +01:00
teknomunk 397ad0c64f Make TNT minecarts available in creative menu 2024-11-10 02:46:38 +01:00
teknomunk 83ad76d3ba Implement custom item dropper handlers, implement droppers placing minecarts 2024-11-10 02:46:38 +01:00
teknomunk f122e38f3c Hopper minecarts pull from containers above rail 2024-11-10 02:46:38 +01:00
teknomunk 698d038e10 Rework in preparation to add code to pull from containers into the hopper minecart 2024-11-10 02:46:38 +01:00
teknomunk 9b89b200aa Move fiction constant to top of file, suppress cart flips when direction reverses due to gravity or end of track 2024-11-10 02:46:38 +01:00
teknomunk 1fb1865052 Add code to reattach carts to rail when data corruption occurs, fix bug in last commit that caused carts to bury into the ground 2024-11-10 02:46:38 +01:00
teknomunk 66164e1f0e Remove dip into the ground that occured when gravity caused the cart to reverse directions 2024-11-10 02:46:38 +01:00
teknomunk 865a278554 Implement gravity, move orientation update to own function, fix cart stopping in process_acceleration 2024-11-10 02:46:38 +01:00
teknomunk c13c800cd8 Change connected railcar behavior to fix unreliable end of track stopping, set maximum acceleration of powered rails to 8 blocks per second (per https://minecraft.fandom.com/wiki/Powered_Rail), stop powered rails from powering the block underneath it (allows below rail hopper to work while the rail is powered like in https://www.youtube.com/watch?v=szjO0-duTAk), modify mcl_hoppers to allow triggering a hopper pull once the minecart is stopped on top of the hopper and wait before allowing the cart to move to allow redstone circuits time to process 2024-11-10 02:46:38 +01:00
teknomunk bb8a2ee637 Make minecart always stop at correct location at end of track, fix crash when placing chest minecart after changing how staticdata is handled 2024-11-10 02:46:38 +01:00
teknomunk a67203c378 Modify do_movement_step to move to always move to the edge of the current rail segment before updating the direction to prevent oscillations at corners, fix end of track stop location with new movement behavior, disable experimental controls, swap code to detach the driver on float with a call to detach_driver() 2024-11-10 02:46:38 +01:00
teknomunk 0828372339 Add DEBUG flag, stop small do_movement_step's from occuring (this improves but doesn't eliminate the bug I with the a6be179ed commit), add recovery when staticdata field gets lost 2024-11-10 02:46:38 +01:00
teknomunk f476e43084 Fix initial_properties for minecarts 2024-11-10 02:46:38 +01:00
teknomunk d45bf2d65f Change left,right and back vectors to matrix math results with no branching 2024-11-10 02:46:38 +01:00
teknomunk 89867adbfe Remove now unused properties from minecart definition, convert more vectors to use vector.new syntax 2024-11-10 02:46:38 +01:00
teknomunk 7c898db3a2 Complete rewrite of minecart movement that resolves MineClone2/MineClone2#2446 and MineClone2/MineClone2#247 (comment) but has a bug where carts will synchronize movements that I am still investigating 2024-11-10 02:46:38 +01:00
teknomunk afbe257bee Change staticdata serialization (with migration from old data), disable debugging code used to investigate MineClone2/MineClone2#2446 2024-11-10 02:46:38 +01:00
teknomunk c64d9eea02 Change to vector.new from {x=...}, relocate movement code to own function for future changes 2024-11-10 02:46:38 +01:00
kno10 b540e6c77b Improve head swivel code (#4622)
* Utilize the minetest 5.9.0 API that uses radians not degree.
* Simplify computations to make this more efficient, in particular by querying and updating the bone position less frequently.
* Resolves minetest warning `Deprecated call to set_bone_position, use set_bone_override instead` in this location, but other uses remain.
* `mcl_util.set_bone_position` not modified, because it redundantly compares to the previous rotation once more.

Reviewed-on: VoxeLibre/VoxeLibre#4622
Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>
Co-authored-by: kno10 <erich.schubert@gmail.com>
Co-committed-by: kno10 <erich.schubert@gmail.com>
2024-11-10 02:41:55 +01:00
kno10 d49426d453 Cleanup of mcl_core/functions (#4592)
Cleanup of mods/ITEMS/mcl_core/functions.lua

This improves several further ABMs such as vine growing, and uses the `vector` API instead of tables.

Reviewed-on: VoxeLibre/VoxeLibre#4592
Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>
Co-authored-by: kno10 <erich.schubert@gmail.com>
Co-committed-by: kno10 <erich.schubert@gmail.com>
2024-11-10 02:32:51 +01:00
the-real-herowl 2b7b7f1872 Merge pull request 'Improve plant growth system, add moisture level' (#4681) from kno10/VoxeLibre:pumpkin-melon-growth-1 into master
Reviewed-on: VoxeLibre/VoxeLibre#4681
Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>
2024-11-10 02:11:37 +01:00
kno10 b5afa34469 Remove "wet" metadata altogether 2024-11-10 02:11:37 +01:00
kno10 ebf6cf32e8 meta:set_private("wet"), require only walkable nodes 2024-11-10 02:11:37 +01:00
kno10 a8318f6600 simplify catch-up LBM logic 2024-11-10 02:11:37 +01:00
kno10 fa7a7f4e81 more fixes to plant growth 2024-11-10 02:11:37 +01:00
kno10 c097c65262 adjust growth rates again 2024-11-10 02:11:37 +01:00
kno10 220a7b06e6 code review feedback 2024-11-10 02:11:37 +01:00
kno10 540a070c59 always use day light level, more fixes 2024-11-10 02:11:37 +01:00
kno10 78a958db4e Double the odds, to halve the ABM frequencies. 2024-11-10 02:11:37 +01:00
kno10 e9453d6210 Add plant growth speed option, drop average light level
Closes: #4683 by removal
2024-11-10 02:11:37 +01:00
kno10 9376cf92b1 Adjust growth speeds 2024-11-10 02:11:37 +01:00
kno10 c4030115c4 improve moisture logic 2024-11-10 02:11:37 +01:00
kno10 e1ace4ad01 pumpkin/melon growth only tests one neighbor every time 2024-11-10 02:11:37 +01:00
the-real-herowl e3b7847df1 Merge pull request 'Shield improvements and bugfixes (fixes #2756)' (#4582) from shieldy_shields into master
Reviewed-on: VoxeLibre/VoxeLibre#4582
Reviewed-by: kno10 <kno10@noreply.git.minetest.land>
Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>
2024-11-10 01:34:50 +01:00
Mikita Wiśniewski f86a641dfa Improve shield block code and unhardcode offhand group 2024-11-10 01:34:50 +01:00
Mikita Wiśniewski 084741b733 Fix using shield on unknown nodes and cleanup 2024-11-10 01:34:50 +01:00
Mikita Wiśniewski d5bc0613d8 Make node itemstack check in mcl_shields less hacky 2024-11-10 01:34:50 +01:00
Loveaabb f26c34e65f Bugfix: Shield fails to block arrows 2024-11-10 01:34:50 +01:00
Loveaabb 04e29c5796 Several improvements to the Shield 2024-11-10 01:34:50 +01:00
Elias Åström 45ae170447 Deduplicate shield slowdown removal code 2024-11-10 01:34:50 +01:00
Elias Åström d0d1217dec Remove unused code in mcl_privs 2024-11-10 01:34:50 +01:00
Elias Åström cffc8e0145 Fix loosing interact bug in mcl_shields 2024-11-10 01:34:50 +01:00
18 changed files with 664 additions and 900 deletions

View File

@ -5,6 +5,7 @@ local validate_vector = mcl_util.validate_vector
local active_particlespawners = {} local active_particlespawners = {}
local disable_blood = minetest.settings:get_bool("mobs_disable_blood") local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
local DEFAULT_FALL_SPEED = -9.81*1.5 local DEFAULT_FALL_SPEED = -9.81*1.5
local PI_THIRD = math.pi / 3 -- 60 degrees
local PATHFINDING = "gowp" local PATHFINDING = "gowp"
@ -294,86 +295,66 @@ function mcl_mobs:set_animation(self, anim)
self:set_animation(anim) self:set_animation(anim)
end end
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 who_are_you_looking_at (self, dtime) local function who_are_you_looking_at (self, dtime)
local pos = self.object:get_pos() if self.order == "sleep" then
self._locked_object = nil
return
end
local stop_look_at_player_chance = math.random(833/self.curiosity)
-- was 10000 - div by 12 for avg entities as outside loop -- was 10000 - div by 12 for avg entities as outside loop
local stop_look_at_player = math.random() * 833 <= self.curiosity
local stop_look_at_player = stop_look_at_player_chance == 1
if self.attack then if self.attack then
if not self.target_time_lost then self._locked_object = not self.target_time_lost and self.attack or nil
self._locked_object = self.attack
else
self._locked_object = nil
end
elseif self.following then elseif self.following then
self._locked_object = self.following self._locked_object = self.following
elseif self._locked_object then elseif self._locked_object then
if stop_look_at_player then if stop_look_at_player then self._locked_object = nil end
--minetest.log("Stop look: ".. self.name)
self._locked_object = nil
end
elseif not self._locked_object then elseif not self._locked_object then
if mcl_util.check_dtime_timer(self, dtime, "step_look_for_someone", 0.2) then if mcl_util.check_dtime_timer(self, dtime, "step_look_for_someone", 0.2) then
--minetest.log("Change look check: ".. self.name) local pos = self.object:get_pos()
-- For the wither this was 20/60=0.33, so probably need to rebalance and divide rates.
-- but frequency of check isn't good as it is costly. Making others too infrequent requires testing
local chance = 150/self.curiosity
if chance < 1 then chance = 1 end
local look_at_player_chance = math.random(chance)
-- was 5000 but called in loop based on entities. so div by 12 as estimate avg of entities found,
-- then div by 20 as less freq lookup
local look_at_player = look_at_player_chance == 1
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 8)) do for _, obj in pairs(minetest.get_objects_inside_radius(pos, 8)) do
if obj:is_player() and vector.distance(pos,obj:get_pos()) < 4 then if obj:is_player() and vector.distance(pos, obj:get_pos()) < 4 then
--minetest.log("Change look to player: ".. self.name)
self._locked_object = obj self._locked_object = obj
break break
elseif obj:is_player() or (obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity()) then elseif obj:is_player() or (obj:get_luaentity() and self ~= obj:get_luaentity() and obj:get_luaentity().name == self.name) then
if look_at_player then -- For the wither this was 20/60=0.33, so probably need to rebalance and divide rates.
--minetest.log("Change look to mob: ".. self.name) -- but frequency of check isn't good as it is costly. Making others too infrequent requires testing
-- was 5000 but called in loop based on entities. so div by 12 as estimate avg of entities found,
-- then div by 20 as less freq lookup
if math.random() * 150 <= self.curiosity then
self._locked_object = obj self._locked_object = obj
break break
end end
end end
end end
end end
end end
end end
function mob_class:check_head_swivel(dtime) function mob_class:check_head_swivel(dtime)
if not self.head_swivel or type(self.head_swivel) ~= "string" then return end if not self.head_swivel or type(self.head_swivel) ~= "string" then return end
who_are_you_looking_at(self, dtime)
who_are_you_looking_at (self, dtime) local newr, oldp, oldr = vector.zero(), nil, nil
if self.object.get_bone_override then -- minetest >= 5.9
local ov = self.object:get_bone_override(self.head_swivel)
oldp, oldr = ov.position.vec, ov.rotation.vec
else -- minetest < 5.9
oldp, oldr = self.object:get_bone_position(self.head_swivel)
oldr = vector.apply(oldr, math.rad) -- old API uses radians
end
local final_rotation = vector.zero() local locked_object = self._locked_object
local oldp,oldr = self.object:get_bone_position(self.head_swivel) if locked_object and (locked_object:is_player() or locked_object:get_luaentity()) and locked_object:get_hp() > 0 then
if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then
local _locked_object_eye_height = 1.5 local _locked_object_eye_height = 1.5
if self._locked_object:get_luaentity() then if locked_object:is_player() then
_locked_object_eye_height = self._locked_object:get_luaentity().head_eye_height _locked_object_eye_height = locked_object:get_properties().eye_height
end elseif locked_object:get_luaentity() then
if self._locked_object:is_player() then _locked_object_eye_height = locked_object:get_luaentity().head_eye_height
_locked_object_eye_height = self._locked_object:get_properties().eye_height
end end
if _locked_object_eye_height then if _locked_object_eye_height then
local self_rot = self.object:get_rotation() local self_rot = self.object:get_rotation()
-- If a mob is attached, should we really be messing with what they are looking at? -- If a mob is attached, should we really be messing with what they are looking at?
-- Should this be excluded? -- Should this be excluded?
@ -381,40 +362,48 @@ function mob_class:check_head_swivel(dtime)
self_rot = self.object:get_attach():get_rotation() self_rot = self.object:get_attach():get_rotation()
end end
local player_pos = self._locked_object:get_pos() local ps = self.object:get_pos()
local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0))) ps.y = ps.y + self.head_eye_height * .7
local mob_yaw = math.deg(-(-(self_rot.y)-(-minetest.dir_to_yaw(direction_player))))+self.head_yaw_offset local pt = locked_object:get_pos()
local mob_pitch = math.deg(-dir_to_pitch(direction_player))*self.head_pitch_multiplier pt.y = pt.y + _locked_object_eye_height
local dir = vector.direction(ps, pt)
local mob_yaw = self_rot.y + math.atan2(dir.x, dir.z) + self.head_yaw_offset
local mob_pitch = math.asin(-dir.y) * self.head_pitch_multiplier
if (mob_yaw < -60 or mob_yaw > 60) and not (self.attack and self.state == "attack" and not self.runaway) then if (mob_yaw < -PI_THIRD or mob_yaw > PI_THIRD) and not (self.attack and self.state == "attack" and not self.runaway) then
final_rotation = vector.multiply(oldr, 0.9) newr = vector.multiply(oldr, 0.9)
elseif self.attack and self.state == "attack" and not self.runaway then elseif self.attack and self.state == "attack" and not self.runaway then
if self.head_yaw == "y" then if self.head_yaw == "y" then
final_rotation = vector.new(mob_pitch, mob_yaw, 0) newr = vector.new(mob_pitch, mob_yaw, 0)
elseif self.head_yaw == "z" then elseif self.head_yaw == "z" then
final_rotation = vector.new(mob_pitch, 0, -mob_yaw) newr = vector.new(mob_pitch, 0, -mob_yaw)
end end
else else
if self.head_yaw == "y" then if self.head_yaw == "y" then
final_rotation = vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, ((mob_yaw-oldr.y)*.3)+oldr.y, 0) newr = vector.new((mob_pitch-oldr.x)*.3+oldr.x, (mob_yaw-oldr.y)*.3+oldr.y, 0)
elseif self.head_yaw == "z" then elseif self.head_yaw == "z" then
final_rotation = vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, 0, -(((mob_yaw-oldr.y)*.3)+oldr.y)*3) newr = vector.new((mob_pitch-oldr.x)*.3+oldr.x, 0, ((mob_yaw-oldr.y)*.3+oldr.y)*-3)
end end
end end
end end
elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then elseif not locked_object and math.abs(oldr.y) > 0.05 and math.abs(oldr.x) < 0.05 then
final_rotation = vector.multiply(oldr, 0.9) newr = vector.multiply(oldr, 0.9)
else end
--final_rotation = vector.new(0,0,0)
-- 0.02 is about 1.14 degrees tolerance, to update less often
local newp = vector.new(0, self.bone_eye_height, self.horizontal_head_height)
if math.abs(oldr.x-newr.x) + math.abs(oldr.y-newr.y) + math.abs(oldr.z-newr.z) < 0.02 and vector.equals(oldp, newp) then return end
if self.object.get_bone_override then -- minetest >= 5.9
self.object:set_bone_override(self.head_swivel, {
position = { vec = newp, absolute = true },
rotation = { vec = newr, absolute = true } })
else -- minetest < 5.9
-- old API uses degrees not radians
self.object:set_bone_position(self.head_swivel, newp, vector.apply(newr, math.deg))
end end
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horizontal_head_height), final_rotation)
end end
function mob_class:set_animation_speed() function mob_class:set_animation_speed()
local v = self.object:get_velocity() local v = self.object:get_velocity()
if v then if v then

View File

@ -141,7 +141,7 @@ function mcl_mobs.register_mob(name, def)
local final_def = { local final_def = {
use_texture_alpha = def.use_texture_alpha, use_texture_alpha = def.use_texture_alpha,
head_swivel = def.head_swivel or nil, -- bool to activate this function head_swivel = def.head_swivel or nil, -- bool to activate this function
head_yaw_offset = def.head_yaw_offset or 0, -- for wonkey model bones head_yaw_offset = math.rad(def.head_yaw_offset or 0), -- for wonkey model bones
head_pitch_multiplier = def.head_pitch_multiplier or 1, --for inverted pitch head_pitch_multiplier = def.head_pitch_multiplier or 1, --for inverted pitch
bone_eye_height = def.bone_eye_height or 1.4, -- head bone offset bone_eye_height = def.bone_eye_height or 1.4, -- head bone offset
head_eye_height = def.head_eye_height or def.bone_eye_height or 0, -- how hight aproximatly the mobs head is fromm the ground to tell the mob how high to look up at the player head_eye_height = def.head_eye_height or def.bone_eye_height or 0, -- how hight aproximatly the mobs head is fromm the ground to tell the mob how high to look up at the player

View File

@ -257,10 +257,10 @@ function ARROW_ENTITY.on_step(self, dtime)
mcl_burning.set_on_fire(obj, 5) mcl_burning.set_on_fire(obj, 5)
end end
if not self._in_player and not self._blocked then if not self._in_player and not self._blocked then
obj:punch(self.object, 1.0, { mcl_util.deal_damage(obj, self._damage, {type = "arrow", source = self._shooter, direct = self.object})
full_punch_interval=1.0, if self._extra_hit_func then
damage_groups={fleshy=self._damage}, self._extra_hit_func(obj)
}, self.object:get_velocity()) end
if obj:is_player() then if obj:is_player() then
if not mcl_shields.is_blocking(obj) then if not mcl_shields.is_blocking(obj) then
local placement local placement

View File

@ -168,7 +168,7 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
itemstack:get_meta():set_string("active", "true") itemstack:get_meta():set_string("active", "true")
return itemstack return itemstack
end, end,
groups = {weapon=1,weapon_ranged=1,bow=1,enchantability=1}, groups = {weapon=1,weapon_ranged=1,bow=1,cannot_block=1,enchantability=1},
_mcl_uses = 385, _mcl_uses = 385,
}) })
@ -216,7 +216,7 @@ for level=0, 2 do
wield_scale = mcl_vars.tool_wield_scale, wield_scale = mcl_vars.tool_wield_scale,
stack_max = 1, stack_max = 1,
range = 0, -- Pointing range to 0 to prevent punching with bow :D 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}, groups = {not_in_creative_inventory=1, not_in_craft_guide=1, bow=1, cannot_block=1, enchantability=1},
-- Trick to disable digging as well -- Trick to disable digging as well
on_use = function() return end, on_use = function() return end,
on_drop = function(itemstack, dropper, pos) on_drop = function(itemstack, dropper, pos)

View File

@ -158,7 +158,7 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
itemstack:get_meta():set_string("active", "true") itemstack:get_meta():set_string("active", "true")
return itemstack return itemstack
end, end,
groups = {weapon=1,weapon_ranged=1,crossbow=1,enchantability=1}, groups = {weapon=1,weapon_ranged=1,crossbow=1,cannot_block=1,enchantability=1},
_mcl_uses = 326, _mcl_uses = 326,
}) })
@ -193,7 +193,7 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
itemstack:get_meta():set_string("active", "true") itemstack:get_meta():set_string("active", "true")
return itemstack return itemstack
end, end,
groups = {weapon=1,weapon_ranged=1,crossbow=1,enchantability=1,not_in_creative_inventory=1}, groups = {weapon=1,weapon_ranged=1,crossbow=1,cannot_block=1,enchantability=1,not_in_creative_inventory=1},
_mcl_uses = 326, _mcl_uses = 326,
}) })
@ -238,7 +238,7 @@ for level=0, 2 do
wield_scale = mcl_vars.tool_wield_scale, wield_scale = mcl_vars.tool_wield_scale,
stack_max = 1, stack_max = 1,
range = 0, -- Pointing range to 0 to prevent punching with bow :D 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}, groups = {not_in_creative_inventory=1, not_in_craft_guide=1, cannot_block=1, bow=1, enchantability=1},
-- Trick to disable digging as well -- Trick to disable digging as well
on_use = function() return end, on_use = function() return end,
on_drop = function(itemstack, dropper, pos) on_drop = function(itemstack, dropper, pos)

File diff suppressed because it is too large Load Diff

View File

@ -171,7 +171,8 @@ minetest.register_craft({
}, },
}) })
mcl_farming:add_plant("plant_beetroot", "mcl_farming:beetroot", {"mcl_farming:beetroot_0", "mcl_farming:beetroot_1", "mcl_farming:beetroot_2"}, 68, 3) -- beetroots grow at 2/3rd of the default speed
mcl_farming:add_plant("plant_beetroot", "mcl_farming:beetroot", {"mcl_farming:beetroot_0", "mcl_farming:beetroot_1", "mcl_farming:beetroot_2"}, 8.7012, 35)
if minetest.get_modpath("doc") then if minetest.get_modpath("doc") then
for i = 1, 2 do for i = 1, 2 do

View File

@ -118,7 +118,7 @@ minetest.register_craft({
} }
}) })
mcl_farming:add_plant("plant_carrot", "mcl_farming:carrot", {"mcl_farming:carrot_1", "mcl_farming:carrot_2", "mcl_farming:carrot_3", "mcl_farming:carrot_4", "mcl_farming:carrot_5", "mcl_farming:carrot_6", "mcl_farming:carrot_7"}, 25, 20) mcl_farming:add_plant("plant_carrot", "mcl_farming:carrot", {"mcl_farming:carrot_1", "mcl_farming:carrot_2", "mcl_farming:carrot_3", "mcl_farming:carrot_4", "mcl_farming:carrot_5", "mcl_farming:carrot_6", "mcl_farming:carrot_7"}, 5.8013, 35)
if minetest.get_modpath("doc") then if minetest.get_modpath("doc") then
for i=2,7 do for i=2,7 do

View File

@ -123,10 +123,10 @@ local stem_def = {
} }
-- Register stem growth -- Register stem growth
mcl_farming:add_plant("plant_melon_stem", "mcl_farming:melontige_unconnect", {"mcl_farming:melontige_1", "mcl_farming:melontige_2", "mcl_farming:melontige_3", "mcl_farming:melontige_4", "mcl_farming:melontige_5", "mcl_farming:melontige_6", "mcl_farming:melontige_7"}, 30, 5) mcl_farming:add_plant("plant_melon_stem", "mcl_farming:melontige_unconnect", {"mcl_farming:melontige_1", "mcl_farming:melontige_2", "mcl_farming:melontige_3", "mcl_farming:melontige_4", "mcl_farming:melontige_5", "mcl_farming:melontige_6", "mcl_farming:melontige_7"}, 5.8014, 35)
-- Register actual melon, connected stems and stem-to-melon growth -- Register actual melon, connected stems and stem-to-melon growth
mcl_farming:add_gourd("mcl_farming:melontige_unconnect", "mcl_farming:melontige_linked", "mcl_farming:melontige_unconnect", stem_def, stem_drop, "mcl_farming:melon", melon_base_def, 25, 15, "mcl_farming_melon_stem_connected.png^[colorize:#FFA800:127") mcl_farming:add_gourd("mcl_farming:melontige_unconnect", "mcl_farming:melontige_linked", "mcl_farming:melontige_unconnect", stem_def, stem_drop, "mcl_farming:melon", melon_base_def, 5.8015, 35, "mcl_farming_melon_stem_connected.png^[colorize:#FFA800:127")
-- Items and crafting -- Items and crafting
minetest.register_craftitem("mcl_farming:melon_item", { minetest.register_craftitem("mcl_farming:melon_item", {

View File

@ -135,7 +135,7 @@ minetest.register_craft({
cooktime = 10, cooktime = 10,
}) })
mcl_farming:add_plant("plant_potato", "mcl_farming:potato", {"mcl_farming:potato_1", "mcl_farming:potato_2", "mcl_farming:potato_3", "mcl_farming:potato_4", "mcl_farming:potato_5", "mcl_farming:potato_6", "mcl_farming:potato_7"}, 19.75, 20) mcl_farming:add_plant("plant_potato", "mcl_farming:potato", {"mcl_farming:potato_1", "mcl_farming:potato_2", "mcl_farming:potato_3", "mcl_farming:potato_4", "mcl_farming:potato_5", "mcl_farming:potato_6", "mcl_farming:potato_7"}, 5.8016, 35)
minetest.register_on_item_eat(function (hp_change, replace_with_item, itemstack, user, pointed_thing) minetest.register_on_item_eat(function (hp_change, replace_with_item, itemstack, user, pointed_thing)

View File

@ -180,10 +180,10 @@ if minetest.get_modpath("mcl_armor") then
end end
-- Register stem growth -- Register stem growth
mcl_farming:add_plant("plant_pumpkin_stem", "mcl_farming:pumpkintige_unconnect", {"mcl_farming:pumpkin_1", "mcl_farming:pumpkin_2", "mcl_farming:pumpkin_3", "mcl_farming:pumpkin_4", "mcl_farming:pumpkin_5", "mcl_farming:pumpkin_6", "mcl_farming:pumpkin_7"}, 30, 5) mcl_farming:add_plant("plant_pumpkin_stem", "mcl_farming:pumpkintige_unconnect", {"mcl_farming:pumpkin_1", "mcl_farming:pumpkin_2", "mcl_farming:pumpkin_3", "mcl_farming:pumpkin_4", "mcl_farming:pumpkin_5", "mcl_farming:pumpkin_6", "mcl_farming:pumpkin_7"}, 5.8017, 35)
-- Register actual pumpkin, connected stems and stem-to-pumpkin growth -- Register actual pumpkin, connected stems and stem-to-pumpkin growth
mcl_farming:add_gourd("mcl_farming:pumpkintige_unconnect", "mcl_farming:pumpkintige_linked", "mcl_farming:pumpkintige_unconnect", stem_def, stem_drop, "mcl_farming:pumpkin", pumpkin_base_def, 30, 15, "mcl_farming_pumpkin_stem_connected.png^[colorize:#FFA800:127") mcl_farming:add_gourd("mcl_farming:pumpkintige_unconnect", "mcl_farming:pumpkintige_linked", "mcl_farming:pumpkintige_unconnect", stem_def, stem_drop, "mcl_farming:pumpkin", pumpkin_base_def, 5.8018, 35, "mcl_farming_pumpkin_stem_connected.png^[colorize:#FFA800:127")
-- Steal function to properly disconnect a carved pumpkin -- Steal function to properly disconnect a carved pumpkin
pumpkin_face_base_def.after_destruct = minetest.registered_nodes["mcl_farming:pumpkin"].after_destruct pumpkin_face_base_def.after_destruct = minetest.registered_nodes["mcl_farming:pumpkin"].after_destruct

View File

@ -5,73 +5,99 @@
-- --
local math = math local math = math
local vector = vector local vector = vector
local random = math.random
local floor = math.floor
local plant_lists = {} local plant_lists = {}
mcl_farming.plant_lists = plant_lists -- export mcl_farming.plant_lists = plant_lists -- export
local plant_nodename_to_id_list = {} local plant_nodename_to_id = {} -- map nodes to plants
local plant_step_from_name = {} -- map nodes to growth steps
local time_speed = tonumber(minetest.settings:get("time_speed")) or 72 local growth_factor = tonumber(minetest.settings:get("vl_plant_growth")) or 1.0
local time_multiplier = time_speed > 0 and (86400 / time_speed) or 0
local function get_intervals_counter(pos, interval, chance) -- wetness of the surroundings
if time_multiplier == 0 then return 0 end -- dry farmland = 1 point
-- "wall clock time", so plants continue to grow while sleeping -- wet farmland = 3 points
local current_game_time = (minetest.get_day_count() + minetest.get_timeofday()) * time_multiplier -- center point gives + 1 point, so 2 resp. 4
local approx_interval = math.max(interval, 1) * math.max(chance, 1) -- neighbors only 25%
local function get_moisture_level(pos)
local meta = minetest.get_meta(pos) local n = vector.offset(pos, 0, -1, 0)
local last_game_time = meta:get_float("last_gametime") local totalm = 1
if last_game_time < 1 then for z = -1,1 do
last_game_time = current_game_time - approx_interval * 0.5 n.z = pos.z + z
elseif last_game_time == current_game_time then for x = -1,1 do
current_game_time = current_game_time + approx_interval n.x = pos.x + x
local ndef = minetest.registered_nodes[minetest.get_node(n).name]
local soil = ndef and ndef.groups.soil
if soil and soil >= 2 then
local m = soil > 2 and 3 or 1
-- corners have less weight
if x ~= 0 or z ~= 0 then m = m * 0.25 end
totalm = totalm + m
end
end
end end
meta:set_float("last_gametime", current_game_time) return totalm
return (current_game_time - last_game_time) / approx_interval
end end
local function get_avg_light_level(pos) -- moisture penalty function:
local meta = minetest.get_meta(pos) -- 0.5 if both on the x axis and the z axis at least one of the same plants grows
-- EWMA would use a single variable: -- 0.5 if at least one diagonal neighbor is the same
-- local avg = meta:get_float("avg_light") -- 1.0 otherwise
-- avg = avg + (node_light - avg) * 0.985 -- we cannot use the names directly, because growth is encoded in the names
-- meta.set_float("avg_light", avg) local function get_same_crop_penalty(pos)
local summary = meta:get_int("avg_light_summary") local name = minetest.get_node(pos).name
local counter = meta:get_int("avg_light_count") local plant = plant_nodename_to_id[name]
if counter > 99 then if not plant then return 1 end
summary, counter = math.ceil(summary * 0.5), 50 local n = vector.copy(pos)
-- check adjacent positions, avoid vector allocations and reduce node accesses
n.x = pos.x - 1
local dx = plant_nodename_to_id[minetest.get_node(n).name] == plant
n.x = pos.x + 1
dx = dx or plant_nodename_to_id[minetest.get_node(n).name] == plant
if dx then -- no need to check z otherwise
n.x = pos.x
n.z = pos.z - 1
local dz = plant_nodename_to_id[minetest.get_node(n).name] == plant
n.z = pos.z + 1
dz = dz or plant_nodename_to_id[minetest.get_node(n).name] == plant
if dz then return 0.5 end
end end
local node_light = minetest.get_node_light(pos) -- check diagonals, clockwise
if node_light ~= nil then n.x, n.z = pos.x - 1, pos.z - 1
summary, counter = summary + node_light, counter + 1 if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
meta:set_int("avg_light_summary", summary) n.x = pos.x + 1
meta:set_int("avg_light_count", counter) if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
end n.z = pos.z + 1
return math.ceil(summary / counter) if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
n.x = pos.x - 1
if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
return 1
end end
function mcl_farming:add_plant(identifier, full_grown, names, interval, chance) function mcl_farming:add_plant(identifier, full_grown, names, interval, chance)
interval = growth_factor > 0 and (interval / growth_factor) or 0
local plant_info = {} local plant_info = {}
plant_info.full_grown = full_grown plant_info.full_grown = full_grown
plant_info.names = names plant_info.names = names
plant_info.interval = interval plant_info.interval = interval
plant_info.chance = chance plant_info.chance = chance
plant_nodename_to_id[full_grown] = identifier
for _, nodename in pairs(names) do for _, nodename in pairs(names) do
plant_nodename_to_id_list[nodename] = identifier plant_nodename_to_id[nodename] = identifier
end end
plant_info.step_from_name = {}
for i, name in ipairs(names) do for i, name in ipairs(names) do
plant_info.step_from_name[name] = i plant_step_from_name[name] = i
end end
plant_lists[identifier] = plant_info plant_lists[identifier] = plant_info
if interval == 0 then return end -- growth disabled
minetest.register_abm({ minetest.register_abm({
label = string.format("Farming plant growth (%s)", identifier), label = string.format("Farming plant growth (%s)", identifier),
nodenames = names, nodenames = names,
interval = interval, interval = interval,
chance = chance, chance = chance,
action = function(pos, node) action = function(pos, node)
local low_speed = minetest.get_node(vector.offset(pos, 0, -1, 0)).name ~= "mcl_farming:soil_wet" mcl_farming:grow_plant(identifier, pos, node, 1, false)
mcl_farming:grow_plant(identifier, pos, node, 1, false, low_speed)
end, end,
}) })
end end
@ -81,40 +107,30 @@ end
-- pos: Position -- pos: Position
-- node: Node table -- node: Node table
-- stages: Number of stages to advance (optional, defaults to 1) -- stages: Number of stages to advance (optional, defaults to 1)
-- ignore_light: if true, ignore light requirements for growing -- ignore_light_water: if true, ignore light and water requirements for growing
-- low_speed: grow more slowly (not wet), default false
-- Returns true if plant has been grown by 1 or more stages. -- Returns true if plant has been grown by 1 or more stages.
-- Returns false if nothing changed. -- Returns false if nothing changed.
function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light, low_speed) function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light_water)
stages = stages or 1 -- number of missed interval ticks, for catch-up in block loading
local plant_info = plant_lists[identifier] local plant_info = plant_lists[identifier]
local intervals_counter = get_intervals_counter(pos, plant_info.interval, plant_info.chance) if not plant_info then return end
if stages > 0 then intervals_counters = intervals_counter - 1 end if not ignore_light_water then
if low_speed then -- 10% speed approximately if (minetest.get_node_light(pos, 0.5) or 0) < 0 then return false end -- day light
if intervals_counter < 1.01 and math.random(0, 9) > 0 then return false end local odds = floor(25 / (get_moisture_level(pos) * get_same_crop_penalty(pos))) + 1
intervals_counter = intervals_counter / 10 for i = 1,stages do
end -- compared to info from the MC wiki, our ABM runs a third as often, hence we use triple the chance
if not ignore_light and intervals_counter < 1.5 then if random() * odds >= 3 then stages = stages - 1 end
local light = minetest.get_node_light(pos)
if not light or light < 10 then return false end
end
if intervals_counter >= 1.5 then
local average_light_level = get_avg_light_level(pos)
if average_light_level < 0.1 then return false end
if average_light_level < 10 then
intervals_counter = intervals_counter * average_light_level / 10
end end
end end
local step = plant_info.step_from_name[node.name]
if step == nil then return false end
stages = stages + math.floor(intervals_counter)
if stages == 0 then return false end if stages == 0 then return false end
local new_node = { name = plant_info.names[step + stages] or plant_info.full_grown } local step = plant_step_from_name[node.name]
new_node.param = node.param if step == nil then return false end
new_node.param2 = node.param2 minetest.set_node(pos, {
minetest.set_node(pos, new_node) name = plant_info.names[step + stages] or plant_info.full_grown,
param = node.param,
param2 = node.param2,
})
return true return true
end end
@ -157,40 +173,13 @@ end
function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, stem_itemstring, stem_def, stem_drop, gourd_itemstring, gourd_def, grow_interval, grow_chance, connected_stem_texture) function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, stem_itemstring, stem_def, stem_drop, gourd_itemstring, gourd_def, grow_interval, grow_chance, connected_stem_texture)
grow_interval = growth_factor > 0 and (grow_interval / growth_factor) or 0
local connected_stem_names = { local connected_stem_names = {
connected_stem_basename .. "_r", connected_stem_basename .. "_r",
connected_stem_basename .. "_l", connected_stem_basename .. "_l",
connected_stem_basename .. "_t", connected_stem_basename .. "_t",
connected_stem_basename .. "_b" } connected_stem_basename .. "_b" }
-- Connect the stem at stempos to the first neighboring gourd block.
-- No-op if not a stem or no gourd block found
local function try_connect_stem(stempos)
local stem = minetest.get_node(stempos)
if stem.name ~= full_unconnected_stem then return false end
-- four directions, but avoid table allocation
local neighbor = vector.offset(stempos, 1, 0, 0)
if minetest.get_node(neighbor).name == gourd_itemstring then
minetest.swap_node(stempos, { name = connected_stem_names[1] })
return true
end
local neighbor = vector.offset(stempos, -1, 0, 0)
if minetest.get_node(neighbor).name == gourd_itemstring then
minetest.swap_node(stempos, { name = connected_stem_names[2] })
return true
end
local neighbor = vector.offset(stempos, 0, 0, 1)
if minetest.get_node(neighbor).name == gourd_itemstring then
minetest.swap_node(stempos, { name = connected_stem_names[3] })
return true
end
local neighbor = vector.offset(stempos, 0, 0, -1)
if minetest.get_node(neighbor).name == gourd_itemstring then
minetest.swap_node(stempos, { name = connected_stem_names[4] })
return true
end
end
-- Register gourd -- Register gourd
if not gourd_def.after_destruct then if not gourd_def.after_destruct then
gourd_def.after_destruct = function(blockpos, oldnode) gourd_def.after_destruct = function(blockpos, oldnode)
@ -200,34 +189,21 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
local stempos = vector.offset(blockpos, -1, 0, 0) local stempos = vector.offset(blockpos, -1, 0, 0)
if minetest.get_node(stempos).name == connected_stem_names[1] then if minetest.get_node(stempos).name == connected_stem_names[1] then
minetest.swap_node(stempos, { name = full_unconnected_stem }) minetest.swap_node(stempos, { name = full_unconnected_stem })
try_connect_stem(stempos)
end end
local stempos = vector.offset(blockpos, 1, 0, 0) local stempos = vector.offset(blockpos, 1, 0, 0)
if minetest.get_node(stempos).name == connected_stem_names[2] then if minetest.get_node(stempos).name == connected_stem_names[2] then
minetest.swap_node(stempos, { name = full_unconnected_stem }) minetest.swap_node(stempos, { name = full_unconnected_stem })
try_connect_stem(stempos)
end end
local stempos = vector.offset(blockpos, 0, 0, -1) local stempos = vector.offset(blockpos, 0, 0, -1)
if minetest.get_node(stempos).name == connected_stem_names[3] then if minetest.get_node(stempos).name == connected_stem_names[3] then
minetest.swap_node(stempos, { name = full_unconnected_stem }) minetest.swap_node(stempos, { name = full_unconnected_stem })
try_connect_stem(stempos)
end end
local stempos = vector.offset(blockpos, 0, 0, 1) local stempos = vector.offset(blockpos, 0, 0, 1)
if minetest.get_node(stempos).name == connected_stem_names[4] then if minetest.get_node(stempos).name == connected_stem_names[4] then
minetest.swap_node(stempos, { name = full_unconnected_stem }) minetest.swap_node(stempos, { name = full_unconnected_stem })
try_connect_stem(stempos)
end end
end end
end end
if not gourd_def.on_construct then
function gourd_def.on_construct(blockpos)
-- Connect all unconnected stems at full size
try_connect_stem(vector.offset(blockpos, 1, 0, 0))
try_connect_stem(vector.offset(blockpos, -1, 0, 0))
try_connect_stem(vector.offset(blockpos, 0, 0, 1))
try_connect_stem(vector.offset(blockpos, 0, 0, -1))
end
end
minetest.register_node(gourd_itemstring, gourd_def) minetest.register_node(gourd_itemstring, gourd_def)
-- Register unconnected stem -- Register unconnected stem
@ -243,8 +219,8 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
stem_def.drop = stem_def.drop or stem_drop stem_def.drop = stem_def.drop or stem_drop
stem_def.groups = stem_def.groups or { dig_immediate = 3, not_in_creative_inventory = 1, plant = 1, attached_node = 1, dig_by_water = 1, destroy_by_lava_flow = 1 } stem_def.groups = stem_def.groups or { dig_immediate = 3, not_in_creative_inventory = 1, plant = 1, attached_node = 1, dig_by_water = 1, destroy_by_lava_flow = 1 }
stem_def.sounds = stem_def.sounds or mcl_sounds.node_sound_leaves_defaults() stem_def.sounds = stem_def.sounds or mcl_sounds.node_sound_leaves_defaults()
stem_def.on_construct = stem_def.on_construct or try_connect_stem
minetest.register_node(stem_itemstring, stem_def) minetest.register_node(stem_itemstring, stem_def)
plant_nodename_to_id[stem_itemstring] = stem_itemstring
-- Register connected stems -- Register connected stems
@ -307,22 +283,14 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
sounds = mcl_sounds.node_sound_leaves_defaults(), sounds = mcl_sounds.node_sound_leaves_defaults(),
_mcl_blast_resistance = 0, _mcl_blast_resistance = 0,
}) })
plant_nodename_to_id[connected_stem_names[i]] = stem_itemstring
if minetest.get_modpath("doc") then if minetest.get_modpath("doc") then
doc.add_entry_alias("nodes", full_unconnected_stem, "nodes", connected_stem_names[i]) doc.add_entry_alias("nodes", full_unconnected_stem, "nodes", connected_stem_names[i])
end end
end end
-- Check for a suitable spot to grow if grow_interval == 0 then return end
local function check_neighbor_soil(blockpos)
if minetest.get_node(blockpos).name ~= "air" then return false end
local floorpos = vector.offset(blockpos, 0, -1, 0)
local floorname = minetest.get_node(floorpos).name
if floorname == "mcl_core:dirt" then return true end
local floordef = minetest.registered_nodes[floorname]
return floordef.groups.grass_block or floordef.groups.dirt or (floordef.groups.soil or 0) >= 2
end
minetest.register_abm({ minetest.register_abm({
label = "Grow gourd stem to gourd (" .. full_unconnected_stem .. "" .. gourd_itemstring .. ")", label = "Grow gourd stem to gourd (" .. full_unconnected_stem .. "" .. gourd_itemstring .. ")",
nodenames = { full_unconnected_stem }, nodenames = { full_unconnected_stem },
@ -330,39 +298,27 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
interval = grow_interval, interval = grow_interval,
chance = grow_chance, chance = grow_chance,
action = function(stempos) action = function(stempos)
local light = minetest.get_node_light(stempos) local light = minetest.get_node_light(stempos, 0.5)
if not light or light <= 10 then return end if not light or light < 9 then return end
-- Check the four neighbors and filter out neighbors where gourds can't grow -- Pick one neighbor and check if it can be used to grow
local neighbor, dir, nchance = nil, -1, 1 -- reservoir sampling local dir = random(1, 4) -- pick direction at random
if nchance == 1 or math.random(1, nchance) == 1 then local neighbor = (dir == 1 and vector.offset(stempos, 1, 0, 0))
local blockpos = vector.offset(stempos, 1, 0, 0) or (dir == 2 and vector.offset(stempos, -1, 0, 0))
if check_neighbor_soil(blockpos) then or (dir == 3 and vector.offset(stempos, 0, 0, 1))
neighbor, dir, nchance = blockpos, 1, nchance + 1 or vector.offset(stempos, 0, 0, -1)
end if minetest.get_node(neighbor).name ~= "air" then return end -- occupied
end -- check for suitable floor -- in contrast to MC, we think everything solid is fine
if nchance == 1 or math.random(1, nchance) == 1 then local floorpos = vector.offset(neighbor, 0, -1, 0)
local blockpos = vector.offset(stempos, -1, 0, 0) local floorname = minetest.get_node(floorpos).name
if check_neighbor_soil(blockpos) then local floordef = minetest.registered_nodes[floorname]
neighbor, dir, nchance = blockpos, 2, nchance + 1 if not floordef or not floordef.walkable then return end
end
end -- check moisture level
if nchance == 1 or math.random(1, nchance) == 1 then local odds = floor(25 / (get_moisture_level(stempos) * get_same_crop_penalty(stempos))) + 1
local blockpos = vector.offset(stempos, 0, 0, 1) -- we triple the odds, and rather call the ABM less often
if check_neighbor_soil(blockpos) then if random() * odds >= 3 then return end
neighbor, dir, nchance = blockpos, 3, nchance + 1
end
end
if nchance == 1 or math.random(1, nchance) == 1 then
local blockpos = vector.offset(stempos, 0, 0, -1)
if check_neighbor_soil(blockpos) then
neighbor, dir, nchance = blockpos, 4, nchance + 1
end
end
-- Gourd needs at least 1 free neighbor to grow
if not neighbor then return end
minetest.swap_node(stempos, { name = connected_stem_names[dir] }) minetest.swap_node(stempos, { name = connected_stem_names[dir] })
-- Place the gourd
if gourd_def.paramtype2 == "facedir" then if gourd_def.paramtype2 == "facedir" then
local p2 = (dir == 1 and 3) or (dir == 2 and 1) or (dir == 3 and 2) or 0 local p2 = (dir == 1 and 3) or (dir == 2 and 1) or (dir == 3 and 2) or 0
minetest.add_node(neighbor, { name = gourd_itemstring, param2 = p2 }) minetest.add_node(neighbor, { name = gourd_itemstring, param2 = p2 })
@ -371,8 +327,7 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
end end
-- Reset farmland, etc. to dirt when the gourd grows on top -- Reset farmland, etc. to dirt when the gourd grows on top
local floorpos = vector.offset(neighbor, 0, -1, 0) if (floordef.groups.dirtifies_below_solid or 0) > 0 then
if minetest.get_item_group(minetest.get_node(floorpos).name, "dirtifies_below_solid") == 1 then
minetest.set_node(floorpos, { name = "mcl_core:dirt" }) minetest.set_node(floorpos, { name = "mcl_core:dirt" })
end end
end, end,
@ -409,10 +364,21 @@ minetest.register_lbm({
nodenames = { "group:plant" }, nodenames = { "group:plant" },
run_at_every_load = true, run_at_every_load = true,
action = function(pos, node, dtime_s) action = function(pos, node, dtime_s)
local identifier = plant_nodename_to_id_list[node.name] local identifier = plant_nodename_to_id[node.name]
if not identifier then return end if not identifier then return end
local low_speed = minetest.get_node(vector.offset(pos, 0, -1, 0)).name ~= "mcl_farming:soil_wet"
mcl_farming:grow_plant(identifier, pos, node, 0, false, low_speed) local plant_info = plant_lists[identifier]
if not plant_info then return end
local rolls = floor(dtime_s / plant_info.interval)
if rolls <= 0 then return end
-- simulate how often the block will be ticked
local stages = 0
for i = 1,rolls do
if random(1, plant_info.chance) == 1 then stages = stages + 1 end
end
if stages > 0 then
mcl_farming:grow_plant(identifier, pos, node, stages, false)
end
end, end,
}) })

View File

@ -15,10 +15,6 @@ minetest.register_node("mcl_farming:soil", {
{-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5}, {-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5},
} }
}, },
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("wet", 0)
end,
groups = {handy=1,shovely=1, dirtifies_below_solid=1, dirtifier=1, soil=2, soil_sapling=1, deco_block=1 }, groups = {handy=1,shovely=1, dirtifies_below_solid=1, dirtifier=1, soil=2, soil_sapling=1, deco_block=1 },
sounds = mcl_sounds.node_sound_dirt_defaults(), sounds = mcl_sounds.node_sound_dirt_defaults(),
_mcl_blast_resistance = 0.6, _mcl_blast_resistance = 0.6,
@ -38,10 +34,6 @@ minetest.register_node("mcl_farming:soil_wet", {
{-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5}, {-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5},
} }
}, },
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("wet", 7)
end,
groups = {handy=1,shovely=1, not_in_creative_inventory=1, dirtifies_below_solid=1, dirtifier=1, soil=3, soil_sapling=1 }, groups = {handy=1,shovely=1, not_in_creative_inventory=1, dirtifies_below_solid=1, dirtifier=1, soil=3, soil_sapling=1 },
sounds = mcl_sounds.node_sound_dirt_defaults(), sounds = mcl_sounds.node_sound_dirt_defaults(),
_mcl_blast_resistance = 0.6, _mcl_blast_resistance = 0.6,
@ -51,75 +43,54 @@ minetest.register_node("mcl_farming:soil_wet", {
minetest.register_abm({ minetest.register_abm({
label = "Farmland hydration", label = "Farmland hydration",
nodenames = {"mcl_farming:soil", "mcl_farming:soil_wet"}, nodenames = {"mcl_farming:soil", "mcl_farming:soil_wet"},
interval = 15, interval = 2.73,
chance = 4, chance = 25,
action = function(pos, node) action = function(pos, node)
-- Get wetness value
local meta = minetest.get_meta(pos)
local wet = meta:get_int("wet")
if not wet then
if node.name == "mcl_farming:soil" then
wet = 0
else
wet = 7
end
end
-- Turn back into dirt when covered by solid node -- Turn back into dirt when covered by solid node
local above_node = minetest.get_node_or_nil({x=pos.x,y=pos.y+1,z=pos.z}) local above_node = minetest.get_node_or_nil(vector.offset(pos, 0, 1, 0))
if above_node then if above_node and minetest.get_item_group(above_node.name, "solid") ~= 0 then
if minetest.get_item_group(above_node.name, "solid") ~= 0 then node.name = "mcl_core:dirt"
node.name = "mcl_core:dirt" minetest.set_node(pos, node)
minetest.set_node(pos, node) return
return
end
end end
-- Check an area of 9×2×9 around the node for nodename (9×9 on same level and 9×9 below) -- in rain, become wet, do not decay
local function check_surroundings(pos, nodename) if mcl_weather and mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
local nodes = minetest.find_nodes_in_area({x=pos.x-4,y=pos.y,z=pos.z-4}, {x=pos.x+4,y=pos.y+1,z=pos.z+4}, {nodename}) if node.name == "mcl_farming:soil" then
return #nodes > 0
end
if check_surroundings(pos, "group:water") then
if node.name ~= "mcl_farming:soil_wet" then
-- Make it wet
node.name = "mcl_farming:soil_wet" node.name = "mcl_farming:soil_wet"
minetest.set_node(pos, node) minetest.set_node(pos, node)
end end
else -- No water nearby. return
-- The decay branch (make farmland dry or turn back to dirt) end
-- Don't decay while it's raining -- Check an area of 9x2x9 around the node for nodename (9x9 on same level and 9x9 above)
if mcl_weather.rain.raining then -- include "ignore" to detect unloaded blocks
if mcl_weather.is_outdoor(pos) then local nodes, counts = minetest.find_nodes_in_area(vector.offset(pos, -4, 0, -4), vector.offset(pos, 4, 1, 4), {"group:water", "ignore"})
return local ignore = counts.ignore or 0
end local has_water, fully_loaded = #nodes > ignore, ignore == 0
end
-- No decay near unloaded areas since these might include water.
if not check_surroundings(pos, "ignore") then
if wet <= 0 then
--local n_def = minetest.registered_nodes[node.name] or nil
local nn = minetest.get_node_or_nil({x=pos.x,y=pos.y+1,z=pos.z})
if not nn or not nn.name then
return
end
local nn_def = minetest.registered_nodes[nn.name] or nil
if nn_def and minetest.get_item_group(nn.name, "plant") == 0 then -- Hydrate by rain or water, do not decay
node.name = "mcl_core:dirt" if has_water then
minetest.set_node(pos, node) if node.name == "mcl_farming:soil" then
return node.name = "mcl_farming:soil_wet"
end minetest.set_node(pos, node)
else
if wet == 7 then
node.name = "mcl_farming:soil"
minetest.swap_node(pos, node)
end
-- Slowly count down wetness
meta:set_int("wet", wet-1)
end
end end
return
end
-- No decay near unloaded areas (ignore) since these might include water.
if not fully_loaded then return end
-- Decay: make wet farmland dry up
if node.name == "mcl_farming:soil_wet" then
node.name = "mcl_farming:soil"
minetest.set_node(pos, node)
return
end
-- Revert to dirt if wetness is 0, and no plant above
local above = minetest.get_node_or_nil(vector.offset(pos, 0, 1, 0))
if minetest.get_item_group(above.name, "plant") == 0 then
node.name = "mcl_core:dirt"
minetest.set_node(pos, node)
end end
end, end,
}) })

View File

@ -99,8 +99,8 @@ minetest.register_craftitem("mcl_farming:sweet_berry", {
}) })
minetest.register_alias("mcl_sweet_berry:sweet_berry", "mcl_farming:sweet_berry") minetest.register_alias("mcl_sweet_berry:sweet_berry", "mcl_farming:sweet_berry")
-- TODO: Find proper interval and chance values for sweet berry bushes. Current interval and chance values are copied from mcl_farming:beetroot which has similar growth stages. -- TODO: Find proper interval and chance values for sweet berry bushes. Current interval and chance values are copied from mcl_farming:beetroot which has similar growth stages, 2/3rd of the default.
mcl_farming:add_plant("plant_sweet_berry_bush", "mcl_farming:sweet_berry_bush_3", {"mcl_farming:sweet_berry_bush_0", "mcl_farming:sweet_berry_bush_1", "mcl_farming:sweet_berry_bush_2"}, 68, 3) mcl_farming:add_plant("plant_sweet_berry_bush", "mcl_farming:sweet_berry_bush_3", {"mcl_farming:sweet_berry_bush_0", "mcl_farming:sweet_berry_bush_1", "mcl_farming:sweet_berry_bush_2"}, 8.7019, 35)
local function berry_damage_check(obj) local function berry_damage_check(obj)
local p = obj:get_pos() local p = obj:get_pos()

View File

@ -99,7 +99,7 @@ minetest.register_node("mcl_farming:wheat", {
} }
}) })
mcl_farming:add_plant("plant_wheat", "mcl_farming:wheat", {"mcl_farming:wheat_1", "mcl_farming:wheat_2", "mcl_farming:wheat_3", "mcl_farming:wheat_4", "mcl_farming:wheat_5", "mcl_farming:wheat_6", "mcl_farming:wheat_7"}, 25, 20) mcl_farming:add_plant("plant_wheat", "mcl_farming:wheat", {"mcl_farming:wheat_1", "mcl_farming:wheat_2", "mcl_farming:wheat_3", "mcl_farming:wheat_4", "mcl_farming:wheat_5", "mcl_farming:wheat_6", "mcl_farming:wheat_7"}, 5.8020, 35)
minetest.register_craftitem("mcl_farming:wheat_item", { minetest.register_craftitem("mcl_farming:wheat_item", {
description = S("Wheat"), description = S("Wheat"),

View File

@ -211,16 +211,37 @@ local function set_interact(player, interact)
return return
end end
local meta = player:get_meta() local meta = player:get_meta()
if meta:get_int("mcl_privs:interact_revoked") ~= 1 then
privs.interact = interact if interact and meta:get_int("mcl_shields:interact_revoked") ~= 0 then
minetest.set_player_privs(player_name, privs) meta:set_int("mcl_shields:interact_revoked", 0)
meta:set_int("mcl_privs:interact_revoked",0) privs.interact = true
elseif not interact then
meta:set_int("mcl_shields:interact_revoked", privs.interact and 1 or 0)
privs.interact = nil
end end
minetest.set_player_privs(player_name, privs)
end end
-- Prevent player from being able to circumvent interact privilage removal by
-- using shield.
minetest.register_on_priv_revoke(function(name, revoker, priv)
if priv == "interact" and revoker then
local player = minetest.get_player_by_name(name)
if not player then
return
end
local meta = player:get_meta()
meta:set_int("mcl_shields:interact_revoked", 0)
end
end)
local shield_hud = {} local shield_hud = {}
local function remove_shield_hud(player) local function remove_shield_hud(player)
set_interact(player, true)
playerphysics.remove_physics_factor(player, "speed", "shield_speed")
if not shield_hud[player] then return end --this function takes a long time. only run it when necessary if not shield_hud[player] then return end --this function takes a long time. only run it when necessary
player:hud_remove(shield_hud[player]) player:hud_remove(shield_hud[player])
shield_hud[player] = nil shield_hud[player] = nil
@ -231,9 +252,6 @@ local function remove_shield_hud(player)
if not hf.wielditem then if not hf.wielditem then
player:hud_set_flags({wielditem = true}) player:hud_set_flags({wielditem = true})
end end
playerphysics.remove_physics_factor(player, "speed", "shield_speed")
set_interact(player, true)
end end
local function add_shield_entity(player, i) local function add_shield_entity(player, i)
@ -251,6 +269,11 @@ local function remove_shield_entity(player, i)
end end
end end
local function is_rmb_conflicting_node(nodename)
local nodedef = minetest.registered_nodes[nodename] or {}
return nodedef.on_rightclick
end
local function handle_blocking(player) local function handle_blocking(player)
local player_shield = mcl_shields.players[player] local player_shield = mcl_shields.players[player]
local rmb = player:get_player_control().RMB local rmb = player:get_player_control().RMB
@ -259,14 +282,25 @@ local function handle_blocking(player)
return return
end end
local pointed_thing = mcl_util.get_pointed_thing(player, true)
local wielded_stack = player:get_wielded_item()
local shield_in_offhand = mcl_shields.wielding_shield(player, 1) local shield_in_offhand = mcl_shields.wielding_shield(player, 1)
local shield_in_hand = mcl_shields.wielding_shield(player) local shield_in_hand = mcl_shields.wielding_shield(player)
local not_blocking = player_shield.blocking == 0 local not_blocking = player_shield.blocking == 0
local pos = player:get_pos() if pointed_thing and pointed_thing.type == "node" then
local pointed_node = minetest.get_node(pointed_thing.under)
if minetest.get_item_group(pointed_node.name, "container") > 1
or is_rmb_conflicting_node(pointed_node.name)
or wielded_stack:get_definition().type == "node" then
return
end
end
if shield_in_hand then if shield_in_hand then
if not_blocking then if not_blocking then
minetest.after(0.25, function() minetest.after(0.05, function()
if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then
player_shield.blocking = 2 player_shield.blocking = 2
set_shield(player, true, 2) set_shield(player, true, 2)
@ -276,22 +310,15 @@ local function handle_blocking(player)
player_shield.blocking = 2 player_shield.blocking = 2
end end
elseif shield_in_offhand then elseif shield_in_offhand then
local pointed_thing = mcl_util.get_pointed_thing(player, true) local offhand_can_block = minetest.get_item_group(wielded_item(player), "cannot_block") ~= 1
local offhand_can_block = (wielded_item(player) == "" or not pointed_thing)
and (minetest.get_item_group(wielded_item(player), "bow") ~= 1 and minetest.get_item_group(wielded_item(player), "crossbow") ~= 1)
if pointed_thing and pointed_thing.type == "node" then
if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "container") > 1 then
return
end
end
if not offhand_can_block then if not offhand_can_block then
return return
end end
if not_blocking then if not_blocking then
minetest.after(0.25, function() minetest.after(0.05, function()
if (not_blocking or not shield_in_hand) and shield_in_offhand and rmb and offhand_can_block then if (not_blocking or not shield_in_hand) and shield_in_offhand
and rmb and offhand_can_block then
player_shield.blocking = 1 player_shield.blocking = 1
set_shield(player, true, 1) set_shield(player, true, 1)
end end
@ -344,7 +371,7 @@ local function add_shield_hud(shieldstack, player, blocking)
z_index = -200, z_index = -200,
}) })
playerphysics.add_physics_factor(player, "speed", "shield_speed", 0.5) playerphysics.add_physics_factor(player, "speed", "shield_speed", 0.5)
set_interact(player, nil) set_interact(player, false)
end end
local function update_shield_hud(player, blocking, shieldstack) local function update_shield_hud(player, blocking, shieldstack)

View File

@ -30,17 +30,5 @@ for _, action in pairs({"grant", "revoke"}) do
if priv == "fly" then if priv == "fly" then
meta:set_int("mcl_privs:fly_changed", 1) meta:set_int("mcl_privs:fly_changed", 1)
end end
--[[
so e.g. hackers who have been revoked of the interact privilege
will not automatically get the interact privilege through the mcl shields code back
]]
if priv == "interact" then
if action == "revoke" then
meta:set_int("mcl_privs:interact_revoked", 1)
else
meta:set_int("mcl_privs:interact_revoked", 0)
end
end
end) end)
end end

View File

@ -45,6 +45,9 @@ mcl_disabled_structures (Disabled structures) string
# Comma separated list of disabled event names # Comma separated list of disabled event names
mcl_disabled_events (Disabled events) string mcl_disabled_events (Disabled events) string
# Control the relative plant growth speed (default: 1)
vl_plant_growth (Plant growth factor) float 1.0 0 100
[Players] [Players]
# If enabled, players respawn at the bed they last lay on instead of normal # If enabled, players respawn at the bed they last lay on instead of normal
# spawn. # spawn.