From 3195df3864f65489c2e120c0a2aea9e29e750eaa Mon Sep 17 00:00:00 2001 From: NO11 Date: Wed, 28 Apr 2021 17:53:40 +0000 Subject: [PATCH 01/22] remove object crosshair --- .../textures/object_crosshair.png | Bin 150 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 mods/HUD/mcl_base_textures/textures/object_crosshair.png diff --git a/mods/HUD/mcl_base_textures/textures/object_crosshair.png b/mods/HUD/mcl_base_textures/textures/object_crosshair.png deleted file mode 100644 index e5a400e951b3fc543b6e2baf007c24f0949229cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^HXzIhBp8I+pWFvhOeH~n!3+##lh0ZJdH$X*jv*C{ z$r3>gt&NVrF-;(b vWgXi(?mWIbDLY~dZa;k2xLe@ivxS@t;avh+c8nGmKo)ws`njxgN@xNA{9!K; From 32c03dc27eb835fb60fdc2e396f6c3d5e5fc010d Mon Sep 17 00:00:00 2001 From: NO11 Date: Wed, 28 Apr 2021 17:55:03 +0000 Subject: [PATCH 02/22] new object overlay --- .../textures/object_crosshair.png | Bin 0 -> 144 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mods/HUD/mcl_base_textures/textures/object_crosshair.png diff --git a/mods/HUD/mcl_base_textures/textures/object_crosshair.png b/mods/HUD/mcl_base_textures/textures/object_crosshair.png new file mode 100644 index 0000000000000000000000000000000000000000..8e94dcc6bef47196a2f5cd93226eec0e8a8c3a24 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw3=&b&bO2I}#X;^)4C~IxyaaOC0(?STf%O0X z|CipJe-|WO666=m;PC858jz#y>EamTas2JYjl2v7Jcl>@_`kf^@w<{*x$i7SEfvA; k^G7OwTYihYBfxAcmUfh3mZZ_ebf7i{Pgg&ebxsLQ0Dz7xGXMYp literal 0 HcmV?d00001 From a6ac6f5c766deb0f97e876af74fe213deb092f96 Mon Sep 17 00:00:00 2001 From: kay27 Date: Thu, 29 Apr 2021 04:11:33 +0400 Subject: [PATCH 03/22] Merge NEW MOBS by @jordan4ibanez from `mineclone5` branch commit cd472337985d6e885eef019185f0965d13148e7f Author: jordan4ibanez Date: Sun Apr 25 22:02:20 2021 -0400 Fix rabbit rotation commit 0f4628db09d68f69a997f98dcd462f29e7ecbe06 Author: jordan4ibanez Date: Sun Apr 25 20:48:42 2021 -0400 Bring mob spawning variable to the top of the spawning.lua file so it's easier to find commit ddb33acf0d85f29dddb8bdab7a3a7030f9f595be Author: jordan4ibanez Date: Sun Apr 25 20:46:45 2021 -0400 Add in unused head code elements commit e52aab45c07c22605993126c4a8ba39c8318d904 Author: jordan4ibanez Date: Sun Apr 25 20:23:46 2021 -0400 Implement no-op head operations for enderman commit ac852309388e1f9a7dec294440975c7dc89e498c Author: jordan4ibanez Date: Sun Apr 25 20:08:45 2021 -0400 Add in chicken head code with additional pitch modifier commit f57c4709ac74d1e2b0b683bebc706a1a3e59db73 Author: jordan4ibanez Date: Sun Apr 25 19:54:11 2021 -0400 Comment out code that causes mobs to glitch push players in mcl_playerplus commit b6c9a1c423a9831cb3684e6a7e1b57163d6d4ab4 Author: jordan4ibanez Date: Sun Apr 25 19:51:11 2021 -0400 Fix creeper head commit a8152760b96ca3a9f142b006d2d888da0ebeff6a Author: jordan4ibanez Date: Sun Apr 25 19:44:15 2021 -0400 Integrate more switches into internal api elements of head code commit 6a38198e97fd0b573b3b9e590177977d900d5b14 Author: jordan4ibanez Date: Sun Apr 25 18:24:10 2021 -0400 Add in swap_y_with_x and reverse_head_yaw to flesh out head code api element commit d28e81bc9fc1f11b10da524d6874e8e1ee4a956d Author: jordan4ibanez Date: Sun Apr 25 17:54:14 2021 -0400 Add in mobs look pitch commit 5a2773ea1abb6c8706c477802aae2fa60704714c Author: jordan4ibanez Date: Sun Apr 25 17:48:41 2021 -0400 Add in basics of head code yaw commit 555935ff3d35d4ac28dad42f5facac0bbfe9b1c9 Author: jordan4ibanez Date: Sun Apr 25 16:43:23 2021 -0400 Implement basic fall damage commit 7e3b69348e405425712cf8196907a913be10b62e Author: jordan4ibanez Date: Sun Apr 25 16:11:45 2021 -0400 Add secondary existence check after main logic has been executed to prevent future crashes commit c898e1e4db3b866ddc4ff391ff89798397775fbf Author: jordan4ibanez Date: Sun Apr 25 15:59:00 2021 -0400 Update sheep.lua commit 9b5c9dc8ae9d1221340d1c72e4f48f3212a07fb7 Author: jordan4ibanez Date: Sun Apr 25 04:31:48 2021 -0400 Make farmable mobs/food mobs a lot less rare commit 5e6653ff651a65e6bfc4057cb5de39f09e9b9cca Author: jordan4ibanez Date: Sun Apr 25 04:19:02 2021 -0400 Implement mob cramming commit 1616cb7538141cd38485b4bf59a7b8b049ddd3f0 Author: jordan4ibanez Date: Sun Apr 25 04:09:35 2021 -0400 Fix nametags commit a3ff108cd4b71cd823518eae0186cbf1d819267e Author: jordan4ibanez Date: Sun Apr 25 04:03:06 2021 -0400 Make mobs walk up stairs/slabs properly, yet not glitch out when jumping over solid nodes commit df364eed286fced64f3c4bff897fcfe91a9dd540 Author: jordan4ibanez Date: Sun Apr 25 01:45:35 2021 -0400 Implement basics of head movement and fix walking mobs flying away after floating commit bac191293bc23405bfc02ef0795f0296fdaeb95a Author: jordan4ibanez Date: Sun Apr 25 01:45:03 2021 -0400 Fix clientside guessing making floating go crazy client side commit b7c7c2627beba086c922df0a20939b67ae1eb464 Author: jordan4ibanez Date: Sun Apr 25 01:44:46 2021 -0400 Fix parrots not drowning commit 38c22f277db652226ce9911e8bffbb8e8b8bc398 Author: jordan4ibanez Date: Sun Apr 25 01:24:19 2021 -0400 Add pop sound when baby mob is born commit f83ccdb2ed5974486a030196f9b31d0490dcdff3 Author: jordan4ibanez Date: Sun Apr 25 01:22:43 2021 -0400 Add in breeding and feeding baby mob sounds commit 7733e05a120cb07ed37c351956c1f451da3658b1 Author: jordan4ibanez Date: Sun Apr 25 01:14:48 2021 -0400 Add in random sounds/hurt/death sounds and stop mobs from reviving on server restart again commit 0a380265c888c64386406187b34914438cdff161 Author: jordan4ibanez Date: Sun Apr 25 00:16:54 2021 -0400 Fix dead-alive mobs and add in hurt/die sound commit 8d3eff0c16abeff9fbce2f9d4af2b64931765696 Author: jordan4ibanez Date: Sun Apr 25 00:06:12 2021 -0400 Enable mob drowning commit 56086bf02be689ba83ba3ccf4858429ad4d6a10b Author: jordan4ibanez Date: Sat Apr 24 23:33:46 2021 -0400 Fix villager commit 079811984cd952714e6cf85297c91830c0790a1d Author: jordan4ibanez Date: Sat Apr 24 23:29:56 2021 -0400 Make every mob besides spiders get slowed down by cobwebs like players commit 7e8e63b0e37300b16a4556aa45758d737514316e Author: jordan4ibanez Date: Sat Apr 24 23:15:40 2021 -0400 If mob is in daylight and ignites_in_daylight = true, make mob burn commit 49b01dca4fcea165314c1548f6c3e673a5de0bd3 Author: jordan4ibanez Date: Sat Apr 24 22:28:26 2021 -0400 Make mobs drop xp on death commit 3d5cceab76768e360e3ea958c71bcf79e9cc2eec Author: jordan4ibanez Date: Sat Apr 24 22:21:58 2021 -0400 Fix ghast strange behavior in the nether commit a73e5b57c02275a37b98dc9c80cf35a8c782d9f7 Author: jordan4ibanez Date: Sat Apr 24 22:14:25 2021 -0400 Make pitch movement for fly/swim mobs more dynamic and make ghasts randomly fly around when attacking commit b401b50c045830386c1c06c22be2232bda3e5b61 Author: jordan4ibanez Date: Sat Apr 24 21:15:42 2021 -0400 Give mobs 6 seconds of memory to prevent strange behavior when player hides behind something commit 807fb6966d747550da276b264e8e3bf376b332ab Author: jordan4ibanez Date: Sat Apr 24 20:27:37 2021 -0400 Make spiders climb up walls, fix problems with mob following freaking out when under, fix spider collisionbox commit 11b5684a90a7779986b5685d899a55a606922a0f Author: jordan4ibanez Date: Sat Apr 24 20:05:14 2021 -0400 Remove wolf-dog shift click breeding, and implement better logic commit 41bfaae370729b7409d5dea2cc65a6f5c83979ac Author: jordan4ibanez Date: Sat Apr 24 20:02:59 2021 -0400 Allow putting chest on carpeted llama by owner, enable swapping carpets commit 8c855f5b0955ebce15a1aaf4c17e407b5cad7ae8 Author: jordan4ibanez Date: Sat Apr 24 19:29:37 2021 -0400 Add in llama carpets commit e0185a93113136862b24ad06bea75f1b2e24901f Author: jordan4ibanez Date: Sat Apr 24 18:43:17 2021 -0400 Fix pig logic issue commit c2cb15a47f75674afaac721217384c8d7ead1c57 Author: jordan4ibanez Date: Sat Apr 24 18:36:22 2021 -0400 Fix horse breeding commit 39f7d0cf3cc7d33d786761376a035a31e434434f Author: jordan4ibanez Date: Sat Apr 24 18:18:53 2021 -0400 Update api.txt commit 3e9bbca91400e0f587aef13df1ece7d8071b188a Author: jordan4ibanez Date: Sat Apr 24 18:06:24 2021 -0400 Fix enderman crashing commit 81713a342d8038c2b51140dbd4bc00f1440b73e8 Author: jordan4ibanez Date: Sat Apr 24 00:38:50 2021 -0400 Allow tamed wolves to be shift click bred commit a27e6731cd97a1e41861d8a2acbdd4d2d530c220 Author: jordan4ibanez Date: Sat Apr 24 00:29:30 2021 -0400 Make sheep breedable commit efce97c1723ac25e9dabdfd9572781a6d50f0821 Author: jordan4ibanez Date: Sat Apr 24 00:27:17 2021 -0400 Make llamas shift click breedable commit 53c96cae2d28c3a6f4642b8a6d5b72365d32267d Author: jordan4ibanez Date: Sat Apr 24 00:26:45 2021 -0400 Make pigs shift click breedable commit dbe712bc17cc875c5e9b4b1a919880b0f6893ea1 Author: jordan4ibanez Date: Sat Apr 24 00:23:33 2021 -0400 Make llama breedable commit 0d4d85bac6b3412a2fec3f01ebc5b3ff6c294173 Author: jordan4ibanez Date: Sat Apr 24 00:19:41 2021 -0400 Fix horse literally blinding you following you commit 6f2e2ab4c57fe651dd90b4897e4f10673da1de3a Author: jordan4ibanez Date: Sat Apr 24 00:17:22 2021 -0400 Make chicken breedable commit 3649e5f6f50c917e3c29bbd0b95327e3667ae1ef Author: jordan4ibanez Date: Sat Apr 24 00:17:09 2021 -0400 Make horse breedable commit 2dab0773dffd40cb166c8a14ad79035ac898d4dc Author: jordan4ibanez Date: Sat Apr 24 00:00:21 2021 -0400 Remove unused breedable api call commit 0568c14a435e663dccc1a42ae999a76d0936f153 Author: jordan4ibanez Date: Fri Apr 23 23:59:35 2021 -0400 Fix timer and make mooshroom breedable commit 531253008a13559cdab63f420e9d35c78b382c95 Author: jordan4ibanez Date: Fri Apr 23 23:56:59 2021 -0400 Complete mob breeding, make cows breedable commit 79cb6ddc4923ea8a009b2810efe785cf3720c63f Author: jordan4ibanez Date: Fri Apr 23 22:35:35 2021 -0400 Fix lua locals in environment.lua commit 6eb3eef21561ddf2091682f3703fa9a23e35915e Author: jordan4ibanez Date: Fri Apr 23 22:34:40 2021 -0400 Fix typo in function commit c37a82d4a2589d372f88b5101918858c2d210e57 Author: jordan4ibanez Date: Fri Apr 23 22:03:29 2021 -0400 Add comments commit ed9d629b99a9f873cebfa8e45239271a81a8025c Author: jordan4ibanez Date: Fri Apr 23 21:59:42 2021 -0400 Add in mob following for cows commit fcfd6b9d19bbc1e894b8dafed490e04102c87878 Author: jordan4ibanez Date: Fri Apr 23 21:14:23 2021 -0400 Set up basics for breeding mechanics commit 5ee6cf6c9b3b9da36830c8a58f105d289dfbe54c Author: jordan4ibanez Date: Fri Apr 23 19:49:35 2021 -0400 Implement mob despawner/mob limiter commit 19c8dd1dd48532bfb07eac133cd11b702ad74de7 Author: jordan4ibanez Date: Fri Apr 23 18:41:41 2021 -0400 Stop hostile mobs from falling through water when stunned commit 31ded5e40fc97a7afd252fd74154183afaf1f568 Author: jordan4ibanez Date: Fri Apr 23 18:34:20 2021 -0400 Re-implement neutral mob switch commit 13c321e8f2c8cb43460093852d44ddae7edec0c1 Author: jordan4ibanez Date: Fri Apr 23 18:03:01 2021 -0400 Re-enable mob spawning commit ea6912c980952bed2a0b5e62009e0a2639d75d75 Author: jordan4ibanez Date: Fri Apr 23 17:44:49 2021 -0400 Don't do knockback effect for mobs when hurt by a rider commit 8dafac50a865f189074272303b83f37391c11c3c Author: jordan4ibanez Date: Fri Apr 23 17:37:20 2021 -0400 Make mobs run away slightly faster commit 3560bda4a5a8be026c5d50eb8ddeca9ed45e0b8e Author: jordan4ibanez Date: Fri Apr 23 17:29:23 2021 -0400 Remove unused code and variables from mob punch commit 9720986c4d30bf8fcd2cf1117d80eea06da5332a Author: jordan4ibanez Date: Fri Apr 23 17:27:08 2021 -0400 Fix punching a mob breaking it's velocity commit dc7592528cf948556e4e925310e830648b52dff1 Author: jordan4ibanez Date: Fri Apr 23 17:23:00 2021 -0400 Add red tint hurt effect commit 304cbed447adbcccff246f242d18d51fc010df35 Author: jordan4ibanez Date: Fri Apr 23 17:12:02 2021 -0400 Make mobs that should be skittish, skittish commit af4c42fea7112ada76fd9b273f771611532bdcf9 Author: jordan4ibanez Date: Fri Apr 23 17:10:44 2021 -0400 Add skittish behavior (runaway from punch) and fix ocelot commit 8daf197fb899a0bee8f61aad4ccedec1108f5f92 Author: jordan4ibanez Date: Fri Apr 23 16:52:07 2021 -0400 Fix iron golem rotation commit c138050e0b877f5dc987959efe4acbe17ffd86f2 Author: jordan4ibanez Date: Fri Apr 23 16:45:12 2021 -0400 Make iron golem neutral and protective, fix rotation commit 36d5af1d15b432d84e24e161b78d4b41ce2731bd Author: jordan4ibanez Date: Fri Apr 23 16:35:16 2021 -0400 Stop dead mobs from getting in the way of fighting other mobs commit 73b4d3c1d2c74cb5bd5bb23604ce1d74e183cb0d Author: jordan4ibanez Date: Fri Apr 23 16:31:13 2021 -0400 stop projectile mobs from being completely disabled while stunned commit eb7ae5e10e731fc949a9a4184e02a39103f83a1e Author: jordan4ibanez Date: Fri Apr 23 16:28:30 2021 -0400 Fix random crash commit c831da2c02253450df965930cbfcd539b820f3b9 Author: jordan4ibanez Date: Fri Apr 23 16:22:34 2021 -0400 Fix mobs not making hit sound when hit by node commit d5a38fef58c1862490c9f32238ec83cf1a2c2d5c Author: jordan4ibanez Date: Fri Apr 23 16:19:37 2021 -0400 Add in new mob punched sounds commit 8e7ce5a72ae3e7cedf985a414c64ca259bcd6136 Author: jordan4ibanez Date: Fri Apr 23 16:04:01 2021 -0400 Add in a visual for horse taming (hearts) commit 189c0ad157a8871d51045effcded0662aff7b1af Author: jordan4ibanez Date: Fri Apr 23 15:53:01 2021 -0400 Half finish horse (riding logic, etc) commit f64f8e31e3ba8e7a14b22d084be5ef584895242d Author: jordan4ibanez Date: Fri Apr 23 14:50:38 2021 -0400 Fix llama blaze and ghast projectile sprites commit 58bee2a2dd1b4d6d3d1873d3ac566be9e0aa7930 Author: jordan4ibanez Date: Fri Apr 23 14:43:00 2021 -0400 Fix projectile tails clipping through sprite commit 16cc7e37d2fc83e50d4e2c380cef05224dbbed38 Author: jordan4ibanez Date: Fri Apr 23 14:34:59 2021 -0400 Randomize projectile cooldown timer commit 8eb9ba12cef918cb116aea8eaea5a1e757123b01 Author: jordan4ibanez Date: Fri Apr 23 14:33:40 2021 -0400 Fix crash when mob collides with nil entity commit 5d59583583462563f7d65747a198b0d6d8ed34fc Author: jordan4ibanez Date: Fri Apr 23 14:10:12 2021 -0400 Massive overhaul to projectile mobs with custom projectile function, make llamas spit commit f6fa90096dfdb9d21b6f52968daa60943a07470e Author: jordan4ibanez Date: Fri Apr 23 13:35:30 2021 -0400 Fix enderman teleport attack commit 4fb9e69e41a8c2ee91c659acb0b11fc76a6a97fe Author: jordan4ibanez Date: Fri Apr 23 13:27:17 2021 -0400 Make enderman become hostile when stared at, freeze when attacking when stared at commit 99f13f84b563c1962c285b2e9973aec8a5d079d7 Author: jordan4ibanez Date: Fri Apr 23 13:13:23 2021 -0400 Half-fix enderman commit dd76b15c501a1a458f2fa112b29784e26c3140bd Author: jordan4ibanez Date: Fri Apr 23 13:06:57 2021 -0400 Make ghasts not insta-kill commit b6f19699e9059a382421f55ac9ee5b642e7751a6 Author: jordan4ibanez Date: Fri Apr 23 13:06:17 2021 -0400 Make enderdragon half work commit 4efec1ef58ba4afe4692a22a361079b5026a7de3 Author: jordan4ibanez Date: Fri Apr 23 12:55:11 2021 -0400 Add in chicken slow falling commit 08956664073078fd896add1e57ff0a524de2a32f Author: jordan4ibanez Date: Thu Apr 22 23:36:58 2021 -0400 Fix random crash with mixed mob ally data types commit 408296140a4fe0c785f5fb4760899fdb3851fe00 Author: jordan4ibanez Date: Thu Apr 22 23:30:32 2021 -0400 Fix and overhaul wolves commit aac1e1933677d119b52c25a64b3ee6c77e16e770 Author: jordan4ibanez Date: Thu Apr 22 23:18:33 2021 -0400 Implement rotation locking when standing, fix rotation unlock/lock for fly/swim mobs commit fa059b5df245e81d71d73bbc87b51c59cd47a876 Author: jordan4ibanez Date: Thu Apr 22 22:59:03 2021 -0400 Fix ghast's eyeheight commit 2e3e92e39337e5c4ecba13855f134af1bd672ae6 Author: jordan4ibanez Date: Thu Apr 22 22:58:32 2021 -0400 Fix ghast's insane difficulty commit 11bcf3aa34e85dcc19142258ca2c4abaf963b806 Author: jordan4ibanez Date: Thu Apr 22 22:51:13 2021 -0400 Add attributes to epCode commit 2099be43ea25740a402587f40b3004f6ef2d8c1d Author: jordan4ibanez Date: Thu Apr 22 22:50:14 2021 -0400 Update to epCode's fixed version of ghast model commit 5037ec3736a564157408df12699c91df17c934b6 Author: jordan4ibanez Date: Thu Apr 22 22:40:16 2021 -0400 Fix ghasts horrible collisionbox commit 0a8fff65249610aba7fef7e9675bf28469265f29 Author: jordan4ibanez Date: Thu Apr 22 22:08:54 2021 -0400 Add in mob criticals when falling commit afdcada1fd6f7c8cbe68b0fd1486d6d92f3d12f7 Author: jordan4ibanez Date: Thu Apr 22 21:46:13 2021 -0400 Fix endermite commit 5d876725c599b060c5150b0508f21b6a83001f9a Author: jordan4ibanez Date: Thu Apr 22 21:45:00 2021 -0400 Fix bats commit ef0d52a2df9a3d2d2c1e59b12084017c405bc398 Author: jordan4ibanez Date: Thu Apr 22 21:41:54 2021 -0400 Update backup_code_api.lua commit 8142f7e51214672292d3bffe3fa8119eb8a1cf1c Author: jordan4ibanez Date: Thu Apr 22 21:36:42 2021 -0400 Add in mob death commit ebf27866ca3bb02c726d4729c0666ee28e20a3dd Author: jordan4ibanez Date: Thu Apr 22 21:12:08 2021 -0400 Fix typo and error in animation.lua commit 3fe8d2d3c59ca6c173817a9d2d6b48e3549acd57 Author: jordan4ibanez Date: Thu Apr 22 20:30:50 2021 -0400 Add file death_logic.lua commit b73ab976a1115044bc336f9e3f181ecf6e75cc06 Author: jordan4ibanez Date: Thu Apr 22 20:25:58 2021 -0400 Implement framework for mob death commit 8530e6ee368f510581c618666613432f25266ce5 Author: jordan4ibanez Date: Thu Apr 22 20:20:56 2021 -0400 Make mob punching time based commit e1812b2cdba132afec9ed6cdc45ee9f078806264 Author: jordan4ibanez Date: Thu Apr 22 20:12:02 2021 -0400 Reset pause timer to 0 commit 991bba0a1d611cf545020c9129fdcbc4806e73c6 Author: jordan4ibanez Date: Thu Apr 22 20:10:01 2021 -0400 Add comments into ai.lua commit f9a7144b658f747be895bb6a8b69c8a0124fdd2a Author: jordan4ibanez Date: Thu Apr 22 20:07:30 2021 -0400 Implement ability to hurt mobs commit 45790c0be0eec380e281a687a1ff03ea1f114143 Author: jordan4ibanez Date: Thu Apr 22 19:12:02 2021 -0400 Re-enable mob punching (broken) commit 31a791c33b19d76350993d844747a0c51a77382c Author: jordan4ibanez Date: Thu Apr 22 18:20:58 2021 -0400 Undo debug.txt spam from mob spawning commit d0d128c1d8f84e8de590e34adfe0265556ccd3e1 Author: jordan4ibanez Date: Thu Apr 22 18:18:57 2021 -0400 Break infinite loop if unable to find any mob to spawn commit ee905642c2cdfaa3be3eb5c2af7ec75599ffd41e Author: jordan4ibanez Date: Thu Apr 22 17:56:38 2021 -0400 Add temporary warning debug to spawning algorithm output commit 2cef9e7cca2e70e544eb3068a0e3e36487cab669 Author: jordan4ibanez Date: Thu Apr 22 00:39:32 2021 -0400 Optimize mob spawning even further with additional lua locals commit edb1939649c62a2b486e1c04c5af27458f978388 Author: jordan4ibanez Date: Thu Apr 22 00:27:35 2021 -0400 Fix mob_counter in mob spawning limiter commit 7c1adeab459d452ac016108b588957082c1347c1 Author: jordan4ibanez Date: Thu Apr 22 00:20:57 2021 -0400 Hyper-optimize mob spawning commit fbe3ccc5c05b5d5141737d3a73df3e4d14a33a33 Author: jordan4ibanez Date: Wed Apr 21 23:28:38 2021 -0400 Delete current state of things comment commit 5e15af260bed13b07b295f558f5cb05bedaa7eae Author: jordan4ibanez Date: Wed Apr 21 23:25:19 2021 -0400 Fix pig rotation commit 6aa636449211b1bbec1297723281f72b4c76c4da Author: jordan4ibanez Date: Wed Apr 21 23:25:10 2021 -0400 Fix sheep rotation commit 29305f548db88b0b895ec747ebfbc092c51c4762 Author: jordan4ibanez Date: Wed Apr 21 15:08:35 2021 -0400 Overhaul arrow register, implement basic blaze, break parts of arrow register for now, remove fallback for detecting players commit 08c90c34e83c498ee2cc883a2cad9b98a269a850 Author: jordan4ibanez Date: Wed Apr 21 13:05:46 2021 -0400 Make parrots and squids work with tilt fly/swim commit 91099c3be93689c2569f838a63e75e38ca382162 Author: jordan4ibanez Date: Wed Apr 21 13:01:14 2021 -0400 Fix auto-true statement for tilt fly/swim commit 71c34823bc87b0892d4450b877fb1c78cd6ad416 Author: jordan4ibanez Date: Wed Apr 21 12:56:36 2021 -0400 Make tilt flying/swimming dynamic commit 20886f54bb8887fb88ce0e0e0c6f28a789868740 Author: jordan4ibanez Date: Wed Apr 21 12:48:23 2021 -0400 Make shooty mobs jump commit ebd995fbd2eb089a37b659e9ae87c86562e3ed69 Author: jordan4ibanez Date: Wed Apr 21 12:45:02 2021 -0400 Simplify skeleton arrow damage calculation commit c9f71d66f52f2e80fea6cd01fcb2db30ae399c39 Author: jordan4ibanez Date: Wed Apr 21 12:42:34 2021 -0400 Implement skeletons/strays commit 99e808296b81f37a9e01d4b4beb02120526bb4e9 Author: jordan4ibanez Date: Wed Apr 21 12:17:51 2021 -0400 Add missing skeleton/stray run animation commit 74094938bb0918df12ffa778c95b966d7bd6c9f3 Author: jordan4ibanez Date: Wed Apr 21 12:10:29 2021 -0400 Fix crash with non-punch attack mobs in collision commit 6bd279255c7e4b5623afa39caae8f988127f7ac3 Author: jordan4ibanez Date: Wed Apr 21 11:50:22 2021 -0400 Fully implement zombie pigmen commit 964ce9ccf7101aef387bdd5ec2213ba4ac361a51 Author: jordan4ibanez Date: Wed Apr 21 11:42:01 2021 -0400 Temporarily disable spawn eggs from setting owner commit 5062d56a5d89346234f6125848799f32915b31a4 Author: jordan4ibanez Date: Wed Apr 21 11:00:02 2021 -0400 Implement neutral mob mechanics and partial implement of zombie pigmen commit b0b1ec9436776fdc89edaf3046499a9e2cfaed0f Author: jordan4ibanez Date: Wed Apr 21 10:53:20 2021 -0400 Implement zombie pigmen and make them turn hostile when punched commit f1dc2864425bab2eed2f5bec7b7ccd0307145b1f Author: jordan4ibanez Date: Wed Apr 21 10:23:51 2021 -0400 Dump mob_punch from backup_code_api.lua back into interaction.lua commit cc2a0ae52cefc388d18c9d106ef70fc0718f5e40 Author: jordan4ibanez Date: Wed Apr 21 10:21:11 2021 -0400 Complete charged creeper commit 486959515ca13ba0d5756ba5d930ff43e9d135b5 Author: jordan4ibanez Date: Wed Apr 21 10:20:31 2021 -0400 Make creepers even more dangerous commit 576621169b468f317cf32d6d0be391252a033d3a Author: jordan4ibanez Date: Tue Apr 20 23:26:18 2021 -0400 Make creepers and zombies even harder commit 2c87bd19f3c6a4a5a1a3b88a45cd673ecccb838b Author: jordan4ibanez Date: Tue Apr 20 23:14:53 2021 -0400 Overhaul zombie villager commit 1ed3377559c4690fa19488f526bcaf97d5ff94b1 Author: jordan4ibanez Date: Tue Apr 20 23:11:18 2021 -0400 Add punch mobs knockback to players when hit commit 8c9356a18cb60cd28691e3782723df763b75a1fa Author: jordan4ibanez Date: Tue Apr 20 22:58:39 2021 -0400 Implement eye_height and viewing range for hostile mobs, along with making punchy mobs jump over nodes commit a05ebd7cc29c96b622dbc043529513b07d5cf47b Author: jordan4ibanez Date: Tue Apr 20 22:44:34 2021 -0400 Add informative text art commit 60ac3058ce1e3e05caa87c18bdf95c78a71ed750 Author: jordan4ibanez Date: Tue Apr 20 22:42:51 2021 -0400 Make zombies more difficult commit 751c4c2d995a011a3298d374c77b9c4567ed2fa1 Author: jordan4ibanez Date: Tue Apr 20 22:41:13 2021 -0400 Integrate mob punching into collision detection commit 6b52b945165a8501e09ca70c18514049df194c05 Author: jordan4ibanez Date: Tue Apr 20 22:30:34 2021 -0400 Start setting up hostile punch attack type commit d371d6fdc9cb85e140399eafb89f15195f72d09f Author: jordan4ibanez Date: Tue Apr 20 22:04:54 2021 -0400 Adjust creeper explosion settings commit fabd4d64e6745b9ea8c4bb1a76c190c2d66576be Author: jordan4ibanez Date: Tue Apr 20 21:35:19 2021 -0400 Slow down creeper type mobs explosion buildup commit bf367fffd054fe180dbc6d7f46e20e286d68bb09 Author: jordan4ibanez Date: Tue Apr 20 21:34:18 2021 -0400 Add in sound_handling and make explosion type mobs make their attack sound before explosion animation commit 0b763f54b55ea47b7889816612759447bfb50422 Author: jordan4ibanez Date: Tue Apr 20 21:00:36 2021 -0400 Finish creeper movement ai and move jump_check into environment commit cd6f07537f64bdbe7573642982ec24ac3fb19ec1 Author: jordan4ibanez Date: Tue Apr 20 20:43:45 2021 -0400 Make creepers even more deadly commit 9678b556e17b124f841b0019b3a31880a415bd11 Author: jordan4ibanez Date: Tue Apr 20 20:33:30 2021 -0400 Fix crashes when trying to collision detect a removed mob commit cdb840609dc2586b31a1e44c8c1004379ef37979 Author: jordan4ibanez Date: Tue Apr 20 20:19:55 2021 -0400 Add in creeper basic prototype commit 008d670ed9006d918b1ed1698a5b644de27191b1 Author: jordan4ibanez Date: Tue Apr 20 17:10:51 2021 -0400 Remove wandering from ai commit 491ef6c8f818e43ef0545963eb27b5476c95ea28 Author: jordan4ibanez Date: Tue Apr 20 16:48:20 2021 -0400 Add in auto mob removal if something goes horribly wrong commit 348df0fcecc2709fe088493d5665112827f08129 Author: jordan4ibanez Date: Tue Apr 20 16:46:10 2021 -0400 Rename detect_players_in_area to detect_closest_player_within_radius commit ac08c6991c0ce7f9bb8d9de5880ec64a7882c3e7 Author: jordan4ibanez Date: Tue Apr 20 16:39:05 2021 -0400 Add in detect_players_in_area commit 3d776138e97b904c9b299119ae9b9a8a2811ae7a Author: jordan4ibanez Date: Tue Apr 20 14:55:22 2021 -0400 Start implementing creeper ai commit 85e531bf106df326b2ca470b5a94aeb06f92d4d6 Author: jordan4ibanez Date: Sun Apr 18 21:24:31 2021 -0400 Remove unneeded mobs:protect from code commit 4d589dfb2aa10cb664b4d3b3471960e6d648b92c Author: jordan4ibanez Date: Sun Apr 18 21:22:39 2021 -0400 Remove literally unneeded mobs:capture_mob commit 39985aa558d9f43a6a2e82fb6d59ad0ca8b6324d Author: jordan4ibanez Date: Sun Apr 18 21:22:21 2021 -0400 Up fallback max xp to 3 commit 1920ddf91530a7c033c8288cd3a752f3ee7ba850 Author: jordan4ibanez Date: Sun Apr 18 21:02:03 2021 -0400 Change all enemy attack info to more workable and understandable attacks commit 719bb2a3c96ca020f8f828959e377831f47cd27b Author: jordan4ibanez Date: Sat Apr 17 18:21:33 2021 -0400 Add in prototype jump-only mobs api commit db87b8e0a37cd15ef7931a76d21bbb190a158205 Author: jordan4ibanez Date: Sat Apr 17 17:09:57 2021 -0400 fix chicken rotation commit e2987245fd6c6ee75383ea92da30e9fc5e10ad1e Author: jordan4ibanez Date: Sat Apr 17 17:00:34 2021 -0400 Balance out collision forces for mobs commit 3cf263d292f9fc5a7a18fafa2aa1fbc8e1840a0a Author: jordan4ibanez Date: Sat Apr 17 16:23:38 2021 -0400 Add in dynamic pitch in flying/swimming mobs commit 5ade34115cff228994ff3fd680aa15c8225ab6e7 Author: jordan4ibanez Date: Sat Apr 17 13:17:29 2021 -0400 Remove random state initialization in set_up.lua commit d9729fc8651d06566e61bcfcb2e7df0484f25f48 Author: jordan4ibanez Date: Sat Apr 17 13:13:45 2021 -0400 Fix parrot's rotation commit 58d9670e777c3798c676924023375a2579450142 Author: jordan4ibanez Date: Sat Apr 17 13:11:39 2021 -0400 Remove collisionbox addition for y position for fly mobs commit a20f272e08f0170b2761eeba2a12aeaf88efad7b Author: jordan4ibanez Date: Sat Apr 17 13:05:53 2021 -0400 re-adjust logic gate for mobs floating in water and lava commit 0794bc54372c6aaa9c653693da3a18194adf5c95 Author: jordan4ibanez Date: Sat Apr 17 13:04:55 2021 -0400 Make flying mobs float in water and lava commit 8783912938aed1f5566f3e2f5056213f0cefe4a6 Author: jordan4ibanez Date: Sat Apr 17 12:48:57 2021 -0400 Add in mobs api swimming animation commit f2e909ab8d182febabbdacd9de50a65f27137761 Author: jordan4ibanez Date: Sat Apr 17 12:41:14 2021 -0400 Add in fly logic gate commit 07841c89632626f1c3bb4790f8db0c2adddfb2eb Author: jordan4ibanez Date: Sat Apr 17 12:38:48 2021 -0400 Swap name of quick_rotate_45 to quick_rotate commit 240d6ea21155f2044d3b728a210811821540013a Author: jordan4ibanez Date: Sat Apr 17 12:37:04 2021 -0400 Add note about quick_rotate_45 actually rotating 11.25 degrees commit e8148f81ab7641554096bc03ecda8927d9ad9491 Author: jordan4ibanez Date: Sat Apr 17 12:36:19 2021 -0400 Make underwater mobs try to continuously swim around with quick_rotate_45 commit 061602d9d46d4e4607e407c064070709ef99f9b7 Author: jordan4ibanez Date: Sat Apr 17 12:28:07 2021 -0400 Overhaul separation of swimming and flying for ease of use with writing mobs api commit 5365dec19a8a088263916a3686f27859be51e870 Author: jordan4ibanez Date: Sat Apr 17 12:01:27 2021 -0400 Adjust "flying" vector checks for mobs commit dda7839d8c4c2292e9c8d6472faf38372654d886 Author: jordan4ibanez Date: Fri Apr 16 21:43:02 2021 -0400 Add in prototype swimming commit f1141aed9fa52bf57e8867fdb3ffb520793dab07 Author: jordan4ibanez Date: Fri Apr 16 21:08:54 2021 -0400 Make mobs flop when outside of flying node commit 84ca7681fc9ee3e9945488865678b2b82eb0a22d Author: jordan4ibanez Date: Fri Apr 16 20:47:16 2021 -0400 Make squids fly in water flowing and water source commit 52c3db041e602ebd0861a0b86c55b35662c8c33a Author: jordan4ibanez Date: Fri Apr 16 20:32:05 2021 -0400 Add in fly state prep for mobs commit 6db4511dd5b038cd95c7ea196559bb25a53246e9 Author: jordan4ibanez Date: Fri Apr 16 20:06:55 2021 -0400 Add notes commit 15ea9c1c71f3e4d4dd24ce145d385f8457e4905e Author: jordan4ibanez Date: Fri Apr 16 19:59:20 2021 -0400 Implement self walking velocity for walking state commit 9d6d042ee325a010d97abdff7efc37f3dcf46b5e Author: jordan4ibanez Date: Fri Apr 16 19:37:01 2021 -0400 Fix formatting in ai.lua commit ce7f4918b061fa9a4d46045a389497cb0da1a5ee Author: jordan4ibanez Date: Fri Apr 16 19:35:19 2021 -0400 Re-organize comments commit 05d06a4c8f0128ac5edd21b8096bb75553c1f89e Author: jordan4ibanez Date: Fri Apr 16 18:36:23 2021 -0400 Add comment to state_execution commit c761db86c7e67aab27d3806a76b7a58504a7d5c6 Author: jordan4ibanez Date: Fri Apr 16 18:29:42 2021 -0400 re-arrange mob logic for random wandering commit ed456ecb47d788efe9aa526849110015e9c04e9a Author: jordan4ibanez Date: Fri Apr 16 18:17:51 2021 -0400 Make mobs not fear cliffs if fear_height is 0 commit 8ca5f221ec9ce534e91f7094193b4ec951e743b1 Author: jordan4ibanez Date: Fri Apr 16 18:13:54 2021 -0400 clean up ai.lua commit cadd53c103f4047069f581abdc033d2def4ed2dd Author: jordan4ibanez Date: Fri Apr 16 16:39:03 2021 -0400 Adjust mob jumping default to account for higher gravity commit 57b293de2b02be81ff3e17e620807c653fe9b625 Author: jordan4ibanez Date: Fri Apr 16 16:37:15 2021 -0400 Make mobs gravity equal to player's commit fb9a55e562c3e4102fa4e02603f93d1c78e397ad Author: jordan4ibanez Date: Fri Apr 16 15:55:11 2021 -0400 Make jump_check more modular and allow mobs to turn if at a wall commit a6a54b34140c279d7a9ff3db5b21f1be0ead15f8 Author: jordan4ibanez Date: Fri Apr 16 15:49:03 2021 -0400 Make mobs not jump if against a wall commit 6c5393427f72c082a5c85514cb3b54aa4a9ce45f Author: jordan4ibanez Date: Fri Apr 16 15:39:39 2021 -0400 Smooth out mob cliff check and check if falling before cliff check commit 2486ffef11113a40b43a2548bde57e9cca186da9 Author: jordan4ibanez Date: Fri Apr 16 15:30:44 2021 -0400 Make wandering mobs avoid cliffs commit adc683c6a7cd56c33bebc22ce1363671db4f4846 Author: jordan4ibanez Date: Fri Apr 16 14:19:22 2021 -0400 Clear mob animation on activate commit d0695e7929460728f7da2e01cc809cb343481e1a Author: jordan4ibanez Date: Fri Apr 16 13:58:08 2021 -0400 Fix mob animation "memory leak" commit 024cf46307abb6fefbfe8be04941205026561177 Author: jordan4ibanez Date: Fri Apr 16 11:52:29 2021 -0400 Adjust spacing in animation.lua commit f38492bcb031b7fcc2ee8299f66fcd3cd3a68398 Author: jordan4ibanez Date: Fri Apr 16 11:50:29 2021 -0400 Re-implement animation check gate for mobs commit a934a59f3b64e8adef64676daaf81b574a6ceecd Author: jordan4ibanez Date: Fri Apr 16 11:50:13 2021 -0400 Implement mob random walk directions commit 94ca7e8b89bd39144d85bc6a622778babb226d47 Author: jordan4ibanez Date: Fri Apr 16 11:31:18 2021 -0400 Add in state switch and state execution for mobs commit 626c30de6d4191cd4a18b0f11cb4805c425f9648 Author: jordan4ibanez Date: Fri Apr 16 11:30:55 2021 -0400 Create todo.txt commit c2bac87a6d03364193aedf67c780fdea9f545cac Author: jordan4ibanez Date: Thu Apr 15 21:46:33 2021 -0400 Update set_up.lua commit 375d683d08266586d024491dcba2268c66583989 Author: jordan4ibanez Date: Thu Apr 15 16:18:42 2021 -0400 Fix forgotten localization in collision.lua commit 246bdf9707c98f787cb5264dc7ff638e340d768b Author: jordan4ibanez Date: Thu Apr 15 15:55:10 2021 -0400 Implement basic mob walking animation test commit d07d0ae31c0d39c526c8418e725b5dce1d120793 Author: jordan4ibanez Date: Thu Apr 15 15:34:07 2021 -0400 Make mobs jump properly commit 6cb6d714c9bcf55213a9449416bec37c0fe318af Author: jordan4ibanez Date: Thu Apr 15 15:04:55 2021 -0400 Reorganize all mob sections into multiple files commit 5155d12d05c5b563a78923b3fc02a885cd23fe85 Author: jordan4ibanez Date: Thu Apr 15 14:09:54 2021 -0400 Reformat mobs_mcl to api folder for ease of use commit bbcfb3fdb171053e3142854f658860e7693f31d1 Author: jordan4ibanez Date: Thu Apr 15 11:33:09 2021 -0400 Randomize walking or standing on spawn in commit 9e4bf6e130195b4f2176658581ad17646a48ce3a Author: jordan4ibanez Date: Thu Apr 15 11:29:18 2021 -0400 Move old set_yaw and add node on set_velocity commit e53a193c4fe61e88e6501a2a863e22d533132ae4 Author: jordan4ibanez Date: Thu Apr 15 11:25:55 2021 -0400 Fix get_velocity (mobs internal) commit 14207dd96aa60652c0ad1f4351441659c33d3ff6 Author: jordan4ibanez Date: Thu Apr 15 11:23:52 2021 -0400 Smooth out mob movement set_velocity more commit a0ed1a0b2004baeb3d0f64c5eb02bbf0b21bf823 Author: jordan4ibanez Date: Thu Apr 15 10:05:24 2021 -0400 Add automatic rotation lock commit ba46e7fa42bbd25175d3505ca9699a11912d491f Author: jordan4ibanez Date: Thu Apr 15 09:28:58 2021 -0400 Remove old debug of colliding with objects commit 61124905f3d862d00f00674067003d8da7722405 Author: jordan4ibanez Date: Thu Apr 15 09:28:22 2021 -0400 Add in mob auto rotation (implementation 1) commit 8b200c7352cb9fdd01f1b073308acacd36b2672a Author: jordan4ibanez Date: Wed Apr 14 19:38:14 2021 -0400 Add in basic movement rotation testing commit 67259891a85e54f56dc543087bd98cfe12feb6f4 Author: jordan4ibanez Date: Wed Apr 14 18:01:29 2021 -0400 Remove unneeded comments commit d063db751c1657c367f2277b24a5aa51a8d90fa3 Author: jordan4ibanez Date: Wed Apr 14 17:26:20 2021 -0400 Disable mcl_playerplus random check that moves players randomly commit d4db27f0e1edd439f65821b814146a237ebea799 Author: jordan4ibanez Date: Wed Apr 14 17:25:39 2021 -0400 Update backup_code_api.lua commit 755533beeb6c708603096cce4f99bea558c8b6ce Author: jordan4ibanez Date: Wed Apr 14 11:50:22 2021 -0400 Disable literally everything in mobs api commit 3f6312a631c6726c3bc4b09d9ec3e64b3ae810e5 Author: jordan4ibanez Date: Tue Apr 13 20:24:46 2021 -0400 Make mobs magnetic collision more jello-y commit aa4d34c10e4bc367fc6ad7d898cd145d9f58ed0c Author: jordan4ibanez Date: Tue Apr 13 20:00:38 2021 -0400 Improve mob to mob collision commit 1210bc463adb949496fc521e3169fb88e49fc4e9 Author: jordan4ibanez Date: Tue Apr 13 19:44:24 2021 -0400 prevent mob collision detection shootout commit ed6026671381c99723eccbf2089d99748e19bfe2 Author: jordan4ibanez Date: Tue Apr 13 19:17:48 2021 -0400 Gut even more elements of the api commit 220d30df5f159d69be22663733feb1fbf51c45f8 Author: jordan4ibanez Date: Tue Apr 13 19:13:29 2021 -0400 Completely gut do_states commit 9758bbf2e7e382948b4ad1ab8c360519270fec14 Author: jordan4ibanez Date: Tue Apr 13 08:21:04 2021 -0400 Finish gutting mob api commit f29ad4b8b78689ed0d759c18178a6b2dbc9a1e25 Author: jordan4ibanez Date: Tue Apr 13 08:20:11 2021 -0400 Reorganize more settings to the top of file commit 54f5bee8a379bf910c1cc6ea3d33bd32b819f3dd Author: jordan4ibanez Date: Tue Apr 13 08:08:29 2021 -0400 reorganize load settings commit 02515f0778bbe9cd962acc514b084c9dedf55074 Author: jordan4ibanez Date: Tue Apr 13 08:07:32 2021 -0400 Move a large chunk of code to backup_code_api.lua commit 3fc0184182f70be0c2fd9b3be1c5d78fa7f00503 Author: jordan4ibanez Date: Tue Apr 13 07:39:57 2021 -0400 Disable entire mob ai to work on vanilla walking commit 6fff719322ee250fc7c074d2362edbf0c4090406 Author: jordan4ibanez Date: Mon Apr 12 08:47:07 2021 -0400 Localize minetest library commit adaf74fc5c6354cf2fb1a9f784e5a37a4fb31caa Author: jordan4ibanez Date: Mon Apr 12 08:13:11 2021 -0400 Remove spacing and delete old collision comments commit a564009e4aeda08372b80fb1a5fc2d16f5dfd364 Author: jordan4ibanez Date: Mon Apr 12 08:11:55 2021 -0400 Change HORNY_TIMER to BREED_TIMER commit 00759da39d621b36be6200fa365c51be86dbb99f Author: jordan4ibanez Date: Sun Apr 11 18:29:32 2021 -0400 Unlimit mob ai commit 9aafc28a2009998017753d0aa4d013e3cd8795b6 Author: jordan4ibanez Date: Sun Apr 11 14:47:56 2021 -0400 Fix mobs nil check during mob_step commit 67c40885ef62b4e4e8dcaba3b65c58502c558f7e Author: jordan4ibanez Date: Sun Apr 11 14:21:19 2021 -0400 Fix mobs collision system only running during movement - major overhaul with ai disabled commit 2456e3cd1ef6954415e4a771bb704a12364895eb Author: jordan4ibanez Date: Sun Apr 11 12:52:31 2021 -0400 Adjust math localizations in api.lua commit 725dc731ddc2a6f1cf1a20832e06883613d5974a Author: jordan4ibanez Date: Sun Apr 11 11:58:33 2021 -0400 Adjust mob collision detection - this breaks a lot of things and will be fixed later commit e15fd2f4b60fafcae3b765d345914032b4a52668 Author: jordan4ibanez Date: Fri Apr 9 01:38:34 2021 -0400 Add lua locals into mcl_dungeons for performance commit c937b2a97338097700cd3836811ce46366e88027 Author: jordan4ibanez Date: Thu Apr 8 14:19:42 2021 -0400 test commit 8c10fe4057d5a973d448e32addbc07617f9b8edc Author: jordan4ibanez Date: Thu Apr 8 12:48:02 2021 -0400 Adjust spawning to be closer and more frequent commit bd7866d7983aae52aef426bc7a305ae166817ed7 Author: jordan4ibanez Date: Thu Apr 8 12:07:20 2021 -0400 Finish mob limiter commit 9369c9cab8f25d5fa34fe0cdaeee4f9570db4551 Author: jordan4ibanez Date: Thu Apr 8 10:01:15 2021 -0400 Fix spawn timer reset debug commit 28823298e1536d4ce34d67ada624dcb5aaf377e0 Author: jordan4ibanez Date: Thu Apr 8 10:00:04 2021 -0400 Fix forgotten biome check commit 9d48549ec5901de887eb9fb2d75fd07f08edb39b Author: jordan4ibanez Date: Thu Apr 8 09:52:50 2021 -0400 Complete prototype of biome generated mobs commit 518252679f642d00057889b462eb8c87b0992de7 Author: jordan4ibanez Date: Thu Apr 8 08:42:57 2021 -0400 Fix a lot of things commit bb078b0c4c48ac6932d2953561ac03bea3bde51a Author: jordan4ibanez Date: Thu Apr 8 08:33:50 2021 -0400 Fix silverfish typo commit adab48ff0c95c2fad11e4d58824d635ae6945875 Author: jordan4ibanez Date: Thu Apr 8 08:29:16 2021 -0400 Readjust mobs internal settings to not cause insane memory usage commit 47c59edb511fde5db934fca519b9d8aa1fc68838 Author: jordan4ibanez Date: Thu Apr 8 08:13:46 2021 -0400 Fix typo commit 5ca30fa8eec24a1f9bee879bb49d3dfce82484fb Author: jordan4ibanez Date: Thu Apr 8 08:12:43 2021 -0400 Combine air and ground type spawning into ground commit aacb8fc7b95013e42c832927088708b8c9889201 Author: jordan4ibanez Date: Thu Apr 8 08:09:43 2021 -0400 Add in extra_mobs information commit f900b24b53a802fd5db1bf1a633d7f89e42bcce5 Author: jordan4ibanez Date: Thu Apr 8 07:39:18 2021 -0400 Add in all biome information to mobs commit 0ad833c046095d83a789705aa15dd7f30fd8f3ed Author: jordan4ibanez Date: Thu Apr 8 06:57:24 2021 -0400 Add bats, chicken, and blaze spawn info commit f4a6bdc6b89b2d605cfd06f0b7baa6170a19314c Author: jordan4ibanez Date: Thu Apr 8 06:48:25 2021 -0400 Make reference list copy-pastable commit bf4bf9a0cc60a1a15f1ddbfed314ec5a9c75561c Author: jordan4ibanez Date: Thu Apr 8 06:10:07 2021 -0400 Ignore default or void dimensions commit 8e1e02d1fbc189680dbd004bdd905446467a4e29 Author: jordan4ibanez Date: Thu Apr 8 06:04:36 2021 -0400 Add biome list commit da045c207d3bd5931e3cf73c5459b45d86596c12 Author: jordan4ibanez Date: Thu Apr 8 02:07:15 2021 -0400 Refactor spawning into it's own file commit 6ec66ef6f666007e411e23689e0d4eccd5a5fbfe Author: jordan4ibanez Date: Wed Apr 7 23:16:03 2021 -0400 Fix mobs colliding with other mobs/players commit 6bd249547a888493af6c5cfc65d3e206e1467c19 Author: jordan4ibanez Date: Wed Apr 7 23:07:04 2021 -0400 Fix mobs colliding with objects commit c4d030d111ea6e21ca6343f76fb98b8aa9d29f6c Author: jordan4ibanez Date: Thu Apr 1 23:48:00 2021 -0400 Fix item drop on laggy servers --- mods/ENTITIES/mcl_mobs/api.txt | 32 +- mods/ENTITIES/mcl_mobs/api/api.lua | 761 +++ .../mcl_mobs/api/mob_functions/ai.lua | 1153 +++++ .../mcl_mobs/api/mob_functions/animation.lua | 259 + .../attack_type_instructions.lua | 351 ++ .../mob_functions/backup_code_api.lua} | 4342 ++++++----------- .../mcl_mobs/api/mob_functions/breeding.lua | 184 + .../mcl_mobs/api/mob_functions/collision.lua | 140 + .../api/mob_functions/death_logic.lua | 154 + .../api/mob_functions/environment.lua | 260 + .../mcl_mobs/api/mob_functions/head_logic.lua | 112 + .../api/mob_functions/interaction.lua | 291 ++ .../api/mob_functions/mob_effects.lua | 152 + .../mcl_mobs/api/mob_functions/movement.lua | 391 ++ .../api/mob_functions/projectile_handling.lua | 44 + .../mcl_mobs/api/mob_functions/set_up.lua | 226 + .../api/mob_functions/sound_handling.lua | 59 + mods/ENTITIES/mcl_mobs/{ => api}/mount.lua | 55 +- mods/ENTITIES/mcl_mobs/{ => api}/spawning.lua | 314 +- mods/ENTITIES/mcl_mobs/init.lua | 8 +- mods/ENTITIES/mcl_mobs/lucky_block.lua | 8 - mods/ENTITIES/mcl_mobs/sounds/attributes.txt | 4 + .../mcl_mobs/sounds/default_punch.1.ogg | Bin 0 -> 12658 bytes .../mcl_mobs/sounds/default_punch.2.ogg | Bin 0 -> 12801 bytes .../mcl_mobs/sounds/default_punch.3.ogg | Bin 0 -> 12943 bytes .../mcl_mobs/sounds/default_punch.ogg | Bin 5946 -> 0 bytes mods/ENTITIES/mcl_mobs/todo.txt | 1 + mods/ENTITIES/mobs_mc/0_gameconfig.lua | 2 + mods/ENTITIES/mobs_mc/bat.lua | 5 +- mods/ENTITIES/mobs_mc/blaze.lua | 33 +- mods/ENTITIES/mobs_mc/chicken.lua | 103 +- mods/ENTITIES/mobs_mc/cow+mooshroom.lua | 115 +- mods/ENTITIES/mobs_mc/creeper.lua | 50 +- mods/ENTITIES/mobs_mc/ender_dragon.lua | 20 +- mods/ENTITIES/mobs_mc/enderman.lua | 44 +- mods/ENTITIES/mobs_mc/endermite.lua | 3 + mods/ENTITIES/mobs_mc/ghast.lua | 52 +- mods/ENTITIES/mobs_mc/guardian.lua | 2 +- mods/ENTITIES/mobs_mc/guardian_elder.lua | 2 +- mods/ENTITIES/mobs_mc/horse.lua | 105 +- mods/ENTITIES/mobs_mc/iron_golem.lua | 7 +- mods/ENTITIES/mobs_mc/llama.lua | 131 +- mods/ENTITIES/mobs_mc/models/attributes.txt | 1 + .../ENTITIES/mobs_mc/models/mobs_mc_ghast.b3d | Bin 75657 -> 69843 bytes mods/ENTITIES/mobs_mc/ocelot.lua | 8 +- mods/ENTITIES/mobs_mc/parrot.lua | 7 +- mods/ENTITIES/mobs_mc/pig.lua | 108 +- mods/ENTITIES/mobs_mc/polar_bear.lua | 2 +- mods/ENTITIES/mobs_mc/rabbit.lua | 67 +- mods/ENTITIES/mobs_mc/sheep.lua | 102 +- mods/ENTITIES/mobs_mc/shulker.lua | 2 +- mods/ENTITIES/mobs_mc/silverfish.lua | 2 +- mods/ENTITIES/mobs_mc/skeleton+stray.lua | 30 +- mods/ENTITIES/mobs_mc/skeleton_wither.lua | 2 +- mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 10 +- .../mobs_mc/sounds/mobs_mc_villager.4.ogg | Bin 10341 -> 14731 bytes .../mobs_mc/sounds/mobs_mc_villager.5.ogg | Bin 14731 -> 11187 bytes .../mobs_mc/sounds/mobs_mc_villager.6.ogg | Bin 11187 -> 11068 bytes .../mobs_mc/sounds/mobs_mc_villager.7.ogg | Bin 11068 -> 0 bytes .../sounds/mobs_mc_villager_hurt.1.ogg | Bin 0 -> 10341 bytes mods/ENTITIES/mobs_mc/spider.lua | 13 +- mods/ENTITIES/mobs_mc/squid.lua | 5 +- .../mobs_mc/textures/mobs_mc_llama_chest.png | Bin 0 -> 20594 bytes .../textures/mobs_mc_llama_decor_black.png | Bin 0 -> 4602 bytes .../textures/mobs_mc_llama_decor_blue.png | Bin 0 -> 6585 bytes .../textures/mobs_mc_llama_decor_brown.png | Bin 0 -> 6231 bytes .../textures/mobs_mc_llama_decor_cyan.png | Bin 0 -> 7612 bytes .../textures/mobs_mc_llama_decor_gray.png | Bin 0 -> 5236 bytes .../textures/mobs_mc_llama_decor_green.png | Bin 0 -> 5809 bytes .../mobs_mc_llama_decor_light_blue.png | Bin 0 -> 7643 bytes .../mobs_mc_llama_decor_light_gray.png | Bin 0 -> 6354 bytes .../textures/mobs_mc_llama_decor_lime.png | Bin 0 -> 7388 bytes .../textures/mobs_mc_llama_decor_magenta.png | Bin 0 -> 7352 bytes .../textures/mobs_mc_llama_decor_orange.png | Bin 0 -> 7396 bytes .../textures/mobs_mc_llama_decor_pink.png | Bin 0 -> 7732 bytes .../textures/mobs_mc_llama_decor_purple.png | Bin 0 -> 5790 bytes .../textures/mobs_mc_llama_decor_red.png | Bin 0 -> 6659 bytes .../textures/mobs_mc_llama_decor_white.png | Bin 0 -> 6866 bytes .../textures/mobs_mc_llama_decor_yellow.png | Bin 0 -> 7571 bytes .../mobs_mc/textures/mobs_mc_spit.png | Bin 0 -> 677 bytes mods/ENTITIES/mobs_mc/vex.lua | 2 +- mods/ENTITIES/mobs_mc/villager.lua | 6 +- mods/ENTITIES/mobs_mc/villager_evoker.lua | 2 +- mods/ENTITIES/mobs_mc/villager_illusioner.lua | 4 +- mods/ENTITIES/mobs_mc/villager_vindicator.lua | 2 +- mods/ENTITIES/mobs_mc/villager_zombie.lua | 7 +- mods/ENTITIES/mobs_mc/witch.lua | 2 +- mods/ENTITIES/mobs_mc/wither.lua | 2 +- mods/ENTITIES/mobs_mc/wolf.lua | 43 +- mods/ENTITIES/mobs_mc/zombie.lua | 26 +- mods/ENTITIES/mobs_mc/zombiepig.lua | 21 +- 91 files changed, 7120 insertions(+), 3331 deletions(-) create mode 100644 mods/ENTITIES/mcl_mobs/api/api.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/ai.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/animation.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/attack_type_instructions.lua rename mods/ENTITIES/mcl_mobs/{api.lua => api/mob_functions/backup_code_api.lua} (55%) create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/breeding.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/collision.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/death_logic.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/environment.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/head_logic.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/interaction.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/mob_effects.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/movement.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/projectile_handling.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/set_up.lua create mode 100644 mods/ENTITIES/mcl_mobs/api/mob_functions/sound_handling.lua rename mods/ENTITIES/mcl_mobs/{ => api}/mount.lua (92%) rename mods/ENTITIES/mcl_mobs/{ => api}/spawning.lua (67%) delete mode 100644 mods/ENTITIES/mcl_mobs/lucky_block.lua create mode 100644 mods/ENTITIES/mcl_mobs/sounds/attributes.txt create mode 100644 mods/ENTITIES/mcl_mobs/sounds/default_punch.1.ogg create mode 100644 mods/ENTITIES/mcl_mobs/sounds/default_punch.2.ogg create mode 100644 mods/ENTITIES/mcl_mobs/sounds/default_punch.3.ogg delete mode 100644 mods/ENTITIES/mcl_mobs/sounds/default_punch.ogg create mode 100644 mods/ENTITIES/mcl_mobs/todo.txt create mode 100644 mods/ENTITIES/mobs_mc/models/attributes.txt delete mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager_hurt.1.ogg create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_chest.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_black.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_blue.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_brown.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_cyan.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_gray.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_green.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_blue.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_gray.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_lime.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_magenta.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_orange.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_pink.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_purple.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_red.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_white.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_yellow.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_spit.png diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index eda74aeb4..2d8cef5b0 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -502,20 +502,6 @@ and damages any entity caught inside the blast radius. Protection will limit node destruction but not entity damage. -mobs:capture_mob ----------------- - -mobs:capture_mob(...) - -Does nothing and returns false. - -This function is provided for compability with Mobs Redo for an attempt to -capture a mob. -Mobs cannot be captured in MineClone 2. - -In Mobs Redo, this is generally called inside the on_rightclick section of the mob -api code, it provides a chance of capturing the mob. See Mobs Redo documentation -of parameters. Feeding and Taming/Breeding --------------------------- @@ -535,19 +521,6 @@ Will return true when mob is fed with item it likes. them up -Protecting Mobs ---------------- - -mobs:protect(self, clicker) - -This function can be used to right-click any tamed mob with mobs:protector item, -this will protect the mob from harm inside of a protected area from other -players. Will return true when mob right-clicked with mobs:protector item. - - 'self' mob information - 'clicker' player information - - Riding Mobs ----------- @@ -605,7 +578,7 @@ Note: animation names above are from the pre-defined animation lists inside mob registry without extensions. -mobs:set_animation(self, name) +mobs.set_mob_animation(self, name) This function sets the current animation for mob, defaulting to "stand" if not found. @@ -781,8 +754,5 @@ mobs:register_mob("mob_horse:horse", { inv:remove_item("main", "mobs:saddle") end end - - -- used to capture horse with magic lasso - mobs:capture_mob(self, clicker, 0, 0, 80, false, nil) end }) diff --git a/mods/ENTITIES/mcl_mobs/api/api.lua b/mods/ENTITIES/mcl_mobs/api/api.lua new file mode 100644 index 000000000..d413bae72 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/api.lua @@ -0,0 +1,761 @@ +-- API for Mobs Redo: MineClone 2 Delux 2.0 DRM Free Early Access Super Extreme Edition + +-- mobs library +mobs = {} + +-- lua locals - can grab from this to easily plop them into the api lua files + +--localize minetest functions +local minetest_settings = minetest.settings +local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius +local minetest_get_modpath = minetest.get_modpath +local minetest_registered_nodes = minetest.registered_nodes +local minetest_get_node = minetest.get_node +local minetest_get_item_group = minetest.get_item_group +local minetest_registered_entities = minetest.registered_entities +local minetest_line_of_sight = minetest.line_of_sight +local minetest_after = minetest.after +local minetest_sound_play = minetest.sound_play +local minetest_add_particlespawner = minetest.add_particlespawner +local minetest_registered_items = minetest.registered_items +local minetest_set_node = minetest.set_node +local minetest_add_item = minetest.add_item +local minetest_get_craft_result = minetest.get_craft_result +local minetest_find_path = minetest.find_path +local minetest_is_protected = minetest.is_protected +local minetest_is_creative_enabled = minetest.is_creative_enabled +local minetest_find_node_near = minetest.find_node_near +local minetest_find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air +local minetest_raycast = minetest.raycast +local minetest_get_us_time = minetest.get_us_time +local minetest_add_entity = minetest.add_entity +local minetest_get_natural_light = minetest.get_natural_light +local minetest_get_node_or_nil = minetest.get_node_or_nil + +-- localize math functions +local math_pi = math.pi +local math_sin = math.sin +local math_cos = math.cos +local math_abs = math.abs +local math_min = math.min +local math_max = math.max +local math_atan = math.atan +local math_random = math.random +local math_floor = math.floor + +-- localize vector functions +local vector_new = vector.new +local vector_add = vector.add +local vector_length = vector.length +local vector_direction = vector.direction +local vector_normalize = vector.normalize +local vector_multiply = vector.multiply +local vector_divide = vector.divide + +-- mob constants +local BREED_TIME = 30 +local BREED_TIME_AGAIN = 300 +local CHILD_GROW_TIME = 60*20 +local DEATH_DELAY = 0.5 +local DEFAULT_FALL_SPEED = -10 +local FLOP_HEIGHT = 5.0 +local FLOP_HOR_SPEED = 1.5 +local GRAVITY = minetest_settings:get("movement_gravity")-- + 9.81 + + +local MOB_CAP = {} +MOB_CAP.hostile = 70 +MOB_CAP.passive = 10 +MOB_CAP.ambient = 15 +MOB_CAP.water = 15 + +-- Load main settings +local damage_enabled = minetest_settings:get_bool("enable_damage") +local disable_blood = minetest_settings:get_bool("mobs_disable_blood") +local mobs_drop_items = minetest_settings:get_bool("mobs_drop_items") ~= false +local mobs_griefing = minetest_settings:get_bool("mobs_griefing") ~= false +local spawn_protected = minetest_settings:get_bool("mobs_spawn_protected") ~= false +local remove_far = true +local difficulty = tonumber(minetest_settings:get("mob_difficulty")) or 1.0 +local show_health = false +local max_per_block = tonumber(minetest_settings:get("max_objects_per_block") or 64) +local mobs_spawn_chance = tonumber(minetest_settings:get("mobs_spawn_chance") or 2.5) + +-- pathfinding settings +local enable_pathfinding = true +local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching +local stuck_path_timeout = 10 -- how long will mob follow path before giving up + +-- default nodes +local node_ice = "mcl_core:ice" +local node_snowblock = "mcl_core:snowblock" +local node_snow = "mcl_core:snow" +mobs.fallback_node = minetest.registered_aliases["mapgen_dirt"] or "mcl_core:dirt" + +local mod_weather = minetest_get_modpath("mcl_weather") ~= nil +local mod_explosions = minetest_get_modpath("mcl_explosions") ~= nil +local mod_mobspawners = minetest_get_modpath("mcl_mobspawners") ~= nil +local mod_hunger = minetest_get_modpath("mcl_hunger") ~= nil +local mod_worlds = minetest_get_modpath("mcl_worlds") ~= nil +local mod_armor = minetest_get_modpath("mcl_armor") ~= nil +local mod_experience = minetest_get_modpath("mcl_experience") ~= nil + + +-- random locals I found +local los_switcher = false +local height_switcher = false + +-- Get translator +local S = minetest.get_translator("mcl_mobs") + +-- CMI support check +local use_cmi = minetest.global_exists("cmi") + + +-- Invisibility mod check +mobs.invis = {} +if minetest.global_exists("invisibility") then + mobs.invis = invisibility +end + + +-- creative check +function mobs.is_creative(name) + return minetest_is_creative_enabled(name) +end + + +local atan = function(x) + if not x or x ~= x then + return 0 + else + return math_atan(x) + end +end + + + + +-- Shows helpful debug info above each mob +local mobs_debug = minetest_settings:get_bool("mobs_debug", false) + +-- Peaceful mode message so players will know there are no monsters +if minetest_settings:get_bool("only_peaceful_mobs", false) then + minetest.register_on_joinplayer(function(player) + minetest.chat_send_player(player:get_player_name(), + S("Peaceful mode active! No monsters will spawn.")) + end) +end + + +local api_path = minetest.get_modpath(minetest.get_current_modname()).."/api/mob_functions/" + +--ignite all parts of the api +dofile(api_path .. "ai.lua") +dofile(api_path .. "animation.lua") +dofile(api_path .. "collision.lua") +dofile(api_path .. "environment.lua") +dofile(api_path .. "interaction.lua") +dofile(api_path .. "movement.lua") +dofile(api_path .. "set_up.lua") +dofile(api_path .. "attack_type_instructions.lua") +dofile(api_path .. "sound_handling.lua") +dofile(api_path .. "death_logic.lua") +dofile(api_path .. "mob_effects.lua") +dofile(api_path .. "projectile_handling.lua") +dofile(api_path .. "breeding.lua") +dofile(api_path .. "head_logic.lua") + + +mobs.spawning_mobs = {} + + + + +-- register mob entity +function mobs:register_mob(name, def) + + local collisionbox = def.collisionbox or {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25} + + -- Workaround for : + -- Increase upper Y limit to avoid mobs glitching through solid nodes. + -- FIXME: Remove workaround if it's no longer needed. + + if collisionbox[5] < 0.79 then + collisionbox[5] = 0.79 + end + + mobs.spawning_mobs[name] = true + + local function scale_difficulty(value, default, min, special) + if (not value) or (value == default) or (value == special) then + return default + else + return math_max(min, value * difficulty) + end + end + + minetest.register_entity(name, { + description = def.description, + use_texture_alpha = def.use_texture_alpha, + stepheight = def.stepheight or 0.6, + stepheight_backup = def.stepheight or 0.6, + name = name, + type = def.type, + attack_type = def.attack_type, + fly = def.fly, + fly_in = def.fly_in or {"air", "__airlike"}, + owner = def.owner or "", + order = def.order or "", + on_die = def.on_die, + spawn_small_alternative = def.spawn_small_alternative, + do_custom = def.do_custom, + jump_height = def.jump_height or 4, -- was 6 + rotate = def.rotate or 0, -- 0=front, 90=side, 180=back, 270=side2 + hp_min = scale_difficulty(def.hp_min, 5, 1), + hp_max = scale_difficulty(def.hp_max, 10, 1), + xp_min = def.xp_min or 1, + xp_max = def.xp_max or 5, + breath_max = def.breath_max or 6, + breathes_in_water = def.breathes_in_water or false, + physical = true, + collisionbox = collisionbox, + collide_with_objects = def.collide_with_objects or false, + selectionbox = def.selectionbox or def.collisionbox, + visual = def.visual, + visual_size = def.visual_size or {x = 1, y = 1}, + mesh = def.mesh, + makes_footstep_sound = def.makes_footstep_sound or false, + view_range = def.view_range or 16, + walk_velocity = def.walk_velocity or 1, + run_velocity = def.run_velocity or 2, + damage = scale_difficulty(def.damage, 0, 0), + light_damage = def.light_damage or 0, + sunlight_damage = def.sunlight_damage or 0, + water_damage = def.water_damage or 0, + lava_damage = def.lava_damage or 8, + fire_damage = def.fire_damage or 1, + suffocation = def.suffocation or true, + fall_damage = def.fall_damage or 1, + fall_speed = def.fall_speed or DEFAULT_FALL_SPEED, -- must be lower than -2 + drops = def.drops or {}, + armor = def.armor or 100, + on_rightclick = mobs.create_mob_on_rightclick(def.on_rightclick), + arrow = def.arrow, + shoot_interval = def.shoot_interval, + sounds = def.sounds or {}, + animation = def.animation, + jump = def.jump ~= false, + walk_chance = def.walk_chance or 50, + attacks_monsters = def.attacks_monsters or false, + group_attack = def.group_attack or false, + passive = def.passive or false, + knock_back = def.knock_back ~= false, + shoot_offset = def.shoot_offset or 0, + floats = def.floats or 1, -- floats in water by default + floats_on_lava = def.floats_on_lava or 0, + replace_rate = def.replace_rate, + replace_what = def.replace_what, + replace_with = def.replace_with, + replace_offset = def.replace_offset or 0, + on_replace = def.on_replace, + timer = 0, + state_timer = 0, + env_damage_timer = 0, + tamed = false, + pause_timer = 0, + gotten = false, + reach = def.reach or 3, + htimer = 0, + texture_list = def.textures, + child_texture = def.child_texture, + docile_by_day = def.docile_by_day or false, + time_of_day = 0.5, + fear_height = def.fear_height or 0, + runaway = def.runaway, + runaway_timer = 0, + pathfinding = def.pathfinding, + immune_to = def.immune_to or {}, + explosion_radius = def.explosion_radius, -- LEGACY + explosion_damage_radius = def.explosion_damage_radius, -- LEGACY + explosiontimer_reset_radius = def.explosiontimer_reset_radius, + explosion_timer = def.explosion_timer or 3, + allow_fuse_reset = def.allow_fuse_reset ~= false, + stop_to_explode = def.stop_to_explode ~= false, + custom_attack = def.custom_attack, + double_melee_attack = def.double_melee_attack, + dogshoot_switch = def.dogshoot_switch, + dogshoot_count = 0, + dogshoot_count_max = def.dogshoot_count_max or 5, + dogshoot_count2_max = def.dogshoot_count2_max or (def.dogshoot_count_max or 5), + attack_animals = def.attack_animals or false, + specific_attack = def.specific_attack, + runaway_from = def.runaway_from, + owner_loyal = def.owner_loyal, + facing_fence = false, + + _cmi_is_mob = true, + + pushable = def.pushable or true, + + --j4i stuff + yaw = 0, + automatic_face_movement_dir = def.rotate or 0, -- 0=front, 90=side, 180=back, 270=side2 + automatic_face_movement_max_rotation_per_sec = 360, --degrees + backface_culling = true, + walk_timer = 0, + stand_timer = 0, + current_animation = "", + gravity = GRAVITY, + swim = def.swim, + swim_in = def.swim_in or {mobs_mc.items.water_source, "mcl_core:water_flowing", mobs_mc.items.river_water_source}, + pitch_switch = "static", + jump_only = def.jump_only, + hostile = def.hostile, + neutral = def.neutral, + attacking = nil, + visual_size_origin = def.visual_size or {x = 1, y = 1, z = 1}, + punch_timer_cooloff = def.punch_timer_cooloff or 0.5, + death_animation_timer = 0, + hostile_cooldown = def.hostile_cooldown or 15, + tilt_fly = def.tilt_fly, + tilt_swim = def.tilt_swim, + fall_slow = def.fall_slow, + projectile_cooldown_min = def.projectile_cooldown_min or 2, + projectile_cooldown_max = def.projectile_cooldown_max or 6, + skittish = def.skittish, + + minimum_follow_distance = def.minimum_follow_distance or 0.5, --make mobs not freak out when underneath + + memory = 0, -- memory timer if chasing/following + fly_random_while_attack = def.fly_random_while_attack, + + --for spiders + always_climb = def.always_climb, + + --despawn mechanic variables + lifetimer_reset = 30, --30 seconds + lifetimer = 30, --30 seconds + + --breeding stuff + breed_timer = 0, + breed_lookout_timer = 0, + breed_distance = def.breed_distance or 1.5, --how far away mobs have to be to begin actual breeding + breed_lookout_timer_goal = 30, --30 seconds (this timer is for how long the mob looks for a mate) + breed_timer_cooloff = 5*60, -- 5 minutes (this timer is for how long the mob has to wait before being bred again) + bred = false, + follow = def.follow, --this item is also used for the breeding mechanism + follow_distance = def.follow_distance or 2, + baby_size = def.baby_size or 0.5, + baby = false, + grow_up_timer = 0, + grow_up_goal = 20*60, --in 20 minutes the mob grows up + special_breed_timer = 0, --this is used for the AHEM AHEM part of breeding + + backup_visual_size = def.visual_size, + backup_collisionbox = collisionbox, + backup_selectionbox = def.selectionbox or def.collisionbox, + + + --fire timer + burn_timer = 0, + + ignores_cobwebs = def.ignores_cobwebs, + breath = def.breath_max or 6, + + random_sound_timer_min = 3, + random_sound_timer_max = 10, + + + --head code variables + --defaults are for the cow's default + --because I don't know what else to set them + --to :P + + has_head = def.has_head or false, + head_bone = def.head_bone, + + --you must use these to adjust the mob's head positions + + --has_head is used as a logic gate (quick easy check) + has_head = def.has_head or false, + --head_bone is the actual bone in the model which the head + --is attached to for animation + head_bone = def.head_bone or "head", + + --this part controls the base position of the head calculations + --localized to the mob's visual yaw when gotten (self.object:get_yaw()) + --you can enable the debug in /mob_functions/head_logic.lua by uncommenting the + --particle spawner code + head_height_offset = def.head_height_offset or 1.0525, + head_direction_offset = def.head_direction_offset or 0.5, + + --this part controls the visual of the head + head_bone_pos_y = def.head_bone_pos_y or 3.6, + head_bone_pos_z = def.head_bone_pos_z or -0.6, + head_pitch_modifier = def.head_pitch_modifier or 0, + + --these variables are switches in case the model + --moves the wrong way + swap_y_with_x = def.swap_y_with_x or false, + reverse_head_yaw = def.reverse_head_yaw or false, + + --END HEAD CODE VARIABLES + + --end j4i stuff + + -- MCL2 extensions + teleport = mobs.teleport, + do_teleport = def.do_teleport, + spawn_class = def.spawn_class, + ignores_nametag = def.ignores_nametag or false, + rain_damage = def.rain_damage or 0, + glow = def.glow, + --can_despawn = can_despawn, + child = def.child or false, + texture_mods = {}, + shoot_arrow = def.shoot_arrow, + sounds_child = def.sounds_child, + explosion_strength = def.explosion_strength, + suffocation_timer = 0, + follow_velocity = def.follow_velocity or 2.4, + instant_death = def.instant_death or false, + fire_resistant = def.fire_resistant or false, + fire_damage_resistant = def.fire_damage_resistant or false, + ignited_by_sunlight = def.ignited_by_sunlight or false, + eye_height = def.eye_height or 1.5, + defuse_reach = def.defuse_reach or 4, + -- End of MCL2 extensions + + on_spawn = def.on_spawn, + + --on_blast = def.on_blast or do_tnt, + + on_step = mobs.mob_step, + + --do_punch = def.do_punch, + + on_punch = mobs.mob_punch, + + --on_breed = def.on_breed, + + --on_grown = def.on_grown, + + --on_detach_child = mob_detach_child, + + on_activate = function(self, staticdata, dtime) + self.object:set_acceleration(vector_new(0,-GRAVITY, 0)) + return mobs.mob_activate(self, staticdata, def, dtime) + end, + + get_staticdata = function(self) + return mobs.mob_staticdata(self) + end, + + --harmed_by_heal = def.harmed_by_heal, + }) + + if minetest_get_modpath("doc_identifier") ~= nil then + doc.sub.identifier.register_object(name, "basics", "mobs") + end + +end -- END mobs:register_mob function + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-- register arrow for shoot attack +function mobs:register_arrow(name, def) + + -- errorcheck + if not name or not def then + print("failed to register arrow entity") + return + end + + minetest.register_entity(name.."_entity", { + + physical = false, + visual = def.visual, + visual_size = def.visual_size, + textures = def.textures, + velocity = def.velocity, + hit_player = def.hit_player, + hit_node = def.hit_node, + hit_mob = def.hit_mob, + hit_object = def.hit_object, + drop = def.drop or false, -- drops arrow as registered item when true + collisionbox = {0, 0, 0, 0, 0, 0}, -- remove box around arrows + timer = 0, + switch = 0, + owner_id = def.owner_id, + rotate = def.rotate, + speed = def.speed or nil, + on_step = function(self) + + local vel = self.object:get_velocity() + + local pos = self.object:get_pos() + + if self.timer > 150 + or not mobs.within_limits(pos, 0) then + mcl_burning.extinguish(self.object) + self.object:remove(); + return + end + + -- does arrow have a tail (fireball) + if def.tail + and def.tail == 1 + and def.tail_texture then + + --do this to prevent clipping through main entity sprite + local pos_adjustment = vector_multiply(vector_normalize(vel), -1) + local divider = def.tail_distance_divider or 1 + pos_adjustment = vector_divide(pos_adjustment, divider) + local new_pos = vector_add(pos, pos_adjustment) + minetest.add_particle({ + pos = new_pos, + velocity = {x = 0, y = 0, z = 0}, + acceleration = {x = 0, y = 0, z = 0}, + expirationtime = def.expire or 0.25, + collisiondetection = false, + texture = def.tail_texture, + size = def.tail_size or 5, + glow = def.glow or 0, + }) + end + + if self.hit_node then + + local node = minetest_get_node(pos).name + + if minetest_registered_nodes[node].walkable then + + self.hit_node(self, pos, node) + + if self.drop == true then + + pos.y = pos.y + 1 + + self.lastpos = (self.lastpos or pos) + + minetest_add_item(self.lastpos, self.object:get_luaentity().name) + end + + self.object:remove(); + + return + end + end + + if self.hit_player or self.hit_mob or self.hit_object then + + for _,player in pairs(minetest_get_objects_inside_radius(pos, 1.5)) do + + if self.hit_player + and player:is_player() then + + if self.hit_player then + self.hit_player(self, player) + else + mobs.arrow_hit(self, player) + end + + self.object:remove(); + return + end + + --[[ + local entity = player:get_luaentity() + + if entity + and self.hit_mob + and entity._cmi_is_mob == true + and tostring(player) ~= self.owner_id + and entity.name ~= self.object:get_luaentity().name + and (self._shooter and entity.name ~= self._shooter:get_luaentity().name) then + + --self.hit_mob(self, player) + self.object:remove(); + return + end + ]]-- + + --[[ + if entity + and self.hit_object + and (not entity._cmi_is_mob) + and tostring(player) ~= self.owner_id + and entity.name ~= self.object:get_luaentity().name + and (self._shooter and entity.name ~= self._shooter:get_luaentity().name) then + + --self.hit_object(self, player) + self.object:remove(); + return + end + ]]-- + end + end + + self.lastpos = pos + end + }) +end + +-- Register spawn eggs + +-- Note: This also introduces the “spawn_egg” group: +-- * spawn_egg=1: Spawn egg (generic mob, no metadata) +-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata) +function mobs:register_egg(mob, desc, background, addegg, no_creative) + + local grp = {spawn_egg = 1} + + -- do NOT add this egg to creative inventory (e.g. dungeon master) + if no_creative == true then + grp.not_in_creative_inventory = 1 + end + + local invimg = background + + if addegg == 1 then + invimg = "mobs_chicken_egg.png^(" .. invimg .. + "^[mask:mobs_chicken_egg_overlay.png)" + end + + -- register old stackable mob egg + minetest.register_craftitem(mob, { + + description = desc, + inventory_image = invimg, + groups = grp, + + _doc_items_longdesc = S("This allows you to place a single mob."), + _doc_items_usagehelp = S("Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns."), + + on_place = function(itemstack, placer, pointed_thing) + + local pos = pointed_thing.above + + -- am I clicking on something with existing on_rightclick function? + local under = minetest_get_node(pointed_thing.under) + local def = minetest_registered_nodes[under.name] + if def and def.on_rightclick then + return def.on_rightclick(pointed_thing.under, under, placer, itemstack) + end + + if pos + --and within_limits(pos, 0) + and not minetest_is_protected(pos, placer:get_player_name()) then + + local name = placer:get_player_name() + local privs = minetest.get_player_privs(name) + if mod_mobspawners and under.name == "mcl_mobspawners:spawner" then + if minetest_is_protected(pointed_thing.under, name) then + minetest.record_protection_violation(pointed_thing.under, name) + return itemstack + end + if not privs.maphack then + minetest.chat_send_player(name, S("You need the “maphack” privilege to change the mob spawner.")) + return itemstack + end + mcl_mobspawners.setup_spawner(pointed_thing.under, itemstack:get_name()) + if not mobs.is_creative(name) then + itemstack:take_item() + end + return itemstack + end + + if not minetest_registered_entities[mob] then + return itemstack + end + + if minetest_settings:get_bool("only_peaceful_mobs", false) + and minetest_registered_entities[mob].type == "monster" then + minetest.chat_send_player(name, S("Only peaceful mobs allowed!")) + return itemstack + end + + local mob = minetest_add_entity(pos, mob) + minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos)) + local ent = mob:get_luaentity() + + -- don't set owner if monster or sneak pressed + --[[ + if ent.type ~= "monster" + and not placer:get_player_control().sneak then + ent.owner = placer:get_player_name() + ent.tamed = true + end + ]]-- + + -- set nametag + local nametag = itemstack:get_meta():get_string("name") + if nametag ~= "" then + if string.len(nametag) > MAX_MOB_NAME_LENGTH then + nametag = string.sub(nametag, 1, MAX_MOB_NAME_LENGTH) + end + ent.nametag = nametag + update_tag(ent) + end + + -- if not in creative then take item + if not mobs.is_creative(placer:get_player_name()) then + itemstack:take_item() + end + end + + return itemstack + end, + }) + +end + + diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/ai.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/ai.lua new file mode 100644 index 000000000..eda7e8871 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/ai.lua @@ -0,0 +1,1153 @@ +local math_random = math.random +local math_pi = math.pi +local math_floor = math.floor +local math_round = math.round + +local vector_multiply = vector.multiply +local vector_add = vector.add +local vector_new = vector.new +local vector_distance = vector.distance + +local minetest_yaw_to_dir = minetest.yaw_to_dir +local minetest_get_item_group = minetest.get_item_group +local minetest_get_node = minetest.get_node +local minetest_line_of_sight = minetest.line_of_sight +local minetest_get_node_light = minetest.get_node_light + +local DOUBLE_PI = math.pi * 2 +local THIRTY_SECONDTH_PI = DOUBLE_PI * 0.03125 + + +--a simple helper function which is too small to move into movement.lua +local quick_rotate = function(self,dtime) + self.yaw = self.yaw + THIRTY_SECONDTH_PI + if self.yaw > DOUBLE_PI then + self.yaw = self.yaw - DOUBLE_PI + end +end + +--a simple helper function for rounding +--http://lua-users.org/wiki/SimpleRound +function round2(num, numDecimalPlaces) + return tonumber(string.format("%." .. (numDecimalPlaces or 0) .. "f", num)) +end + + +--[[ + _ _ +| | | | +| | __ _ _ __ __| | +| | / _` | '_ \ / _` | +| |___| (_| | | | | (_| | +\_____/\__,_|_| |_|\__,_| +]]-- + +--this is basically reverse jump_check +local cliff_check = function(self,dtime) + --mobs will flip out if they are falling without this + if self.object:get_velocity().y ~= 0 then + return false + end + + local pos = self.object:get_pos() + local dir = minetest_yaw_to_dir(self.yaw) + local collisionbox = self.object:get_properties().collisionbox + local radius = collisionbox[4] + 0.5 + + dir = vector_multiply(dir,radius) + + local free_fall, blocker = minetest_line_of_sight( + {x = pos.x + dir.x, y = pos.y, z = pos.z + dir.z}, + {x = pos.x + dir.x, y = pos.y - self.fear_height, z = pos.z + dir.z}) + + return free_fall +end + + +-- state switching logic (stand, walk, run, attacks) +local land_state_list_wandering = {"stand", "walk"} + +local land_state_switch = function(self, dtime) + + --do math before sure not attacking, following, or running away so continue + --doing random walking for mobs if all states are not met + self.state_timer = self.state_timer - dtime + + --only run away + if self.skittish and self.state == "run" then + self.run_timer = self.run_timer - dtime + if self.run_timer > 0 then + return + end + --continue + end + + --ignore everything else if breeding + if self.breed_lookout_timer and self.breed_lookout_timer > 0 then + self.state = "breed" + return + --reset the state timer to get the mob out of + --the breed state + elseif self.state == "breed" then + self.state_timer = 0 + end + + --ignore everything else if following + if mobs.check_following(self) and + (not self.breed_lookout_timer or (self.breed_lookout_timer and self.breed_lookout_timer == 0)) and + (not self.breed_timer or (self.breed_timer and self.breed_timer == 0)) then + self.state = "follow" + return + --reset the state timer to get the mob out of + --the follow state - not the cleanest option + --but the easiest + elseif self.state == "follow" then + self.state_timer = 0 + end + + --only attack + if self.hostile and self.attacking then + self.state = "attack" + return + end + + --if finally reached here then do random wander + if self.state_timer <= 0 then + self.state_timer = math.random(4,10) + math.random() + self.state = land_state_list_wandering[math.random(1,#land_state_list_wandering)] + end + +end + +-- states are executed here +local land_state_execution = function(self,dtime) + + --[[ -- this is a debug which shows the timer and makes mobs breed 100 times faster + print(self.breed_timer) + if self.breed_timer > 0 then + self.breed_timer = self.breed_timer - (dtime * 100) + if self.breed_timer <= 0 then + self.breed_timer = 0 + end + end + ]]-- + + --no collisionbox exception + if not self.object:get_properties() then + return + end + + + --timer to time out looking for mate + if self.breed_lookout_timer and self.breed_lookout_timer > 0 then + self.breed_lookout_timer = self.breed_lookout_timer - dtime + --looking for mate failed + if self.breed_lookout_timer <= 0 then + self.breed_lookout_timer = 0 + end + end + + --cool off after breeding + if self.breed_timer and self.breed_timer > 0 then + self.breed_timer = self.breed_timer - dtime + --do this to skip the first check, using as switch + if self.breed_timer <= 0 then + self.breed_timer = 0 + end + end + + + local pos = self.object:get_pos() + local collisionbox = self.object:get_properties().collisionbox + --get the center of the mob + pos.y = pos.y + (collisionbox[2] + collisionbox[5] / 2) + local current_node = minetest_get_node(pos).name + local float_now = false + + --recheck if in water or lava + if minetest_get_item_group(current_node, "water") ~= 0 or minetest_get_item_group(current_node, "lava") ~= 0 then + float_now = true + end + + --make slow falling mobs fall slow + if self.fall_slow then + local velocity = self.object:get_velocity() + if velocity then + if velocity.y < 0 then + --lua is acting really weird so we have to help it + if round2(self.object:get_acceleration().y, 1) == -self.gravity then + self.object:set_acceleration(vector_new(0,0,0)) + mobs.mob_fall_slow(self) + end + else + if round2(self.object:get_acceleration().y, 1) == 0 then + self.object:set_acceleration(vector_new(0,-self.gravity,0)) + end + end + end + end + + --calculate fall damage + if self.fall_damage then + mobs.calculate_fall_damage(self) + end + + if self.state == "stand" then + + --do animation + mobs.set_mob_animation(self, "stand") + + --set the velocity of the mob + mobs.set_velocity(self,0) + + --animation fixes for explosive mobs + if self.attack_type == "explode" then + mobs.reverse_explosion_animation(self,dtime) + end + + mobs.lock_yaw(self) + elseif self.state == "follow" then + + --always look at players + mobs.set_yaw_while_following(self) + + --check distance + local distance_from_follow_person = vector_distance(self.object:get_pos(), self.following_person:get_pos()) + local distance_2d = mobs.get_2d_distance(self.object:get_pos(), self.following_person:get_pos()) + + --don't push the player if too close + --don't spin around randomly + if self.follow_distance < distance_from_follow_person and self.minimum_follow_distance < distance_2d then + mobs.set_mob_animation(self, "run") + mobs.set_velocity(self,self.run_velocity) + + if mobs.jump_check(self) == 1 then + mobs.jump(self) + end + else + mobs.set_mob_animation(self, "stand") + mobs.set_velocity(self,0) + end + + elseif self.state == "walk" then + + self.walk_timer = self.walk_timer - dtime + + --reset the walk timer + if self.walk_timer <= 0 then + + --re-randomize the walk timer + self.walk_timer = math.random(1,6) + math.random() + + --set the mob into a random direction + self.yaw = (math_random() * (math.pi * 2)) + end + + --do animation + mobs.set_mob_animation(self, "walk") + + --enable rotation locking + mobs.movement_rotation_lock(self) + + --check for nodes to jump over + local node_in_front_of = mobs.jump_check(self) + + if node_in_front_of == 1 then + + mobs.jump(self) + + --turn if on the edge of cliff + --(this is written like this because unlike + --jump_check which simply tells the mob to jump + --this requires a mob to turn, removing the + --ease of a full implementation for it in a single + --function) + elseif node_in_front_of == 2 or (self.fear_height ~= 0 and cliff_check(self,dtime)) then + --turn 45 degrees if so + quick_rotate(self,dtime) + --stop the mob so it doesn't fall off + mobs.set_velocity(self,0) + end + + --only move forward if path is clear + if node_in_front_of == 0 or node_in_front_of == 1 then + --set the velocity of the mob + mobs.set_velocity(self,self.walk_velocity) + end + + --animation fixes for explosive mobs + if self.attack_type == "explode" then + mobs.reverse_explosion_animation(self,dtime) + end + + elseif self.state == "run" then + + --do animation + mobs.set_mob_animation(self, "run") + + --enable rotation locking + mobs.movement_rotation_lock(self) + + --check for nodes to jump over + local node_in_front_of = mobs.jump_check(self) + + if node_in_front_of == 1 then + + mobs.jump(self) + + --turn if on the edge of cliff + --(this is written like this because unlike + --jump_check which simply tells the mob to jump + --this requires a mob to turn, removing the + --ease of a full implementation for it in a single + --function) + elseif node_in_front_of == 2 or (self.fear_height ~= 0 and cliff_check(self,dtime)) then + --turn 45 degrees if so + quick_rotate(self,dtime) + --stop the mob so it doesn't fall off + mobs.set_velocity(self,0) + end + + --only move forward if path is clear + if node_in_front_of == 0 or node_in_front_of == 1 then + --set the velocity of the mob + mobs.set_velocity(self,self.run_velocity) + end + + elseif self.state == "attack" then + + --execute mob attack type + if self.attack_type == "explode" then + + mobs.explode_attack_walk(self, dtime) + + elseif self.attack_type == "punch" then + + mobs.punch_attack_walk(self,dtime) + + elseif self.attack_type == "projectile" then + + mobs.projectile_attack_walk(self,dtime) + + end + elseif self.state == "breed" then + + mobs.breeding_effect(self) + + local mate = mobs.look_for_mate(self) + + --found a mate + if mate then + mobs.set_yaw_while_breeding(self,mate) + mobs.set_velocity(self, self.walk_velocity) + + --smoosh together basically + if vector_distance(self.object:get_pos(), mate:get_pos()) <= self.breed_distance then + mobs.set_mob_animation(self, "stand") + if self.special_breed_timer == 0 then + self.special_breed_timer = 2 --breeding takes 2 seconds + end + + self.special_breed_timer = self.special_breed_timer - dtime + if self.special_breed_timer <= 0 then + + --pop a baby out, it's a miracle! + local baby_pos = vector.divide(vector.add(self.object:get_pos(), mate:get_pos()), 2) + local baby_mob = minetest.add_entity(pos, self.name, minetest.serialize({baby = true, grow_up_timer = self.grow_up_goal, bred = true})) + + mobs.play_sound_specific(self,"item_drop_pickup") + + self.special_breed_timer = 0 + self.breed_lookout_timer = 0 + self.breed_timer = self.breed_timer_cooloff + + mate:get_luaentity().special_breed_timer = 0 + mate:get_luaentity().breed_lookout_timer = 0 + mate:get_luaentity().breed_timer = self.breed_timer_cooloff -- can reuse because it's the same mob + end + else + mobs.set_mob_animation(self, "walk") + end + --couldn't find a mate, just stand there until the player pushes it towards one + --or the timer runs out + else + mobs.set_mob_animation(self, "stand") + mobs.set_velocity(self,0) + end + + end + + if float_now then + mobs.float(self) + else + local acceleration = self.object:get_acceleration() + if acceleration and acceleration.y == 0 then + self.object:set_acceleration(vector_new(0,-self.gravity,0)) + end + end +end + + + + +--[[ + _____ _ +/ ___| (_) +\ `--.__ ___ _ __ ___ + `--. \ \ /\ / / | '_ ` _ \ +/\__/ /\ V V /| | | | | | | +\____/ \_/\_/ |_|_| |_| |_| +]]-- + + + +-- state switching logic (stand, walk, run, attacks) +local swim_state_list_wandering = {"stand", "swim"} + +local swim_state_switch = function(self, dtime) + self.state_timer = self.state_timer - dtime + if self.state_timer <= 0 then + self.state_timer = math.random(4,10) + math.random() + self.state = swim_state_list_wandering[math.random(1,#swim_state_list_wandering)] + end +end + + +--check if a mob needs to turn while swimming +local swim_turn_check = function(self,dtime) + + local pos = self.object:get_pos() + pos.y = pos.y + 0.1 + local dir = minetest_yaw_to_dir(self.yaw) + + local collisionbox = self.object:get_properties().collisionbox + local radius = collisionbox[4] + 0.5 + + vector_multiply(dir, radius) + + local test_dir = vector.add(pos,dir) + + local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0 + + return(green_flag_1) +end + +--this is to swap the built in engine acceleration modifier +local swim_physics_swapper = function(self,inside_swim_node) + + --should be swimming, gravity is applied, switch to floating + if inside_swim_node and self.object:get_acceleration().y ~= 0 then + self.object:set_acceleration(vector_new(0,0,0)) + --not be swim, gravity isn't applied, switch to falling + elseif not inside_swim_node and self.object:get_acceleration().y == 0 then + self.pitch = 0 + self.object:set_acceleration(vector_new(0,-self.gravity,0)) + end +end + + +local random_pitch_multiplier = {-1,1} +-- states are executed here +local swim_state_execution = function(self,dtime) + + local pos = self.object:get_pos() + + pos.y = pos.y + self.object:get_properties().collisionbox[5] + local current_node = minetest_get_node(pos).name + local inside_swim_node = false + + --quick scan everything to see if inside swim node + for _,id in pairs(self.swim_in) do + if id == current_node then + inside_swim_node = true + break + end + end + + --turn gravity on or off + swim_physics_swapper(self,inside_swim_node) + + --swim properly if inside swim node + if inside_swim_node then + + if self.state == "stand" then + + --do animation + mobs.set_mob_animation(self, "stand") + + mobs.set_swim_velocity(self,0) + + if self.tilt_swim then + mobs.set_static_pitch(self) + end + + mobs.lock_yaw(self) + + elseif self.state == "swim" then + + self.walk_timer = self.walk_timer - dtime + + --reset the walk timer + if self.walk_timer <= 0 then + + --re-randomize the walk timer + self.walk_timer = math.random(1,6) + math.random() + + --set the mob into a random direction + self.yaw = (math_random() * (math.pi * 2)) + + --create a truly random pitch, since there is no easy access to pitch math that I can find + self.pitch = math_random() * math.random(1,3) * random_pitch_multiplier[math_random(1,2)] + end + + --do animation + mobs.set_mob_animation(self, "walk") + + --do a quick turn to make mob continuously move + --if in a fish tank or something + if swim_turn_check(self,dtime) then + quick_rotate(self,dtime) + end + + mobs.set_swim_velocity(self,self.walk_velocity) + + --only enable tilt swimming if enabled + if self.tilt_swim then + mobs.set_dynamic_pitch(self) + end + + --enable rotation locking + mobs.movement_rotation_lock(self) + end + --flop around if not inside swim node + else + --do animation + mobs.set_mob_animation(self, "stand") + + mobs.flop(self) + + if self.tilt_swim then + mobs.set_static_pitch(self) + end + end + +end + + +--[[ +______ _ +| ___| | +| |_ | |_ _ +| _| | | | | | +| | | | |_| | +\_| |_|\__, | + __/ | + |___/ +]]-- + +-- state switching logic (stand, walk, run, attacks) +local fly_state_list_wandering = {"stand", "fly"} + +local fly_state_switch = function(self, dtime) + + if self.hostile and self.attacking then + self.state = "attack" + return + end + + self.state_timer = self.state_timer - dtime + if self.state_timer <= 0 then + self.state_timer = math.random(4,10) + math.random() + self.state = fly_state_list_wandering[math.random(1,#fly_state_list_wandering)] + end +end + + +--check if a mob needs to turn while flying +local fly_turn_check = function(self,dtime) + + local pos = self.object:get_pos() + pos.y = pos.y + 0.1 + local dir = minetest_yaw_to_dir(self.yaw) + + local collisionbox = self.object:get_properties().collisionbox + local radius = collisionbox[4] + 0.5 + + vector_multiply(dir, radius) + + local test_dir = vector.add(pos,dir) + + local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0 + + return(green_flag_1) +end + +--this is to swap the built in engine acceleration modifier +local fly_physics_swapper = function(self,inside_fly_node) + + --should be flyming, gravity is applied, switch to floating + if inside_fly_node and self.object:get_acceleration().y ~= 0 then + self.object:set_acceleration(vector_new(0,0,0)) + --not be fly, gravity isn't applied, switch to falling + elseif not inside_fly_node and self.object:get_acceleration().y == 0 then + self.pitch = 0 + self.object:set_acceleration(vector_new(0,-self.gravity,0)) + end +end + + +local random_pitch_multiplier = {-1,1} +-- states are executed here +local fly_state_execution = function(self,dtime) + local pos = self.object:get_pos() + pos.y = pos.y + 0.1 + local current_node = minetest_get_node(pos).name + local inside_fly_node = minetest_get_item_group(current_node, "solid") == 0 + + local float_now = false + --recheck if in water or lava + if minetest_get_item_group(current_node, "water") ~= 0 or minetest_get_item_group(current_node, "lava") ~= 0 then + inside_fly_node = false + float_now = true + end + + --turn gravity on or off + fly_physics_swapper(self,inside_fly_node) + + --fly properly if inside fly node + if inside_fly_node then + if self.state == "stand" then + + --do animation + mobs.set_mob_animation(self, "stand") + + mobs.set_fly_velocity(self,0) + + if self.tilt_fly then + mobs.set_static_pitch(self) + end + + mobs.lock_yaw(self) + + elseif self.state == "fly" then + + self.walk_timer = self.walk_timer - dtime + + --reset the walk timer + if self.walk_timer <= 0 then + + --re-randomize the walk timer + self.walk_timer = math.random(1,6) + math.random() + + --set the mob into a random direction + self.yaw = (math_random() * (math.pi * 2)) + + --create a truly random pitch, since there is no easy access to pitch math that I can find + self.pitch = math_random() * math.random(1,3) * random_pitch_multiplier[math_random(1,2)] + end + + --do animation + mobs.set_mob_animation(self, "walk") + + --do a quick turn to make mob continuously move + --if in a bird cage or something + if fly_turn_check(self,dtime) then + quick_rotate(self,dtime) + end + + if self.tilt_fly then + mobs.set_dynamic_pitch(self) + end + + mobs.set_fly_velocity(self,self.walk_velocity) + + --enable rotation locking + mobs.movement_rotation_lock(self) + + elseif self.state == "attack" then + + --execute mob attack type + --if self.attack_type == "explode" then + + --mobs.explode_attack_fly(self, dtime) + + --elseif self.attack_type == "punch" then + + --mobs.punch_attack_fly(self,dtime) + + if self.attack_type == "projectile" then + + mobs.projectile_attack_fly(self,dtime) + + end + end + else + --make the mob float + if self.floats and float_now then + mobs.set_velocity(self, 0) + + mobs.float(self) + + if self.tilt_fly then + mobs.set_static_pitch(self) + end + end + end +end + + +--[[ + ___ + |_ | + | |_ _ _ __ ___ _ __ + | | | | | '_ ` _ \| '_ \ +/\__/ / |_| | | | | | | |_) | +\____/ \__,_|_| |_| |_| .__/ + | | + |_| +]]-- + + +--check if a mob needs to turn while jumping +local jump_turn_check = function(self,dtime) + + local pos = self.object:get_pos() + pos.y = pos.y + 0.1 + local dir = minetest_yaw_to_dir(self.yaw) + + local collisionbox = self.object:get_properties().collisionbox + local radius = collisionbox[4] + 0.5 + + vector_multiply(dir, radius) + + local test_dir = vector.add(pos,dir) + + local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0 + + return(green_flag_1) +end + +-- state switching logic (stand, jump, run, attacks) +local jump_state_list_wandering = {"stand", "jump"} + +local jump_state_switch = function(self, dtime) + self.state_timer = self.state_timer - dtime + if self.state_timer <= 0 then + self.state_timer = math.random(4,10) + math.random() + self.state = jump_state_list_wandering[math.random(1,#jump_state_list_wandering)] + end +end + +-- states are executed here +local jump_state_execution = function(self,dtime) + + local pos = self.object:get_pos() + local collisionbox = self.object:get_properties().collisionbox + --get the center of the mob + pos.y = pos.y + (collisionbox[2] + collisionbox[5] / 2) + local current_node = minetest_get_node(pos).name + + local float_now = false + + --recheck if in water or lava + if minetest_get_item_group(current_node, "water") ~= 0 or minetest_get_item_group(current_node, "lava") ~= 0 then + float_now = true + end + + if self.state == "stand" then + + --do animation + mobs.set_mob_animation(self, "stand") + + --set the velocity of the mob + mobs.set_velocity(self,0) + + mobs.lock_yaw(self) + + elseif self.state == "jump" then + + self.walk_timer = self.walk_timer - dtime + + --reset the jump timer + if self.walk_timer <= 0 then + + --re-randomize the jump timer + self.walk_timer = math.random(1,6) + math.random() + + --set the mob into a random direction + self.yaw = (math_random() * (math.pi * 2)) + end + + --do animation + mobs.set_mob_animation(self, "walk") + + --enable rotation locking + mobs.movement_rotation_lock(self) + + --jumping mobs are more loosey goosey + if node_in_front_of == 1 then + quick_rotate(self,dtime) + end + + --only move forward if path is clear + mobs.jump_move(self,self.walk_velocity) + + elseif self.state == "run" then + + print("run") + + elseif self.state == "attack" then + + print("attack") + + end + + if float_now then + mobs.float(self) + end +end + + + + +--[[ +___ ___ _ _ _ +| \/ | (_) | | (_) +| . . | __ _ _ _ __ | | ___ __ _ _ ___ +| |\/| |/ _` | | '_ \ | | / _ \ / _` | |/ __| +| | | | (_| | | | | | | |___| (_) | (_| | | (__ +\_| |_/\__,_|_|_| |_| \_____/\___/ \__, |_|\___| + __/ | + |___/ +]]-- + +--the main loop +mobs.mob_step = function(self, dtime) + + --do not continue if non-existent + if not self or not self.object or not self.object:get_luaentity() then + self.object:remove() + return false + end + + + --DEBUG TIME! + --REMEMBER TO MOVE THIS AFTER DEATH CHECK + + --if self.has_head then + -- mobs.do_head_logic(self,dtime) + --end + + + + --if true then--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG + -- return + --end + + --despawn mechanism + --don't despawned tamed or bred mobs + if not self.tamed and not self.bred then + self.lifetimer = self.lifetimer - dtime + if self.lifetimer <= 0 then + self.lifetimer = self.lifetimer_reset + if not mobs.check_for_player_within_area(self, 64) then + --print("removing in MAIN LOGIC!") + self.object:remove() + return + end + end + end + + --color modifier which coincides with the pause_timer + if self.old_health and self.health < self.old_health then + self.object:set_texture_mod("^[colorize:red:120") + --fix double death sound + if self.health > 0 then + mobs.play_sound(self,"damage") + end + end + self.old_health = self.health + + --do death logic (animation, poof, explosion, etc) + if self.health <= 0 or self.dead then + --play death sound once + if not self.played_death_sound then + self.dead = true + mobs.play_sound(self,"death") + self.played_death_sound = true + end + + mobs.death_logic(self, dtime) + + --this is here because the mob must continue to move + --while stunned before coming to a complete halt even during + --the death tilt + if self.pause_timer > 0 then + self.pause_timer = self.pause_timer - dtime + --perfectly reset pause_timer + if self.pause_timer < 0 then + self.pause_timer = 0 + end + end + + return + end + + mobs.random_sound_handling(self,dtime) + + --mobs drowning mechanic + if not self.breathes_in_water then + + local pos = self.object:get_pos() + + pos.y = pos.y + self.eye_height + + local node = minetest_get_node(pos).name + + if minetest_get_item_group(node, "water") ~= 0 then + self.breath = self.breath - dtime + + --reset breath when drowning + if self.breath <= 0 then + self.health = self.health - 4 + self.breath = 1 + self.pause_timer = 0.5 + end + + elseif self.breath < self.breath_max then + self.breath = self.breath + dtime + + --clean timer reset + if self.breath > self.breath_max then + self.breath = self.breath_max + end + end + end + + --set mobs on fire when burned by sunlight + if self.ignited_by_sunlight then + local pos = self.object:get_pos() + pos.y = pos.y + 0.1 + + if self.burn_timer > 0 then + self.burn_timer = self.burn_timer - dtime + + if self.burn_timer <= 0 then + self.health = self.health - 4 + self.burn_timer = 0 + end + end + + if self.burn_timer == 0 and minetest_get_node_light(pos) > 12 and minetest_get_node_light(pos, 0.5) == 15 then + mcl_burning.set_on_fire(self.object, 1) + self.burn_timer = 1 --1.7 seconds + self.pause_timer = 0.4 + end + end + + + + + + --baby grows up + if self.baby then + --print(self.grow_up_timer) + --catch missing timer + if not self.grow_up_timer then + self.grow_up_timer = self.grow_up_goal + end + + self.grow_up_timer = self.grow_up_timer - dtime + + --baby grows up! + if self.grow_up_timer <= 0 then + self.grow_up_timer = 0 + mobs.baby_grow_up(self) + end + end + + + + --do custom mob instructions + if self.do_custom then + -- when false skip going any further + if self.do_custom(self, dtime) == false then + --this needs to be here or the mob becomes immortal + if self.pause_timer > 0 then + self.pause_timer = self.pause_timer - dtime + --perfectly reset pause_timer + if self.pause_timer <= 0 then + self.pause_timer = 0 + self.object:set_texture_mod("") + end + end + --this overrides internal lua collision detection + return + end + end + + local attacking = nil + + --scan for players within eyesight + if self.hostile then + --true for line_of_sight is debug + attacking = mobs.detect_closest_player_within_radius(self,true,self.view_range,self.eye_height) + + --go get the closest player + if attacking then + + self.memory = 6 --6 seconds of memory + + --set initial punch timer + if self.attacking == nil then + if self.attack_type == "punch" then + self.punch_timer = -1 + end + end + self.attacking = attacking + + --no player in area + elseif self.memory > 0 then + --try to remember + self.memory = self.memory - dtime + --get if memory player is within viewing range + if self.attacking and self.attacking:is_player() then + local distance = vector_distance(self.object:get_pos(), self.attacking:get_pos()) + if distance > self.view_range then + self.memory = 0 + end + --out of viewing range, forget em + else + self.memory = 0 + end + + if self.memory <= 0 then + + --reset states when coming out of hostile state + if self.attacking ~= nil then + self.state_timer = -1 + end + + self.attacking = nil + self.memory = 0 + end + end + end + + --count down hostile cooldown timer when no players in range + if self.neutral and self.hostile and not attacking and self.hostile_cooldown_timer then + + self.hostile_cooldown_timer = self.hostile_cooldown_timer - dtime + + if self.hostile_cooldown_timer <= 0 then + self.hostile = false + self.hostile_cooldown_timer = 0 + end + end + + --mob is stunned after being hit + if self.pause_timer > 0 then + self.pause_timer = self.pause_timer - dtime + --don't break eye contact + if self.hostile and self.attacking then + mobs.set_yaw_while_attacking(self) + end + + --perfectly reset pause_timer + if self.pause_timer <= 0 then + self.pause_timer = 0 + self.object:set_texture_mod("") + end + + --stop walking mobs from falling through the water + if not self.jump_only and not self.swim and not self.fly then + local pos = self.object:get_pos() + local collisionbox = self.object:get_properties().collisionbox + --get the center of the mob + pos.y = pos.y + (collisionbox[2] + collisionbox[5] / 2) + local current_node = minetest_get_node(pos).name + + --recheck if in water or lava + if minetest_get_item_group(current_node, "water") ~= 0 or minetest_get_item_group(current_node, "lava") ~= 0 then + mobs.float(self) + end + end + + --stop projectile mobs from being completely disabled while stunned + if self.projectile_timer and self.projectile_timer > 0.01 then + self.projectile_timer = self.projectile_timer - dtime + if self.projectile_timer < 0.01 then + self.projectile_timer = 0.01 + end + end + + return -- don't allow collision detection + --do normal ai + else + --jump only (like slimes) + if self.jump_only then + jump_state_switch(self, dtime) + jump_state_execution(self, dtime) + --swimming + elseif self.swim then + swim_state_switch(self, dtime) + swim_state_execution(self, dtime) + --flying + elseif self.fly then + fly_state_switch(self, dtime) + fly_state_execution(self,dtime) + --regular mobs that walk around + else + land_state_switch(self, dtime) + land_state_execution(self,dtime) + end + end + + --do not continue if non-existent + if not self or not self.object or not self.object:get_luaentity() then + self.object:remove() + return false + end + + --make it so mobs do not glitch out when walking around/jumping + mobs.swap_auto_step_height_adjust(self) + + + -- can mob be pushed, if so calculate direction -- do this last (overrides everything) + if self.pushable then + mobs.collision(self) + end + + --overrides absolutely everything + --mobs get stuck in cobwebs like players + if not self.ignores_cobwebs then + + local pos = self.object:get_pos() + local node = pos and minetest_get_node(pos).name + + if node == "mcl_core:cobweb" then + + --fight the rest of the api + if self.object:get_acceleration().y ~= 0 then + self.object:set_acceleration(vector_new(0,0,0)) + end + + mobs.stick_in_cobweb(self) + + self.was_stuck_in_cobweb = true + + else + --do not override other functions + if self.was_stuck_in_cobweb == true then + --return the mob back to normal + self.was_stuck_in_cobweb = nil + if self.object:get_acceleration().y == 0 and not self.swim and not self.fly then + self.object:set_acceleration(vector_new(0,-self.gravity,0)) + end + end + end + end + + self.old_velocity = self.object:get_velocity() + self.old_pos = self.object:get_pos() +end diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/animation.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/animation.lua new file mode 100644 index 000000000..c26d33089 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/animation.lua @@ -0,0 +1,259 @@ +local math_pi = math.pi +local math_floor = math.floor +local math_random = math.random +local HALF_PI = math_pi/2 + + +local vector_direction = vector.direction +local vector_distance = vector.distance +local vector_new = vector.new + +local minetest_dir_to_yaw = minetest.dir_to_yaw + +-- set defined animation +mobs.set_mob_animation = function(self, anim, fixed_frame) + + if not self.animation or not anim then + return + end + + if self.state == "die" and anim ~= "die" and anim ~= "stand" then + return + end + + + if (not self.animation[anim .. "_start"] or not self.animation[anim .. "_end"]) then + return + end + + --animations break if they are constantly set + --so we put this return gate to check if it is + --already at the animation we are trying to implement + if self.current_animation == anim then + return + end + + local a_start = self.animation[anim .. "_start"] + local a_end + + if fixed_frame then + a_end = a_start + else + a_end = self.animation[anim .. "_end"] + end + + self.object:set_animation({ + x = a_start, + y = a_end}, + self.animation[anim .. "_speed"] or self.animation.speed_normal or 15, + 0, self.animation[anim .. "_loop"] ~= false) + + + self.current_animation = anim +end + + + + +mobs.death_effect = function(pos, yaw, collisionbox, rotate) + local min, max + if collisionbox then + min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]} + max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]} + else + min = { x = -0.5, y = 0, z = -0.5 } + max = { x = 0.5, y = 0.5, z = 0.5 } + end + if rotate then + min = vector.rotate(min, {x=0, y=yaw, z=math_pi/2}) + max = vector.rotate(max, {x=0, y=yaw, z=math_pi/2}) + min, max = vector.sort(min, max) + min = vector.multiply(min, 0.5) + max = vector.multiply(max, 0.5) + end + + minetest_add_particlespawner({ + amount = 50, + time = 0.001, + minpos = vector.add(pos, min), + maxpos = vector.add(pos, max), + minvel = vector_new(-5,-5,-5), + maxvel = vector_new(5,5,5), + minexptime = 1.1, + maxexptime = 1.5, + minsize = 1, + maxsize = 2, + collisiondetection = false, + vertical = false, + texture = "mcl_particles_mob_death.png^[colorize:#000000:255", + }) + + minetest_sound_play("mcl_mobs_mob_poof", { + pos = pos, + gain = 1.0, + max_hear_distance = 8, + }, true) +end + + +--this allows auto facedir rotation while making it so mobs +--don't look like wet noodles flopping around +mobs.movement_rotation_lock = function(self) + + local current_engine_yaw = self.object:get_yaw() + local current_lua_yaw = self.yaw + + if current_engine_yaw > math.pi * 2 then + current_engine_yaw = current_engine_yaw - (math.pi * 2) + end + + if math.abs(current_engine_yaw - current_lua_yaw) <= 0.05 and self.object:get_properties().automatic_face_movement_dir then + self.object:set_properties{automatic_face_movement_dir = false} + elseif math.abs(current_engine_yaw - current_lua_yaw) > 0.05 and self.object:get_properties().automatic_face_movement_dir == false then + self.object:set_properties{automatic_face_movement_dir = self.rotate} + end +end + + +--this is used when a mob is chasing a player +mobs.set_yaw_while_attacking = function(self) + + if self.object:get_properties().automatic_face_movement_dir then + self.object:set_properties{automatic_face_movement_dir = false} + end + + --turn positions into pseudo 2d vectors + local pos1 = self.object:get_pos() + pos1.y = 0 + + local pos2 = self.attacking:get_pos() + pos2.y = 0 + + local new_direction = vector_direction(pos1,pos2) + local new_yaw = minetest_dir_to_yaw(new_direction) + + self.object:set_yaw(new_yaw) + self.yaw = new_yaw +end + +--this is used to unlock a mob's yaw after attacking +mobs.unlock_yaw = function(self) + if self.object:get_properties().automatic_face_movement_dir == false then + self.object:set_properties{automatic_face_movement_dir = self.rotate} + end +end + +--this is used to lock a mob's yaw when they're standing +mobs.lock_yaw = function(self) + if self.object:get_properties().automatic_face_movement_dir then + self.object:set_properties{automatic_face_movement_dir = false} + end +end + + +local calculate_pitch = function(self) + local pos = self.object:get_pos() + local pos2 = self.old_pos + + if pos == nil or pos2 == nil then + return false + end + + return(minetest_dir_to_yaw(vector_new(vector_distance(vector_new(pos.x,0,pos.z),vector_new(pos2.x,0,pos2.z)),0,pos.y - pos2.y)) + HALF_PI) +end + +--this is a helper function used to make mobs pitch rotation dynamically flow when flying/swimming +mobs.set_dynamic_pitch = function(self) + local pitch = calculate_pitch(self) + + if not pitch then + return + end + + local current_rotation = self.object:get_rotation() + + current_rotation.x = pitch + + self.object:set_rotation(current_rotation) + + self.pitch_switch = "dynamic" +end + +--this is a helper function used to make mobs pitch rotation reset when flying/swimming +mobs.set_static_pitch = function(self) + + if self.pitch_switch == "static" then + return + end + + local current_rotation = self.object:get_rotation() + + current_rotation.x = 0 + + self.object:set_rotation(current_rotation) + self.pitch_switch = "static" +end + +--this is a helper function for mobs explosion animation +mobs.handle_explosion_animation = function(self) + + --secondary catch-all + if not self.explosion_animation then + self.explosion_animation = 0 + end + + --the timer works from 0 for sense of a 0 based counting + --but this just bumps it up so it's usable in here + local explosion_timer_adjust = self.explosion_animation + 1 + + + local visual_size_modified = table.copy(self.visual_size_origin) + + visual_size_modified.x = visual_size_modified.x * (explosion_timer_adjust ^ 3) + visual_size_modified.y = visual_size_modified.y * explosion_timer_adjust + + self.object:set_properties({visual_size = visual_size_modified}) +end + + +--this is used when a mob is following player +mobs.set_yaw_while_following = function(self) + + if self.object:get_properties().automatic_face_movement_dir then + self.object:set_properties{automatic_face_movement_dir = false} + end + + --turn positions into pseudo 2d vectors + local pos1 = self.object:get_pos() + pos1.y = 0 + + local pos2 = self.following_person:get_pos() + pos2.y = 0 + + local new_direction = vector_direction(pos1,pos2) + local new_yaw = minetest_dir_to_yaw(new_direction) + + self.object:set_yaw(new_yaw) + self.yaw = new_yaw +end + +--this is used for when mobs breed +mobs.set_yaw_while_breeding = function(self, mate) + + if self.object:get_properties().automatic_face_movement_dir then + self.object:set_properties{automatic_face_movement_dir = false} + end + + --turn positions into pseudo 2d vectors + local pos1 = self.object:get_pos() + pos1.y = 0 + + local pos2 = mate:get_pos() + pos2.y = 0 + + local new_direction = vector_direction(pos1,pos2) + local new_yaw = minetest_dir_to_yaw(new_direction) + + self.object:set_yaw(new_yaw) + self.yaw = new_yaw +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/attack_type_instructions.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/attack_type_instructions.lua new file mode 100644 index 000000000..c973f3d1b --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/attack_type_instructions.lua @@ -0,0 +1,351 @@ +local vector_direction = vector.direction +local minetest_dir_to_yaw = minetest.dir_to_yaw +local vector_distance = vector.distance +local vector_multiply = vector.multiply +local math_random = math.random + +--[[ + _ _ _ _ +| | | | | | | | +| | | | __ _ _ __ __| | | | +| | | | / _` | '_ \ / _` | | | +|_| | |___| (_| | | | | (_| | |_| +(_) \_____/\__,_|_| |_|\__,_| (_) +]]-- + + + +--[[ + _____ _ _ +| ___| | | | | +| |____ ___ __ | | ___ __| | ___ +| __\ \/ / '_ \| |/ _ \ / _` |/ _ \ +| |___> <| |_) | | (_) | (_| | __/ +\____/_/\_\ .__/|_|\___/ \__,_|\___| + | | + |_| +]]-- + +mobs.explode_attack_walk = function(self,dtime) + + --this needs an exception + if self.attacking == nil or not self.attacking:is_player() then + self.attacking = nil + return + end + + mobs.set_yaw_while_attacking(self) + + local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos()) + + --make mob walk up to player within 2 nodes distance then start exploding + if distance_from_attacking >= self.reach and + --don't allow explosion to cancel unless out of the reach boundary + not (self.explosion_animation ~= nil and self.explosion_animation > 0 and distance_from_attacking <= self.defuse_reach) then + + mobs.set_velocity(self, self.run_velocity) + mobs.set_mob_animation(self,"run") + + mobs.reverse_explosion_animation(self,dtime) + else + mobs.set_velocity(self,0) + + --this is the only way I can reference this without dumping extra data on all mobs + if not self.explosion_animation then + self.explosion_animation = 0 + end + + --play ignite sound + if self.explosion_animation == 0 then + mobs.play_sound(self,"attack") + end + + mobs.set_mob_animation(self,"stand") + + mobs.handle_explosion_animation(self) + + self.explosion_animation = self.explosion_animation + (dtime/2.5) + end + + --make explosive mobs jump + --check for nodes to jump over + --explosive mobs will just ride against walls for now + local node_in_front_of = mobs.jump_check(self) + if node_in_front_of == 1 then + mobs.jump(self) + end + + + --do biggening explosion thing + if self.explosion_animation and self.explosion_animation > self.explosion_timer then + mcl_explosions.explode(self.object:get_pos(), self.explosion_strength,{ drop_chance = 1.0 }) + self.object:remove() + end +end + + +--this is a small helper function to make working with explosion animations easier +mobs.reverse_explosion_animation = function(self,dtime) + + --if explosion animation was greater than 0 then reverse it + if self.explosion_animation ~= nil and self.explosion_animation > 0 then + self.explosion_animation = self.explosion_animation - dtime + if self.explosion_animation < 0 then + self.explosion_animation = 0 + end + end + + mobs.handle_explosion_animation(self) +end + + + + +--[[ +______ _ +| ___ \ | | +| |_/ / _ _ __ ___| |__ +| __/ | | | '_ \ / __| '_ \ +| | | |_| | | | | (__| | | | +\_| \__,_|_| |_|\___|_| |_| +]]-- + + + +mobs.punch_attack_walk = function(self,dtime) + + --this needs an exception + if self.attacking == nil or not self.attacking:is_player() then + self.attacking = nil + return + end + + local distance_from_attacking = mobs.get_2d_distance(self.object:get_pos(), self.attacking:get_pos()) + + if distance_from_attacking >= self.minimum_follow_distance then + mobs.set_velocity(self, self.run_velocity) + mobs.set_mob_animation(self, "run") + else + mobs.set_velocity(self, 0) + mobs.set_mob_animation(self, "stand") + end + + mobs.set_yaw_while_attacking(self) + + --make punchy mobs jump + --check for nodes to jump over + --explosive mobs will just ride against walls for now + local node_in_front_of = mobs.jump_check(self) + + if node_in_front_of == 1 then + mobs.jump(self) + end + + --mobs that can climb over stuff + if self.always_climb and node_in_front_of > 0 then + mobs.climb(self) + end + + + --auto reset punch_timer + if not self.punch_timer then + self.punch_timer = 0 + end + + if self.punch_timer > 0 then + self.punch_timer = self.punch_timer - dtime + end +end + +mobs.punch_attack = function(self) + + self.attacking:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = self.damage} + }, nil) + + self.punch_timer = self.punch_timer_cooloff + + + --knockback + local pos1 = self.object:get_pos() + pos1.y = 0 + local pos2 = self.attacking:get_pos() + pos2.y = 0 + local dir = vector_direction(pos1,pos2) + + dir = vector_multiply(dir,3) + + if self.attacking:get_velocity().y <= 1 then + dir.y = 5 + end + + self.attacking:add_velocity(dir) +end + + + + +--[[ +______ _ _ _ _ +| ___ \ (_) | | (_) | +| |_/ / __ ___ _ ___ ___| |_ _| | ___ +| __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \ +| | | | | (_) | | __/ (__| |_| | | __/ +\_| |_| \___/| |\___|\___|\__|_|_|\___| + _/ | + |__/ +]]-- + + +mobs.projectile_attack_walk = function(self,dtime) + + --this needs an exception + if self.attacking == nil or not self.attacking:is_player() then + self.attacking = nil + return + end + + mobs.set_yaw_while_attacking(self) + + local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos()) + + + if distance_from_attacking >= self.reach then + mobs.set_velocity(self, self.run_velocity) + mobs.set_mob_animation(self,"run") + else + mobs.set_velocity(self,0) + mobs.set_mob_animation(self,"stand") + end + + --do this to not load data into other mobs + if not self.projectile_timer then + self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max) + end + + --run projectile timer + if self.projectile_timer > 0 then + self.projectile_timer = self.projectile_timer - dtime + + --shoot + if self.projectile_timer <= 0 then + --reset timer + self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max) + mobs.shoot_projectile(self) + end + end + + --make shooty mobs jump + --check for nodes to jump over + --explosive mobs will just ride against walls for now + local node_in_front_of = mobs.jump_check(self) + if node_in_front_of == 1 then + mobs.jump(self) + end + +end + + + + + + + + + +--[[ + _ ______ _ _ +| | | ___| | | | +| | | |_ | |_ _ | | +| | | _| | | | | | | | +|_| | | | | |_| | |_| +(_) \_| |_|\__, | (_) + __/ | + |___/ +]]-- + + + + +--[[ +______ _ _ _ _ +| ___ \ (_) | | (_) | +| |_/ / __ ___ _ ___ ___| |_ _| | ___ +| __/ '__/ _ \| |/ _ \/ __| __| | |/ _ \ +| | | | | (_) | | __/ (__| |_| | | __/ +\_| |_| \___/| |\___|\___|\__|_|_|\___| + _/ | + |__/ +]]-- + +local random_pitch_multiplier = {-1,1} + +mobs.projectile_attack_fly = function(self, dtime) + + --this needs an exception + if self.attacking == nil or not self.attacking:is_player() then + self.attacking = nil + return + end + + --this is specifically for random ghast movement + if self.fly_random_while_attack then + + --enable rotation locking + mobs.movement_rotation_lock(self) + + self.walk_timer = self.walk_timer - dtime + + --reset the walk timer + if self.walk_timer <= 0 then + --re-randomize the walk timer + self.walk_timer = math.random(1,6) + math.random() + --set the mob into a random direction + self.yaw = (math_random() * (math.pi * 2)) + --create a truly random pitch, since there is no easy access to pitch math that I can find + self.pitch = math_random() * math.random(1,3) * random_pitch_multiplier[math_random(1,2)] + end + + mobs.set_fly_velocity(self, self.run_velocity) + + else + + mobs.set_yaw_while_attacking(self) + + local distance_from_attacking = vector_distance(self.object:get_pos(), self.attacking:get_pos()) + + if distance_from_attacking >= self.reach then + mobs.set_pitch_while_attacking(self) + mobs.set_fly_velocity(self, self.run_velocity) + mobs.set_mob_animation(self,"run") + else + mobs.set_pitch_while_attacking(self) + mobs.set_fly_velocity(self, 0) + mobs.set_mob_animation(self,"stand") + end + end + + + --do this to not load data into other mobs + if not self.projectile_timer then + self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max) + end + + --run projectile timer + if self.projectile_timer > 0 then + self.projectile_timer = self.projectile_timer - dtime + + --shoot + if self.projectile_timer <= 0 then + + if self.fly_random_while_attack then + mobs.set_yaw_while_attacking(self) + self.walk_timer = 0 + end + --reset timer + self.projectile_timer = math_random(self.projectile_cooldown_min, self.projectile_cooldown_max) + mobs.shoot_projectile(self) + end + end +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua similarity index 55% rename from mods/ENTITIES/mcl_mobs/api.lua rename to mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua index bc4d3067d..d5b644f73 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua @@ -1,118 +1,3 @@ - --- API for Mobs Redo: MineClone 2 Edition (MRM) - -mobs = {} -mobs.mod = "mrm" -mobs.version = "20210106" -- don't rely too much on this, rarely updated, if ever - -local MAX_MOB_NAME_LENGTH = 30 -local HORNY_TIME = 30 -local HORNY_AGAIN_TIME = 300 -local CHILD_GROW_TIME = 60*20 -local DEATH_DELAY = 0.5 -local DEFAULT_FALL_SPEED = -10 -local FLOP_HEIGHT = 5.0 -local FLOP_HOR_SPEED = 1.5 - -local MOB_CAP = {} -MOB_CAP.hostile = 70 -MOB_CAP.passive = 10 -MOB_CAP.ambient = 15 -MOB_CAP.water = 15 - --- Localize -local S = minetest.get_translator("mcl_mobs") - --- CMI support check -local use_cmi = minetest.global_exists("cmi") - - --- Invisibility mod check -mobs.invis = {} -if minetest.global_exists("invisibility") then - mobs.invis = invisibility -end - - --- creative check -function mobs.is_creative(name) - return minetest.is_creative_enabled(name) -end - - --- localize math functions -local pi = math.pi -local sin = math.sin -local cos = math.cos -local abs = math.abs -local min = math.min -local max = math.max -local atann = math.atan -local random = math.random -local floor = math.floor -local atan = function(x) - if not x or x ~= x then - return 0 - else - return atann(x) - end -end - - --- Load settings -local damage_enabled = minetest.settings:get_bool("enable_damage") -local disable_blood = minetest.settings:get_bool("mobs_disable_blood") -local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false -local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false -local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false -local remove_far = true -local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0 -local show_health = false -local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 64) -local mobs_spawn_chance = tonumber(minetest.settings:get("mobs_spawn_chance") or 2.5) - --- Shows helpful debug info above each mob -local mobs_debug = minetest.settings:get_bool("mobs_debug", false) - --- Peaceful mode message so players will know there are no monsters -if minetest.settings:get_bool("only_peaceful_mobs", false) then - minetest.register_on_joinplayer(function(player) - minetest.chat_send_player(player:get_player_name(), - S("Peaceful mode active! No monsters will spawn.")) - end) -end - --- pathfinding settings -local enable_pathfinding = true -local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching -local stuck_path_timeout = 10 -- how long will mob follow path before giving up - --- default nodes -local node_ice = "mcl_core:ice" -local node_snowblock = "mcl_core:snowblock" -local node_snow = "mcl_core:snow" -mobs.fallback_node = minetest.registered_aliases["mapgen_dirt"] or "mcl_core:dirt" - -local mod_weather = minetest.get_modpath("mcl_weather") ~= nil -local mod_explosions = minetest.get_modpath("mcl_explosions") ~= nil -local mod_mobspawners = minetest.get_modpath("mcl_mobspawners") ~= nil -local mod_hunger = minetest.get_modpath("mcl_hunger") ~= nil -local mod_worlds = minetest.get_modpath("mcl_worlds") ~= nil -local mod_armor = minetest.get_modpath("mcl_armor") ~= nil -local mod_experience = minetest.get_modpath("mcl_experience") ~= nil - -----For Water Flowing: -local enable_physics = function(object, luaentity, ignore_check) - if luaentity.physical_state == false or ignore_check == true then - luaentity.physical_state = true - object:set_properties({ - physical = true - }) - object:set_velocity({x=0,y=0,z=0}) - object:set_acceleration({x=0,y=-9.81,z=0}) - end -end - local disable_physics = function(object, luaentity, ignore_check, reset_movement) if luaentity.physical_state == true or ignore_check == true then luaentity.physical_state = false @@ -126,630 +11,912 @@ local disable_physics = function(object, luaentity, ignore_check, reset_movement end end - --- play sound -local mob_sound = function(self, soundname, is_opinion, fixed_pitch) - - local soundinfo - if self.sounds_child and self.child then - soundinfo = self.sounds_child - elseif self.sounds then - soundinfo = self.sounds +----For Water Flowing: +local enable_physics = function(object, luaentity, ignore_check) + if luaentity.physical_state == false or ignore_check == true then + luaentity.physical_state = true + object:set_properties({ + physical = true + }) + object:set_velocity({x=0,y=0,z=0}) + object:set_acceleration({x=0,y=-9.81,z=0}) end - if not soundinfo then - return - end - local sound = soundinfo[soundname] - if sound then - if is_opinion and self.opinion_sound_cooloff > 0 then - return - end - local pitch - if not fixed_pitch then - local base_pitch = soundinfo.base_pitch - if not base_pitch then - base_pitch = 1 +end + +--[[ +local timer = 0 +minetest.register_globalstep(function(dtime) + timer = timer + dtime + if timer < 1 then return end + for _, player in pairs(minetest.get_connected_players()) do + local pos = player:get_pos() + for _, obj in pairs(minetest_get_objects_inside_radius(pos, 47)) do + local lua = obj:get_luaentity() + if lua and lua._cmi_is_mob then + lua.lifetimer = math.max(20, lua.lifetimer) + lua.despawn_immediately = false end - if self.child and (not self.sounds_child) then - -- Children have higher pitch - pitch = base_pitch * 1.5 - else - pitch = base_pitch + end + end + timer = 0 +end) +]]-- + +-- compatibility function for old entities to new modpack entities +function mobs:alias_mob(old_name, new_name) + + -- spawn egg + minetest.register_alias(old_name, new_name) + + -- entity + minetest.register_entity(":" .. old_name, { + + physical = false, + + on_step = function(self) + + if minetest_registered_entities[new_name] then + minetest_add_entity(self.object:get_pos(), new_name) end - -- randomize the pitch a bit - pitch = pitch + math.random(-10, 10) * 0.005 + + self.object:remove() end - minetest.sound_play(sound, { - object = self.object, - gain = 1.0, - max_hear_distance = self.sounds.distance, - pitch = pitch, - }, true) - self.opinion_sound_cooloff = 1 - end -end - --- Return true if object is in view_range -local function object_in_range(self, object) - if not object then - return false - end - local factor - -- Apply view range reduction for special player armor - if object:is_player() and mod_armor then - local factors = mcl_armor.player_view_range_factors[object] - factor = factors and factors[self.name] - end - -- Distance check - local dist - if factor and factor == 0 then - return false - elseif factor then - dist = self.view_range * factor - else - dist = self.view_range - end - - local p1, p2 = self.object:get_pos(), object:get_pos() - return p1 and p2 and (vector.distance(p1, p2) <= dist) -end - --- attack player/mob -local do_attack = function(self, player) - - if self.state == "attack" or self.state == "die" then - return - end - - self.attack = player - self.state = "attack" - - -- TODO: Implement war_cry sound without being annoying - --if random(0, 100) < 90 then - --mob_sound(self, "war_cry", true) - --end -end - - --- collision function borrowed amended from jordan4ibanez open_ai mod -local collision = function(self) - - local pos = self.object:get_pos() - local vel = self.object:get_velocity() - local x = 0 - local z = 0 - local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5 - - for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do - - if object:is_player() - or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then - - local pos2 = object:get_pos() - local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z} - local force = (width + 0.5) - vector.distance( - {x = pos.x, y = 0, z = pos.z}, - {x = pos2.x, y = 0, z = pos2.z}) - - x = x + (vec.x * force) - z = z + (vec.z * force) - end - end - - return({x,z}) -end - --- move mob in facing direction -local set_velocity = function(self, v) - - local c_x, c_y = 0, 0 - - -- can mob be pushed, if so calculate direction - if self.pushable then - c_x, c_y = unpack(collision(self)) - end - - -- halt mob if it has been ordered to stay - if self.order == "stand" then - self.object:set_velocity({x = 0, y = 0, z = 0}) - return - end - - local yaw = (self.object:get_yaw() or 0) + self.rotate - - self.object:set_velocity({ - x = (sin(yaw) * -v) + c_x, - y = self.object:get_velocity().y, - z = (cos(yaw) * v) + c_y, }) end - - --- calculate mob velocity -local get_velocity = function(self) - - local v = self.object:get_velocity() - if v then - return (v.x * v.x + v.z * v.z) ^ 0.5 - end - - return 0 -end - -local function update_roll(self) - local is_Fleckenstein = self.nametag == "Fleckenstein" - local was_Fleckenstein = false - - local rot = self.object:get_rotation() - rot.z = is_Fleckenstein and pi or 0 - self.object:set_rotation(rot) - - local cbox = table.copy(self.collisionbox) - local acbox = self.object:get_properties().collisionbox - - if math.abs(cbox[2] - acbox[2]) > 0.1 then - was_Fleckenstein = true - end - - if is_Fleckenstein ~= was_Fleckenstein then - local pos = self.object:get_pos() - pos.y = pos.y + (acbox[2] + acbox[5]) - self.object:set_pos(pos) - end - - if is_Fleckenstein then - cbox[2], cbox[5] = -cbox[5], -cbox[2] - end - - self.object:set_properties({collisionbox = cbox}) -end - --- set and return valid yaw -local set_yaw = function(self, yaw, delay, dtime) - - if not yaw or yaw ~= yaw then - yaw = 0 - end - - delay = delay or 0 - - if delay == 0 then - if self.shaking and dtime then - yaw = yaw + (math.random() * 2 - 1) * 5 * dtime - end - self.object:set_yaw(yaw) - update_roll(self) - return yaw - end - - self.target_yaw = yaw - self.delay = delay - - return self.target_yaw -end - --- global function to set mob yaw -function mobs:yaw(self, yaw, delay, dtime) - set_yaw(self, yaw, delay, dtime) -end - -local add_texture_mod = function(self, mod) - local full_mod = "" - local already_added = false - for i=1, #self.texture_mods do - if mod == self.texture_mods[i] then - already_added = true - end - full_mod = full_mod .. self.texture_mods[i] - end - if not already_added then - full_mod = full_mod .. mod - table.insert(self.texture_mods, mod) - end - self.object:set_texture_mod(full_mod) -end -local remove_texture_mod = function(self, mod) - local full_mod = "" - local remove = {} - for i=1, #self.texture_mods do - if self.texture_mods[i] ~= mod then - full_mod = full_mod .. self.texture_mods[i] - else - table.insert(remove, i) - end - end - for i=#remove, 1 do - table.remove(self.texture_mods, remove[i]) - end - self.object:set_texture_mod(full_mod) -end - --- set defined animation -local set_animation = function(self, anim, fixed_frame) - if not self.animation or not anim then - return - end - if self.state == "die" and anim ~= "die" and anim ~= "stand" then +-- Spawn a child +function mobs:spawn_child(pos, mob_type) + local child = minetest_add_entity(pos, mob_type) + if not child then return end - self.animation.current = self.animation.current or "" + local ent = child:get_luaentity() + effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5) - if (anim == self.animation.current - or not self.animation[anim .. "_start"] - or not self.animation[anim .. "_end"]) and self.state ~= "die" then - return + ent.child = true + + local textures + -- using specific child texture (if found) + if ent.child_texture then + textures = ent.child_texture[1] end - self.animation.current = anim + -- and resize to half height + child:set_properties({ + textures = textures, + visual_size = { + x = ent.base_size.x * .5, + y = ent.base_size.y * .5, + }, + collisionbox = { + ent.base_colbox[1] * .5, + ent.base_colbox[2] * .5, + ent.base_colbox[3] * .5, + ent.base_colbox[4] * .5, + ent.base_colbox[5] * .5, + ent.base_colbox[6] * .5, + }, + selectionbox = { + ent.base_selbox[1] * .5, + ent.base_selbox[2] * .5, + ent.base_selbox[3] * .5, + ent.base_selbox[4] * .5, + ent.base_selbox[5] * .5, + ent.base_selbox[6] * .5, + }, + }) - local a_start = self.animation[anim .. "_start"] - local a_end - if fixed_frame then - a_end = a_start - else - a_end = self.animation[anim .. "_end"] - end - - self.object:set_animation({ - x = a_start, - y = a_end}, - self.animation[anim .. "_speed"] or self.animation.speed_normal or 15, - 0, self.animation[anim .. "_loop"] ~= false) + return child end --- above function exported for mount.lua -function mobs:set_animation(self, anim) - set_animation(self, anim) -end --- Returns true is node can deal damage to self -local is_node_dangerous = function(self, nodename) - local nn = nodename - if self.lava_damage > 0 then - if minetest.get_item_group(nn, "lava") ~= 0 then - return true - end - end - if self.fire_damage > 0 then - if minetest.get_item_group(nn, "fire") ~= 0 then - return true - end - end - if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].damage_per_second and minetest.registered_nodes[nn].damage_per_second > 0 then - return true - end - return false -end - - --- Returns true if node is a water hazard -local is_node_waterhazard = function(self, nodename) - local nn = nodename - if self.water_damage > 0 then - if minetest.get_item_group(nn, "water") ~= 0 then - return true - end - end - if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].drowning and minetest.registered_nodes[nn].drowning > 0 then - if self.breath_max ~= -1 then - -- check if the mob is water-breathing _and_ the block is water; only return true if neither is the case - -- this will prevent water-breathing mobs to classify water or e.g. sand below them as dangerous - if not self.breathes_in_water and minetest.get_item_group(nn, "water") ~= 0 then - return true - end - end - end - return false -end - - --- check line of sight (BrunoMine) -local line_of_sight = function(self, pos1, pos2, stepsize) - - stepsize = stepsize or 1 - - local s, pos = minetest.line_of_sight(pos1, pos2, stepsize) - - -- normal walking and flying mobs can see you through air - if s == true then - return true - end - - -- New pos1 to be analyzed - local npos1 = {x = pos1.x, y = pos1.y, z = pos1.z} - - local r, pos = minetest.line_of_sight(npos1, pos2, stepsize) - - -- Checks the return - if r == true then return true end - - -- Nodename found - local nn = minetest.get_node(pos).name - - -- Target Distance (td) to travel - local td = vector.distance(pos1, pos2) - - -- Actual Distance (ad) traveled - local ad = 0 - - -- It continues to advance in the line of sight in search of a real - -- obstruction which counts as 'normal' nodebox. - while minetest.registered_nodes[nn] - and minetest.registered_nodes[nn].walkable == false do - - -- Check if you can still move forward - if td < ad + stepsize then - return true -- Reached the target - end - - -- Moves the analyzed pos - local d = vector.distance(pos1, pos2) - - npos1.x = ((pos2.x - pos1.x) / d * stepsize) + pos1.x - npos1.y = ((pos2.y - pos1.y) / d * stepsize) + pos1.y - npos1.z = ((pos2.z - pos1.z) / d * stepsize) + pos1.z - - -- NaN checks - if d == 0 - or npos1.x ~= npos1.x - or npos1.y ~= npos1.y - or npos1.z ~= npos1.z then - return false - end - - ad = ad + stepsize - - -- scan again - r, pos = minetest.line_of_sight(npos1, pos2, stepsize) - - if r == true then return true end - - -- New Nodename found - nn = minetest.get_node(pos).name - - end - - return false -end - - --- are we flying in what we are suppose to? (taikedz) -local flight_check = function(self) - - local nod = self.standing_in - local def = minetest.registered_nodes[nod] - - if not def then return false end -- nil check - - local fly_in - if type(self.fly_in) == "string" then - fly_in = { self.fly_in } - elseif type(self.fly_in) == "table" then - fly_in = self.fly_in - else +-- feeding, taming and breeding (thanks blert2112) +function mobs:feed_tame(self, clicker, feed_count, breed, tame) + if not self.follow then return false end - for _,checknode in pairs(fly_in) do - if nod == checknode then - return true - elseif checknode == "__airlike" and def.walkable == false and - (def.liquidtype == "none" or minetest.get_item_group(nod, "fake_liquid") == 1) then - return true + -- can eat/tame with item in hand + if follow_holding(self, clicker) then + + -- if not in creative then take item + if not mobs.is_creative(clicker:get_player_name()) then + + local item = clicker:get_wielded_item() + + item:take_item() + + clicker:set_wielded_item(item) end - end - return false -end + mob_sound(self, "eat", nil, true) + -- increase health + self.health = self.health + 4 --- custom particle effects -local effect = function(pos, amount, texture, min_size, max_size, radius, gravity, glow, go_down) + if self.health >= self.hp_max then - radius = radius or 2 - min_size = min_size or 0.5 - max_size = max_size or 1 - gravity = gravity or -10 - glow = glow or 0 - go_down = go_down or false + self.health = self.hp_max - local ym - if go_down then - ym = 0 - else - ym = -radius - end - - minetest.add_particlespawner({ - amount = amount, - time = 0.25, - minpos = pos, - maxpos = pos, - minvel = {x = -radius, y = ym, z = -radius}, - maxvel = {x = radius, y = radius, z = radius}, - minacc = {x = 0, y = gravity, z = 0}, - maxacc = {x = 0, y = gravity, z = 0}, - minexptime = 0.1, - maxexptime = 1, - minsize = min_size, - maxsize = max_size, - texture = texture, - glow = glow, - }) -end - -local damage_effect = function(self, damage) - -- damage particles - if (not disable_blood) and damage > 0 then - - local amount_large = math.floor(damage / 2) - local amount_small = damage % 2 - - local pos = self.object:get_pos() - - pos.y = pos.y + (self.collisionbox[5] - self.collisionbox[2]) * .5 - - local texture = "mobs_blood.png" - -- full heart damage (one particle for each 2 HP damage) - if amount_large > 0 then - effect(pos, amount_large, texture, 2, 2, 1.75, 0, nil, true) - end - -- half heart damage (one additional particle if damage is an odd number) - if amount_small > 0 then - -- TODO: Use "half heart" - effect(pos, amount_small, texture, 1, 1, 1.75, 0, nil, true) - end - end -end - -mobs.death_effect = function(pos, yaw, collisionbox, rotate) - local min, max - if collisionbox then - min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]} - max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]} - else - min = { x = -0.5, y = 0, z = -0.5 } - max = { x = 0.5, y = 0.5, z = 0.5 } - end - if rotate then - min = vector.rotate(min, {x=0, y=yaw, z=pi/2}) - max = vector.rotate(max, {x=0, y=yaw, z=pi/2}) - min, max = vector.sort(min, max) - min = vector.multiply(min, 0.5) - max = vector.multiply(max, 0.5) - end - - minetest.add_particlespawner({ - amount = 50, - time = 0.001, - minpos = vector.add(pos, min), - maxpos = vector.add(pos, max), - minvel = vector.new(-5,-5,-5), - maxvel = vector.new(5,5,5), - minexptime = 1.1, - maxexptime = 1.5, - minsize = 1, - maxsize = 2, - collisiondetection = false, - vertical = false, - texture = "mcl_particles_mob_death.png^[colorize:#000000:255", - }) - - minetest.sound_play("mcl_mobs_mob_poof", { - pos = pos, - gain = 1.0, - max_hear_distance = 8, - }, true) -end - -local update_tag = function(self) - local tag - if mobs_debug then - tag = "nametag = '"..tostring(self.nametag).."'\n".. - "state = '"..tostring(self.state).."'\n".. - "order = '"..tostring(self.order).."'\n".. - "attack = "..tostring(self.attack).."\n".. - "health = "..tostring(self.health).."\n".. - "breath = "..tostring(self.breath).."\n".. - "gotten = "..tostring(self.gotten).."\n".. - "tamed = "..tostring(self.tamed).."\n".. - "horny = "..tostring(self.horny).."\n".. - "hornytimer = "..tostring(self.hornytimer).."\n".. - "runaway_timer = "..tostring(self.runaway_timer).."\n".. - "following = "..tostring(self.following) - else - tag = self.nametag - end - self.object:set_properties({ - nametag = tag, - }) - - update_roll(self) -end - --- drop items -local item_drop = function(self, cooked, looting_level) - - -- no drops if disabled by setting - if not mobs_drop_items then return end - - looting_level = looting_level or 0 - - -- no drops for child mobs (except monster) - if (self.child and self.type ~= "monster") then - return - end - - local obj, item, num - local pos = self.object:get_pos() - - self.drops = self.drops or {} -- nil check - - for n = 1, #self.drops do - local dropdef = self.drops[n] - local chance = 1 / dropdef.chance - local looting_type = dropdef.looting - - if looting_level > 0 then - local chance_function = dropdef.looting_chance_function - if chance_function then - chance = chance_function(looting_level) - elseif looting_type == "rare" then - chance = chance + (dropdef.looting_factor or 0.01) * looting_level + if self.htimer < 1 then + self.htimer = 5 end end - local num = 0 - local do_common_looting = (looting_level > 0 and looting_type == "common") - if random() < chance then - num = random(dropdef.min or 1, dropdef.max or 1) - elseif not dropdef.looting_ignore_chance then - do_common_looting = false + self.object:set_hp(self.health) + + update_tag(self) + + -- make children grow quicker + if self.child == true then + + -- deduct 10% of the time to adulthood + self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1) + + return true end - if do_common_looting then - num = num + math.floor(math.random(0, looting_level) + 0.5) - end + -- feed and tame + self.food = (self.food or 0) + 1 + if self.food >= feed_count then - if num > 0 then - item = dropdef.name + self.food = 0 - -- cook items when true - if cooked then + if breed and self.hornytimer == 0 then + self.horny = true + end - local output = minetest.get_craft_result({ - method = "cooking", width = 1, items = {item}}) + if tame then - if output and output.item and not output.item:is_empty() then - item = output.item:get_name() + self.tamed = true + + if not self.owner or self.owner == "" then + self.owner = clicker:get_player_name() end end - -- add item if it exists - for x = 1, num do - obj = minetest.add_item(pos, ItemStack(item .. " " .. 1)) + -- make sound when fed so many times + mob_sound(self, "random", true) + end + + return true + end + + return false +end + +-- no damage to nodes explosion +function mobs:safe_boom(self, pos, strength) + minetest_sound_play(self.sounds and self.sounds.explode or "tnt_explode", { + pos = pos, + gain = 1.0, + max_hear_distance = self.sounds and self.sounds.distance or 32 + }, true) + local radius = strength + entity_physics(pos, radius) + effect(pos, 32, "mcl_particles_smoke.png", radius * 3, radius * 5, radius, 1, 0) +end + + +-- make explosion with protection and tnt mod check +function mobs:boom(self, pos, strength, fire) + self.object:remove() + if mod_explosions then + if mobs_griefing and not minetest_is_protected(pos, "") then + mcl_explosions.explode(pos, strength, { drop_chance = 1.0, fire = fire }, self.object) + else + mobs:safe_boom(self, pos, strength) + end + else + mobs:safe_boom(self, pos, strength) + end +end + +-- falling and fall damage +-- returns true if mob died +local falling = function(self, pos) + + if self.fly and self.state ~= "die" then + return + end + + if mcl_portals ~= nil then + if mcl_portals.nether_portal_cooloff(self.object) then + return false -- mob has teleported through Nether portal - it's 99% not falling + end + end + + -- floating in water (or falling) + local v = self.object:get_velocity() + + if v.y > 0 then + + -- apply gravity when moving up + self.object:set_acceleration({ + x = 0, + y = -10, + z = 0 + }) + + elseif v.y <= 0 and v.y > self.fall_speed then + + -- fall downwards at set speed + self.object:set_acceleration({ + x = 0, + y = self.fall_speed, + z = 0 + }) + else + -- stop accelerating once max fall speed hit + self.object:set_acceleration({x = 0, y = 0, z = 0}) + end + + if minetest_registered_nodes[node_ok(pos).name].groups.lava then + + if self.floats_on_lava == 1 then + + self.object:set_acceleration({ + x = 0, + y = -self.fall_speed / (max(1, v.y) ^ 2), + z = 0 + }) + end + end + + -- in water then float up + if minetest_registered_nodes[node_ok(pos).name].groups.water then + + if self.floats == 1 then + + self.object:set_acceleration({ + x = 0, + y = -self.fall_speed / (math_max(1, v.y) ^ 2), + z = 0 + }) + end + else + + end +end + + + + +-- find someone to runaway from +local runaway_from = function(self) + + if not self.runaway_from and self.state ~= "flop" then + return + end + + local s = self.object:get_pos() + local p, sp, dist + local player, obj, min_player + local type, name = "", "" + local min_dist = self.view_range + 1 + local objs = minetest_get_objects_inside_radius(s, self.view_range) + + for n = 1, #objs do + + if objs[n]:is_player() then + + if mobs.invis[ objs[n]:get_player_name() ] + or self.owner == objs[n]:get_player_name() + or (not object_in_range(self, objs[n])) then + type = "" + else + player = objs[n] + type = "player" + name = "player" end + else + obj = objs[n]:get_luaentity() - if obj and obj:get_luaentity() then + if obj then + player = obj.object + type = obj.type + name = obj.name or "" + end + end - obj:set_velocity({ - x = random(-10, 10) / 9, - y = 6, - z = random(-10, 10) / 9, - }) - elseif obj then - obj:remove() -- item does not exist + -- find specific mob to runaway from + if name ~= "" and name ~= self.name + and specific_runaway(self.runaway_from, name) then + + p = player:get_pos() + sp = s + + -- aim higher to make looking up hills more realistic + p.y = p.y + 1 + sp.y = sp.y + 1 + + dist = vector.distance(p, s) + + + -- choose closest player/mpb to runaway from + if dist < min_dist + and line_of_sight(self, sp, p, 2) == true then + min_dist = dist + min_player = player end end end - self.drops = {} + if min_player then + + local lp = player:get_pos() + local vec = { + x = lp.x - s.x, + y = lp.y - s.y, + z = lp.z - s.z + } + + local yaw = (atan(vec.z / vec.x) + 3 * math_pi / 2) - self.rotate + + if lp.x > s.x then + yaw = yaw + math_pi + end + + yaw = set_yaw(self, yaw, 4) + self.state = "runaway" + self.runaway_timer = 3 + self.following = nil + end end +-- specific runaway +local specific_runaway = function(list, what) + + -- no list so do not run + if list == nil then + return false + end + + -- found entity on list to attack? + for no = 1, #list do + + if list[no] == what then + return true + end + end + + return false +end + + +-- follow player if owner or holding item, if fish outta water then flop +local follow_flop = function(self) + + -- find player to follow + if (self.follow ~= "" + or self.order == "follow") + and not self.following + and self.state ~= "attack" + and self.order ~= "sit" + and self.state ~= "runaway" then + + local s = self.object:get_pos() + local players = minetest.get_connected_players() + + for n = 1, #players do + + if (object_in_range(self, players[n])) + and not mobs.invis[ players[n]:get_player_name() ] then + + self.following = players[n] + + break + end + end + end + + if self.type == "npc" + and self.order == "follow" + and self.state ~= "attack" + and self.order ~= "sit" + and self.owner ~= "" then + + -- npc stop following player if not owner + if self.following + and self.owner + and self.owner ~= self.following:get_player_name() then + self.following = nil + end + else + -- stop following player if not holding specific item, + -- mob is horny, fleeing or attacking + if self.following + and self.following:is_player() + and (follow_holding(self, self.following) == false or + self.horny or self.state == "runaway") then + self.following = nil + end + + end + + -- follow that thing + if self.following then + + local s = self.object:get_pos() + local p + + if self.following:is_player() then + + p = self.following:get_pos() + + elseif self.following.object then + + p = self.following.object:get_pos() + end + + if p then + + local dist = vector.distance(p, s) + + -- dont follow if out of range + if (not object_in_range(self, self.following)) then + self.following = nil + else + local vec = { + x = p.x - s.x, + z = p.z - s.z + } + + local yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + + if p.x > s.x then yaw = yaw + math_pi end + + set_yaw(self, yaw, 2.35) + + -- anyone but standing npc's can move along + if dist > 3 + and self.order ~= "stand" then + + set_velocity(self, self.follow_velocity) + + if self.walk_chance ~= 0 then + set_animation(self, "run") + end + else + set_velocity(self, 0) + set_animation(self, "stand") + end + + return + end + end + end + + -- swimmers flop when out of their element, and swim again when back in + if self.fly then + local s = self.object:get_pos() + if not flight_check(self, s) then + + self.state = "flop" + self.object:set_acceleration({x = 0, y = DEFAULT_FALL_SPEED, z = 0}) + + local sdef = minetest_registered_nodes[self.standing_on] + -- Flop on ground + if sdef and sdef.walkable then + mob_sound(self, "flop") + self.object:set_velocity({ + x = math_random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED), + y = FLOP_HEIGHT, + z = math_random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED), + }) + end + + set_animation(self, "stand", true) + + return + elseif self.state == "flop" then + self.state = "stand" + self.object:set_acceleration({x = 0, y = 0, z = 0}) + set_velocity(self, 0) + end + end +end + + +-- npc, find closest monster to attack +local npc_attack = function(self) + + if self.type ~= "npc" + or not self.attacks_monsters + or self.state == "attack" then + return + end + + local p, sp, obj, min_player + local s = self.object:get_pos() + local min_dist = self.view_range + 1 + local objs = minetest_get_objects_inside_radius(s, self.view_range) + + for n = 1, #objs do + + obj = objs[n]:get_luaentity() + + if obj and obj.type == "monster" then + + p = obj.object:get_pos() + sp = s + + local dist = vector.distance(p, s) + + -- aim higher to make looking up hills more realistic + p.y = p.y + 1 + sp.y = sp.y + 1 + + if dist < min_dist + and line_of_sight(self, sp, p, 2) == true then + min_dist = dist + min_player = obj.object + end + end + end + + if min_player then + do_attack(self, min_player) + end +end + + +-- monster find someone to attack +local monster_attack = function(self) + + if self.type ~= "monster" + or not damage_enabled + or minetest_is_creative_enabled("") + or self.passive + or self.state == "attack" + or day_docile(self) then + return + end + + local s = self.object:get_pos() + local p, sp, dist + local player, obj, min_player + local type, name = "", "" + local min_dist = self.view_range + 1 + local objs = minetest_get_objects_inside_radius(s, self.view_range) + + for n = 1, #objs do + + if objs[n]:is_player() then + + if mobs.invis[ objs[n]:get_player_name() ] or (not object_in_range(self, objs[n])) then + type = "" + else + player = objs[n] + type = "player" + name = "player" + end + else + obj = objs[n]:get_luaentity() + + if obj then + player = obj.object + type = obj.type + name = obj.name or "" + end + end + + -- find specific mob to attack, failing that attack player/npc/animal + if specific_attack(self.specific_attack, name) + and (type == "player" or type == "npc" + or (type == "animal" and self.attack_animals == true)) then + + p = player:get_pos() + sp = s + + dist = vector.distance(p, s) + + -- aim higher to make looking up hills more realistic + p.y = p.y + 1 + sp.y = sp.y + 1 + + + -- choose closest player to attack + if dist < min_dist + and line_of_sight(self, sp, p, 2) == true then + min_dist = dist + min_player = player + end + end + end + + -- attack player + if min_player then + do_attack(self, min_player) + end +end + + +-- specific attacks +local specific_attack = function(list, what) + + -- no list so attack default (player, animals etc.) + if list == nil then + return true + end + + -- found entity on list to attack? + for no = 1, #list do + + if list[no] == what then + return true + end + end + + return false +end + + +-- dogfight attack switch and counter function +local dogswitch = function(self, dtime) + + -- switch mode not activated + if not self.dogshoot_switch + or not dtime then + return 0 + end + + self.dogshoot_count = self.dogshoot_count + dtime + + if (self.dogshoot_switch == 1 + and self.dogshoot_count > self.dogshoot_count_max) + or (self.dogshoot_switch == 2 + and self.dogshoot_count > self.dogshoot_count2_max) then + + self.dogshoot_count = 0 + + if self.dogshoot_switch == 1 then + self.dogshoot_switch = 2 + else + self.dogshoot_switch = 1 + end + end + + return self.dogshoot_switch +end + +-- path finding and smart mob routine by rnd, line_of_sight and other edits by Elkien3 +local smart_mobs = function(self, s, p, dist, dtime) + + local s1 = self.path.lastpos + + local target_pos = self.attack:get_pos() + + -- is it becoming stuck? + if math_abs(s1.x - s.x) + math_abs(s1.z - s.z) < .5 then + self.path.stuck_timer = self.path.stuck_timer + dtime + else + self.path.stuck_timer = 0 + end + + self.path.lastpos = {x = s.x, y = s.y, z = s.z} + + local use_pathfind = false + local has_lineofsight = minetest_line_of_sight( + {x = s.x, y = (s.y) + .5, z = s.z}, + {x = target_pos.x, y = (target_pos.y) + 1.5, z = target_pos.z}, .2) + + -- im stuck, search for path + if not has_lineofsight then + + if los_switcher == true then + use_pathfind = true + los_switcher = false + end -- cannot see target! + else + if los_switcher == false then + + los_switcher = true + use_pathfind = false + + minetest_after(1, function(self) + if not self.object:get_luaentity() then + return + end + if has_lineofsight then self.path.following = false end + end, self) + end -- can see target! + end + + if (self.path.stuck_timer > stuck_timeout and not self.path.following) then + + use_pathfind = true + self.path.stuck_timer = 0 + + minetest_after(1, function(self) + if not self.object:get_luaentity() then + return + end + if has_lineofsight then self.path.following = false end + end, self) + end + + if (self.path.stuck_timer > stuck_path_timeout and self.path.following) then + + use_pathfind = true + self.path.stuck_timer = 0 + + minetest_after(1, function(self) + if not self.object:get_luaentity() then + return + end + if has_lineofsight then self.path.following = false end + end, self) + end + + if math_abs(vector.subtract(s,target_pos).y) > self.stepheight then + + if height_switcher then + use_pathfind = true + height_switcher = false + end + else + if not height_switcher then + use_pathfind = false + height_switcher = true + end + end + + if use_pathfind then + -- lets try find a path, first take care of positions + -- since pathfinder is very sensitive + local sheight = self.collisionbox[5] - self.collisionbox[2] + + -- round position to center of node to avoid stuck in walls + -- also adjust height for player models! + s.x = math_floor(s.x + 0.5) + s.z = math_floor(s.z + 0.5) + + local ssight, sground = minetest_line_of_sight(s, { + x = s.x, y = s.y - 4, z = s.z}, 1) + + -- determine node above ground + if not ssight then + s.y = sground.y + 1 + end + + local p1 = self.attack:get_pos() + + p1.x = math_floor(p1.x + 0.5) + p1.y = math_floor(p1.y + 0.5) + p1.z = math_floor(p1.z + 0.5) + + local dropheight = 12 + if self.fear_height ~= 0 then dropheight = self.fear_height end + local jumpheight = 0 + if self.jump and self.jump_height >= 4 then + jumpheight = math.min(math.ceil(self.jump_height / 4), 4) + elseif self.stepheight > 0.5 then + jumpheight = 1 + end + self.path.way = minetest_find_path(s, p1, 16, jumpheight, dropheight, "A*_noprefetch") + + self.state = "" + do_attack(self, self.attack) + + -- no path found, try something else + if not self.path.way then + + self.path.following = false + + -- lets make way by digging/building if not accessible + if self.pathfinding == 2 and mobs_griefing then + + -- is player higher than mob? + if s.y < p1.y then + + -- build upwards + if not minetest_is_protected(s, "") then + + local ndef1 = minetest_registered_nodes[self.standing_in] + + if ndef1 and (ndef1.buildable_to or ndef1.groups.liquid) then + + minetest_set_node(s, {name = mobs.fallback_node}) + end + end + + local sheight = math.ceil(self.collisionbox[5]) + 1 + + -- assume mob is 2 blocks high so it digs above its head + s.y = s.y + sheight + + -- remove one block above to make room to jump + if not minetest_is_protected(s, "") then + + local node1 = node_ok(s, "air").name + local ndef1 = minetest_registered_nodes[node1] + + if node1 ~= "air" + and node1 ~= "ignore" + and ndef1 + and not ndef1.groups.level + and not ndef1.groups.unbreakable + and not ndef1.groups.liquid then + + minetest_set_node(s, {name = "air"}) + minetest_add_item(s, ItemStack(node1)) + + end + end + + s.y = s.y - sheight + self.object:set_pos({x = s.x, y = s.y + 2, z = s.z}) + + else -- dig 2 blocks to make door toward player direction + + local yaw1 = self.object:get_yaw() + math_pi / 2 + local p1 = { + x = s.x + math_cos(yaw1), + y = s.y, + z = s.z + math_sin(yaw1) + } + + if not minetest_is_protected(p1, "") then + + local node1 = node_ok(p1, "air").name + local ndef1 = minetest_registered_nodes[node1] + + if node1 ~= "air" + and node1 ~= "ignore" + and ndef1 + and not ndef1.groups.level + and not ndef1.groups.unbreakable + and not ndef1.groups.liquid then + + minetest_add_item(p1, ItemStack(node1)) + minetest_set_node(p1, {name = "air"}) + end + + p1.y = p1.y + 1 + node1 = node_ok(p1, "air").name + ndef1 = minetest_registered_nodes[node1] + + if node1 ~= "air" + and node1 ~= "ignore" + and ndef1 + and not ndef1.groups.level + and not ndef1.groups.unbreakable + and not ndef1.groups.liquid then + + minetest_add_item(p1, ItemStack(node1)) + minetest_set_node(p1, {name = "air"}) + end + + end + end + end + + -- will try again in 2 seconds + self.path.stuck_timer = stuck_timeout - 2 + elseif s.y < p1.y and (not self.fly) then + do_jump(self) --add jump to pathfinding + self.path.following = true + -- Yay, I found path! + -- TODO: Implement war_cry sound without being annoying + --mob_sound(self, "war_cry", true) + else + set_velocity(self, self.walk_velocity) + + -- follow path now that it has it + self.path.following = true + end + end +end + + + + + + -- check if mob is dead or only hurt local check_for_death = function(self, cause, cmi_cause) @@ -776,7 +943,7 @@ local check_for_death = function(self, cause, cmi_cause) -- play damage sound if health was reduced and make mob flash red. if damaged then add_texture_mod(self, "^[colorize:red:130") - minetest.after(.2, function(self) + minetest_after(.2, function(self) if self and self.object then remove_texture_mod(self, "^[colorize:red:130") end @@ -819,8 +986,8 @@ local check_for_death = function(self, cause, cmi_cause) local looting = mcl_enchanting.get_enchantment(wielditem, "looting") item_drop(self, cooked, looting) - if mod_experience and ((not self.child) or self.type ~= "animal") and (minetest.get_us_time() - self.xp_timestamp <= 5000000) then - mcl_experience.throw_experience(self.object:get_pos(), math.random(self.xp_min, self.xp_max)) + if mod_experience and ((not self.child) or self.type ~= "animal") and (minetest_get_us_time() - self.xp_timestamp <= 5000000) then + mcl_experience.throw_experience(self.object:get_pos(), math_random(self.xp_min, self.xp_max)) end end end @@ -885,7 +1052,7 @@ local check_for_death = function(self, cause, cmi_cause) set_animation(self, "die") else local rot = self.object:get_rotation() - rot.z = pi/2 + rot.z = math_pi/2 self.object:set_rotation(rot) length = 1 + DEATH_DELAY set_animation(self, "stand", true) @@ -912,34 +1079,366 @@ local check_for_death = function(self, cause, cmi_cause) if length <= 0 then kill(self) else - minetest.after(length, kill, self) + minetest_after(length, kill, self) end return true end +local damage_effect = function(self, damage) + -- damage particles + if (not disable_blood) and damage > 0 then --- check if within physical map limits (-30911 to 30927) -local within_limits, wmin, wmax = nil, -30913, 30928 -within_limits = function(pos, radius) - if mcl_vars then - if mcl_vars.mapgen_edge_min and mcl_vars.mapgen_edge_max then - wmin, wmax = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max - within_limits = function(pos, radius) - return pos - and (pos.x - radius) > wmin and (pos.x + radius) < wmax - and (pos.y - radius) > wmin and (pos.y + radius) < wmax - and (pos.z - radius) > wmin and (pos.z + radius) < wmax + local amount_large = math_floor(damage / 2) + local amount_small = damage % 2 + + local pos = self.object:get_pos() + + pos.y = pos.y + (self.collisionbox[5] - self.collisionbox[2]) * .5 + + local texture = "mobs_blood.png" + -- full heart damage (one particle for each 2 HP damage) + if amount_large > 0 then + effect(pos, amount_large, texture, 2, 2, 1.75, 0, nil, true) + end + -- half heart damage (one additional particle if damage is an odd number) + if amount_small > 0 then + -- TODO: Use "half heart" + effect(pos, amount_small, texture, 1, 1, 1.75, 0, nil, true) + end + end +end + + +-- custom particle effects +local effect = function(pos, amount, texture, min_size, max_size, radius, gravity, glow, go_down) + + radius = radius or 2 + min_size = min_size or 0.5 + max_size = max_size or 1 + gravity = gravity or -10 + glow = glow or 0 + go_down = go_down or false + + local ym + if go_down then + ym = 0 + else + ym = -radius + end + + minetest_add_particlespawner({ + amount = amount, + time = 0.25, + minpos = pos, + maxpos = pos, + minvel = {x = -radius, y = ym, z = -radius}, + maxvel = {x = radius, y = radius, z = radius}, + minacc = {x = 0, y = gravity, z = 0}, + maxacc = {x = 0, y = gravity, z = 0}, + minexptime = 0.1, + maxexptime = 1, + minsize = min_size, + maxsize = max_size, + texture = texture, + glow = glow, + }) +end + + +-- are we flying in what we are suppose to? (taikedz) +local flight_check = function(self) + + local nod = self.standing_in + local def = minetest_registered_nodes[nod] + + if not def then return false end -- nil check + + local fly_in + if type(self.fly_in) == "string" then + fly_in = { self.fly_in } + elseif type(self.fly_in) == "table" then + fly_in = self.fly_in + else + return false + end + + for _,checknode in pairs(fly_in) do + if nod == checknode then + return true + elseif checknode == "__airlike" and def.walkable == false and + (def.liquidtype == "none" or minetest_get_item_group(nod, "fake_liquid") == 1) then + return true + end + end + + return false +end + + +-- check line of sight (BrunoMine) +local line_of_sight = function(self, pos1, pos2, stepsize) + + stepsize = stepsize or 1 + + local s, pos = minetest_line_of_sight(pos1, pos2, stepsize) + + -- normal walking and flying mobs can see you through air + if s == true then + return true + end + + -- New pos1 to be analyzed + local npos1 = {x = pos1.x, y = pos1.y, z = pos1.z} + + local r, pos = minetest_line_of_sight(npos1, pos2, stepsize) + + -- Checks the return + if r == true then return true end + + -- Nodename found + local nn = minetest_get_node(pos).name + + -- Target Distance (td) to travel + local td = vector.distance(pos1, pos2) + + -- Actual Distance (ad) traveled + local ad = 0 + + -- It continues to advance in the line of sight in search of a real + -- obstruction which counts as 'normal' nodebox. + while minetest_registered_nodes[nn] + and minetest_registered_nodes[nn].walkable == false do + + -- Check if you can still move forward + if td < ad + stepsize then + return true -- Reached the target + end + + -- Moves the analyzed pos + local d = vector.distance(pos1, pos2) + + npos1.x = ((pos2.x - pos1.x) / d * stepsize) + pos1.x + npos1.y = ((pos2.y - pos1.y) / d * stepsize) + pos1.y + npos1.z = ((pos2.z - pos1.z) / d * stepsize) + pos1.z + + -- NaN checks + if d == 0 + or npos1.x ~= npos1.x + or npos1.y ~= npos1.y + or npos1.z ~= npos1.z then + return false + end + + ad = ad + stepsize + + -- scan again + r, pos = minetest_line_of_sight(npos1, pos2, stepsize) + + if r == true then return true end + + -- New Nodename found + nn = minetest_get_node(pos).name + + end + + return false +end + +-- Returns true if node is a water hazard +local is_node_waterhazard = function(self, nodename) + local nn = nodename + if self.water_damage > 0 then + if minetest_get_item_group(nn, "water") ~= 0 then + return true + end + end + if minetest_registered_nodes[nn] and minetest_registered_nodes[nn].drowning and minetest_registered_nodes[nn].drowning > 0 then + if self.breath_max ~= -1 then + -- check if the mob is water-breathing _and_ the block is water; only return true if neither is the case + -- this will prevent water-breathing mobs to classify water or e.g. sand below them as dangerous + if not self.breathes_in_water and minetest_get_item_group(nn, "water") ~= 0 then + return true end end end - return pos - and (pos.x - radius) > wmin and (pos.x + radius) < wmax - and (pos.y - radius) > wmin and (pos.y + radius) < wmax - and (pos.z - radius) > wmin and (pos.z + radius) < wmax + return false end +-- Returns true is node can deal damage to self +local is_node_dangerous = function(self, nodename) + local nn = nodename + if self.lava_damage > 0 then + if minetest_get_item_group(nn, "lava") ~= 0 then + return true + end + end + if self.fire_damage > 0 then + if minetest_get_item_group(nn, "fire") ~= 0 then + return true + end + end + if minetest_registered_nodes[nn] and minetest_registered_nodes[nn].damage_per_second and minetest_registered_nodes[nn].damage_per_second > 0 then + return true + end + return false +end + + +local add_texture_mod = function(self, mod) + local full_mod = "" + local already_added = false + for i=1, #self.texture_mods do + if mod == self.texture_mods[i] then + already_added = true + end + full_mod = full_mod .. self.texture_mods[i] + end + if not already_added then + full_mod = full_mod .. mod + table.insert(self.texture_mods, mod) + end + self.object:set_texture_mod(full_mod) +end + + +local remove_texture_mod = function(self, mod) + local full_mod = "" + local remove = {} + for i=1, #self.texture_mods do + if self.texture_mods[i] ~= mod then + full_mod = full_mod .. self.texture_mods[i] + else + table.insert(remove, i) + end + end + for i=#remove, 1 do + table.remove(self.texture_mods, remove[i]) + end + self.object:set_texture_mod(full_mod) +end + + +-- Return true if object is in view_range +local function object_in_range(self, object) + if not object then + return false + end + local factor + -- Apply view range reduction for special player armor + if not object then + return false + end + local factor + -- Apply view range reduction for special player armor + if object:is_player() and mod_armor then + local factors = mcl_armor.player_view_range_factors[object] + factor = factors and factors[self.name] + end + -- Distance check + local dist + if factor and factor == 0 then + return false + elseif factor then + dist = self.view_range * factor + else + dist = self.view_range + end + + local p1, p2 = self.object:get_pos(), object:get_pos() + return p1 and p2 and (vector.distance(p1, p2) <= dist) +end + +-- attack player/mob +local do_attack = function(self, player) + + if self.state == "attack" or self.state == "die" then + return + end + + self.attack = player + self.state = "attack" + + -- TODO: Implement war_cry sound without being annoying + --if math_random(0, 100) < 90 then + --mob_sound(self, "war_cry", true) + --end +end + + +-- play sound +local mob_sound = function(self, soundname, is_opinion, fixed_pitch) + local soundinfo + if self.sounds_child and self.child then + soundinfo = self.sounds_child + elseif self.sounds then + soundinfo = self.sounds + end + if not soundinfo then + return + end + local sound = soundinfo[soundname] + if sound then + if is_opinion and self.opinion_sound_cooloff > 0 then + return + end + local pitch + if not fixed_pitch then + local base_pitch = soundinfo.base_pitch + if not base_pitch then + base_pitch = 1 + end + if self.child and (not self.sounds_child) then + -- Children have higher pitch + pitch = base_pitch * 1.5 + else + pitch = base_pitch + end + -- randomize the pitch a bit + pitch = pitch + math_random(-10, 10) * 0.005 + end + minetest_sound_play(sound, { + object = self.object, + gain = 1.0, + max_hear_distance = self.sounds.distance, + pitch = pitch, + }, true) + self.opinion_sound_cooloff = 1 + end +end + + +local function update_roll(self) + local is_Fleckenstein = self.nametag == "Fleckenstein" + local was_Fleckenstein = false + + local rot = self.object:get_rotation() + rot.z = is_Fleckenstein and math_pi or 0 + self.object:set_rotation(rot) + + local cbox = table.copy(self.collisionbox) + local acbox = self.object:get_properties().collisionbox + + if math_abs(cbox[2] - acbox[2]) > 0.1 then + was_Fleckenstein = true + end + + if is_Fleckenstein ~= was_Fleckenstein then + local pos = self.object:get_pos() + pos.y = pos.y + (acbox[2] + acbox[5]) + self.object:set_pos(pos) + end + + if is_Fleckenstein then + cbox[2], cbox[5] = -cbox[5], -cbox[2] + end + + self.object:set_properties({collisionbox = cbox}) +end + + + -- is mob facing a cliff or danger local is_at_cliff_or_danger = function(self) @@ -951,23 +1450,23 @@ local is_at_cliff_or_danger = function(self) return false end local yaw = self.object:get_yaw() - local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) - local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5) + local dir_x = -math_sin(yaw) * (self.collisionbox[4] + 0.5) + local dir_z = math_cos(yaw) * (self.collisionbox[4] + 0.5) local pos = self.object:get_pos() local ypos = pos.y + self.collisionbox[2] -- just above floor - local free_fall, blocker = minetest.line_of_sight( + local free_fall, blocker = minetest_line_of_sight( {x = pos.x + dir_x, y = ypos, z = pos.z + dir_z}, {x = pos.x + dir_x, y = ypos - self.fear_height, z = pos.z + dir_z}) if free_fall then return true else - local bnode = minetest.get_node(blocker) + local bnode = minetest_get_node(blocker) local danger = is_node_dangerous(self, bnode.name) if danger then return true else - local def = minetest.registered_nodes[bnode.name] + local def = minetest_registered_nodes[bnode.name] if def and def.walkable then return false end @@ -986,18 +1485,18 @@ local is_at_water_danger = function(self) return false end local yaw = self.object:get_yaw() - local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) - local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5) + local dir_x = -math_sin(yaw) * (self.collisionbox[4] + 0.5) + local dir_z = math_cos(yaw) * (self.collisionbox[4] + 0.5) local pos = self.object:get_pos() local ypos = pos.y + self.collisionbox[2] -- just above floor - local free_fall, blocker = minetest.line_of_sight( + local free_fall, blocker = minetest_line_of_sight( {x = pos.x + dir_x, y = ypos, z = pos.z + dir_z}, {x = pos.x + dir_x, y = ypos - 3, z = pos.z + dir_z}) if free_fall then return true else - local bnode = minetest.get_node(blocker) + local bnode = minetest_get_node(blocker) local waterdanger = is_node_waterhazard(self, bnode.name) if waterdanger and (is_node_waterhazard(self, self.standing_in) or is_node_waterhazard(self, self.standing_on)) then @@ -1005,7 +1504,7 @@ local is_at_water_danger = function(self) elseif waterdanger and (is_node_waterhazard(self, self.standing_in) or is_node_waterhazard(self, self.standing_on)) == false then return true else - local def = minetest.registered_nodes[bnode.name] + local def = minetest_registered_nodes[bnode.name] if def and def.walkable then return false end @@ -1015,21 +1514,6 @@ local is_at_water_danger = function(self) return false end - --- get node but use fallback for nil or unknown -local node_ok = function(pos, fallback) - - fallback = fallback or mobs.fallback_node - - local node = minetest.get_node_or_nil(pos) - - if node and minetest.registered_nodes[node.name] then - return node - end - - return minetest.registered_nodes[fallback] -end - local function get_light(pos, tod) if minetest.get_node_or_nil(pos) then local lightfunc = minetest.get_natural_light or minetest.get_node_light @@ -1121,7 +1605,7 @@ local do_env_damage = function(self) self.object:set_velocity({x = 0, y = 0, z = 0}) end - local nodef = minetest.registered_nodes[self.standing_in] + local nodef = minetest_registered_nodes[self.standing_in] -- rain if self.rain_damage > 0 and mod_weather then @@ -1203,7 +1687,7 @@ local do_env_damage = function(self) if self.breath_max ~= -1 then local drowning = false if self.breathes_in_water then - if minetest.get_item_group(self.standing_in, "water") == 0 then + if minetest_get_item_group(self.standing_in, "water") == 0 then drowning = true end elseif nodef.drowning > 0 then @@ -1211,7 +1695,7 @@ local do_env_damage = function(self) end if drowning then - self.breath = math.max(0, self.breath - 1) + self.breath = math_max(0, self.breath - 1) effect(pos, 2, "bubble.png", nil, nil, 1, nil) if self.breath <= 0 then @@ -1229,7 +1713,7 @@ local do_env_damage = function(self) return true end else - self.breath = math.min(self.breath_max, self.breath + 1) + self.breath = math_min(self.breath_max, self.breath + 1) end end @@ -1295,13 +1779,13 @@ local do_jump = function(self) local nod = node_ok(pos) - if minetest.registered_nodes[nod.name].walkable == false then + if minetest_registered_nodes[nod.name].walkable == false then return false end -- where is front - local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) - local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5) + local dir_x = -math_sin(yaw) * (self.collisionbox[4] + 0.5) + local dir_z = math_cos(yaw) * (self.collisionbox[4] + 0.5) -- what is in front of mob? nod = node_ok({ @@ -1319,7 +1803,7 @@ local do_jump = function(self) }, "air") -- we don't attempt to jump if there's a stack of blocks blocking - if minetest.registered_nodes[nodTop.name].walkable == true then + if minetest_registered_nodes[nodTop.name].walkable == true then return false end @@ -1329,11 +1813,11 @@ local do_jump = function(self) end if self.walk_chance == 0 - or minetest.registered_items[nod.name].walkable then + or minetest_registered_items[nod.name].walkable then - if minetest.get_item_group(nod.name, "fence") == 0 - and minetest.get_item_group(nod.name, "fence_gate") == 0 - and minetest.get_item_group(nod.name, "wall") == 0 then + if minetest_get_item_group(nod.name, "fence") == 0 + and minetest_get_item_group(nod.name, "fence_gate") == 0 + and minetest_get_item_group(nod.name, "wall") == 0 then local v = self.object:get_velocity() @@ -1344,7 +1828,7 @@ local do_jump = function(self) self.object:set_velocity(v) -- when in air move forward - minetest.after(0.3, function(self, v) + minetest_after(0.3, function(self, v) if (not self.object) or (not self.object:get_luaentity()) or (self.state == "die") then return end @@ -1391,7 +1875,7 @@ local entity_physics = function(pos, radius) radius = radius * 2 - local objs = minetest.get_objects_inside_radius(pos, radius) + local objs = minetest_get_objects_inside_radius(pos, radius) local obj_pos, dist for n = 1, #objs do @@ -1401,7 +1885,7 @@ local entity_physics = function(pos, radius) dist = vector.distance(pos, obj_pos) if dist < 1 then dist = 1 end - local damage = floor((4 / dist) * radius) + local damage = math_floor((4 / dist) * radius) local ent = objs[n]:get_luaentity() -- punches work on entities AND players @@ -1481,14 +1965,14 @@ local breed = function(self) return end - -- horny animal can mate for HORNY_TIME seconds, - -- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds + -- horny animal can mate for BREED_TIME seconds, + -- afterwards horny animal cannot mate again for BREED_TIME_AGAIN seconds if self.horny == true - and self.hornytimer < HORNY_TIME + HORNY_AGAIN_TIME then + and self.hornytimer < BREED_TIME + BREED_TIME_AGAIN then self.hornytimer = self.hornytimer + 1 - if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then + if self.hornytimer >= BREED_TIME + BREED_TIME_AGAIN then self.hornytimer = 0 self.horny = false end @@ -1496,13 +1980,13 @@ local breed = function(self) -- find another same animal who is also horny and mate if nearby if self.horny == true - and self.hornytimer <= HORNY_TIME then + and self.hornytimer <= BREED_TIME then local pos = self.object:get_pos() effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1) - local objs = minetest.get_objects_inside_radius(pos, 3) + local objs = minetest_get_objects_inside_radius(pos, 3) local num = 0 local ent = nil @@ -1535,18 +2019,18 @@ local breed = function(self) if ent and canmate == true and ent.horny == true - and ent.hornytimer <= HORNY_TIME then + and ent.hornytimer <= BREED_TIME then num = num + 1 end -- found your mate? then have a baby if num > 1 then - self.hornytimer = HORNY_TIME + 1 - ent.hornytimer = HORNY_TIME + 1 + self.hornytimer = BREED_TIME + 1 + ent.hornytimer = BREED_TIME + 1 -- spawn baby - minetest.after(5, function(parent1, parent2, pos) + minetest_after(5, function(parent1, parent2, pos) if not parent1.object:get_luaentity() then return end @@ -1556,7 +2040,7 @@ local breed = function(self) -- Give XP if mod_experience then - mcl_experience.throw_experience(pos, math.random(1, 7)) + mcl_experience.throw_experience(pos, math_random(1, 7)) end -- custom breed function @@ -1573,7 +2057,7 @@ local breed = function(self) -- Use texture of one of the parents - local p = math.random(1, 2) + local p = math_random(1, 2) if p == 1 then ent_c.base_texture = parent1.base_texture else @@ -1596,7 +2080,6 @@ local breed = function(self) end end - -- find and replace what mob is looking for (grass, wheat etc.) local replace = function(self, pos) @@ -1604,7 +2087,7 @@ local replace = function(self, pos) or not self.replace_what or self.child == true or self.object:get_velocity().y ~= 0 - or random(1, self.replace_rate) > 1 then + or math_random(1, self.replace_rate) > 1 then return end @@ -1612,7 +2095,7 @@ local replace = function(self, pos) if type(self.replace_what[1]) == "table" then - local num = random(#self.replace_what) + local num = math_random(#self.replace_what) what = self.replace_what[num][1] or "" with = self.replace_what[num][2] or "" @@ -1625,7 +2108,7 @@ local replace = function(self, pos) pos.y = pos.y + y_offset - local node = minetest.get_node(pos) + local node = minetest_get_node(pos) if node.name == what then local oldnode = {name = what, param2 = node.param2} @@ -1639,7 +2122,7 @@ local replace = function(self, pos) if on_replace_return ~= false then if mobs_griefing then - minetest.set_node(pos, newnode) + minetest_set_node(pos, newnode) end end @@ -1663,650 +2146,24 @@ local day_docile = function(self) end -local los_switcher = false -local height_switcher = false --- path finding and smart mob routine by rnd, line_of_sight and other edits by Elkien3 -local smart_mobs = function(self, s, p, dist, dtime) +local mob_detach_child = function(self, child) - local s1 = self.path.lastpos - - local target_pos = self.attack:get_pos() - - -- is it becoming stuck? - if abs(s1.x - s.x) + abs(s1.z - s.z) < .5 then - self.path.stuck_timer = self.path.stuck_timer + dtime - else - self.path.stuck_timer = 0 + if self.driver == child then + self.driver = nil end - self.path.lastpos = {x = s.x, y = s.y, z = s.z} - - local use_pathfind = false - local has_lineofsight = minetest.line_of_sight( - {x = s.x, y = (s.y) + .5, z = s.z}, - {x = target_pos.x, y = (target_pos.y) + 1.5, z = target_pos.z}, .2) - - -- im stuck, search for path - if not has_lineofsight then - - if los_switcher == true then - use_pathfind = true - los_switcher = false - end -- cannot see target! - else - if los_switcher == false then - - los_switcher = true - use_pathfind = false - - minetest.after(1, function(self) - if not self.object:get_luaentity() then - return - end - if has_lineofsight then self.path.following = false end - end, self) - end -- can see target! - end - - if (self.path.stuck_timer > stuck_timeout and not self.path.following) then - - use_pathfind = true - self.path.stuck_timer = 0 - - minetest.after(1, function(self) - if not self.object:get_luaentity() then - return - end - if has_lineofsight then self.path.following = false end - end, self) - end - - if (self.path.stuck_timer > stuck_path_timeout and self.path.following) then - - use_pathfind = true - self.path.stuck_timer = 0 - - minetest.after(1, function(self) - if not self.object:get_luaentity() then - return - end - if has_lineofsight then self.path.following = false end - end, self) - end - - if math.abs(vector.subtract(s,target_pos).y) > self.stepheight then - - if height_switcher then - use_pathfind = true - height_switcher = false - end - else - if not height_switcher then - use_pathfind = false - height_switcher = true - end - end - - if use_pathfind then - -- lets try find a path, first take care of positions - -- since pathfinder is very sensitive - local sheight = self.collisionbox[5] - self.collisionbox[2] - - -- round position to center of node to avoid stuck in walls - -- also adjust height for player models! - s.x = floor(s.x + 0.5) - s.z = floor(s.z + 0.5) - - local ssight, sground = minetest.line_of_sight(s, { - x = s.x, y = s.y - 4, z = s.z}, 1) - - -- determine node above ground - if not ssight then - s.y = sground.y + 1 - end - - local p1 = self.attack:get_pos() - - p1.x = floor(p1.x + 0.5) - p1.y = floor(p1.y + 0.5) - p1.z = floor(p1.z + 0.5) - - local dropheight = 12 - if self.fear_height ~= 0 then dropheight = self.fear_height end - local jumpheight = 0 - if self.jump and self.jump_height >= 4 then - jumpheight = math.min(math.ceil(self.jump_height / 4), 4) - elseif self.stepheight > 0.5 then - jumpheight = 1 - end - self.path.way = minetest.find_path(s, p1, 16, jumpheight, dropheight, "A*_noprefetch") - - self.state = "" - do_attack(self, self.attack) - - -- no path found, try something else - if not self.path.way then - - self.path.following = false - - -- lets make way by digging/building if not accessible - if self.pathfinding == 2 and mobs_griefing then - - -- is player higher than mob? - if s.y < p1.y then - - -- build upwards - if not minetest.is_protected(s, "") then - - local ndef1 = minetest.registered_nodes[self.standing_in] - - if ndef1 and (ndef1.buildable_to or ndef1.groups.liquid) then - - minetest.set_node(s, {name = mobs.fallback_node}) - end - end - - local sheight = math.ceil(self.collisionbox[5]) + 1 - - -- assume mob is 2 blocks high so it digs above its head - s.y = s.y + sheight - - -- remove one block above to make room to jump - if not minetest.is_protected(s, "") then - - local node1 = node_ok(s, "air").name - local ndef1 = minetest.registered_nodes[node1] - - if node1 ~= "air" - and node1 ~= "ignore" - and ndef1 - and not ndef1.groups.level - and not ndef1.groups.unbreakable - and not ndef1.groups.liquid then - - minetest.set_node(s, {name = "air"}) - minetest.add_item(s, ItemStack(node1)) - - end - end - - s.y = s.y - sheight - self.object:set_pos({x = s.x, y = s.y + 2, z = s.z}) - - else -- dig 2 blocks to make door toward player direction - - local yaw1 = self.object:get_yaw() + pi / 2 - local p1 = { - x = s.x + cos(yaw1), - y = s.y, - z = s.z + sin(yaw1) - } - - if not minetest.is_protected(p1, "") then - - local node1 = node_ok(p1, "air").name - local ndef1 = minetest.registered_nodes[node1] - - if node1 ~= "air" - and node1 ~= "ignore" - and ndef1 - and not ndef1.groups.level - and not ndef1.groups.unbreakable - and not ndef1.groups.liquid then - - minetest.add_item(p1, ItemStack(node1)) - minetest.set_node(p1, {name = "air"}) - end - - p1.y = p1.y + 1 - node1 = node_ok(p1, "air").name - ndef1 = minetest.registered_nodes[node1] - - if node1 ~= "air" - and node1 ~= "ignore" - and ndef1 - and not ndef1.groups.level - and not ndef1.groups.unbreakable - and not ndef1.groups.liquid then - - minetest.add_item(p1, ItemStack(node1)) - minetest.set_node(p1, {name = "air"}) - end - - end - end - end - - -- will try again in 2 seconds - self.path.stuck_timer = stuck_timeout - 2 - elseif s.y < p1.y and (not self.fly) then - do_jump(self) --add jump to pathfinding - self.path.following = true - -- Yay, I found path! - -- TODO: Implement war_cry sound without being annoying - --mob_sound(self, "war_cry", true) - else - set_velocity(self, self.walk_velocity) - - -- follow path now that it has it - self.path.following = true - end - end end - --- specific attacks -local specific_attack = function(list, what) - - -- no list so attack default (player, animals etc.) - if list == nil then - return true - end - - -- found entity on list to attack? - for no = 1, #list do - - if list[no] == what then - return true - end - end - - return false -end - --- monster find someone to attack -local monster_attack = function(self) - - if self.type ~= "monster" - or not damage_enabled - or minetest.is_creative_enabled("") - or self.passive - or self.state == "attack" - or day_docile(self) then - return - end - - local s = self.object:get_pos() - local p, sp, dist - local player, obj, min_player - local type, name = "", "" - local min_dist = self.view_range + 1 - local objs = minetest.get_objects_inside_radius(s, self.view_range) - - for n = 1, #objs do - - if objs[n]:is_player() then - - if mobs.invis[ objs[n]:get_player_name() ] or (not object_in_range(self, objs[n])) then - type = "" - else - player = objs[n] - type = "player" - name = "player" - end - else - obj = objs[n]:get_luaentity() - - if obj then - player = obj.object - type = obj.type - name = obj.name or "" - end - end - - -- find specific mob to attack, failing that attack player/npc/animal - if specific_attack(self.specific_attack, name) - and (type == "player" or type == "npc" - or (type == "animal" and self.attack_animals == true)) then - - p = player:get_pos() - sp = s - - dist = vector.distance(p, s) - - -- aim higher to make looking up hills more realistic - p.y = p.y + 1 - sp.y = sp.y + 1 - - - -- choose closest player to attack - if dist < min_dist - and line_of_sight(self, sp, p, 2) == true then - min_dist = dist - min_player = player - end - end - end - - -- attack player - if min_player then - do_attack(self, min_player) - end -end - - --- npc, find closest monster to attack -local npc_attack = function(self) - - if self.type ~= "npc" - or not self.attacks_monsters - or self.state == "attack" then - return - end - - local p, sp, obj, min_player - local s = self.object:get_pos() - local min_dist = self.view_range + 1 - local objs = minetest.get_objects_inside_radius(s, self.view_range) - - for n = 1, #objs do - - obj = objs[n]:get_luaentity() - - if obj and obj.type == "monster" then - - p = obj.object:get_pos() - sp = s - - local dist = vector.distance(p, s) - - -- aim higher to make looking up hills more realistic - p.y = p.y + 1 - sp.y = sp.y + 1 - - if dist < min_dist - and line_of_sight(self, sp, p, 2) == true then - min_dist = dist - min_player = obj.object - end - end - end - - if min_player then - do_attack(self, min_player) - end -end - - --- specific runaway -local specific_runaway = function(list, what) - - -- no list so do not run - if list == nil then - return false - end - - -- found entity on list to attack? - for no = 1, #list do - - if list[no] == what then - return true - end - end - - return false -end - - --- find someone to runaway from -local runaway_from = function(self) - - if not self.runaway_from and self.state ~= "flop" then - return - end - - local s = self.object:get_pos() - local p, sp, dist - local player, obj, min_player - local type, name = "", "" - local min_dist = self.view_range + 1 - local objs = minetest.get_objects_inside_radius(s, self.view_range) - - for n = 1, #objs do - - if objs[n]:is_player() then - - if mobs.invis[ objs[n]:get_player_name() ] - or self.owner == objs[n]:get_player_name() - or (not object_in_range(self, objs[n])) then - type = "" - else - player = objs[n] - type = "player" - name = "player" - end - else - obj = objs[n]:get_luaentity() - - if obj then - player = obj.object - type = obj.type - name = obj.name or "" - end - end - - -- find specific mob to runaway from - if name ~= "" and name ~= self.name - and specific_runaway(self.runaway_from, name) then - - p = player:get_pos() - sp = s - - -- aim higher to make looking up hills more realistic - p.y = p.y + 1 - sp.y = sp.y + 1 - - dist = vector.distance(p, s) - - - -- choose closest player/mpb to runaway from - if dist < min_dist - and line_of_sight(self, sp, p, 2) == true then - min_dist = dist - min_player = player - end - end - end - - if min_player then - - local lp = player:get_pos() - local vec = { - x = lp.x - s.x, - y = lp.y - s.y, - z = lp.z - s.z - } - - local yaw = (atan(vec.z / vec.x) + 3 * pi / 2) - self.rotate - - if lp.x > s.x then - yaw = yaw + pi - end - - yaw = set_yaw(self, yaw, 4) - self.state = "runaway" - self.runaway_timer = 3 - self.following = nil - end -end - - --- follow player if owner or holding item, if fish outta water then flop -local follow_flop = function(self) - - -- find player to follow - if (self.follow ~= "" - or self.order == "follow") - and not self.following - and self.state ~= "attack" - and self.order ~= "sit" - and self.state ~= "runaway" then - - local s = self.object:get_pos() - local players = minetest.get_connected_players() - - for n = 1, #players do - - if (object_in_range(self, players[n])) - and not mobs.invis[ players[n]:get_player_name() ] then - - self.following = players[n] - - break - end - end - end - - if self.type == "npc" - and self.order == "follow" - and self.state ~= "attack" - and self.order ~= "sit" - and self.owner ~= "" then - - -- npc stop following player if not owner - if self.following - and self.owner - and self.owner ~= self.following:get_player_name() then - self.following = nil - end - else - -- stop following player if not holding specific item, - -- mob is horny, fleeing or attacking - if self.following - and self.following:is_player() - and (follow_holding(self, self.following) == false or - self.horny or self.state == "runaway") then - self.following = nil - end - - end - - -- follow that thing - if self.following then - - local s = self.object:get_pos() - local p - - if self.following:is_player() then - - p = self.following:get_pos() - - elseif self.following.object then - - p = self.following.object:get_pos() - end - - if p then - - local dist = vector.distance(p, s) - - -- dont follow if out of range - if (not object_in_range(self, self.following)) then - self.following = nil - else - local vec = { - x = p.x - s.x, - z = p.z - s.z - } - - local yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - - if p.x > s.x then yaw = yaw + pi end - - set_yaw(self, yaw, 2.35) - - -- anyone but standing npc's can move along - if dist > 3 - and self.order ~= "stand" then - - set_velocity(self, self.follow_velocity) - - if self.walk_chance ~= 0 then - set_animation(self, "run") - end - else - set_velocity(self, 0) - set_animation(self, "stand") - end - - return - end - end - end - - -- swimmers flop when out of their element, and swim again when back in - if self.fly then - local s = self.object:get_pos() - if not flight_check(self, s) then - - self.state = "flop" - self.object:set_acceleration({x = 0, y = DEFAULT_FALL_SPEED, z = 0}) - - local sdef = minetest.registered_nodes[self.standing_on] - -- Flop on ground - if sdef and sdef.walkable then - mob_sound(self, "flop") - self.object:set_velocity({ - x = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED), - y = FLOP_HEIGHT, - z = math.random(-FLOP_HOR_SPEED, FLOP_HOR_SPEED), - }) - end - - set_animation(self, "stand", true) - - return - elseif self.state == "flop" then - self.state = "stand" - self.object:set_acceleration({x = 0, y = 0, z = 0}) - set_velocity(self, 0) - end - end -end - - --- dogshoot attack switch and counter function -local dogswitch = function(self, dtime) - - -- switch mode not activated - if not self.dogshoot_switch - or not dtime then - return 0 - end - - self.dogshoot_count = self.dogshoot_count + dtime - - if (self.dogshoot_switch == 1 - and self.dogshoot_count > self.dogshoot_count_max) - or (self.dogshoot_switch == 2 - and self.dogshoot_count > self.dogshoot_count2_max) then - - self.dogshoot_count = 0 - - if self.dogshoot_switch == 1 then - self.dogshoot_switch = 2 - else - self.dogshoot_switch = 1 - end - end - - return self.dogshoot_switch -end - --- execute current state (stand, walk, run, attacks) --- returns true if mob has died -local do_states = function(self, dtime) - - local yaw = self.object:get_yaw() or 0 +function do_states(self) if self.state == "stand" then - if random(1, 4) == 1 then + if math_random(1, 4) == 1 then local lp = nil local s = self.object:get_pos() - local objs = minetest.get_objects_inside_radius(s, 3) + local objs = minetest_get_objects_inside_radius(s, 3) for n = 1, #objs do @@ -2324,11 +2181,11 @@ local do_states = function(self, dtime) z = lp.z - s.z } - yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - if lp.x > s.x then yaw = yaw + pi end + if lp.x > s.x then yaw = yaw + math_pi end else - yaw = yaw + random(-0.5, 0.5) + yaw = yaw + math_random(-0.5, 0.5) end yaw = set_yaw(self, yaw, 8) @@ -2343,7 +2200,7 @@ local do_states = function(self, dtime) if self.walk_chance ~= 0 and self.facing_fence ~= true - and random(1, 100) <= self.walk_chance + and math_random(1, 100) <= self.walk_chance and is_at_cliff_or_danger(self) == false then set_velocity(self, self.walk_velocity) @@ -2362,19 +2219,19 @@ local do_states = function(self, dtime) and self.lava_damage > 0) or self.breath_max ~= -1 then - lp = minetest.find_node_near(s, 1, {"group:water", "group:lava"}) + lp = minetest_find_node_near(s, 1, {"group:water", "group:lava"}) elseif self.water_damage > 0 then - lp = minetest.find_node_near(s, 1, {"group:water"}) + lp = minetest_find_node_near(s, 1, {"group:water"}) elseif self.lava_damage > 0 then - lp = minetest.find_node_near(s, 1, {"group:lava"}) + lp = minetest_find_node_near(s, 1, {"group:lava"}) elseif self.fire_damage > 0 then - lp = minetest.find_node_near(s, 1, {"group:fire"}) + lp = minetest_find_node_near(s, 1, {"group:fire"}) end @@ -2388,12 +2245,12 @@ local do_states = function(self, dtime) -- If mob in or on dangerous block, look for land if is_in_danger then -- Better way to find shore - copied from upstream - lp = minetest.find_nodes_in_area_under_air( + lp = minetest_find_nodes_in_area_under_air( {x = s.x - 5, y = s.y - 0.5, z = s.z - 5}, {x = s.x + 5, y = s.y + 1, z = s.z + 5}, {"group:solid"}) - lp = #lp > 0 and lp[random(#lp)] + lp = #lp > 0 and lp[math_random(#lp)] -- did we find land? if lp then @@ -2403,10 +2260,10 @@ local do_states = function(self, dtime) z = lp.z - s.z } - yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - if lp.x > s.x then yaw = yaw + pi end + if lp.x > s.x then yaw = yaw + math_pi end -- look towards land and move in that direction yaw = set_yaw(self, yaw, 6) @@ -2419,8 +2276,8 @@ local do_states = function(self, dtime) else -- Randomly turn - if random(1, 100) <= 30 then - yaw = yaw + random(-0.5, 0.5) + if math_random(1, 100) <= 30 then + yaw = yaw + math_random(-0.5, 0.5) yaw = set_yaw(self, yaw, 8) end end @@ -2428,9 +2285,9 @@ local do_states = function(self, dtime) yaw = set_yaw(self, yaw, 8) -- otherwise randomly turn - elseif random(1, 100) <= 30 then + elseif math_random(1, 100) <= 30 then - yaw = yaw + random(-0.5, 0.5) + yaw = yaw + math_random(-0.5, 0.5) yaw = set_yaw(self, yaw, 8) end @@ -2441,7 +2298,7 @@ local do_states = function(self, dtime) end if self.facing_fence == true or cliff_or_danger - or random(1, 100) <= 30 then + or math_random(1, 100) <= 30 then set_velocity(self, 0) self.state = "stand" @@ -2516,9 +2373,9 @@ local do_states = function(self, dtime) z = p.z - s.z } - yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - if p.x > s.x then yaw = yaw + pi end + if p.x > s.x then yaw = yaw + math_pi end yaw = set_yaw(self, yaw, 0, dtime) @@ -2584,10 +2441,10 @@ local do_states = function(self, dtime) local pos = self.object:get_pos() if mod_explosions then - if mobs_griefing and not minetest.is_protected(pos, "") then + if mobs_griefing and not minetest_is_protected(pos, "") then mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object) else - minetest.sound_play(self.sounds.explode, { + minetest_sound_play(self.sounds.explode, { pos = pos, gain = 1.0, max_hear_distance = self.sounds.distance or 32 @@ -2612,9 +2469,9 @@ local do_states = function(self, dtime) and dist > self.reach then local p1 = s - local me_y = floor(p1.y) + local me_y = math_floor(p1.y) local p2 = p - local p_y = floor(p2.y + 1) + local p_y = math_floor(p2.y + 1) local v = self.object:get_velocity() if flight_check(self, s) then @@ -2675,7 +2532,7 @@ local do_states = function(self, dtime) return end - if abs(p1.x-s.x) + abs(p1.z - s.z) < 0.6 then + if math_abs(p1.x-s.x) + math_abs(p1.z - s.z) < 0.6 then -- reached waypoint, remove it from queue table.remove(self.path.way, 1) end @@ -2689,9 +2546,9 @@ local do_states = function(self, dtime) z = p.z - s.z } - yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - if p.x > s.x then yaw = yaw + pi end + if p.x > s.x then yaw = yaw + math_pi end yaw = set_yaw(self, yaw, 0, dtime) @@ -2741,7 +2598,7 @@ local do_states = function(self, dtime) self.timer = 0 if self.double_melee_attack - and random(1, 2) == 1 then + and math_random(1, 2) == 1 then set_animation(self, "punch2") else set_animation(self, "punch") @@ -2794,9 +2651,9 @@ local do_states = function(self, dtime) z = p.z - s.z } - yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate - if p.x > s.x then yaw = yaw + pi end + if p.x > s.x then yaw = yaw + math_pi end yaw = set_yaw(self, yaw, 0, dtime) @@ -2807,8 +2664,8 @@ local do_states = function(self, dtime) if self.shoot_interval and self.timer > self.shoot_interval - and not minetest.raycast(p, self.attack:get_pos(), false, false):next() - and random(1, 100) <= 60 then + and not minetest_raycast(p, self.attack:get_pos(), false, false):next() + and math_random(1, 100) <= 60 then self.timer = 0 set_animation(self, "shoot") @@ -2817,16 +2674,16 @@ local do_states = function(self, dtime) mob_sound(self, "shoot_attack") -- Shoot arrow - if minetest.registered_entities[self.arrow] then + if minetest_registered_entities[self.arrow] then local arrow, ent local v = 1 if not self.shoot_arrow then self.firing = true - minetest.after(1, function() + minetest_after(1, function() self.firing = false end) - arrow = minetest.add_entity(p, self.arrow) + arrow = minetest_add_entity(p, self.arrow) ent = arrow:get_luaentity() if ent.velocity then v = ent.velocity @@ -2854,851 +2711,48 @@ local do_states = function(self, dtime) end --- falling and fall damage --- returns true if mob died -local falling = function(self, pos) - if self.fly and self.state ~= "die" then + +-- above function exported for mount.lua +function mobs:set_animation(self, anim) + set_animation(self, anim) +end + + +-- set defined animation +local set_animation = function(self, anim, fixed_frame) + if not self.animation or not anim then + return + end + if self.state == "die" and anim ~= "die" and anim ~= "stand" then return end - if mcl_portals ~= nil then - if mcl_portals.nether_portal_cooloff(self.object) then - return false -- mob has teleported through Nether portal - it's 99% not falling - end + self.animation.current = self.animation.current or "" + + if (anim == self.animation.current + or not self.animation[anim .. "_start"] + or not self.animation[anim .. "_end"]) and self.state ~= "die" then + return end - -- floating in water (or falling) - local v = self.object:get_velocity() + self.animation.current = anim - if v.y > 0 then - - -- apply gravity when moving up - self.object:set_acceleration({ - x = 0, - y = -10, - z = 0 - }) - - elseif v.y <= 0 and v.y > self.fall_speed then - - -- fall downwards at set speed - self.object:set_acceleration({ - x = 0, - y = self.fall_speed, - z = 0 - }) + local a_start = self.animation[anim .. "_start"] + local a_end + if fixed_frame then + a_end = a_start else - -- stop accelerating once max fall speed hit - self.object:set_acceleration({x = 0, y = 0, z = 0}) + a_end = self.animation[anim .. "_end"] end - if minetest.registered_nodes[node_ok(pos).name].groups.lava then - - if self.floats_on_lava == 1 then - - self.object:set_acceleration({ - x = 0, - y = -self.fall_speed / (max(1, v.y) ^ 2), - z = 0 - }) - end - end - - -- in water then float up - if minetest.registered_nodes[node_ok(pos).name].groups.water then - - if self.floats == 1 then - - self.object:set_acceleration({ - x = 0, - y = -self.fall_speed / (max(1, v.y) ^ 2), - z = 0 - }) - end - else - - -- fall damage onto solid ground - if self.fall_damage == 1 - and self.object:get_velocity().y == 0 then - - local d = (self.old_y or 0) - self.object:get_pos().y - - if d > 5 then - - local add = minetest.get_item_group(self.standing_on, "fall_damage_add_percent") - local damage = d - 5 - if add ~= 0 then - damage = damage + damage * (add/100) - end - damage = floor(damage) - if damage > 0 then - self.health = self.health - damage - - effect(pos, 5, "mcl_particles_smoke.png", 1, 2, 2, nil) - - if check_for_death(self, "fall", {type = "fall"}) then - return true - end - end - end - - self.old_y = self.object:get_pos().y - end - end + self.object:set_animation({ + x = a_start, + y = a_end}, + self.animation[anim .. "_speed"] or self.animation.speed_normal or 15, + 0, self.animation[anim .. "_loop"] ~= false) end -local teleport = function(self, target) - if self.do_teleport then - if self.do_teleport(self, target) == false then - return - end - end -end - - --- deal damage and effects when mob punched -local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) - - -- custom punch function - if self.do_punch then - - -- when false skip going any further - if self.do_punch(self, hitter, tflp, tool_capabilities, dir) == false then - return - end - end - - -- error checking when mod profiling is enabled - if not tool_capabilities then - minetest.log("warning", "[mobs] Mod profiling enabled, damage not enabled") - return - end - - local is_player = hitter:is_player() - - if is_player then - -- is mob protected? - if self.protected and minetest.is_protected(self.object:get_pos(), hitter:get_player_name()) then - return - end - - -- set/update 'drop xp' timestamp if hitted by player - self.xp_timestamp = minetest.get_us_time() - end - - - -- punch interval - local weapon = hitter:get_wielded_item() - local punch_interval = 1.4 - - -- exhaust attacker - if mod_hunger and is_player then - mcl_hunger.exhaust(hitter:get_player_name(), mcl_hunger.EXHAUST_ATTACK) - end - - -- calculate mob damage - local damage = 0 - local armor = self.object:get_armor_groups() or {} - local tmp - - -- quick error check incase it ends up 0 (serialize.h check test) - if tflp == 0 then - tflp = 0.2 - end - - if use_cmi then - damage = cmi.calculate_damage(self.object, hitter, tflp, tool_capabilities, dir) - else - - for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do - - tmp = tflp / (tool_capabilities.full_punch_interval or 1.4) - - if tmp < 0 then - tmp = 0.0 - elseif tmp > 1 then - tmp = 1.0 - end - - damage = damage + (tool_capabilities.damage_groups[group] or 0) - * tmp * ((armor[group] or 0) / 100.0) - end - end - - if weapon then - local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect") - if fire_aspect_level > 0 then - mcl_burning.set_on_fire(self.object, fire_aspect_level * 4) - end - end - - -- check for tool immunity or special damage - for n = 1, #self.immune_to do - - if self.immune_to[n][1] == weapon:get_name() then - - damage = self.immune_to[n][2] or 0 - break - end - end - - -- healing - if damage <= -1 then - self.health = self.health - floor(damage) - return - end - - if use_cmi then - - local cancel = cmi.notify_punch(self.object, hitter, tflp, tool_capabilities, dir, damage) - - if cancel then return end - end - - if tool_capabilities then - punch_interval = tool_capabilities.full_punch_interval or 1.4 - end - - -- add weapon wear manually - -- Required because we have custom health handling ("health" property) - if minetest.is_creative_enabled("") ~= true - and tool_capabilities then - if tool_capabilities.punch_attack_uses then - -- Without this delay, the wear does not work. Quite hacky ... - minetest.after(0, function(name) - local player = minetest.get_player_by_name(name) - if not player then return end - local weapon = hitter:get_wielded_item(player) - local def = weapon:get_definition() - if def.tool_capabilities and def.tool_capabilities.punch_attack_uses then - local wear = floor(65535/tool_capabilities.punch_attack_uses) - weapon:add_wear(wear) - hitter:set_wielded_item(weapon) - end - end, hitter:get_player_name()) - end - end - - local die = false - - -- only play hit sound and show blood effects if damage is 1 or over; lower to 0.1 to ensure armor works appropriately. - if damage >= 0.1 then - - -- weapon sounds - if weapon:get_definition().sounds ~= nil then - - local s = random(0, #weapon:get_definition().sounds) - - minetest.sound_play(weapon:get_definition().sounds[s], { - object = self.object, --hitter, - max_hear_distance = 8 - }, true) - else - minetest.sound_play("default_punch", { - object = self.object, - max_hear_distance = 5 - }, true) - end - - damage_effect(self, damage) - - -- do damage - self.health = self.health - damage - - -- skip future functions if dead, except alerting others - if check_for_death(self, "hit", {type = "punch", puncher = hitter}) then - die = true - end - - -- knock back effect (only on full punch) - if not die - and self.knock_back - and tflp >= punch_interval then - - local v = self.object:get_velocity() - local r = 1.4 - min(punch_interval, 1.4) - local kb = r * 2.0 - local up = 2 - - -- if already in air then dont go up anymore when hit - if v.y ~= 0 - or self.fly then - up = 0 - end - - -- direction error check - dir = dir or {x = 0, y = 0, z = 0} - - -- check if tool already has specific knockback value - if tool_capabilities.damage_groups["knockback"] then - kb = tool_capabilities.damage_groups["knockback"] - else - kb = kb * 1.5 - end - - - local luaentity - if hitter then - luaentity = hitter:get_luaentity() - end - if hitter and is_player then - local wielditem = hitter:get_wielded_item() - kb = kb + 3 * mcl_enchanting.get_enchantment(wielditem, "knockback") - elseif luaentity and luaentity._knockback then - kb = kb + luaentity._knockback - end - - self.object:set_velocity({ - x = dir.x * kb, - y = dir.y * kb + up * 2, - z = dir.z * kb - }) - - self.pause_timer = 0.25 - end - end -- END if damage - - -- if skittish then run away - if not die and self.runaway == true and self.state ~= "flop" then - - local lp = hitter:get_pos() - local s = self.object:get_pos() - local vec = { - x = lp.x - s.x, - y = lp.y - s.y, - z = lp.z - s.z - } - - local yaw = (atan(vec.z / vec.x) + 3 * pi / 2) - self.rotate - - if lp.x > s.x then - yaw = yaw + pi - end - - yaw = set_yaw(self, yaw, 6) - self.state = "runaway" - self.runaway_timer = 0 - self.following = nil - end - - local name = hitter:get_player_name() or "" - - -- attack puncher and call other mobs for help - if self.passive == false - and self.state ~= "flop" - and (self.child == false or self.type == "monster") - and hitter:get_player_name() ~= self.owner - and not mobs.invis[ name ] then - - if not die then - -- attack whoever punched mob - self.state = "" - do_attack(self, hitter) - end - - -- alert others to the attack - local objs = minetest.get_objects_inside_radius(hitter:get_pos(), self.view_range) - local obj = nil - - for n = 1, #objs do - - obj = objs[n]:get_luaentity() - - if obj then - - -- only alert members of same mob or friends - if obj.group_attack - and obj.state ~= "attack" - and obj.owner ~= name then - if obj.name == self.name then - do_attack(obj, hitter) - elseif type(obj.group_attack) == "table" then - for i=1, #obj.group_attack do - if obj.name == obj.group_attack[i] then - do_attack(obj, hitter) - break - end - end - end - end - - -- have owned mobs attack player threat - if obj.owner == name and obj.owner_loyal then - do_attack(obj, self.object) - end - end - end - end -end - -local mob_detach_child = function(self, child) - - if self.driver == child then - self.driver = nil - end - -end - --- get entity staticdata -local mob_staticdata = function(self) - ---[[ - -- remove mob when out of range unless tamed - if remove_far - and self.can_despawn - and self.remove_ok - and ((not self.nametag) or (self.nametag == "")) - and self.lifetimer <= 20 then - - minetest.log("action", "Mob "..name.." despawns in mob_staticdata at "..minetest.pos_to_string(self.object.get_pos(), 1)) - mcl_burning.extinguish(self.object) - self.object:remove() - - return ""-- nil - end ---]] - self.remove_ok = true - self.attack = nil - self.following = nil - self.state = "stand" - - if use_cmi then - self.serialized_cmi_components = cmi.serialize_components(self._cmi_components) - end - - local tmp = {} - - for _,stat in pairs(self) do - - local t = type(stat) - - if t ~= "function" - and t ~= "nil" - and t ~= "userdata" - and _ ~= "_cmi_components" then - tmp[_] = self[_] - end - end - - return minetest.serialize(tmp) -end - - --- activate mob and reload settings -local mob_activate = function(self, staticdata, def, dtime) - - -- remove monsters in peaceful mode - if self.type == "monster" - and minetest.settings:get_bool("only_peaceful_mobs", false) then - mcl_burning.extinguish(self.object) - self.object:remove() - - return - end - - -- load entity variables - local tmp = minetest.deserialize(staticdata) - - if tmp then - for _,stat in pairs(tmp) do - self[_] = stat - end - end - - -- select random texture, set model and size - if not self.base_texture then - - -- compatiblity with old simple mobs textures - if type(def.textures[1]) == "string" then - def.textures = {def.textures} - end - - self.base_texture = def.textures[random(1, #def.textures)] - self.base_mesh = def.mesh - self.base_size = self.visual_size - self.base_colbox = self.collisionbox - self.base_selbox = self.selectionbox - end - - -- for current mobs that dont have this set - if not self.base_selbox then - self.base_selbox = self.selectionbox or self.base_colbox - end - - -- set texture, model and size - local textures = self.base_texture - local mesh = self.base_mesh - local vis_size = self.base_size - local colbox = self.base_colbox - local selbox = self.base_selbox - - -- specific texture if gotten - if self.gotten == true - and def.gotten_texture then - textures = def.gotten_texture - end - - -- specific mesh if gotten - if self.gotten == true - and def.gotten_mesh then - mesh = def.gotten_mesh - end - - -- set child objects to half size - if self.child == true then - - vis_size = { - x = self.base_size.x * .5, - y = self.base_size.y * .5, - } - - if def.child_texture then - textures = def.child_texture[1] - end - - colbox = { - self.base_colbox[1] * .5, - self.base_colbox[2] * .5, - self.base_colbox[3] * .5, - self.base_colbox[4] * .5, - self.base_colbox[5] * .5, - self.base_colbox[6] * .5 - } - selbox = { - self.base_selbox[1] * .5, - self.base_selbox[2] * .5, - self.base_selbox[3] * .5, - self.base_selbox[4] * .5, - self.base_selbox[5] * .5, - self.base_selbox[6] * .5 - } - end - - if self.health == 0 then - self.health = random (self.hp_min, self.hp_max) - end - if self.breath == nil then - self.breath = self.breath_max - end - - -- pathfinding init - self.path = {} - self.path.way = {} -- path to follow, table of positions - self.path.lastpos = {x = 0, y = 0, z = 0} - self.path.stuck = false - self.path.following = false -- currently following path? - self.path.stuck_timer = 0 -- if stuck for too long search for path - - -- Armor groups - -- immortal=1 because we use custom health - -- handling (using "health" property) - local armor - if type(self.armor) == "table" then - armor = table.copy(self.armor) - armor.immortal = 1 - else - armor = {immortal=1, fleshy = self.armor} - end - self.object:set_armor_groups(armor) - self.old_y = self.object:get_pos().y - self.old_health = self.health - self.sounds.distance = self.sounds.distance or 10 - self.textures = textures - self.mesh = mesh - self.collisionbox = colbox - self.selectionbox = selbox - self.visual_size = vis_size - self.standing_in = "ignore" - self.standing_on = "ignore" - self.jump_sound_cooloff = 0 -- used to prevent jump sound from being played too often in short time - self.opinion_sound_cooloff = 0 -- used to prevent sound spam of particular sound types - - self.texture_mods = {} - self.object:set_texture_mod("") - - self.v_start = false - self.timer = 0 - self.blinktimer = 0 - self.blinkstatus = false - - -- check existing nametag - if not self.nametag then - self.nametag = def.nametag - end - - -- set anything changed above - self.object:set_properties(self) - set_yaw(self, (random(0, 360) - 180) / 180 * pi, 6) - update_tag(self) - set_animation(self, "stand") - - -- run on_spawn function if found - if self.on_spawn and not self.on_spawn_run then - if self.on_spawn(self) then - self.on_spawn_run = true -- if true, set flag to run once only - end - end - - -- run after_activate - if def.after_activate then - def.after_activate(self, staticdata, def, dtime) - end - - if use_cmi then - self._cmi_components = cmi.activate_components(self.serialized_cmi_components) - cmi.notify_activate(self.object, dtime) - end -end - - --- main mob function -local mob_step = function(self, dtime) - - if not self.fire_resistant then - mcl_burning.tick(self.object, dtime, self) - end - - if use_cmi then - cmi.notify_step(self.object, dtime) - end - - local pos = self.object:get_pos() - local yaw = 0 - - if mobs_debug then - update_tag(self) - end - - if self.state == "die" then - return - end - - if self.jump_sound_cooloff > 0 then - self.jump_sound_cooloff = self.jump_sound_cooloff - dtime - end - if self.opinion_sound_cooloff > 0 then - self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime - end - if falling(self, pos) then - -- Return if mob died after falling - return - end - - -- smooth rotation by ThomasMonroe314 - - if self.delay and self.delay > 0 then - - local yaw = self.object:get_yaw() or 0 - - if self.delay == 1 then - yaw = self.target_yaw - else - local dif = abs(yaw - self.target_yaw) - - if yaw > self.target_yaw then - - if dif > pi then - dif = 2 * pi - dif -- need to add - yaw = yaw + dif / self.delay - else - yaw = yaw - dif / self.delay -- need to subtract - end - - elseif yaw < self.target_yaw then - - if dif > pi then - dif = 2 * pi - dif - yaw = yaw - dif / self.delay -- need to subtract - else - yaw = yaw + dif / self.delay -- need to add - end - end - - if yaw > (pi * 2) then yaw = yaw - (pi * 2) end - if yaw < 0 then yaw = yaw + (pi * 2) end - end - - self.delay = self.delay - 1 - if self.shaking then - yaw = yaw + (math.random() * 2 - 1) * 5 * dtime - end - self.object:set_yaw(yaw) - update_roll(self) - end - - -- end rotation - - -- run custom function (defined in mob lua file) - if self.do_custom then - - -- when false skip going any further - if self.do_custom(self, dtime) == false then - return - end - end - - -- knockback timer - if self.pause_timer > 0 then - - self.pause_timer = self.pause_timer - dtime - - return - end - - -- attack timer - self.timer = self.timer + dtime - - if self.state ~= "attack" then - - if self.timer < 1 then - return - end - - self.timer = 0 - end - - -- never go over 100 - if self.timer > 100 then - self.timer = 1 - end - - -- mob plays random sound at times - if random(1, 70) == 1 then - mob_sound(self, "random", true) - end - - -- environmental damage timer (every 1 second) - self.env_damage_timer = self.env_damage_timer + dtime - - if (self.state == "attack" and self.env_damage_timer > 1) - or self.state ~= "attack" then - - self.env_damage_timer = 0 - - -- check for environmental damage (water, fire, lava etc.) - if do_env_damage(self) then - return - end - - -- node replace check (cow eats grass etc.) - replace(self, pos) - end - - monster_attack(self) - - npc_attack(self) - - breed(self) - - if do_states(self, dtime) then - return - end - - if not self.object:get_luaentity() then - return false - end - - do_jump(self) - - runaway_from(self) - - if is_at_water_danger(self) and self.state ~= "attack" then - if random(1, 10) <= 6 then - set_velocity(self, 0) - self.state = "stand" - set_animation(self, "stand") - yaw = yaw + random(-0.5, 0.5) - yaw = set_yaw(self, yaw, 8) - end - end - - -- Add water flowing for mobs from mcl_item_entity - local p, node, nn, def - p = self.object:get_pos() - node = minetest.get_node_or_nil(p) - if node then - nn = node.name - def = minetest.registered_nodes[nn] - end - - -- Move item around on flowing liquids - if def and def.liquidtype == "flowing" then - - --[[ Get flowing direction (function call from flowlib), if there's a liquid. - NOTE: According to Qwertymine, flowlib.quickflow is only reliable for liquids with a flowing distance of 7. - Luckily, this is exactly what we need if we only care about water, which has this flowing distance. ]] - local vec = flowlib.quick_flow(p, node) - -- Just to make sure we don't manipulate the speed for no reason - if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then - -- Minecraft Wiki: Flowing speed is "about 1.39 meters per second" - local f = 1.39 - -- Set new item moving speed into the direciton of the liquid - local newv = vector.multiply(vec, f) - self.object:set_acceleration({x = 0, y = 0, z = 0}) - self.object:set_velocity({x = newv.x, y = -0.22, z = newv.z}) - - self.physical_state = true - self._flowing = true - self.object:set_properties({ - physical = true - }) - return - end - elseif self._flowing == true then - -- Disable flowing physics if not on/in flowing liquid - self._flowing = false - enable_physics(self.object, self, true) - return - end - - --Mob following code. - follow_flop(self) - - if is_at_cliff_or_danger(self) then - set_velocity(self, 0) - self.state = "stand" - set_animation(self, "stand") - local yaw = self.object:get_yaw() or 0 - yaw = set_yaw(self, yaw + 0.78, 8) - end - - -- Despawning: when lifetimer expires, remove mob - if remove_far - and self.can_despawn == true - and ((not self.nametag) or (self.nametag == "")) - and self.state ~= "attack" - and self.following == nil then - - self.lifetimer = self.lifetimer - dtime - if self.despawn_immediately or self.lifetimer <= 0 then - minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos, 1)) - mcl_burning.extinguish(self.object) - self.object:remove() - elseif self.lifetimer <= 10 then - if math.random(10) < 4 then - self.despawn_immediately = true - else - self.lifetimer = 20 - end - end - end -end - - --- default function when mobs are blown up with TNT -local do_tnt = function(obj, damage) - - obj.object:punch(obj.object, 1.0, { - full_punch_interval = 1.0, - damage_groups = {fleshy = damage}, - }, nil) - - return false, true, {} -end - - -mobs.spawning_mobs = {} -- Code to execute before custom on_rightclick handling local on_rightclick_prefix = function(self, clicker) @@ -3736,643 +2790,201 @@ local create_mob_on_rightclick = function(on_rightclick) end end --- register mob entity -function mobs:register_mob(name, def) +-- set and return valid yaw +local set_yaw = function(self, yaw, delay, dtime) - mobs.spawning_mobs[name] = true - -local can_despawn -if def.can_despawn ~= nil then - can_despawn = def.can_despawn -elseif def.spawn_class == "passive" then - can_despawn = false -else - can_despawn = true -end - -local function scale_difficulty(value, default, min, special) - if (not value) or (value == default) or (value == special) then - return default - else - return max(min, value * difficulty) - end -end - -local collisionbox = def.collisionbox or {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25} --- Workaround for : --- Increase upper Y limit to avoid mobs glitching through solid nodes. --- FIXME: Remove workaround if it's no longer needed. -if collisionbox[5] < 0.79 then - collisionbox[5] = 0.79 -end - -minetest.register_entity(name, { - - use_texture_alpha = def.use_texture_alpha, - stepheight = def.stepheight or 0.6, - name = name, - description = def.description, - type = def.type, - attack_type = def.attack_type, - fly = def.fly, - fly_in = def.fly_in or {"air", "__airlike"}, - owner = def.owner or "", - order = def.order or "", - on_die = def.on_die, - spawn_small_alternative = def.spawn_small_alternative, - do_custom = def.do_custom, - jump_height = def.jump_height or 4, -- was 6 - rotate = math.rad(def.rotate or 0), -- 0=front, 90=side, 180=back, 270=side2 - lifetimer = def.lifetimer or 57.73, - hp_min = scale_difficulty(def.hp_min, 5, 1), - hp_max = scale_difficulty(def.hp_max, 10, 1), - xp_min = def.xp_min or 0, - xp_max = def.xp_max or 0, - xp_timestamp = 0, - breath_max = def.breath_max or 15, - breathes_in_water = def.breathes_in_water or false, - physical = true, - collisionbox = collisionbox, - selectionbox = def.selectionbox or def.collisionbox, - visual = def.visual, - visual_size = def.visual_size or {x = 1, y = 1}, - mesh = def.mesh, - makes_footstep_sound = def.makes_footstep_sound or false, - view_range = def.view_range or 16, - walk_velocity = def.walk_velocity or 1, - run_velocity = def.run_velocity or 2, - damage = scale_difficulty(def.damage, 0, 0), - light_damage = def.light_damage or 0, - sunlight_damage = def.sunlight_damage or 0, - water_damage = def.water_damage or 0, - lava_damage = def.lava_damage or 8, - fire_damage = def.fire_damage or 1, - suffocation = def.suffocation or true, - fall_damage = def.fall_damage or 1, - fall_speed = def.fall_speed or DEFAULT_FALL_SPEED, -- must be lower than -2 - drops = def.drops or {}, - armor = def.armor or 100, - on_rightclick = create_mob_on_rightclick(def.on_rightclick), - arrow = def.arrow, - shoot_interval = def.shoot_interval, - sounds = def.sounds or {}, - animation = def.animation, - follow = def.follow, - jump = def.jump ~= false, - walk_chance = def.walk_chance or 50, - attacks_monsters = def.attacks_monsters or false, - group_attack = def.group_attack or false, - passive = def.passive or false, - knock_back = def.knock_back ~= false, - shoot_offset = def.shoot_offset or 0, - floats = def.floats or 1, -- floats in water by default - floats_on_lava = def.floats_on_lava or 0, - replace_rate = def.replace_rate, - replace_what = def.replace_what, - replace_with = def.replace_with, - replace_offset = def.replace_offset or 0, - on_replace = def.on_replace, - timer = 0, - env_damage_timer = 0, - tamed = false, - pause_timer = 0, - horny = false, - hornytimer = 0, - gotten = false, - health = 0, - reach = def.reach or 3, - htimer = 0, - texture_list = def.textures, - child_texture = def.child_texture, - docile_by_day = def.docile_by_day or false, - time_of_day = 0.5, - fear_height = def.fear_height or 0, - runaway = def.runaway, - runaway_timer = 0, - pathfinding = def.pathfinding, - immune_to = def.immune_to or {}, - explosion_radius = def.explosion_radius, -- LEGACY - explosion_damage_radius = def.explosion_damage_radius, -- LEGACY - explosiontimer_reset_radius = def.explosiontimer_reset_radius, - explosion_timer = def.explosion_timer or 3, - allow_fuse_reset = def.allow_fuse_reset ~= false, - stop_to_explode = def.stop_to_explode ~= false, - custom_attack = def.custom_attack, - double_melee_attack = def.double_melee_attack, - dogshoot_switch = def.dogshoot_switch, - dogshoot_count = 0, - dogshoot_count_max = def.dogshoot_count_max or 5, - dogshoot_count2_max = def.dogshoot_count2_max or (def.dogshoot_count_max or 5), - attack_animals = def.attack_animals or false, - specific_attack = def.specific_attack, - runaway_from = def.runaway_from, - owner_loyal = def.owner_loyal, - facing_fence = false, - _cmi_is_mob = true, - pushable = def.pushable or true, - - - -- MCL2 extensions - teleport = teleport, - do_teleport = def.do_teleport, - spawn_class = def.spawn_class, - ignores_nametag = def.ignores_nametag or false, - rain_damage = def.rain_damage or 0, - glow = def.glow, - can_despawn = can_despawn, - child = def.child or false, - texture_mods = {}, - shoot_arrow = def.shoot_arrow, - sounds_child = def.sounds_child, - explosion_strength = def.explosion_strength, - suffocation_timer = 0, - follow_velocity = def.follow_velocity or 2.4, - instant_death = def.instant_death or false, - fire_resistant = def.fire_resistant or false, - fire_damage_resistant = def.fire_damage_resistant or false, - ignited_by_sunlight = def.ignited_by_sunlight or false, - -- End of MCL2 extensions - - on_spawn = def.on_spawn, - - on_blast = def.on_blast or do_tnt, - - on_step = mob_step, - - do_punch = def.do_punch, - - on_punch = mob_punch, - - on_breed = def.on_breed, - - on_grown = def.on_grown, - - on_detach_child = mob_detach_child, - - on_activate = function(self, staticdata, dtime) - --this is a temporary hack so mobs stop - --glitching and acting really weird with the - --default built in engine collision detection - self.object:set_properties({ - collide_with_objects = false, - }) - return mob_activate(self, staticdata, def, dtime) - end, - - get_staticdata = function(self) - return mob_staticdata(self) - end, - - harmed_by_heal = def.harmed_by_heal, - -}) - -if minetest.get_modpath("doc_identifier") ~= nil then - doc.sub.identifier.register_object(name, "basics", "mobs") -end - -end -- END mobs:register_mob function - - --- register arrow for shoot attack -function mobs:register_arrow(name, def) - - if not name or not def then return end -- errorcheck - - minetest.register_entity(name, { - - physical = false, - visual = def.visual, - visual_size = def.visual_size, - textures = def.textures, - velocity = def.velocity, - hit_player = def.hit_player, - hit_node = def.hit_node, - hit_mob = def.hit_mob, - hit_object = def.hit_object, - drop = def.drop or false, -- drops arrow as registered item when true - collisionbox = {0, 0, 0, 0, 0, 0}, -- remove box around arrows - timer = 0, - switch = 0, - owner_id = def.owner_id, - rotate = def.rotate, - on_punch = function(self) - local vel = self.object:get_velocity() - self.object:set_velocity({x=vel.x * -1, y=vel.y * -1, z=vel.z * -1}) - end, - collisionbox = def.collisionbox or {0, 0, 0, 0, 0, 0}, - automatic_face_movement_dir = def.rotate - and (def.rotate - (pi / 180)) or false, - - on_activate = def.on_activate, - - on_step = def.on_step or function(self, dtime) - - self.timer = self.timer + 1 - - local pos = self.object:get_pos() - - if self.switch == 0 - or self.timer > 150 - or not within_limits(pos, 0) then - mcl_burning.extinguish(self.object) - self.object:remove(); - - return - end - - -- does arrow have a tail (fireball) - if def.tail - and def.tail == 1 - and def.tail_texture then - - minetest.add_particle({ - pos = pos, - velocity = {x = 0, y = 0, z = 0}, - acceleration = {x = 0, y = 0, z = 0}, - expirationtime = def.expire or 0.25, - collisiondetection = false, - texture = def.tail_texture, - size = def.tail_size or 5, - glow = def.glow or 0, - }) - end - - if self.hit_node then - - local node = node_ok(pos).name - - if minetest.registered_nodes[node].walkable then - - self.hit_node(self, pos, node) - - if self.drop == true then - - pos.y = pos.y + 1 - - self.lastpos = (self.lastpos or pos) - - minetest.add_item(self.lastpos, self.object:get_luaentity().name) - end - - self.object:remove(); - - return - end - end - - if self.hit_player or self.hit_mob or self.hit_object then - - for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do - - if self.hit_player - and player:is_player() then - - self.hit_player(self, player) - self.object:remove(); - return - end - - local entity = player:get_luaentity() - - if entity - and self.hit_mob - and entity._cmi_is_mob == true - and tostring(player) ~= self.owner_id - and entity.name ~= self.object:get_luaentity().name then - self.hit_mob(self, player) - self.object:remove(); - return - end - - if entity - and self.hit_object - and (not entity._cmi_is_mob) - and tostring(player) ~= self.owner_id - and entity.name ~= self.object:get_luaentity().name then - self.hit_object(self, player) - self.object:remove(); - return - end - end - end - - self.lastpos = pos - end - }) -end - - --- no damage to nodes explosion -function mobs:safe_boom(self, pos, strength) - minetest.sound_play(self.sounds and self.sounds.explode or "tnt_explode", { - pos = pos, - gain = 1.0, - max_hear_distance = self.sounds and self.sounds.distance or 32 - }, true) - local radius = strength - entity_physics(pos, radius) - effect(pos, 32, "mcl_particles_smoke.png", radius * 3, radius * 5, radius, 1, 0) -end - - --- make explosion with protection and tnt mod check -function mobs:boom(self, pos, strength, fire) - self.object:remove() - if mod_explosions then - if mobs_griefing and not minetest.is_protected(pos, "") then - mcl_explosions.explode(pos, strength, { drop_chance = 1.0, fire = fire }, self.object) - else - mobs:safe_boom(self, pos, strength) - end - else - mobs:safe_boom(self, pos, strength) - end -end - - --- Register spawn eggs - --- Note: This also introduces the “spawn_egg” group: --- * spawn_egg=1: Spawn egg (generic mob, no metadata) --- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata) -function mobs:register_egg(mob, desc, background, addegg, no_creative) - - local grp = {spawn_egg = 1} - - -- do NOT add this egg to creative inventory (e.g. dungeon master) - if no_creative == true then - grp.not_in_creative_inventory = 1 + if not yaw or yaw ~= yaw then + yaw = 0 end - local invimg = background + delay = delay or 0 - if addegg == 1 then - invimg = "mobs_chicken_egg.png^(" .. invimg .. - "^[mask:mobs_chicken_egg_overlay.png)" + if delay == 0 then + if self.shaking and dtime then + yaw = yaw + (math_random() * 2 - 1) * 5 * dtime + end + self.yaw(yaw) + update_roll(self) + return yaw end - -- register old stackable mob egg - minetest.register_craftitem(mob, { - - description = desc, - inventory_image = invimg, - groups = grp, - - _doc_items_longdesc = S("This allows you to place a single mob."), - _doc_items_usagehelp = S("Just place it where you want the mob to appear. Animals will spawn tamed, unless you hold down the sneak key while placing. If you place this on a mob spawner, you change the mob it spawns."), - - on_place = function(itemstack, placer, pointed_thing) - - local pos = pointed_thing.above - - -- am I clicking on something with existing on_rightclick function? - local under = minetest.get_node(pointed_thing.under) - local def = minetest.registered_nodes[under.name] - if def and def.on_rightclick then - return def.on_rightclick(pointed_thing.under, under, placer, itemstack) - end - - if pos - and within_limits(pos, 0) - and not minetest.is_protected(pos, placer:get_player_name()) then - - local name = placer:get_player_name() - local privs = minetest.get_player_privs(name) - if mod_mobspawners and under.name == "mcl_mobspawners:spawner" then - if minetest.is_protected(pointed_thing.under, name) then - minetest.record_protection_violation(pointed_thing.under, name) - return itemstack - end - if not privs.maphack then - minetest.chat_send_player(name, S("You need the “maphack” privilege to change the mob spawner.")) - return itemstack - end - mcl_mobspawners.setup_spawner(pointed_thing.under, itemstack:get_name()) - if not mobs.is_creative(name) then - itemstack:take_item() - end - return itemstack - end - - if not minetest.registered_entities[mob] then - return itemstack - end - - if minetest.settings:get_bool("only_peaceful_mobs", false) - and minetest.registered_entities[mob].type == "monster" then - minetest.chat_send_player(name, S("Only peaceful mobs allowed!")) - return itemstack - end - - pos.y = pos.y - 0.5 - - local mob = minetest.add_entity(pos, mob) - minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos)) - local ent = mob:get_luaentity() - - -- don't set owner if monster or sneak pressed - if ent.type ~= "monster" - and not placer:get_player_control().sneak then - ent.owner = placer:get_player_name() - ent.tamed = true - end - - -- set nametag - local nametag = itemstack:get_meta():get_string("name") - if nametag ~= "" then - if string.len(nametag) > MAX_MOB_NAME_LENGTH then - nametag = string.sub(nametag, 1, MAX_MOB_NAME_LENGTH) - end - ent.nametag = nametag - update_tag(ent) - end - - -- if not in creative then take item - if not mobs.is_creative(placer:get_player_name()) then - itemstack:take_item() - end - end - - return itemstack - end, - }) + self.target_yaw = yaw + self.delay = delay + return self.target_yaw end --- No-op in MCL2 (capturing mobs is not possible). --- Provided for compability with Mobs Redo -function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, force_take, replacewith) - return false +-- global function to set mob yaw +function mobs:yaw(self, yaw, delay, dtime) + set_yaw(self, yaw, delay, dtime) end --- No-op in MCL2 (protecting mobs is not possible). -function mobs:protect(self, clicker) - return false -end +mob_step = function() + + --if self.state == "die" then + -- print("need custom die stop moving thing") + -- return + --end + + --if not self.fire_resistant then + -- mcl_burning.tick(self.object, dtime, self) + --end + + --if use_cmi then + --cmi.notify_step(self.object, dtime) + --end + + --local pos = self.object:get_pos() + --local yaw = 0 + + --if mobs_debug then + --update_tag(self) + --end --- feeding, taming and breeding (thanks blert2112) -function mobs:feed_tame(self, clicker, feed_count, breed, tame) - if not self.follow then - return false + + --if self.jump_sound_cooloff > 0 then + -- self.jump_sound_cooloff = self.jump_sound_cooloff - dtime + --end + + --if self.opinion_sound_cooloff > 0 then + -- self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime + --end + + --if falling(self, pos) then + -- Return if mob died after falling + -- return + --end + + + -- run custom function (defined in mob lua file) + --if self.do_custom then + + -- when false skip going any further + --if self.do_custom(self, dtime) == false then + -- return + --end + --end + + -- knockback timer + --if self.pause_timer > 0 then + + -- self.pause_timer = self.pause_timer - dtime + + -- return + --end + + -- attack timer + --self.timer = self.timer + dtime + + --[[ + if self.state ~= "attack" then + + if self.timer < 1 then + print("returning>>error code 1") + return + end + + self.timer = 0 end + ]]-- - -- can eat/tame with item in hand - if follow_holding(self, clicker) then + -- never go over 100 + --if self.timer > 100 then + -- self.timer = 1 + --end - -- if not in creative then take item - if not mobs.is_creative(clicker:get_player_name()) then + -- mob plays random sound at times + --if math_random(1, 70) == 1 then + -- mob_sound(self, "random", true) + --end - local item = clicker:get_wielded_item() + -- environmental damage timer (every 1 second) + --self.env_damage_timer = self.env_damage_timer + dtime - item:take_item() + --if (self.state == "attack" and self.env_damage_timer > 1) + --or self.state ~= "attack" then + -- + -- self.env_damage_timer = 0 + -- + -- -- check for environmental damage (water, fire, lava etc.) + -- if do_env_damage(self) then + -- return + -- end + -- + -- node replace check (cow eats grass etc.) + -- replace(self, pos) + --end - clicker:set_wielded_item(item) - end + --monster_attack(self) - mob_sound(self, "eat", nil, true) + --npc_attack(self) - -- increase health - self.health = self.health + 4 + --breed(self) - if self.health >= self.hp_max then + --do_jump(self) - self.health = self.hp_max + --runaway_from(self) - if self.htimer < 1 then - self.htimer = 5 - end - end - self.object:set_hp(self.health) + --if is_at_water_danger(self) and self.state ~= "attack" then + -- if math_random(1, 10) <= 6 then + -- set_velocity(self, 0) + -- self.state = "stand" + -- set_animation(self, "stand") + -- yaw = yaw + math_random(-0.5, 0.5) + -- yaw = set_yaw(self, yaw, 8) + -- end + --end - update_tag(self) - -- make children grow quicker - if self.child == true then - - -- deduct 10% of the time to adulthood - self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1) - - return true - end - - -- feed and tame - self.food = (self.food or 0) + 1 - if self.food >= feed_count then - - self.food = 0 - - if breed and self.hornytimer == 0 then - self.horny = true - end - - if tame then - - self.tamed = true - - if not self.owner or self.owner == "" then - self.owner = clicker:get_player_name() - end - end - - -- make sound when fed so many times - mob_sound(self, "random", true) - end - - return true - end - - return false -end - --- Spawn a child -function mobs:spawn_child(pos, mob_type) - local child = minetest.add_entity(pos, mob_type) - if not child then + -- Add water flowing for mobs from mcl_item_entity + --[[ + local p, node, nn, def + p = self.object:get_pos() + node = minetest_get_node_or_nil(p) + if node then + nn = node.name + def = minetest_registered_nodes[nnenable_physicss if not on/in flowing liquid + self._flowing = false + enable_physics(self.object, self, true) return end - local ent = child:get_luaentity() - effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5) + --Mob following code. + follow_flop(self) - ent.child = true - local textures - -- using specific child texture (if found) - if ent.child_texture then - textures = ent.child_texture[1] + if is_at_cliff_or_danger(self) then + set_velocity(self, 0) + self.state = "stand" + set_animation(self, "stand") + local yaw = self.object:get_yaw() or 0 + yaw = set_yaw(self, yaw + 0.78, 8) end - -- and resize to half height - child:set_properties({ - textures = textures, - visual_size = { - x = ent.base_size.x * .5, - y = ent.base_size.y * .5, - }, - collisionbox = { - ent.base_colbox[1] * .5, - ent.base_colbox[2] * .5, - ent.base_colbox[3] * .5, - ent.base_colbox[4] * .5, - ent.base_colbox[5] * .5, - ent.base_colbox[6] * .5, - }, - selectionbox = { - ent.base_selbox[1] * .5, - ent.base_selbox[2] * .5, - ent.base_selbox[3] * .5, - ent.base_selbox[4] * .5, - ent.base_selbox[5] * .5, - ent.base_selbox[6] * .5, - }, - }) - - return child -end - - --- compatibility function for old entities to new modpack entities -function mobs:alias_mob(old_name, new_name) - - -- spawn egg - minetest.register_alias(old_name, new_name) - - -- entity - minetest.register_entity(":" .. old_name, { - - physical = false, - - on_step = function(self) - - if minetest.registered_entities[new_name] then - minetest.add_entity(self.object:get_pos(), new_name) - end + -- Despawning: when lifetimer expires, remove mob + if remove_far + and self.can_despawn == true + and ((not self.nametag) or (self.nametag == "")) + and self.state ~= "attack" + and self.following == nil then + self.lifetimer = self.lifetimer - dtime + if self.despawn_immediately or self.lifetimer <= 0 then + minetest.log("action", "Mob "..self.name.." despawns in mob_step at "..minetest.pos_to_string(pos, 1)) + mcl_burning.extinguish(self.object) self.object:remove() - end - }) - -end - - -local timer = 0 -minetest.register_globalstep(function(dtime) - timer = timer + dtime - if timer < 1 then return end - for _, player in pairs(minetest.get_connected_players()) do - local pos = player:get_pos() - for _, obj in pairs(minetest.get_objects_inside_radius(pos, 47)) do - local lua = obj:get_luaentity() - if lua and lua._cmi_is_mob then - lua.lifetimer = math.max(20, lua.lifetimer) - lua.despawn_immediately = false + elseif self.lifetimer <= 10 then + if math_random(10) < 4 then + self.despawn_immediately = true + else + self.lifetimer = 20 end end end - timer = 0 -end) + ]]-- + +end diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/breeding.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/breeding.lua new file mode 100644 index 000000000..5dc0b8884 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/breeding.lua @@ -0,0 +1,184 @@ +local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius + +local vector_distance = vector.distance + +--check to see if someone nearby has some tasty food +mobs.check_following = function(self) -- returns true or false + + --ignore + if not self.follow then + self.following_person = nil + return(false) + end + + --hey look, this thing works for passive mobs too! + local follower = mobs.detect_closest_player_within_radius(self,true,self.view_range,self.eye_height) + + --check if the follower is a player incase they log out + if follower and follower:is_player() then + local stack = follower:get_wielded_item() + --safety check + if not stack then + self.following_person = nil + return(false) + end + + local item_name = stack:get_name() + --all checks have passed, that guy has some good looking food + if item_name == self.follow then + self.following_person = follower + return(true) + end + end + + --everything failed + self.following_person = nil + return(false) +end + +--a function which attempts to make mobs enter +--the breeding state +mobs.enter_breed_state = function(self,clicker) + + --do not breed if baby + if self.baby then + return(false) + end + + --do not do anything if looking for mate or + --if cooling off from breeding + if self.breed_lookout_timer > 0 or self.breed_timer > 0 then + return(false) + end + + --if this is caught, that means something has gone + --seriously wrong + if not clicker or not clicker:is_player() then + return(false) + end + + local stack = clicker:get_wielded_item() + --safety check + if not stack then + return(false) + end + + local item_name = stack:get_name() + --all checks have passed, that guy has some good looking food + if item_name == self.follow then + if not minetest.is_creative_enabled(clicker:get_player_name()) then + stack:take_item() + clicker:set_wielded_item(stack) + end + self.breed_lookout_timer = self.breed_lookout_timer_goal + self.bred = true + mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic") + return(true) + end + + --everything failed + return(false) +end + + +--find the closest mate in the area +mobs.look_for_mate = function(self) + + local pos1 = self.object:get_pos() + pos1.y = pos1.y + self.eye_height + + local mates_in_area = {} + local winner_mate = nil + local mates_detected = 0 + local radius = self.view_range + + --get mates in radius + for _,mate in pairs(minetest_get_objects_inside_radius(pos1, radius)) do + + --look for a breeding mate + if mate and mate:get_luaentity() + and mate:get_luaentity()._cmi_is_mob + and mate:get_luaentity().name == self.name + and mate:get_luaentity().breed_lookout_timer > 0 + and mate:get_luaentity() ~= self then + + local pos2 = mate:get_pos() + + local distance = vector_distance(pos1,pos2) + + if distance <= radius then + if line_of_sight then + --must add eye height or stuff breaks randomly because of + --seethrough nodes being a blocker (like grass) + if minetest_line_of_sight( + vector_new(pos1.x, pos1.y, pos1.z), + vector_new(pos2.x, pos2.y + mate:get_properties().eye_height, pos2.z) + ) then + mates_detected = mates_detected + 1 + mates_in_area[mate] = distance + end + else + mates_detected = mates_detected + 1 + mates_in_area[mate] = distance + end + end + end + end + + + --return if there's no one near by + if mates_detected <= 0 then --handle negative numbers for some crazy error that could possibly happen + return nil + end + + --do a default radius max + local shortest_distance = radius + 1 + + --sort through mates and find the closest mate + for mate,distance in pairs(mates_in_area) do + if distance < shortest_distance then + shortest_distance = distance + winner_mate = mate + end + end + + return(winner_mate) + +end + +--make the baby grow up +mobs.baby_grow_up = function(self) + self.baby = nil + self.visual_size = self.backup_visual_size + self.collisionbox = self.backup_collisionbox + self.selectionbox = self.backup_selectionbox + self.object:set_properties(self) +end + +--makes the baby grow up faster with diminishing returns +mobs.make_baby_grow_faster = function(self,clicker) + if clicker and clicker:is_player() then + local stack = clicker:get_wielded_item() + --safety check + if not stack then + return(false) + end + + local item_name = stack:get_name() + --all checks have passed, that guy has some good looking food + if item_name == self.follow then + self.grow_up_timer = self.grow_up_timer - (self.grow_up_timer * 0.10) --take 10 percent off - diminishing returns + + if not minetest.is_creative_enabled(clicker:get_player_name()) then + stack:take_item() + clicker:set_wielded_item(stack) + end + + mobs.play_sound_specific(self,"mobs_mc_animal_eat_generic") + + return(true) + end + end + + return(false) +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/collision.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/collision.lua new file mode 100644 index 000000000..44f43f20f --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/collision.lua @@ -0,0 +1,140 @@ +local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius + +local math_random = math.random +local vector_multiply = vector.multiply + +local vector_direction = vector.direction + +local integer_test = {-1,1} + +mobs.collision = function(self) + + local pos = self.object:get_pos() + + + if not self or not self.object or not self.object:get_luaentity() then + return + end + + --do collision detection from the base of the mob + local collisionbox = self.object:get_properties().collisionbox + + pos.y = pos.y + collisionbox[2] + + local collision_boundary = collisionbox[4] + + local radius = collision_boundary + + if collisionbox[5] > collision_boundary then + radius = collisionbox[5] + end + + local collision_count = 0 + + + local check_for_attack = false + + if self.attack_type == "punch" and self.hostile and self.attacking then + check_for_attack = true + end + + for _,object in ipairs(minetest_get_objects_inside_radius(pos, radius*1.25)) do + if object and object ~= self.object and (object:is_player() or (object:get_luaentity() and object:get_luaentity()._cmi_is_mob == true and object:get_luaentity().health > 0)) and + --don't collide with rider, rider don't collide with thing + (not object:get_attach() or (object:get_attach() and object:get_attach() ~= self.object)) and + (not self.object:get_attach() or (self.object:get_attach() and self.object:get_attach() ~= object)) then + --stop infinite loop + collision_count = collision_count + 1 + --mob cramming + if collision_count > 30 then + self.health = -20 + break + end + + local pos2 = object:get_pos() + + local object_collisionbox = object:get_properties().collisionbox + + pos2.y = pos2.y + object_collisionbox[2] + + local object_collision_boundary = object_collisionbox[4] + + + --this is checking the difference of the object collided with's possision + --if positive top of other object is inside (y axis) of current object + local y_base_diff = (pos2.y + object_collisionbox[5]) - pos.y + + local y_top_diff = (pos.y + collisionbox[5]) - pos2.y + + + local distance = vector.distance(vector.new(pos.x,0,pos.z),vector.new(pos2.x,0,pos2.z)) + + if distance <= collision_boundary + object_collision_boundary and y_base_diff >= 0 and y_top_diff >= 0 then + + local dir = vector.direction(pos,pos2) + + dir.y = 0 + + --eliminate mob being stuck in corners + if dir.x == 0 and dir.z == 0 then + --slightly adjust mob position to prevent equal length + --corner/wall sticking + dir.x = dir.x + ((math_random()/10)*integer_test[math.random(1,2)]) + dir.z = dir.z + ((math_random()/10)*integer_test[math.random(1,2)]) + end + + local velocity = dir + + --0.5 is the max force multiplier + local force = 0.5 - (0.5 * distance / (collision_boundary + object_collision_boundary)) + + local vel1 = vector.multiply(velocity, -1.5) + local vel2 = vector.multiply(velocity, 1.5) + + vel1 = vector.multiply(vel1, force * 10) + vel2 = vector.multiply(vel2, force) + + if object:is_player() then + vel2 = vector_multiply(vel2, 2.5) + + --integrate mob punching into collision detection + if check_for_attack and self.punch_timer <= 0 then + if object == self.attacking then + mobs.punch_attack(self) + end + end + end + + self.object:add_velocity(vel1) + object:add_velocity(vel2) + end + + end + end +end + + +--this is used for arrow collisions +mobs.arrow_hit = function(self, player) + + player:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = self._damage} + }, nil) + + + --knockback + local pos1 = self.object:get_pos() + pos1.y = 0 + local pos2 = player:get_pos() + pos2.y = 0 + local dir = vector_direction(pos1,pos2) + + dir = vector_multiply(dir,3) + + if player:get_velocity().y <= 1 then + dir.y = 5 + end + + player:add_velocity(dir) +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/death_logic.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/death_logic.lua new file mode 100644 index 000000000..fd95b60ef --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/death_logic.lua @@ -0,0 +1,154 @@ +local minetest_add_item = minetest.add_item +local minetest_sound_play = minetest.sound_play + +local math_pi = math.pi +local math_random = math.random +local math_floor = math.floor +local HALF_PI = math_pi / 2 + +local vector_new = vector.new + + +-- drop items +local item_drop = function(self, cooked, looting_level) + + looting_level = looting_level or 0 + + -- no drops for child mobs (except monster) + if (self.child and self.type ~= "monster") then + return + end + + local obj, item, num + local pos = self.object:get_pos() + + self.drops = self.drops or {} -- nil check + + for n = 1, #self.drops do + local dropdef = self.drops[n] + local chance = 1 / dropdef.chance + local looting_type = dropdef.looting + + if looting_level > 0 then + local chance_function = dropdef.looting_chance_function + if chance_function then + chance = chance_function(looting_level) + elseif looting_type == "rare" then + chance = chance + (dropdef.looting_factor or 0.01) * looting_level + end + end + + local num = 0 + local do_common_looting = (looting_level > 0 and looting_type == "common") + if math_random() < chance then + num = math_random(dropdef.min or 1, dropdef.max or 1) + elseif not dropdef.looting_ignore_chance then + do_common_looting = false + end + + if do_common_looting then + num = num + math_floor(math_random(0, looting_level) + 0.5) + end + + if num > 0 then + item = dropdef.name + + -- cook items when true + if cooked then + + local output = minetest_get_craft_result({ + method = "cooking", width = 1, items = {item}}) + + if output and output.item and not output.item:is_empty() then + item = output.item:get_name() + end + end + + -- add item if it exists + for x = 1, num do + obj = minetest_add_item(pos, ItemStack(item .. " " .. 1)) + end + + if obj and obj:get_luaentity() then + + obj:set_velocity({ + x = math_random(-10, 10) / 9, + y = 6, + z = math_random(-10, 10) / 9, + }) + elseif obj then + obj:remove() -- item does not exist + end + end + end + + self.drops = {} +end + + +mobs.death_logic = function(self, dtime) + self.death_animation_timer = self.death_animation_timer + dtime + + --get all attached entities and sort through them + local attached_entities = self.object:get_children() + if #attached_entities > 0 then + for _,entity in pairs(attached_entities) do + --kick the player off + if entity:is_player() then + mobs.detach(entity) + --kick mobs off + --if there is scaling issues, this needs an additional check + else + entity:set_detach() + end + end + end + + --stop mob from getting in the way of other mobs you're fighting + if self.object:get_properties().pointable then + self.object:set_properties({pointable = false}) + end + + --the final POOF of a mob despawning + 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)) + + self.object:remove() + + return + end + + --I'm sure there's a more efficient way to do this + --but this is the easiest, easier to work with 1 variable synced + --this is also not smooth + local death_animation_roll = self.death_animation_timer * 2 -- * 2 to make it faster + if death_animation_roll > 1 then + death_animation_roll = 1 + end + + local rot = self.object:get_rotation() --(no pun intended) + + rot.z = death_animation_roll * HALF_PI + + self.object:set_rotation(rot) + + mobs.set_mob_animation(self,"stand", true) + + + --flying and swimming mobs just fall down + if self.fly or self.swim then + if self.object:get_acceleration().y ~= -self.gravity then + self.object:set_acceleration(vector_new(0,-self.gravity,0)) + end + end + + --when landing allow mob to slow down and just fall if in air + if self.pause_timer <= 0 then + mobs.set_velocity(self,0) + end +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/environment.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/environment.lua new file mode 100644 index 000000000..7c709c09e --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/environment.lua @@ -0,0 +1,260 @@ +local minetest_line_of_sight = minetest.line_of_sight +local minetest_dir_to_yaw = minetest.dir_to_yaw +local minetest_yaw_to_dir = minetest.yaw_to_dir +local minetest_get_node = minetest.get_node +local minetest_get_item_group = minetest.get_item_group +local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius +local minetest_get_node_or_nil = minetest.get_node_or_nil +local minetest_registered_nodes = minetest.registered_nodes +local minetest_get_connected_players = minetest.get_connected_players + +local vector_new = vector.new +local vector_add = vector.add +local vector_multiply = vector.multiply +local vector_distance = vector.distance + +local table_copy = table.copy + +local math_abs = math.abs + +-- default function when mobs are blown up with TNT +local do_tnt = function(obj, damage) + + obj.object:punch(obj.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = damage}, + }, nil) + + return false, true, {} +end + +--a fast function to be able to detect only players without using objects_in_radius +mobs.detect_closest_player_within_radius = function(self, line_of_sight, radius, object_height_adder) + + local pos1 = self.object:get_pos() + local players_in_area = {} + local winner_player = nil + local players_detected = 0 + + --get players in radius + for _,player in pairs(minetest.get_connected_players()) do + if player and player:get_hp() > 0 then + + local pos2 = player:get_pos() + + local distance = vector_distance(pos1,pos2) + + if distance <= radius then + if line_of_sight then + --must add eye height or stuff breaks randomly because of + --seethrough nodes being a blocker (like grass) + if minetest_line_of_sight( + vector_new(pos1.x, pos1.y + object_height_adder, pos1.z), + vector_new(pos2.x, pos2.y + player:get_properties().eye_height, pos2.z) + ) then + players_detected = players_detected + 1 + players_in_area[player] = distance + end + else + players_detected = players_detected + 1 + players_in_area[player] = distance + end + end + end + end + + + --return if there's no one near by + if players_detected <= 0 then --handle negative numbers for some crazy error that could possibly happen + return nil + end + + --do a default radius max + local shortest_distance = radius + 1 + + --sort through players and find the closest player + for player,distance in pairs(players_in_area) do + if distance < shortest_distance then + shortest_distance = distance + winner_player = player + end + end + + return(winner_player) +end + + +--check if a mob needs to jump +mobs.jump_check = function(self,dtime) + + local pos = self.object:get_pos() + pos.y = pos.y + 0.1 + local dir = minetest_yaw_to_dir(self.yaw) + + local collisionbox = self.object:get_properties().collisionbox + local radius = collisionbox[4] + 0.5 + + vector_multiply(dir, radius) + + --only jump if there's a node and a non-solid node above it + local test_dir = vector_add(pos,dir) + + local green_flag_1 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") ~= 0 + + test_dir.y = test_dir.y + 1 + + local green_flag_2 = minetest_get_item_group(minetest_get_node(test_dir).name, "solid") == 0 + + if green_flag_1 and green_flag_2 then + --can jump over node + return(1) + elseif green_flag_1 and not green_flag_2 then + --wall in front of mob + return(2) + end + + --nothing to jump over + return(0) +end + +-- a helper function to quickly turn neutral passive mobs hostile +local turn_hostile = function(self,detected_mob) + --drop in variables for attacking (stops crash) + detected_mob.punch_timer = 0 + --set to hostile + detected_mob.hostile = true + --hostile_cooldown timer is initialized here + detected_mob.hostile_cooldown_timer = detected_mob.hostile_cooldown + --set target to the same + detected_mob.attacking = self.attacking +end + +--allow hostile mobs to signal to other mobs +--to switch from neutal passive to neutral hostile +mobs.group_attack_initialization = function(self) + + --get basic data + local friends_list + + if self.group_attack == true then + friends_list = {self.name} + else + friends_list = table_copy(self.group_attack) + end + + local objects_in_area = minetest_get_objects_inside_radius(self.object:get_pos(), self.view_range) + + --get the player's name + local name = self.attacking:get_player_name() + + --re-use local variable + local detected_mob + + --run through mobs in viewing distance + for _,object in pairs(objects_in_area) do + if object and object:get_luaentity() then + detected_mob = object:get_luaentity() + -- only alert members of same mob or friends + if detected_mob._cmi_is_mob and detected_mob.state ~= "attack" and detected_mob.owner ~= name then + if detected_mob.name == self.name then + turn_hostile(self,detected_mob) + else + for _,id in pairs(friends_list) do + if detected_mob.name == id then + turn_hostile(self,detected_mob) + break + end + end + end + end + + --THIS NEEDS TO BE RE-IMPLEMENTED AS A GLOBAL HIT IN MOB_PUNCH!! + -- have owned mobs attack player threat + --if obj.owner == name and obj.owner_loyal then + -- do_attack(obj, self.object) + --end + end + end +end + +-- check if within physical map limits (-30911 to 30927) +-- within_limits, wmin, wmax = nil, -30913, 30928 +mobs.within_limits = function(pos, radius) + if mcl_vars then + if mcl_vars.mapgen_edge_min and mcl_vars.mapgen_edge_max then + wmin, wmax = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max + within_limits = function(pos, radius) + return pos + and (pos.x - radius) > wmin and (pos.x + radius) < wmax + and (pos.y - radius) > wmin and (pos.y + radius) < wmax + and (pos.z - radius) > wmin and (pos.z + radius) < wmax + end + end + end + return pos + and (pos.x - radius) > wmin and (pos.x + radius) < wmax + and (pos.y - radius) > wmin and (pos.y + radius) < wmax + and (pos.z - radius) > wmin and (pos.z + radius) < wmax +end + +-- get node but use fallback for nil or unknown +mobs.node_ok = function(pos, fallback) + + fallback = fallback or mobs.fallback_node + + local node = minetest_get_node_or_nil(pos) + + if node and minetest_registered_nodes[node.name] then + return node + end + + return minetest_registered_nodes[fallback] +end + + +--a teleport functoin +mobs.teleport = function(self, target) + if self.do_teleport then + if self.do_teleport(self, target) == false then + return + end + end +end + +--a function used for despawning mobs +mobs.check_for_player_within_area = function(self, radius) + local pos1 = self.object:get_pos() + --get players in radius + for _,player in pairs(minetest_get_connected_players()) do + if player and player:get_hp() > 0 then + local pos2 = player:get_pos() + local distance = vector_distance(pos1,pos2) + if distance < radius then + --found a player + return(true) + end + end + end + --did not find a player + return(false) +end + + +--a simple helper function for mobs following +mobs.get_2d_distance = function(pos1,pos2) + pos1.y = 0 + pos2.y = 0 + return(vector_distance(pos1, pos2)) +end + +-- fall damage onto solid ground +mobs.calculate_fall_damage = function(self) + if self.old_velocity and self.old_velocity.y < -7 and self.object:get_velocity().y == 0 then + local vel = self.object:get_velocity() + if vel then + local damage = math_abs(self.old_velocity.y + 7) * 2 + self.pause_timer = 0.4 + self.health = self.health - damage + end + end +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/head_logic.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/head_logic.lua new file mode 100644 index 000000000..0fc94ffe6 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/head_logic.lua @@ -0,0 +1,112 @@ +local vector_new = vector.new + + +--converts yaw to degrees +local degrees = function(yaw) + return(yaw*180.0/math.pi) +end + + +mobs.do_head_logic = function(self,dtime) + + local player = minetest.get_player_by_name("singleplayer") + + local look_at = player:get_pos() + look_at.y = look_at.y + player:get_properties().eye_height + + + + + local pos = self.object:get_pos() + + local body_yaw = self.object:get_yaw() + + local body_dir = minetest.yaw_to_dir(body_yaw) + + + pos.y = pos.y + self.head_height_offset + + local head_offset = vector.multiply(body_dir, self.head_direction_offset) + + pos = vector.add(pos, head_offset) + + + + + minetest.add_particle({ + pos = pos, + velocity = {x=0, y=0, z=0}, + acceleration = {x=0, y=0, z=0}, + expirationtime = 0.2, + size = 1, + texture = "default_dirt.png", + }) + + + local bone_pos = vector_new(0,0,0) + + + --(horizontal) + bone_pos.y = self.head_bone_pos_y + + --(vertical) + bone_pos.z = self.head_bone_pos_z + + --print(yaw) + + --local _, bone_rot = self.object:get_bone_position("head") + + --bone_rot.x = bone_rot.x + (dtime * 10) + --bone_rot.z = bone_rot.z + (dtime * 10) + + + local head_yaw + head_yaw = minetest.dir_to_yaw(vector.direction(pos,look_at)) - body_yaw + + if self.reverse_head_yaw then + head_yaw = head_yaw * -1 + end + + --over rotation protection + --stops radians from going out of spec + if head_yaw > math.pi then + head_yaw = head_yaw - (math.pi * 2) + elseif head_yaw < -math.pi then + head_yaw = head_yaw + (math.pi * 2) + end + + + local check_failed = false + --upper check + 90 degrees or upper math.radians (3.14/2) + if head_yaw > math.pi - (math.pi/2) then + head_yaw = 0 + check_failed = true + --lower check - 90 degrees or lower negative math.radians (-3.14/2) + elseif head_yaw < -math.pi + (math.pi/2) then + head_yaw = 0 + check_failed = true + end + + local head_pitch = 0 + + --DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG + --head_yaw = 0 + --DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG + + if not check_failed then + head_pitch = minetest.dir_to_yaw(vector.new(vector.distance(vector.new(pos.x,0,pos.z),vector.new(look_at.x,0,look_at.z)),0,pos.y-look_at.y))+(math.pi/2) + end + + if self.head_pitch_modifier then + head_pitch = head_pitch + self.head_pitch_modifier + end + + if self.swap_y_with_x then + self.object:set_bone_position(self.head_bone, bone_pos, vector_new(degrees(head_pitch),degrees(head_yaw),0)) + else + self.object:set_bone_position(self.head_bone, bone_pos, vector_new(degrees(head_pitch),0,degrees(head_yaw))) + end + + + --set_bone_position([bone, position, rotation]) +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/interaction.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/interaction.lua new file mode 100644 index 000000000..6b23d2fe7 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/interaction.lua @@ -0,0 +1,291 @@ +local minetest_after = minetest.after +local minetest_sound_play = minetest.sound_play +local minetest_dir_to_yaw = minetest.dir_to_yaw + +local math_floor = math.floor +local math_min = math.min +local math_random = math.random + +local vector_direction = vector.direction +local vector_multiply = vector.multiply + +local MAX_MOB_NAME_LENGTH = 30 + +mobs.feed_tame = function(self) + return nil +end + +-- Code to execute before custom on_rightclick handling +local on_rightclick_prefix = function(self, clicker) + + local item = clicker:get_wielded_item() + + -- Name mob with nametag + if not self.ignores_nametag and item:get_name() == "mcl_mobs:nametag" then + + local tag = item:get_meta():get_string("name") + if tag ~= "" then + if string.len(tag) > MAX_MOB_NAME_LENGTH then + tag = string.sub(tag, 1, MAX_MOB_NAME_LENGTH) + end + self.nametag = tag + + mobs.update_tag(self) + + if not mobs.is_creative(clicker:get_player_name()) then + item:take_item() + clicker:set_wielded_item(item) + end + return true + end + + end + return false +end + +-- I have no idea what this does +mobs.create_mob_on_rightclick = function(on_rightclick) + return function(self, clicker) + --don't allow rightclicking dead mobs + if self.health <= 0 then + return + end + local stop = on_rightclick_prefix(self, clicker) + if (not stop) and (on_rightclick) then + on_rightclick(self, clicker) + end + end +end + + +-- deal damage and effects when mob punched +mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir) + + --don't do anything if the mob is already dead + if self.health <= 0 then + return + end + + --neutral passive mobs switch to neutral hostile + if self.neutral then + --drop in variables for attacking (stops crash) + self.attacking = hitter + self.punch_timer = 0 + self.hostile = true + --hostile_cooldown timer is initialized here + self.hostile_cooldown_timer = self.hostile_cooldown + + --initialize the group attack (check for other mobs in area, make them neutral hostile) + if self.group_attack then + mobs.group_attack_initialization(self) + end + end + + --turn skittish mobs away and RUN + if self.skittish then + + self.state = "run" + + self.run_timer = 5 --arbitrary 5 seconds + + local pos1 = self.object:get_pos() + pos1.y = 0 + local pos2 = hitter:get_pos() + pos2.y = 0 + + + local dir = vector_direction(pos2,pos1) + + local yaw = minetest_dir_to_yaw(dir) + + self.yaw = yaw + end + + + -- custom punch function + if self.do_punch then + -- when false skip going any further + if self.do_punch(self, hitter, tflp, tool_capabilities, dir) == false then + return + end + end + + --don't do damage until pause timer resets + if self.pause_timer > 0 then + return + end + + + -- error checking when mod profiling is enabled + if not tool_capabilities then + minetest.log("warning", "[mobs_mc] Mod profiling enabled, damage not enabled") + return + end + + + local is_player = hitter:is_player() + + + -- punch interval + local weapon = hitter:get_wielded_item() + + local punch_interval = 1.4 + + -- exhaust attacker + if mod_hunger and is_player then + mcl_hunger.exhaust(hitter:get_player_name(), mcl_hunger.EXHAUST_ATTACK) + end + + -- calculate mob damage + local damage = 0 + local armor = self.object:get_armor_groups() or {} + local tmp + + --calculate damage groups + for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do + damage = damage + (tool_capabilities.damage_groups[group] or 0) * ((armor[group] or 0) / 100.0) + end + + if weapon then + local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect") + if fire_aspect_level > 0 then + mcl_burning.set_on_fire(self.object, fire_aspect_level * 4) + end + end + + -- check for tool immunity or special damage + for n = 1, #self.immune_to do + if self.immune_to[n][1] == weapon:get_name() then + damage = self.immune_to[n][2] or 0 + break + end + end + + -- healing + if damage <= -1 then + self.health = self.health - math_floor(damage) + return + end + + if tool_capabilities then + punch_interval = tool_capabilities.full_punch_interval or 1.4 + end + + -- add weapon wear manually + -- Required because we have custom health handling ("health" property) + --minetest_is_creative_enabled("") ~= true --removed for now + if tool_capabilities then + if tool_capabilities.punch_attack_uses then + -- Without this delay, the wear does not work. Quite hacky ... + minetest_after(0, function(name) + local player = minetest.get_player_by_name(name) + if not player then return end + local weapon = hitter:get_wielded_item(player) + local def = weapon:get_definition() + if def.tool_capabilities and def.tool_capabilities.punch_attack_uses then + local wear = math_floor(65535/tool_capabilities.punch_attack_uses) + weapon:add_wear(wear) + hitter:set_wielded_item(weapon) + end + end, hitter:get_player_name()) + end + end + + + --if player is falling multiply damage by 1.5 + --critical hit + if hitter:get_velocity().y < 0 then + damage = damage * 1.5 + mobs.critical_effect(self) + end + + + -- only play hit sound and show blood effects if damage is 1 or over; lower to 0.1 to ensure armor works appropriately. + if damage >= 0.1 then + + minetest_sound_play("default_punch", { + object = self.object, + max_hear_distance = 16 + }, true) + + -- do damage + self.health = self.health - damage + + + --0.4 seconds until you can hurt the mob again + self.pause_timer = 0.4 + + --don't do knockback from a rider + for _,obj in pairs(self.object:get_children()) do + if obj == hitter then + return + end + end + + -- knock back effect + local velocity = self.object:get_velocity() + + --2d direction + local pos1 = self.object:get_pos() + pos1.y = 0 + local pos2 = hitter:get_pos() + pos2.y = 0 + + local dir = vector.direction(pos2,pos1) + + local up = 3 + + -- if already in air then dont go up anymore when hit + if velocity.y ~= 0 then + up = 0 + end + + + --0.75 for perfect distance to not be too easy, and not be too hard + local multiplier = 0.75 + + -- check if tool already has specific knockback value + local knockback_enchant = mcl_enchanting.get_enchantment(hitter:get_wielded_item(), "knockback") + if knockback_enchant and knockback_enchant > 0 then + multiplier = knockback_enchant + 1 --(starts from 1, 1 would be no change) + end + + --do this to sure you can punch a mob back when + --it's coming for you + if self.hostile then + multiplier = multiplier + 2 + end + + dir = vector_multiply(dir,multiplier) + + dir.y = up + + --add the velocity + self.object:add_velocity(dir) + + end +end + +--do internal per mob projectile calculations +mobs.shoot_projectile = function(self) + + local pos1 = self.object:get_pos() + --add mob eye height + pos1.y = pos1.y + self.eye_height + + local pos2 = self.attacking:get_pos() + --add player eye height + pos2.y = pos2.y + self.attacking:get_properties().eye_height + + --get direction + local dir = vector_direction(pos1,pos2) + + --call internal shoot_arrow function + self.shoot_arrow(self,pos1,dir) +end + +mobs.update_tag = function(self) + self.object:set_properties({ + nametag = self.nametag, + }) +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/mob_effects.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/mob_effects.lua new file mode 100644 index 000000000..847315ff1 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/mob_effects.lua @@ -0,0 +1,152 @@ +local minetest_add_particlespawner = minetest.add_particlespawner + +mobs.death_effect = function(self) + + local pos = self.object:get_pos() + local yaw = self.object:get_yaw() + local collisionbox = self.object:get_properties().collisionbox + + local min, max + + if collisionbox then + min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]} + max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]} + end + + minetest_add_particlespawner({ + amount = 50, + time = 0.0001, + minpos = vector.add(pos, min), + maxpos = vector.add(pos, max), + minvel = vector.new(-0.5,0.5,-0.5), + maxvel = vector.new(0.5,1,0.5), + minexptime = 1.1, + maxexptime = 1.5, + minsize = 1, + maxsize = 2, + collisiondetection = false, + vertical = false, + texture = "mcl_particles_mob_death.png", -- this particle looks strange + }) +end + +mobs.critical_effect = function(self) + + local pos = self.object:get_pos() + local yaw = self.object:get_yaw() + local collisionbox = self.object:get_properties().collisionbox + + local min, max + + if collisionbox then + min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]} + max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]} + end + + minetest_add_particlespawner({ + amount = 10, + time = 0.0001, + minpos = vector.add(pos, min), + maxpos = vector.add(pos, max), + minvel = vector.new(-1,1,-1), + maxvel = vector.new(1,3,1), + minexptime = 0.7, + maxexptime = 1, + minsize = 1, + maxsize = 2, + collisiondetection = false, + vertical = false, + texture = "heart.png^[colorize:black:255", + }) +end + +--when feeding a mob +mobs.feed_effect = function(self) + + local pos = self.object:get_pos() + local yaw = self.object:get_yaw() + local collisionbox = self.object:get_properties().collisionbox + + local min, max + + if collisionbox then + min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]} + max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]} + end + + minetest_add_particlespawner({ + amount = 10, + time = 0.0001, + minpos = vector.add(pos, min), + maxpos = vector.add(pos, max), + minvel = vector.new(-1,1,-1), + maxvel = vector.new(1,3,1), + minexptime = 0.7, + maxexptime = 1, + minsize = 1, + maxsize = 2, + collisiondetection = false, + vertical = false, + texture = "heart.png^[colorize:gray:255", + }) +end + +--hearts when tamed +mobs.tamed_effect = function(self) + local pos = self.object:get_pos() + local yaw = self.object:get_yaw() + local collisionbox = self.object:get_properties().collisionbox + + local min, max + + if collisionbox then + min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]} + max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]} + end + + minetest_add_particlespawner({ + amount = 30, + time = 0.0001, + minpos = vector.add(pos, min), + maxpos = vector.add(pos, max), + minvel = vector.new(-1,1,-1), + maxvel = vector.new(1,3,1), + minexptime = 0.7, + maxexptime = 1, + minsize = 1, + maxsize = 2, + collisiondetection = false, + vertical = false, + texture = "heart.png", + }) +end + +--hearts when breeding +mobs.breeding_effect = function(self) + local pos = self.object:get_pos() + local yaw = self.object:get_yaw() + local collisionbox = self.object:get_properties().collisionbox + + local min, max + + if collisionbox then + min = {x=collisionbox[1], y=collisionbox[2], z=collisionbox[3]} + max = {x=collisionbox[4], y=collisionbox[5], z=collisionbox[6]} + end + + minetest_add_particlespawner({ + amount = 2, + time = 0.0001, + minpos = vector.add(pos, min), + maxpos = vector.add(pos, max), + minvel = vector.new(-1,1,-1), + maxvel = vector.new(1,3,1), + minexptime = 0.7, + maxexptime = 1, + minsize = 1, + maxsize = 2, + collisiondetection = false, + vertical = false, + texture = "heart.png", + }) +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/movement.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/movement.lua new file mode 100644 index 000000000..9a5fd9ea1 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/movement.lua @@ -0,0 +1,391 @@ +local math_pi = math.pi +local math_sin = math.sin +local math_cos = math.cos +local math_random = math.random +local HALF_PI = math_pi / 2 +local DOUBLE_PI = math_pi * 2 + +-- localize vector functions +local vector_new = vector.new +local vector_length = vector.length +local vector_multiply = vector.multiply +local vector_distance = vector.distance +local vector_normalize = vector.normalize + +local minetest_yaw_to_dir = minetest.yaw_to_dir +local minetest_dir_to_yaw = minetest.dir_to_yaw + +local DEFAULT_JUMP_HEIGHT = 5 +local DEFAULT_FLOAT_SPEED = 4 +local DEFAULT_CLIMB_SPEED = 3 + + +mobs.stick_in_cobweb = function(self) + local current_velocity = self.object:get_velocity() + + local goal_velocity = vector_multiply(vector_normalize(current_velocity), 0.4) + + goal_velocity.y = -0.5 + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end +end + +--this is a generic float function +mobs.float = function(self) + + if self.object:get_acceleration().y ~= 0 then + self.object:set_acceleration(vector_new(0,0,0)) + end + + local current_velocity = self.object:get_velocity() + + local goal_velocity = { + x = 0, + y = DEFAULT_FLOAT_SPEED, + z = 0, + } + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + new_velocity_addition.x = 0 + new_velocity_addition.z = 0 + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end +end + +--this is a generic climb function +mobs.climb = function(self) + + local current_velocity = self.object:get_velocity() + + local goal_velocity = { + x = 0, + y = DEFAULT_CLIMB_SPEED, + z = 0, + } + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + new_velocity_addition.x = 0 + new_velocity_addition.z = 0 + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end +end + + + +--[[ + _ _ +| | | | +| | __ _ _ __ __| | +| | / _` | '_ \ / _` | +| |___| (_| | | | | (_| | +\_____/\__,_|_| |_|\__,_| +]] + + +-- move mob in facing direction +--this has been modified to be internal +--internal = lua (self.yaw) +--engine = c++ (self.object:get_yaw()) +mobs.set_velocity = function(self, v) + + local yaw = (self.yaw or 0) + + local current_velocity = self.object:get_velocity() + + local goal_velocity = { + x = (math_sin(yaw) * -v), + y = 0, + z = (math_cos(yaw) * v), + } + + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + if vector_length(new_velocity_addition) > vector_length(goal_velocity) then + vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition))) + end + + new_velocity_addition.y = 0 + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end +end + + + +-- calculate mob velocity +mobs.get_velocity = function(self) + + local v = self.object:get_velocity() + + v.y = 0 + + if v then + return vector_length(v) + end + + return 0 +end + +--make mobs jump +mobs.jump = function(self, velocity) + + if self.object:get_velocity().y ~= 0 or not self.old_velocity or (self.old_velocity and self.old_velocity.y > 0) then + return + end + + --fallback velocity to allow modularity + velocity = velocity or DEFAULT_JUMP_HEIGHT + + self.object:add_velocity(vector_new(0,velocity,0)) +end + +--make mobs fall slowly +mobs.mob_fall_slow = function(self) + + local current_velocity = self.object:get_velocity() + + local goal_velocity = { + x = 0, + y = -2, + z = 0, + } + + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + new_velocity_addition.x = 0 + new_velocity_addition.z = 0 + + if vector_length(new_velocity_addition) > vector_length(goal_velocity) then + vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition))) + end + + new_velocity_addition.x = 0 + new_velocity_addition.z = 0 + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end + +end + + +--[[ + _____ _ +/ ___| (_) +\ `--.__ ___ _ __ ___ + `--. \ \ /\ / / | '_ ` _ \ +/\__/ /\ V V /| | | | | | | +\____/ \_/\_/ |_|_| |_| |_| +]]-- + + + + +--make mobs flop +mobs.flop = function(self, velocity) + + if self.object:get_velocity().y ~= 0 or not self.old_velocity or (self.old_velocity and self.old_velocity.y > 0) then + return false + end + + mobs.set_velocity(self, 0) + + --fallback velocity to allow modularity + velocity = velocity or DEFAULT_JUMP_HEIGHT + + --create a random direction (2d yaw) + local dir = DOUBLE_PI * math_random() + + --create a random force value + local force = math_random(0,3) + math_random() + + --convert the yaw to a direction vector then multiply it times the force + local final_additional_force = vector_multiply(minetest_yaw_to_dir(dir), force) + + --place in the "flop" velocity to make the mob flop + final_additional_force.y = velocity + + self.object:add_velocity(final_additional_force) + + return true +end + + + +-- move mob in facing direction +--this has been modified to be internal +--internal = lua (self.yaw) +--engine = c++ (self.object:get_yaw()) +mobs.set_swim_velocity = function(self, v) + + local yaw = (self.yaw or 0) + local pitch = (self.pitch or 0) + + if v == 0 then + pitch = 0 + end + + local current_velocity = self.object:get_velocity() + + local goal_velocity = { + x = (math_sin(yaw) * -v), + y = pitch, + z = (math_cos(yaw) * v), + } + + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + if vector_length(new_velocity_addition) > vector_length(goal_velocity) then + vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition))) + end + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end +end + +--[[ +______ _ +| ___| | +| |_ | |_ _ +| _| | | | | | +| | | | |_| | +\_| |_|\__, | + __/ | + |___/ +]]-- + +-- move mob in facing direction +--this has been modified to be internal +--internal = lua (self.yaw) +--engine = c++ (self.object:get_yaw()) +mobs.set_fly_velocity = function(self, v) + + local yaw = (self.yaw or 0) + local pitch = (self.pitch or 0) + + if v == 0 then + pitch = 0 + end + + local current_velocity = self.object:get_velocity() + + local goal_velocity = { + x = (math_sin(yaw) * -v), + y = pitch, + z = (math_cos(yaw) * v), + } + + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + if vector_length(new_velocity_addition) > vector_length(goal_velocity) then + vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition))) + end + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end +end + +--a quick and simple pitch calculation between two vector positions +mobs.calculate_pitch = function(pos1, pos2) + + if pos1 == nil or pos2 == nil then + return false + end + + return(minetest_dir_to_yaw(vector_new(vector_distance(vector_new(pos1.x,0,pos1.z),vector_new(pos2.x,0,pos2.z)),0,pos1.y - pos2.y)) + HALF_PI) +end + +--make mobs fly up or down based on their y difference +mobs.set_pitch_while_attacking = function(self) + local pos1 = self.object:get_pos() + local pos2 = self.attacking:get_pos() + + local pitch = mobs.calculate_pitch(pos2,pos1) + + self.pitch = pitch +end + + + +--[[ + ___ + |_ | + | |_ _ _ __ ___ _ __ + | | | | | '_ ` _ \| '_ \ +/\__/ / |_| | | | | | | |_) | +\____/ \__,_|_| |_| |_| .__/ + | | + |_| +]]-- + +--special mob jump movement +mobs.jump_move = function(self, velocity) + + if self.object:get_velocity().y ~= 0 or not self.old_velocity or (self.old_velocity and self.old_velocity.y > 0) then + return + end + + --make the mob stick for a split second + mobs.set_velocity(self,0) + + --fallback velocity to allow modularity + jump_height = DEFAULT_JUMP_HEIGHT + + local yaw = (self.yaw or 0) + + local current_velocity = self.object:get_velocity() + + local goal_velocity = { + x = (math_sin(yaw) * -velocity), + y = jump_height, + z = (math_cos(yaw) * velocity), + } + + + local new_velocity_addition = vector.subtract(goal_velocity,current_velocity) + + if vector_length(new_velocity_addition) > vector_length(goal_velocity) then + vector.multiply(new_velocity_addition, (vector_length(goal_velocity) / vector_length(new_velocity_addition))) + end + + --smooths out mobs a bit + if vector_length(new_velocity_addition) >= 0.0001 then + self.object:add_velocity(new_velocity_addition) + end +end + +--make it so mobs do not glitch out and freak out +--when moving around over nodes +mobs.swap_auto_step_height_adjust = function(self) + local y_vel = self.object:get_velocity().y + + if y_vel == 0 and self.stepheight ~= self.stepheight_backup then + self.stepheight = self.stepheight_backup + elseif y_vel ~= 0 and self.stepheight ~= 0 then + self.stepheight = 0 + end +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/projectile_handling.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/projectile_handling.lua new file mode 100644 index 000000000..e7ae6ffbe --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/projectile_handling.lua @@ -0,0 +1,44 @@ +local GRAVITY = minetest.settings:get("movement_gravity")-- + 9.81 + +mobs.shoot_projectile_handling = function(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable, gravity) + local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity") + if power == nil then + power = 19 + end + if damage == nil then + damage = 3 + end + + gravity = gravity or -GRAVITY + + local knockback + if bow_stack then + local enchantments = mcl_enchanting.get_enchantments(bow_stack) + if enchantments.power then + damage = damage + (enchantments.power + 1) / 4 + end + if enchantments.punch then + knockback = enchantments.punch * 3 + end + if enchantments.flame then + mcl_burning.set_on_fire(obj, math.huge) + 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._damage = damage + le._is_critical = is_critical + le._startpos = pos + le._knockback = knockback + le._collectable = collectable + + --play custom shoot sound + if shooter ~= nil and shooter.shoot_sound then + minetest.sound_play(shooter.shoot_sound, {pos=pos, max_hear_distance=16}, true) + end + + return obj +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/set_up.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/set_up.lua new file mode 100644 index 000000000..dfef98ee8 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/set_up.lua @@ -0,0 +1,226 @@ +local math_random = math.random + +local minetest_settings = minetest.settings + +-- get entity staticdata +mobs.mob_staticdata = function(self) + + --despawn mechanism + --don't despawned tamed or bred mobs + if not self.tamed and not self.bred then + if not mobs.check_for_player_within_area(self, 64) then + --print("removing SERIALIZED!") + self.object:remove() + return + end + end + + self.remove_ok = true + self.attack = nil + self.following = nil + + if use_cmi then + self.serialized_cmi_components = cmi.serialize_components(self._cmi_components) + end + + local tmp = {} + + for _,stat in pairs(self) do + + local t = type(stat) + + if t ~= "function" + and t ~= "nil" + and t ~= "userdata" + and _ ~= "_cmi_components" then + tmp[_] = self[_] + end + end + + return minetest.serialize(tmp) +end + + +-- activate mob and reload settings +mobs.mob_activate = function(self, staticdata, def, dtime) + + -- remove monsters in peaceful mode + if self.type == "monster" and minetest_settings:get_bool("only_peaceful_mobs", false) then + mcl_burning.extinguish(self.object) + self.object:remove() + return + end + + -- load entity variables + local tmp = minetest.deserialize(staticdata) + + if tmp then + for _,stat in pairs(tmp) do + self[_] = stat + end + end + + --set up wandering + if not self.wandering then + self.wandering = true + end + + --clear animation + self.current_animation = nil + + -- select random texture, set model and size + if not self.base_texture then + + -- compatiblity with old simple mobs textures + if type(def.textures[1]) == "string" then + def.textures = {def.textures} + end + + self.base_texture = def.textures[math_random(1, #def.textures)] + self.base_mesh = def.mesh + self.base_size = self.visual_size + self.base_colbox = self.collisionbox + self.base_selbox = self.selectionbox + end + + -- for current mobs that dont have this set + if not self.base_selbox then + self.base_selbox = self.selectionbox or self.base_colbox + end + + -- set texture, model and size + local textures = self.base_texture + local mesh = self.base_mesh + local vis_size = self.base_size + local colbox = self.base_colbox + local selbox = self.base_selbox + + -- specific texture if gotten + if self.gotten == true + and def.gotten_texture then + textures = def.gotten_texture + end + + -- specific mesh if gotten + if self.gotten == true + and def.gotten_mesh then + mesh = def.gotten_mesh + end + + -- set baby mobs to half size + if self.baby == true then + + vis_size = { + x = self.base_size.x * self.baby_size, + y = self.base_size.y * self.baby_size, + } + + if def.child_texture then + textures = def.child_texture[1] + end + + colbox = { + self.base_colbox[1] * self.baby_size, + self.base_colbox[2] * self.baby_size, + self.base_colbox[3] * self.baby_size, + self.base_colbox[4] * self.baby_size, + self.base_colbox[5] * self.baby_size, + self.base_colbox[6] * self.baby_size + } + selbox = { + self.base_selbox[1] * self.baby_size, + self.base_selbox[2] * self.baby_size, + self.base_selbox[3] * self.baby_size, + self.base_selbox[4] * self.baby_size, + self.base_selbox[5] * self.baby_size, + self.base_selbox[6] * self.baby_size + } + end + + --stop mobs from reviving + if not self.dead and not self.health then + self.health = math_random (self.hp_min, self.hp_max) + end + + + + if not self.random_sound_timer then + self.random_sound_timer = math_random(self.random_sound_timer_min,self.random_sound_timer_max) + end + + if self.breath == nil then + self.breath = self.breath_max + end + + -- pathfinding init + self.path = {} + self.path.way = {} -- path to follow, table of positions + self.path.lastpos = {x = 0, y = 0, z = 0} + self.path.stuck = false + self.path.following = false -- currently following path? + self.path.stuck_timer = 0 -- if stuck for too long search for path + + -- Armor groups + -- immortal=1 because we use custom health + -- handling (using "health" property) + local armor + if type(self.armor) == "table" then + armor = table.copy(self.armor) + armor.immortal = 1 + else + armor = {immortal=1, fleshy = self.armor} + end + self.object:set_armor_groups(armor) + self.old_y = self.object:get_pos().y + self.old_health = self.health + self.sounds.distance = self.sounds.distance or 10 + self.textures = textures + self.mesh = mesh + self.collisionbox = colbox + self.selectionbox = selbox + self.visual_size = vis_size + self.standing_in = "ignore" + self.standing_on = "ignore" + self.jump_sound_cooloff = 0 -- used to prevent jump sound from being played too often in short time + self.opinion_sound_cooloff = 0 -- used to prevent sound spam of particular sound types + + self.texture_mods = {} + + + self.v_start = false + self.timer = 0 + self.blinktimer = 0 + self.blinkstatus = false + + + --continue mob effect on server restart + if self.dead or self.health <= 0 then + self.object:set_texture_mod("^[colorize:red:120") + else + self.object:set_texture_mod("") + end + + + -- set anything changed above + self.object:set_properties(self) + + --update_tag(self) + --mobs.set_animation(self, "stand") + + -- run on_spawn function if found + if self.on_spawn and not self.on_spawn_run then + if self.on_spawn(self) then + self.on_spawn_run = true -- if true, set flag to run once only + end + end + + -- run after_activate + if def.after_activate then + def.after_activate(self, staticdata, def, dtime) + end + + if use_cmi then + self._cmi_components = cmi.activate_components(self.serialized_cmi_components) + cmi.notify_activate(self.object, dtime) + end +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/sound_handling.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/sound_handling.lua new file mode 100644 index 000000000..98d2644e8 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/sound_handling.lua @@ -0,0 +1,59 @@ +local math_random = math.random + + +--generic call for sound handler for mobs (data access) +mobs.play_sound = function(self,sound) + local soundinfo = self.sounds + + if not soundinfo then + return + end + + local play_sound = soundinfo[sound] + + if not play_sound then + return + end + + mobs.play_sound_handler(self, play_sound) +end + + +--generic sound handler for mobs +mobs.play_sound_handler = function(self, sound) + local pitch = (100 + math_random(-15,15) + math_random()) / 100 + local distance = self.sounds.distance or 16 + + minetest.sound_play(sound, { + object = self.object, + gain = 1.0, + max_hear_distance = distance, + pitch = pitch, + }, true) +end + + +--random sound timing handler +mobs.random_sound_handling = function(self,dtime) + + self.random_sound_timer = self.random_sound_timer - dtime + + --play sound and reset timer + if self.random_sound_timer <= 0 then + mobs.play_sound(self,"random") + self.random_sound_timer = math_random(self.random_sound_timer_min,self.random_sound_timer_max) + end +end + +--used for playing a non-mob internal sound at random pitches +mobs.play_sound_specific = function(self,soundname) + local pitch = (100 + math_random(-15,15) + math_random()) / 100 + local distance = self.sounds.distance or 16 + + minetest.sound_play(soundname, { + object = self.object, + gain = 1.0, + max_hear_distance = distance, + pitch = pitch, + }, true) +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/mount.lua b/mods/ENTITIES/mcl_mobs/api/mount.lua similarity index 92% rename from mods/ENTITIES/mcl_mobs/mount.lua rename to mods/ENTITIES/mcl_mobs/api/mount.lua index 9383ee067..8ee45f299 100644 --- a/mods/ENTITIES/mcl_mobs/mount.lua +++ b/mods/ENTITIES/mcl_mobs/api/mount.lua @@ -206,21 +206,30 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) -- move forwards if ctrl.up then - entity.v = entity.v + entity.accel / 10 + mobs.set_velocity(entity, entity.run_velocity) + + mobs.set_mob_animation(entity, moving_anim) -- move backwards elseif ctrl.down then - if entity.max_speed_reverse == 0 and entity.v == 0 then - return - end + mobs.set_velocity(entity, -entity.run_velocity) - entity.v = entity.v - entity.accel / 10 + mobs.set_mob_animation(entity, moving_anim) + + --halt + else + + mobs.set_velocity(entity, 0) + + mobs.set_mob_animation(entity, stand_anim) end - -- fix mob rotation + -- mob rotation entity.object:set_yaw(entity.driver:get_look_horizontal() - entity.rotate) + entity.yaw = entity.driver:get_look_horizontal() - entity.rotate + --[[ if can_fly then -- fly up @@ -244,32 +253,21 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) end else + ]]-- - -- jump - if ctrl.jump then + -- jump + if ctrl.jump then - if velo.y == 0 then - velo.y = velo.y + entity.jump_height - acce_y = acce_y + (acce_y * 3) + 1 - end - end - - end - end - - -- if not moving then set animation and return - if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then - - if stand_anim then - mobs:set_animation(entity, stand_anim) + mobs.jump(entity) end - return + --end end + --[[ -- set moving animation if moving_anim then - mobs:set_animation(entity, moving_anim) + mobs:set_mob_animation(entity, moving_anim) end -- Stop! @@ -383,6 +381,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) end entity.v2 = v + ]]-- end @@ -390,6 +389,10 @@ end function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim) + if true then + print("succ") + return + end local ctrl = entity.driver:get_player_control() local velo = entity.object:get_velocity() local dir = entity.driver:get_look_dir() @@ -440,9 +443,9 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim) -- change animation if stopped if velo.x == 0 and velo.y == 0 and velo.z == 0 then - mobs:set_animation(entity, stand_anim) + mobs:set_mob_animation(entity, stand_anim) else -- moving animation - mobs:set_animation(entity, moving_anim) + mobs:set_mob_animation(entity, moving_anim) end end diff --git a/mods/ENTITIES/mcl_mobs/spawning.lua b/mods/ENTITIES/mcl_mobs/api/spawning.lua similarity index 67% rename from mods/ENTITIES/mcl_mobs/spawning.lua rename to mods/ENTITIES/mcl_mobs/api/spawning.lua index 210c6b9c6..ca4dc1e4f 100644 --- a/mods/ENTITIES/mcl_mobs/spawning.lua +++ b/mods/ENTITIES/mcl_mobs/api/spawning.lua @@ -1,17 +1,30 @@ --lua locals -local get_node = minetest.get_node -local get_item_group = minetest.get_item_group -local get_node_light = minetest.get_node_light +local get_node = minetest.get_node +local get_item_group = minetest.get_item_group +local get_node_light = minetest.get_node_light local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air -local new_vector = vector.new +local get_biome_name = minetest.get_biome_name +local get_objects_inside_radius = minetest.get_objects_inside_radius + + local math_random = math.random -local get_biome_name = minetest.get_biome_name +local math_floor = math.floor local max = math.max -local get_objects_inside_radius = minetest.get_objects_inside_radius + local vector_distance = vector.distance +local vector_new = vector.new +local vector_floor = vector.floor + +local table_copy = table.copy +local table_remove = table.remove + -- range for mob count -local aoc_range = 32 +local aoc_range = 48 + +--do mobs spawn? +local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false + --[[ THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs @@ -153,28 +166,14 @@ Overworld regular: - -local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false --- count how many mobs of one type are inside an area - -local count_mobs = function(pos,mobtype) +-- count how many mobs are in an area +local count_mobs = function(pos) local num = 0 - local objs = get_objects_inside_radius(pos, aoc_range) - for n = 1, #objs do - local obj = objs[n]:get_luaentity() - if obj and obj.name and obj._cmi_is_mob then - -- count hostile mobs only - if mobtype == "hostile" then - if obj.spawn_class == "hostile" then - num = num + 1 - end - -- count passive mobs only - else - num = num + 1 - end + for _,object in pairs(get_objects_inside_radius(pos, aoc_range)) do + if object and object:get_luaentity() and object:get_luaentity()._cmi_is_mob then + num = num + 1 end end - return num end @@ -484,23 +483,23 @@ end local axis --inner and outer part of square donut radius -local inner = 1 -local outer = 65 +local inner = 15 +local outer = 64 local int = {-1,1} local position_calculation = function(pos) - pos = vector.floor(pos) + pos = vector_floor(pos) --this is used to determine the axis buffer from the player - axis = math.random(0,1) + axis = math_random(0,1) --cast towards the direction if axis == 0 then --x - pos.x = pos.x + math.random(inner,outer)*int[math.random(1,2)] - pos.z = pos.z + math.random(-outer,outer) + pos.x = pos.x + math_random(inner,outer)*int[math_random(1,2)] + pos.z = pos.z + math_random(-outer,outer) else --z - pos.z = pos.z + math.random(inner,outer)*int[math.random(1,2)] - pos.x = pos.x + math.random(-outer,outer) + pos.z = pos.z + math_random(inner,outer)*int[math_random(1,2)] + pos.x = pos.x + math_random(-outer,outer) end return(pos) end @@ -516,7 +515,7 @@ local decypher_limits_dictionary = { local function decypher_limits(posy) --local min_max_table = decypher_limits_dictionary[dimension] --return min_max_table[1],min_max_table[2] - posy = math.floor(posy) + posy = math_floor(posy) return posy - 32, posy + 32 end @@ -539,108 +538,169 @@ if mobs_spawn then local timer = 0 minetest.register_globalstep(function(dtime) timer = timer + dtime - if timer >= 8 then + if timer >= 10 then timer = 0 for _,player in pairs(minetest.get_connected_players()) do - for i = 1,math_random(3,8) do - repeat -- after this line each "break" means "continue" - local player_pos = player:get_pos() + -- after this line each "break" means "continue" + local do_mob_spawning = true + repeat + --don't need to get these variables more than once + --they happen in a single server step - local _,dimension = mcl_worlds.y_to_layer(player_pos.y) + local player_pos = player:get_pos() + local _,dimension = mcl_worlds.y_to_layer(player_pos.y) - if dimension == "void" or dimension == "default" then - break -- ignore void and unloaded area - end + if dimension == "void" or dimension == "default" then + break -- ignore void and unloaded area + end - local min,max = decypher_limits(player_pos.y) + local min,max = decypher_limits(player_pos.y) - local goal_pos = position_calculation(player_pos) + for i = 1,math_random(1,4) do + -- after this line each "break" means "continue" + local do_mob_algorithm = true + repeat - local spawning_position_list = find_nodes_in_area_under_air(new_vector(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:solid", "group:water", "group:lava"}) + local goal_pos = position_calculation(player_pos) + + local spawning_position_list = find_nodes_in_area_under_air(vector_new(goal_pos.x,min,goal_pos.z), vector_new(goal_pos.x,max,goal_pos.z), {"group:solid", "group:water", "group:lava"}) + + --couldn't find node + if #spawning_position_list <= 0 then + break + end + + local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)] + + --Prevent strange behavior --- this is commented out: /too close to player --fixed with inner circle + if not spawning_position then -- or vector_distance(player_pos, spawning_position) < 15 + break + end + + --hard code mob limit in area to 5 for now + if count_mobs(spawning_position) >= 5 then + break + end + + local gotten_node = get_node(spawning_position).name + + if not gotten_node or gotten_node == "air" then --skip air nodes + break + end + + local gotten_biome = minetest.get_biome_data(spawning_position) + + if not gotten_biome then + break --skip if in unloaded area + end + + gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with + + --add this so mobs don't spawn inside nodes + spawning_position.y = spawning_position.y + 1 + + --only need to poll for node light if everything else worked + local gotten_light = get_node_light(spawning_position) + + local is_water = get_item_group(gotten_node, "water") ~= 0 + local is_lava = get_item_group(gotten_node, "lava") ~= 0 + + local mob_def = nil + + --create a disconnected clone of the spawn dictionary + --prevents memory leak + local mob_library_worker_table = table_copy(spawn_dictionary) + + --grab mob that fits into the spawning location + --randomly grab a mob, don't exclude any possibilities + local repeat_mob_search = true + repeat + + --do not infinite loop + if #mob_library_worker_table <= 0 then + --print("breaking infinite loop") + break + end + + local skip = false + + --use this for removing table elements of mobs that do not match + local temp_index = math_random(1,#mob_library_worker_table) + + local temp_def = mob_library_worker_table[temp_index] + + --skip if something ridiculous happens (nil mob def) + --something truly horrible has happened if skip gets + --activated at this point + if not temp_def then + skip = true + end + + if not skip and (spawning_position.y < temp_def.min_height or spawning_position.y > temp_def.max_height) then + skip = true + end + + --skip if not correct dimension + if not skip and (temp_def.dimension ~= dimension) then + skip = true + end + + --skip if not in correct biome + if not skip and (not biome_check(temp_def.biomes, gotten_biome)) then + skip = true + end + + --don't spawn if not in light limits + if not skip and (gotten_light < temp_def.min_light or gotten_light > temp_def.max_light) then + skip = true + end + + --skip if not in correct spawning type + if not skip and (temp_def.type_of_spawning == "ground" and is_water) then + skip = true + end + + if not skip and (temp_def.type_of_spawning == "ground" and is_lava) then + skip = true + end + + --found a mob, exit out of loop + if not skip then + --minetest.log("warning", "found mob:"..temp_def.name) + --print("found mob:"..temp_def.name) + mob_def = table_copy(temp_def) + break + else + --minetest.log("warning", "deleting temp index "..temp_index) + --print("deleting temp index") + table_remove(mob_library_worker_table, temp_index) + end + + until repeat_mob_search == false --this is needed to sort through mobs randomly + + + --catch if went through all mobs and something went horribly wrong + --could not find a valid mob to spawn that fits the environment + if not mob_def then + break + end + + --adjust the position for water and lava mobs + if mob_def.type_of_spawning == "water" or mob_def.type_of_spawning == "lava" then + spawning_position.y = spawning_position.y - 1 + end + + --print("spawning: " .. mob_def.name) + + --everything is correct, spawn mob + minetest.add_entity(spawning_position, mob_def.name) - --couldn't find node - if #spawning_position_list <= 0 then break - end + until do_mob_algorithm == false --this is a safety catch + end - local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)] - - --Prevent strange behavior/too close to player - if not spawning_position or vector_distance(player_pos, spawning_position) < 15 then - break - end - - local gotten_node = get_node(spawning_position).name - - if not gotten_node or gotten_node == "air" then --skip air nodes - break - end - - local gotten_biome = minetest.get_biome_data(spawning_position) - - if not gotten_biome then - break --skip if in unloaded area - end - - gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with - - --grab random mob - local mob_def = spawn_dictionary[math.random(1,#spawn_dictionary)] - - if not mob_def then - break --skip if something ridiculous happens (nil mob def) - end - - --skip if not correct dimension - if mob_def.dimension ~= dimension then - break - end - - --skip if not in correct biome - if not biome_check(mob_def.biomes, gotten_biome) then - break - end - - --add this so mobs don't spawn inside nodes - spawning_position.y = spawning_position.y + 1 - - if spawning_position.y < mob_def.min_height or spawning_position.y > mob_def.max_height then - break - end - - --only need to poll for node light if everything else worked - local gotten_light = get_node_light(spawning_position) - - --don't spawn if not in light limits - if gotten_light < mob_def.min_light or gotten_light > mob_def.max_light then - break - end - - local is_water = get_item_group(gotten_node, "water") ~= 0 - local is_lava = get_item_group(gotten_node, "lava") ~= 0 - - if mob_def.type_of_spawning == "ground" and is_water then - break - end - - if mob_def.type_of_spawning == "ground" and is_lava then - break - end - - --finally do the heavy check (for now) of mobs in area - if count_mobs(spawning_position, mob_def.spawn_class) >= mob_def.aoc then - break - end - - --adjust the position for water and lava mobs - if mob_def.type_of_spawning == "water" or mob_def.type_of_spawning == "lava" then - spawning_position.y = spawning_position.y - 1 - end - - --everything is correct, spawn mob - minetest.add_entity(spawning_position, mob_def.name) - until true --this is a safety catch - end + break + until do_mob_spawning == false --this is a performance catch end end end) diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index 69246b470..b0daba2c4 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -1,14 +1,16 @@ local path = minetest.get_modpath(minetest.get_current_modname()) +local api_path = path.."/api" + -- Mob API -dofile(path .. "/api.lua") +dofile(api_path .. "/api.lua") -- Spawning Algorithm -dofile(path .. "/spawning.lua") +dofile(api_path .. "/spawning.lua") -- Rideable Mobs -dofile(path .. "/mount.lua") +dofile(api_path .. "/mount.lua") -- Mob Items dofile(path .. "/crafts.lua") \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/lucky_block.lua b/mods/ENTITIES/mcl_mobs/lucky_block.lua deleted file mode 100644 index ea90de74a..000000000 --- a/mods/ENTITIES/mcl_mobs/lucky_block.lua +++ /dev/null @@ -1,8 +0,0 @@ - -if minetest.get_modpath("lucky_block") then - - lucky_block:add_blocks({ - {"dro", {"mcl_mobs:nametag"}, 1}, - {"lig"}, - }) -end diff --git a/mods/ENTITIES/mcl_mobs/sounds/attributes.txt b/mods/ENTITIES/mcl_mobs/sounds/attributes.txt new file mode 100644 index 000000000..1228dd9d7 --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/sounds/attributes.txt @@ -0,0 +1,4 @@ + +default_punch.1 = https://freesound.org/people/Merrick079/sounds/566436/ +default_punch.2 = https://freesound.org/people/Merrick079/sounds/566435/ +default_punch.3 = https://freesound.org/people/Merrick079/sounds/566434/ diff --git a/mods/ENTITIES/mcl_mobs/sounds/default_punch.1.ogg b/mods/ENTITIES/mcl_mobs/sounds/default_punch.1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4d7ba8015eb13ce415ea09f4223a427bc4d2e17d GIT binary patch literal 12658 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 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mcl_mobs/sounds/default_punch.2.ogg b/mods/ENTITIES/mcl_mobs/sounds/default_punch.2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c022d94f871345810b7d90ab953a01985e2d369b GIT binary patch literal 12801 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 R&zZhFM!opw0l>!ge*lM|2+9Be literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mcl_mobs/sounds/default_punch.3.ogg b/mods/ENTITIES/mcl_mobs/sounds/default_punch.3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4c5e3f9b301e682372399f6213210a42d86fc558 GIT binary patch literal 12943 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 10 then @@ -360,11 +377,16 @@ mobs:register_mob("mobs_mc:enderman", { --if looking in general head position, turn hostile if minetest.line_of_sight(ender_eye_pos, look_pos_base) and vector.distance(look_pos, ender_eye_pos) <= 0.4 then self.provoked = "staring" - self.attack = minetest.get_player_by_name(obj:get_player_name()) + self.state = "stand" + self.hostile = false break - else -- I'm not sure what this part does, but I don't want to break anything - jordan4ibanez + --begin attacking the player + else if self.provoked == "staring" then self.provoked = "broke_contact" + self.hostile = true + self.state = "attack" + self.attacking = obj end end @@ -430,7 +452,7 @@ mobs:register_mob("mobs_mc:enderman", { self.base_texture = create_enderman_textures(block_type, self._taken_node) self.object:set_properties({ textures = self.base_texture }) self.animation = select_enderman_animation("block") - mobs:set_animation(self, self.animation.current) + mobs.set_mob_animation(self, self.animation.current) if def.sounds and def.sounds.dug then minetest.sound_play(def.sounds.dug, {pos = take_pos, max_hear_distance = 16}, true) end @@ -453,7 +475,7 @@ mobs:register_mob("mobs_mc:enderman", { local def = minetest.registered_nodes[self._taken_node] -- Update animation accordingly (removes visible block) self.animation = select_enderman_animation("normal") - mobs:set_animation(self, self.animation.current) + mobs.set_mob_animation(self, self.animation.current) if def.sounds and def.sounds.place then minetest.sound_play(def.sounds.place, {pos = place_pos, max_hear_distance = 16}, true) end @@ -557,7 +579,7 @@ mobs:register_mob("mobs_mc:enderman", { water_damage = 8, view_range = 64, fear_height = 4, - attack_type = "dogfight", + attack_type = "punch", }) diff --git a/mods/ENTITIES/mobs_mc/endermite.lua b/mods/ENTITIES/mobs_mc/endermite.lua index 2bffa8304..712086828 100644 --- a/mods/ENTITIES/mobs_mc/endermite.lua +++ b/mods/ENTITIES/mobs_mc/endermite.lua @@ -9,12 +9,15 @@ mobs:register_mob("mobs_mc:endermite", { type = "monster", spawn_class = "hostile", passive = false, + rotate = 270, + hostile = true, hp_min = 8, hp_max = 8, xp_min = 3, xp_max = 3, armor = {fleshy = 100, arthropod = 100}, group_attack = true, + attack_type = "punch", collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.29, 0.2}, visual = "mesh", mesh = "mobs_mc_endermite.b3d", diff --git a/mods/ENTITIES/mobs_mc/ghast.lua b/mods/ENTITIES/mobs_mc/ghast.lua index 1d7179162..609110bdb 100644 --- a/mods/ENTITIES/mobs_mc/ghast.lua +++ b/mods/ENTITIES/mobs_mc/ghast.lua @@ -14,13 +14,17 @@ mobs:register_mob("mobs_mc:ghast", { description = S("Ghast"), type = "monster", spawn_class = "hostile", - pathfinding = 1, group_attack = true, + hostile = true, + fly_random_while_attack = true, hp_min = 10, hp_max = 10, + rotate = 270, xp_min = 5, xp_max = 5, - collisionbox = {-2, 5, -2, 2, 9, 2}, + reach = 20, + eye_height = 2.5, + collisionbox = {-2, 0, -2, 2, 4, 2}, visual = "mesh", mesh = "mobs_mc_ghast.b3d", textures = { @@ -36,8 +40,10 @@ mobs:register_mob("mobs_mc:ghast", { -- TODO: damage -- TODO: better death }, + walk_velocity = 1.6, run_velocity = 3.2, + drops = { {name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 2, looting = "common"}, {name = mobs_mc.items.ghast_tear, chance = 10/6, min = 0, max = 1, looting = "common", looting_ignore_chance = true}, @@ -48,22 +54,23 @@ mobs:register_mob("mobs_mc:ghast", { walk_start = 0, walk_end = 40, run_start = 0, run_end = 40, }, + fall_damage = 0, - view_range = 100, - attack_type = "dogshoot", - arrow = "mobs_mc:fireball", - shoot_interval = 3.5, - shoot_offset = -5, - dogshoot_switch = 1, - dogshoot_count_max =1, - passive = false, - jump = true, - jump_height = 4, + view_range = 28, + attack_type = "projectile", + arrow = "mobs_mc:ghast_fireball", floats=1, fly = true, makes_footstep_sound = false, - instant_death = true, fire_resistant = true, + projectile_cooldown_min = 5, + projectile_cooldown_max = 7, + shoot_arrow = function(self, pos, dir) + -- 2-4 damage per arrow + local dmg = math.random(2,4) + mobs.shoot_projectile_handling("mobs_mc:ghast_fireball", pos, dir, self.object:get_yaw(), self.object, 11, dmg,nil,nil,nil,-0.6) + end, + --[[ do_custom = function(self) if self.firing == true then self.base_texture = {"mobs_mc_ghast_firing.png"} @@ -73,6 +80,7 @@ mobs:register_mob("mobs_mc:ghast", { self.object:set_properties({textures=self.base_texture}) end end, + ]]-- }) @@ -92,32 +100,40 @@ mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) -- fireball (projectile) -mobs:register_arrow("mobs_mc:fireball", { +mobs:register_arrow("mobs_mc:ghast_fireball", { visual = "sprite", visual_size = {x = 1, y = 1}, textures = {"mcl_fire_fire_charge.png"}, velocity = 15, collisionbox = {-.5, -.5, -.5, .5, .5, .5}, + tail = 1, + tail_texture = "mobs_mc_spit.png^[colorize:black:255", --repurpose spit texture + tail_size = 5, _is_fireball = true, hit_player = function(self, player) + --[[ player:punch(self.object, 1.0, { full_punch_interval = 1.0, damage_groups = {fleshy = 6}, }, nil) - mobs:boom(self, self.object:get_pos(), 1, true) + ]]-- + --mobs:boom(self, self.object:get_pos(), 1, true) + mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 }) end, hit_mob = function(self, mob) mob:punch(self.object, 1.0, { full_punch_interval = 1.0, - damage_groups = {fleshy = 6}, + damage_groups = {fleshy = self._damage}, }, nil) - mobs:boom(self, self.object:get_pos(), 1, true) + --mobs:boom(self, self.object:get_pos(), 1, true) + mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 }) end, hit_node = function(self, pos, node) - mobs:boom(self, pos, 1, true) + --mobs:boom(self, pos, 1, true) + mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 }) end }) diff --git a/mods/ENTITIES/mobs_mc/guardian.lua b/mods/ENTITIES/mobs_mc/guardian.lua index 06a2ba2e2..241ac3444 100644 --- a/mods/ENTITIES/mobs_mc/guardian.lua +++ b/mods/ENTITIES/mobs_mc/guardian.lua @@ -14,7 +14,7 @@ mobs:register_mob("mobs_mc:guardian", { xp_max = 10, breath_max = -1, passive = false, - attack_type = "dogfight", + attack_type = "punch", pathfinding = 1, view_range = 16, walk_velocity = 2, diff --git a/mods/ENTITIES/mobs_mc/guardian_elder.lua b/mods/ENTITIES/mobs_mc/guardian_elder.lua index 5b8150dd4..4fb989e2f 100644 --- a/mods/ENTITIES/mobs_mc/guardian_elder.lua +++ b/mods/ENTITIES/mobs_mc/guardian_elder.lua @@ -16,7 +16,7 @@ mobs:register_mob("mobs_mc:guardian_elder", { xp_max = 10, breath_max = -1, passive = false, - attack_type = "dogfight", + attack_type = "punch", pathfinding = 1, view_range = 16, walk_velocity = 2, diff --git a/mods/ENTITIES/mobs_mc/horse.lua b/mods/ENTITIES/mobs_mc/horse.lua index ac631f205..461c60efd 100644 --- a/mods/ENTITIES/mobs_mc/horse.lua +++ b/mods/ENTITIES/mobs_mc/horse.lua @@ -88,6 +88,10 @@ local horse = { spawn_class = "passive", visual = "mesh", mesh = "mobs_mc_horse.b3d", + rotate = 270, + walk_velocity = 1, + run_velocity = 8, + skittish = true, visual_size = {x=3.0, y=3.0}, collisionbox = {-0.69825, -0.01, -0.69825, 0.69825, 1.59, 0.69825}, animation = { @@ -97,7 +101,7 @@ local horse = { walk_speed = 25, walk_start = 0, walk_end = 40, - run_speed = 60, + run_speed = 120, run_start = 0, run_end = 40, }, @@ -114,7 +118,8 @@ local horse = { fly = false, walk_chance = 60, view_range = 16, - follow = mobs_mc.follow.horse, + follow = "mcl_farming:wheat_item", + follow_distance = 3, passive = true, hp_min = 15, hp_max = 30, @@ -182,7 +187,7 @@ local horse = { -- if driver present and horse has a saddle allow control of horse if self.driver and self._saddle then - mobs.drive(self, "walk", "stand", false, dtime) + mobs.drive(self, "run", "stand", false, dtime) return false -- skip rest of mob functions end @@ -214,6 +219,21 @@ local horse = { local iname = item:get_name() local heal = 0 + --sneak click to breed the horse/feed it + if self.owner and self.owner == clicker:get_player_name() then + --attempt to enter breed state + if mobs.enter_breed_state(self,clicker) then + return + end + end + + --don't do any other logic with the baby + --make baby grow faster + if self.baby then + mobs.make_baby_grow_faster(self,clicker) + return + end + -- Taming self.temper = self.temper or (math.random(1,100)) @@ -239,6 +259,7 @@ local horse = { self.buck_off_time = 40 -- TODO how long does it take in minecraft? if self.temper > 100 then self.tamed = true -- NOTE taming can only be finished by riding the horse + mobs.tamed_effect(self) if not self.owner or self.owner == "" then self.owner = clicker:get_player_name() end @@ -253,6 +274,14 @@ local horse = { -- If nothing happened temper_increase = 0 and addition does nothing self.temper = self.temper + temper_increase + --give the player some kind of idea + --of what's happening with the horse's temper + if self.temper <= 100 then + mobs.feed_effect(self) + else + mobs.tamed_effect(self) + end + return end @@ -282,10 +311,6 @@ local horse = { return end - if mobs:protect(self, clicker) then - return - end - -- Make sure tamed horse is mature and being clicked by owner only if self.tamed and not self.child and self.owner == clicker:get_player_name() then @@ -357,9 +382,6 @@ local horse = { self.object:set_properties({stepheight = 1.1}) mobs.attach(self, clicker) - -- Used to capture horse - elseif not self.driver and iname ~= "" then - mobs:capture_mob(self, clicker, 0, 5, 60, false, nil) end end end, @@ -520,22 +542,53 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "FlowerForest_beach", + "Forest_beach", + "StoneBeach", + "ColdTaiga_beach_water", + "Taiga_beach", + "Savanna_beach", + "Plains_beach", + "ExtremeHills_beach", + "ColdTaiga_beach", + "Swampland_shore", + "JungleM_shore", + "Jungle_shore", + "MesaPlateauFM_sandlevel", + "MesaPlateauF_sandlevel", + "MesaBryce_sandlevel", + "Mesa_sandlevel", + "Mesa", + "FlowerForest", + "Swampland", + "Taiga", + "ExtremeHills", + "Jungle", + "Savanna", + "BirchForest", + "MegaSpruceTaiga", + "MegaTaiga", + "ExtremeHills+", + "Forest", + "Plains", + "Desert", + "ColdTaiga", + "IcePlainsSpikes", + "SunflowerPlains", + "IcePlains", + "RoofedForest", + "ExtremeHills+_snowtop", + "MesaPlateauFM_grasstop", + "JungleEdgeM", + "ExtremeHillsM", + "JungleM", + "BirchForestM", + "MesaPlateauF", + "MesaPlateauFM", + "MesaPlateauF_grasstop", + "MesaBryce", + "JungleEdge", + "SavannaM", }, 0, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/iron_golem.lua b/mods/ENTITIES/mobs_mc/iron_golem.lua index 0d3e74645..48e573e13 100644 --- a/mods/ENTITIES/mobs_mc/iron_golem.lua +++ b/mods/ENTITIES/mobs_mc/iron_golem.lua @@ -16,8 +16,11 @@ mobs:register_mob("mobs_mc:iron_golem", { type = "npc", spawn_class = "passive", passive = true, + rotate = 270, hp_min = 100, - hp_max = 100, + hp_max = 100, + protect = true, + neutral = true, breath_max = -1, collisionbox = {-0.7, -0.01, -0.7, 0.7, 2.69, 0.7}, visual = "mesh", @@ -40,7 +43,7 @@ mobs:register_mob("mobs_mc:iron_golem", { reach = 3, group_attack = true, attacks_monsters = true, - attack_type = "dogfight", + attack_type = "punch", drops = { {name = mobs_mc.items.iron_ingot, chance = 1, diff --git a/mods/ENTITIES/mobs_mc/llama.lua b/mods/ENTITIES/mobs_mc/llama.lua index 655cddfb6..58f565ec1 100644 --- a/mods/ENTITIES/mobs_mc/llama.lua +++ b/mods/ENTITIES/mobs_mc/llama.lua @@ -28,6 +28,15 @@ mobs:register_mob("mobs_mc:llama", { description = S("Llama"), type = "animal", spawn_class = "passive", + rotate = 270, + neutral = true, + group_attack = true, + attack_type = "projectile", + shoot_arrow = function(self, pos, dir) + -- 2-4 damage per arrow + local dmg = 1 + mobs.shoot_projectile_handling("mobs_mc:spit", pos, dir, self.object:get_yaw(), self.object, nil, dmg) + end, hp_min = 15, hp_max = 30, xp_min = 1, @@ -50,7 +59,11 @@ mobs:register_mob("mobs_mc:llama", { walk_velocity = 1, run_velocity = 4.4, follow_velocity = 4.4, + breed_distance = 1.5, + baby_size = 0.5, + follow_distance = 2, floats = 1, + reach = 6, drops = { {name = mobs_mc.items.leather, chance = 1, @@ -83,7 +96,7 @@ mobs:register_mob("mobs_mc:llama", { look_start = 78, look_end = 108, }, - follow = mobs_mc.follow.llama, + follow = mobs_mc.items.hay_bale, view_range = 16, do_custom = function(self, dtime) @@ -126,30 +139,71 @@ mobs:register_mob("mobs_mc:llama", { return end - local item = clicker:get_wielded_item() - if item:get_name() == mobs_mc.items.hay_bale then - -- Breed with hay bale - if mobs:feed_tame(self, clicker, 1, true, false) then return end - else - -- Feed with anything else - if mobs:feed_tame(self, clicker, 1, false, true) then return end + --owner is broken for this + --we'll make the owner this guy + --attempt to enter breed state + if mobs.enter_breed_state(self,clicker) then + self.tamed = true + self.owner = clicker:get_player_name() + return + end + + --ignore other logic + --make baby grow faster + if self.baby then + mobs.make_baby_grow_faster(self,clicker) + return end - if mobs:protect(self, clicker) then return end + -- Make sure tamed llama is mature and being clicked by owner only if self.tamed and not self.child and self.owner == clicker:get_player_name() then + local item = clicker:get_wielded_item() + --safety catch + if not item then + return + end + + + + --put chest on carpeted llama + if self.carpet and not self.chest and item:get_name() == "mcl_chests:chest" then + if not minetest.is_creative_enabled(clicker:get_player_name()) then + item:take_item() + clicker:set_wielded_item(item) + end + + self.base_texture = table.copy(self.base_texture) + self.base_texture[1] = "mobs_mc_llama_chest.png" + self.object:set_properties({ + textures = self.base_texture, + }) + self.chest = true + + return --don't attempt to ride + end + + -- Place carpet - --[[ TODO: Re-enable this code when carpet textures arrived. - if minetest.get_item_group(item:get_name(), "carpet") == 1 and not self.carpet then + --TODO: Re-enable this code when carpet textures arrived. + if minetest.get_item_group(item:get_name(), "carpet") == 1 then + for group, carpetdata in pairs(carpets) do if minetest.get_item_group(item:get_name(), group) == 1 then if not minetest.is_creative_enabled(clicker:get_player_name()) then item:take_item() clicker:set_wielded_item(item) + + --shoot off old carpet + if self.carpet then + minetest.add_item(self.object:get_pos(), self.carpet) + end end + local substr = carpetdata[2] local tex_carpet = "mobs_mc_llama_decor_"..substr..".png" + self.base_texture = table.copy(self.base_texture) self.base_texture[2] = tex_carpet self.object:set_properties({ @@ -170,23 +224,21 @@ mobs:register_mob("mobs_mc:llama", { end end end - ]] - -- detatch player already riding llama - if self.driver and clicker == self.driver then + if self.carpet then + -- detatch player already riding llama + if self.driver and clicker == self.driver then - mobs.detach(clicker, {x = 1, y = 0, z = 1}) + mobs.detach(clicker, {x = 1, y = 0, z = 1}) - -- attach player to llama - elseif not self.driver then + -- attach player to llama + elseif not self.driver then - self.object:set_properties({stepheight = 1.1}) - mobs.attach(self, clicker) + self.object:set_properties({stepheight = 1.1}) + mobs.attach(self, clicker) + end end - -- Used to capture llama - elseif not self.driver and clicker:get_wielded_item():get_name() ~= "" then - mobs:capture_mob(self, clicker, 0, 5, 60, false, nil) end end, @@ -240,3 +292,38 @@ mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:llama", S("Llama"), "mobs_mc_spawn_icon_llama.png", 0) + + +-- llama spit +mobs:register_arrow("mobs_mc:spit", { + visual = "sprite", + visual_size = {x = 0.3, y = 0.3}, + textures = {"mobs_mc_spit.png"}, + velocity = 1, + speed = 1, + tail = 1, + tail_texture = "mobs_mc_spit.png", + tail_size = 2, + tail_distance_divider = 4, + + hit_player = function(self, player) + if rawget(_G, "armor") and armor.last_damage_types then + armor.last_damage_types[player:get_player_name()] = "spit" + end + player:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = self._damage}, + }, nil) + end, + + hit_mob = function(self, mob) + mob:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = _damage}, + }, nil) + end, + + hit_node = function(self, pos, node) + --does nothing + end +}) \ No newline at end of file diff --git a/mods/ENTITIES/mobs_mc/models/attributes.txt b/mods/ENTITIES/mobs_mc/models/attributes.txt new file mode 100644 index 000000000..ec59e0f70 --- /dev/null +++ b/mods/ENTITIES/mobs_mc/models/attributes.txt @@ -0,0 +1 @@ +Ghast fixed by epCode - Thanks! \ No newline at end of file diff --git a/mods/ENTITIES/mobs_mc/models/mobs_mc_ghast.b3d b/mods/ENTITIES/mobs_mc/models/mobs_mc_ghast.b3d index cebc037c05efdcf2343c4232099b12fffc4c5c89..ab34f334f8321e30f05ae4b53a946b4095587ef0 100644 GIT binary patch delta 18141 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 KUl*Z12>%DJKTiJu literal 75657 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 V09X&5s-C+ER1az5QHx%`0RZsDdanQg diff --git a/mods/ENTITIES/mobs_mc/ocelot.lua b/mods/ENTITIES/mobs_mc/ocelot.lua index 5a3f135a1..e36abec77 100644 --- a/mods/ENTITIES/mobs_mc/ocelot.lua +++ b/mods/ENTITIES/mobs_mc/ocelot.lua @@ -31,6 +31,8 @@ local ocelot = { type = "animal", spawn_class = "passive", can_despawn = true, + rotate = 270, + skittish = true, hp_min = 10, hp_max = 10, xp_min = 1, @@ -43,7 +45,7 @@ local ocelot = { makes_footstep_sound = true, walk_chance = default_walk_chance, walk_velocity = 1, - run_velocity = 3, + run_velocity = 10, follow_velocity = 1, floats = 1, runaway = true, @@ -57,7 +59,7 @@ local ocelot = { }, animation = { speed_normal = 25, - run_speed = 50, + run_speed = 150, stand_start = 0, stand_end = 0, walk_start = 0, @@ -123,8 +125,6 @@ cat.sounds = { } cat.on_rightclick = function(self, clicker) if mobs:feed_tame(self, clicker, 1, true, false) then return end - if mobs:capture_mob(self, clicker, 0, 60, 5, false, nil) then return end - if mobs:protect(self, clicker) then return end if self.child then return end diff --git a/mods/ENTITIES/mobs_mc/parrot.lua b/mods/ENTITIES/mobs_mc/parrot.lua index c04ea77c6..de52c6252 100644 --- a/mods/ENTITIES/mobs_mc/parrot.lua +++ b/mods/ENTITIES/mobs_mc/parrot.lua @@ -20,11 +20,14 @@ mobs:register_mob("mobs_mc:parrot", { hp_max = 6, xp_min = 1, xp_max = 3, - collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25}, + tilt_fly = true, + collisionbox = {-0.25, 0, -0.25, 0.25, 0.9, 0.25}, + eye_height = 0.45, visual = "mesh", mesh = "mobs_mc_parrot.b3d", textures = {{"mobs_mc_parrot_blue.png"},{"mobs_mc_parrot_green.png"},{"mobs_mc_parrot_grey.png"},{"mobs_mc_parrot_red_blue.png"},{"mobs_mc_parrot_yellow_blue.png"}}, visual_size = {x=3, y=3}, + rotate = 270, walk_velocity = 3, run_velocity = 5, sounds = { @@ -85,8 +88,6 @@ mobs:register_mob("mobs_mc:parrot", { -- Feed to tame, but not breed if mobs:feed_tame(self, clicker, 1, false, true) then return end - if mobs:protect(self, clicker) then return end - if mobs:capture_mob(self, clicker, 0, 50, 80, false, nil) then return end end, }) diff --git a/mods/ENTITIES/mobs_mc/pig.lua b/mods/ENTITIES/mobs_mc/pig.lua index b7d919cff..d7433a092 100644 --- a/mods/ENTITIES/mobs_mc/pig.lua +++ b/mods/ENTITIES/mobs_mc/pig.lua @@ -6,7 +6,8 @@ mobs:register_mob("mobs_mc:pig", { description = S("Pig"), type = "animal", spawn_class = "passive", - runaway = true, + skittish = true, + rotate = 270, hp_min = 10, hp_max = 10, xp_min = 1, @@ -19,11 +20,30 @@ mobs:register_mob("mobs_mc:pig", { "mobs_mc_pig.png", -- base "blank.png", -- saddle }}, + + --head code + has_head = true, + head_bone = "head", + + swap_y_with_x = false, + reverse_head_yaw = false, + + head_bone_pos_y = 2.4, + head_bone_pos_z = 0, + + head_height_offset = 1.1, + head_direction_offset = 0, + head_pitch_modifier = 0, + --end head code + visual_size = {x=2.5, y=2.5}, makes_footstep_sound = true, walk_velocity = 1, run_velocity = 3, follow_velocity = 3.4, + breed_distance = 1.5, + baby_size = 0.5, + follow_distance = 2, drops = { {name = mobs_mc.items.porkchop_raw, chance = 1, @@ -50,7 +70,7 @@ mobs:register_mob("mobs_mc:pig", { run_start = 0, run_end = 40, }, - follow = mobs_mc.follow.pig, + follow = "mcl_farming:carrot_item", view_range = 8, do_custom = function(self, dtime) @@ -91,12 +111,17 @@ mobs:register_mob("mobs_mc:pig", { return end - local wielditem = clicker:get_wielded_item() - -- Feed pig - if wielditem:get_name() ~= mobs_mc.items.carrot_on_a_stick then - if mobs:feed_tame(self, clicker, 1, true, true) then return end + --attempt to enter breed state + if mobs.enter_breed_state(self,clicker) then + return + end + + --ignore other logic + --make baby grow faster + if self.baby then + mobs.make_baby_grow_faster(self,clicker) + return end - if mobs:protect(self, clicker) then return end if self.child then return @@ -104,6 +129,8 @@ mobs:register_mob("mobs_mc:pig", { -- Put saddle on pig local item = clicker:get_wielded_item() + local wielditem = item + if item:get_name() == mobs_mc.items.saddle and self.saddle ~= "yes" then self.base_texture = { "blank.png", -- baby @@ -164,10 +191,6 @@ mobs:register_mob("mobs_mc:pig", { inv:set_stack("main",self.driver:get_wield_index(), wielditem) end return - - -- Capture pig - elseif not self.driver and clicker:get_wielded_item():get_name() ~= "" then - mobs:capture_mob(self, clicker, 0, 5, 60, false, nil) end end, @@ -188,22 +211,53 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "FlowerForest_beach", + "Forest_beach", + "StoneBeach", + "ColdTaiga_beach_water", + "Taiga_beach", + "Savanna_beach", + "Plains_beach", + "ExtremeHills_beach", + "ColdTaiga_beach", + "Swampland_shore", + "JungleM_shore", + "Jungle_shore", + "MesaPlateauFM_sandlevel", + "MesaPlateauF_sandlevel", + "MesaBryce_sandlevel", + "Mesa_sandlevel", + "Mesa", + "FlowerForest", + "Swampland", + "Taiga", + "ExtremeHills", + "Jungle", + "Savanna", + "BirchForest", + "MegaSpruceTaiga", + "MegaTaiga", + "ExtremeHills+", + "Forest", + "Plains", + "Desert", + "ColdTaiga", + "IcePlainsSpikes", + "SunflowerPlains", + "IcePlains", + "RoofedForest", + "ExtremeHills+_snowtop", + "MesaPlateauFM_grasstop", + "JungleEdgeM", + "ExtremeHillsM", + "JungleM", + "BirchForestM", + "MesaPlateauF", + "MesaPlateauFM", + "MesaPlateauF_grasstop", + "MesaBryce", + "JungleEdge", + "SavannaM", }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/polar_bear.lua b/mods/ENTITIES/mobs_mc/polar_bear.lua index 98268961b..0476229b5 100644 --- a/mods/ENTITIES/mobs_mc/polar_bear.lua +++ b/mods/ENTITIES/mobs_mc/polar_bear.lua @@ -31,7 +31,7 @@ mobs:register_mob("mobs_mc:polar_bear", { walk_velocity = 1.2, run_velocity = 2.4, group_attack = true, - attack_type = "dogfight", + attack_type = "punch", drops = { -- 3/4 chance to drop raw fish (poor approximation) {name = mobs_mc.items.fish_raw, diff --git a/mods/ENTITIES/mobs_mc/rabbit.lua b/mods/ENTITIES/mobs_mc/rabbit.lua index 6b47fec70..90d5c27bf 100644 --- a/mods/ENTITIES/mobs_mc/rabbit.lua +++ b/mods/ENTITIES/mobs_mc/rabbit.lua @@ -8,7 +8,7 @@ local rabbit = { spawn_class = "passive", passive = true, reach = 1, - + rotate = 270, hp_min = 3, hp_max = 3, xp_min = 1, @@ -62,8 +62,6 @@ local rabbit = { on_rightclick = function(self, clicker) -- Feed, tame protect or capture if mobs:feed_tame(self, clicker, 1, true, true) then return end - if mobs:protect(self, clicker) then return end - if mobs:capture_mob(self, clicker, 0, 50, 80, false, nil) then return end end, do_custom = function(self) -- Easter egg: Change texture if rabbit is named “Toast” @@ -116,22 +114,53 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "FlowerForest_beach", + "Forest_beach", + "StoneBeach", + "ColdTaiga_beach_water", + "Taiga_beach", + "Savanna_beach", + "Plains_beach", + "ExtremeHills_beach", + "ColdTaiga_beach", + "Swampland_shore", + "JungleM_shore", + "Jungle_shore", + "MesaPlateauFM_sandlevel", + "MesaPlateauF_sandlevel", + "MesaBryce_sandlevel", + "Mesa_sandlevel", + "Mesa", + "FlowerForest", + "Swampland", + "Taiga", + "ExtremeHills", + "Jungle", + "Savanna", + "BirchForest", + "MegaSpruceTaiga", + "MegaTaiga", + "ExtremeHills+", + "Forest", + "Plains", + "Desert", + "ColdTaiga", + "IcePlainsSpikes", + "SunflowerPlains", + "IcePlains", + "RoofedForest", + "ExtremeHills+_snowtop", + "MesaPlateauFM_grasstop", + "JungleEdgeM", + "ExtremeHillsM", + "JungleM", + "BirchForestM", + "MesaPlateauF", + "MesaPlateauFM", + "MesaPlateauF_grasstop", + "MesaBryce", + "JungleEdge", + "SavannaM", }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 9ddc0adee..1527fd6da 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -63,8 +63,13 @@ mobs:register_mob("mobs_mc:sheep", { hp_max = 8, xp_min = 1, xp_max = 3, + skittish = true, + breed_distance = 1.5, + baby_size = 0.5, + follow_distance = 2, + follow = mobs_mc.items.wheat, collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.29, 0.45}, - + rotate = 270, visual = "mesh", visual_size = {x=3, y=3}, mesh = "mobs_mc_sheepfur.b3d", @@ -73,6 +78,23 @@ mobs:register_mob("mobs_mc:sheep", { color = "unicolor_white", makes_footstep_sound = true, walk_velocity = 1, + run_velocity = 3, + + --head code + has_head = true, + head_bone = "head", + + swap_y_with_x = false, + reverse_head_yaw = false, + + head_bone_pos_y = 3.6, + head_bone_pos_z = -0.6, + + head_height_offset = 1.0525, + head_direction_offset = 0.5, + head_pitch_modifier = 0, + --end head code + drops = { {name = mobs_mc.items.mutton_raw, chance = 1, @@ -99,7 +121,6 @@ mobs:register_mob("mobs_mc:sheep", { walk_start = 0, walk_end = 40, run_start = 0, run_end = 40, }, - follow = mobs_mc.follow.sheep, view_range = 12, -- Eat grass @@ -195,8 +216,16 @@ mobs:register_mob("mobs_mc:sheep", { on_rightclick = function(self, clicker) local item = clicker:get_wielded_item() - if mobs:feed_tame(self, clicker, 1, true, true) then return end - if mobs:protect(self, clicker) then return end + --attempt to enter breed state + if mobs.enter_breed_state(self,clicker) then + return + end + + --make baby grow faster + if self.baby then + mobs.make_baby_grow_faster(self,clicker) + return + end if item:get_name() == mobs_mc.items.shears and not self.gotten and not self.child then self.gotten = true @@ -252,7 +281,6 @@ mobs:register_mob("mobs_mc:sheep", { end return end - if mobs:capture_mob(self, clicker, 0, 5, 70, false, nil) then return end end, on_breed = function(parent1, parent2) -- Breed sheep and choose a fur color for the child. @@ -309,22 +337,53 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "FlowerForest_beach", + "Forest_beach", + "StoneBeach", + "ColdTaiga_beach_water", + "Taiga_beach", + "Savanna_beach", + "Plains_beach", + "ExtremeHills_beach", + "ColdTaiga_beach", + "Swampland_shore", + "JungleM_shore", + "Jungle_shore", + "MesaPlateauFM_sandlevel", + "MesaPlateauF_sandlevel", + "MesaBryce_sandlevel", + "Mesa_sandlevel", + "Mesa", + "FlowerForest", + "Swampland", + "Taiga", + "ExtremeHills", + "Jungle", + "Savanna", + "BirchForest", + "MegaSpruceTaiga", + "MegaTaiga", + "ExtremeHills+", + "Forest", + "Plains", + "Desert", + "ColdTaiga", + "IcePlainsSpikes", + "SunflowerPlains", + "IcePlains", + "RoofedForest", + "ExtremeHills+_snowtop", + "MesaPlateauFM_grasstop", + "JungleEdgeM", + "ExtremeHillsM", + "JungleM", + "BirchForestM", + "MesaPlateauF", + "MesaPlateauFM", + "MesaPlateauF_grasstop", + "MesaBryce", + "JungleEdge", + "SavannaM", }, 0, minetest.LIGHT_MAX+1, @@ -336,3 +395,4 @@ mobs_mc.spawn_height.overworld_max) -- spawn eggs mobs:register_egg("mobs_mc:sheep", S("Sheep"), "mobs_mc_spawn_icon_sheep.png", 0) + diff --git a/mods/ENTITIES/mobs_mc/shulker.lua b/mods/ENTITIES/mobs_mc/shulker.lua index 0d5ad880a..9932c5add 100644 --- a/mods/ENTITIES/mobs_mc/shulker.lua +++ b/mods/ENTITIES/mobs_mc/shulker.lua @@ -15,7 +15,7 @@ mobs:register_mob("mobs_mc:shulker", { description = S("Shulker"), type = "monster", spawn_class = "hostile", - attack_type = "shoot", + attack_type = "projectile", shoot_interval = 0.5, arrow = "mobs_mc:shulkerbullet", shoot_offset = 0.5, diff --git a/mods/ENTITIES/mobs_mc/silverfish.lua b/mods/ENTITIES/mobs_mc/silverfish.lua index 5af3c8aa0..148c4c722 100644 --- a/mods/ENTITIES/mobs_mc/silverfish.lua +++ b/mods/ENTITIES/mobs_mc/silverfish.lua @@ -44,7 +44,7 @@ mobs:register_mob("mobs_mc:silverfish", { run_start = 0, run_end = 20, }, view_range = 16, - attack_type = "dogfight", + attack_type = "punch", damage = 1, reach = 1, }) diff --git a/mods/ENTITIES/mobs_mc/skeleton+stray.lua b/mods/ENTITIES/mobs_mc/skeleton+stray.lua index 61e1c6eb2..37b1fc6dd 100644 --- a/mods/ENTITIES/mobs_mc/skeleton+stray.lua +++ b/mods/ENTITIES/mobs_mc/skeleton+stray.lua @@ -16,11 +16,15 @@ local skeleton = { description = S("Skeleton"), type = "monster", spawn_class = "hostile", + hostile = true, + rotate = 270, hp_min = 20, hp_max = 20, xp_min = 6, xp_max = 6, breath_max = -1, + eye_height = 1.5, + projectile_cooldown = 1.5, armor = {undead = 100, fleshy = 100}, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.98, 0.3}, pathfinding = 1, @@ -31,6 +35,22 @@ local skeleton = { "mcl_bows_bow_0.png", -- bow "mobs_mc_skeleton.png", -- skeleton } }, + + --head code + has_head = false, + head_bone = "head", + + swap_y_with_x = true, + reverse_head_yaw = true, + + head_bone_pos_y = 2.4, + head_bone_pos_z = 0, + + head_height_offset = 1.1, + head_direction_offset = 0, + head_pitch_modifier = 0, + --end head code + visual_size = {x=1, y=1}, makes_footstep_sound = true, textures = { @@ -43,7 +63,7 @@ local skeleton = { walk_velocity = 1.2, run_velocity = 2.4, damage = 2, - reach = 2, + reach = 3, drops = { {name = mobs_mc.items.arrow, chance = 1, @@ -75,6 +95,8 @@ local skeleton = { walk_speed = 15, walk_start = 40, walk_end = 60, + run_start = 40, + run_end = 60, run_speed = 30, shoot_start = 70, shoot_end = 90, @@ -86,13 +108,13 @@ local skeleton = { ignited_by_sunlight = true, view_range = 16, fear_height = 4, - attack_type = "dogshoot", + attack_type = "projectile", arrow = "mcl_bows:arrow_entity", shoot_arrow = function(self, pos, dir) if mod_bows then -- 2-4 damage per arrow - local dmg = math.max(4, math.random(2, 8)) - mcl_bows.shoot_arrow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) + local dmg = math.random(2,4) + mobs.shoot_projectile_handling("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) end end, shoot_interval = 2, diff --git a/mods/ENTITIES/mobs_mc/skeleton_wither.lua b/mods/ENTITIES/mobs_mc/skeleton_wither.lua index 1c0bdbea1..279a1d8cb 100644 --- a/mods/ENTITIES/mobs_mc/skeleton_wither.lua +++ b/mods/ENTITIES/mobs_mc/skeleton_wither.lua @@ -87,7 +87,7 @@ mobs:register_mob("mobs_mc:witherskeleton", { fire_damage = 0, light_damage = 0, view_range = 16, - attack_type = "dogfight", + attack_type = "punch", dogshoot_switch = 1, dogshoot_count_max =0.5, fear_height = 4, diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 0c5fe24ac..0cae6757d 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -64,6 +64,7 @@ local slime_big = { hp_max = 16, xp_min = 4, xp_max = 4, + rotate = 270, collisionbox = {-1.02, -0.01, -1.02, 1.02, 2.03, 1.02}, visual_size = {x=12.5, y=12.5}, textures = {{"mobs_mc_slime.png", "mobs_mc_slime.png"}}, @@ -95,8 +96,9 @@ local slime_big = { }, fall_damage = 0, view_range = 16, - attack_type = "dogfight", + attack_type = "jump_punch", passive = false, + jump_only = true, jump = true, walk_velocity = 2.5, run_velocity = 2.5, @@ -309,6 +311,7 @@ local magma_cube_big = { }, walk_velocity = 4, run_velocity = 4, + rotate = 270, damage = 6, reach = 3, armor = 53, @@ -332,12 +335,13 @@ local magma_cube_big = { }, water_damage = 0, lava_damage = 0, - fire_damage = 0, + fire_damage = 0, light_damage = 0, fall_damage = 0, view_range = 16, - attack_type = "dogfight", + attack_type = "jump_punch", passive = false, + jump_only = true, jump = true, jump_height = 8, walk_chance = 0, diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg index 5c9ee492ba4d2315ab820b8149dcb5b73cfc62f6..acb236445e2b530640a1c98a54c81d20a9a3672a 100644 GIT binary patch delta 10470 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 JyN#OB{~zmA!c71G delta 6045 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 diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg index acb236445e2b530640a1c98a54c81d20a9a3672a..1ef7a522744a727da6082e2a3a1f2bf36fc77604 100644 GIT binary patch delta 6897 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 Y^}12-boZEETz}BiBjV(bf8T@u3+ffPY5)KL delta 10469 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 J^-U+>{{WCWcXR*% delta 6898 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 ZS+5)QPIr&##q|eGJt9v2`1d{dzW@w?xjp~@ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg deleted file mode 100644 index c2743fbcc640651eedc1529bbed4e3c209552fc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11068 zcmeHtcT|%}+xLVTstF_^AYkYr1|>jPKy*V1hAIgJLjWbANVOrX-B1kyEP#j<7eWyt zQ6dBtcNLHzh#*K2u`D($h-=wZS=)OD+X=Do%5XUzjw|s%v^KLT=!gM<~IXt zHf#t23gBBhA9tB1uO>}S&%lgfX`8lk<5T1W1P4u6zgqWS6q$XQCdus*JQT2rNy~2Y*ap}=g$J? z5RC>v3Gnc02WqCh69%0(V66^pt#XbJa5{lg70{=g)w+JSjM`Y=TA#Ra(Aom76{-v^ z98hQ`*(ip*;POp!uu!qzaBHv0iHfc2godgNb-P|%rk~xj+M)oLXALz6T%O}whuk%6 zT5tIHk;X!zPW`MBu{&kZ`ANmMLT!E>IOtp4RrI3~?r{0^eCztstX#S}44bccL!|4HhwZ6B!TwArrADkxi@BMWdNXZLXlZuXxjmuhvco2_Bi?6o zusPrIhdsZ%m*@GV<6xl5%(>*Dwb0Z+_`q4Hn3dC{0HWn8!KoFRS{K%M*T*KDiZ5@A zJK2`pe}>q9MsuD8z#tZRs){eG|G#oaaS+;Yx}tlvi)_>?`&g_|0$8pGJ_I9RLc+P`1Ue57Gw1W@IaQZOY1< zDgHMhRme5+Kd1D0e}NWaQW;y4z=PW#;>@ds2ThBuhI?o(NP-yn)sJvxLuGFVoVCjy zS2d!_M>=zZ%dO5gmX^<3FlkW#A!JMItH)$j$A-#M2E8@Q>K1A{bjnr5jW-~g{*wyr z9(@kP7k{Hnwec1U8XG!PHr;R@1=Vtk%dMp6gBRxe<`#|XDh4~9??WSUC(9Ght3^Py zx#)_Q18Q>GKi!7{*^M)S?WxSb?Kz;rMVZu_6d7+js9jV=>b0≦!)j)0i2^(6_4F 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⪼8)D-TJ`->@>Uw(8fCdv}Jn*&O4Gn>9R&mbhvv@|5CwbLtc zT+Cv#3`9_)uRYtkD#uzl*1!*`QQ&9q{K3jO=+~DCVyXK5Nwr6Jz1JP#%{V^kRk?WK zk1wAdXUG%)Uo=b*VVkj(it<5m*jbmmFMI|soRp3ewj4R&hvv_;U7I_@W6{w}I&?nG zLNkqDeRBQBOBYUs;7Egg+2OG#H{KP6UGYwtXixpBZ+GjCdh_|;wK^{TaqIK$WBy*> T_m77=o*i6O^uzS|W#GR6*1vMu diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager_hurt.1.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager_hurt.1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5c9ee492ba4d2315ab820b8149dcb5b73cfc62f6 GIT binary patch literal 10341 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 F{0E)bG4}uf literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/spider.lua b/mods/ENTITIES/mobs_mc/spider.lua index c1cb5be4b..6ade915ab 100644 --- a/mods/ENTITIES/mobs_mc/spider.lua +++ b/mods/ENTITIES/mobs_mc/spider.lua @@ -17,17 +17,22 @@ local spider = { type = "monster", spawn_class = "hostile", passive = false, + hostile = true, + always_climb = true, docile_by_day = true, - attack_type = "dogfight", - pathfinding = 1, + attack_type = "punch", + punch_timer_cooloff = 0.5, + rotate = 270, damage = 2, reach = 2, hp_min = 16, hp_max = 16, + ignores_cobwebs = true, xp_min = 5, xp_max = 5, + eye_height = 0.475, armor = {fleshy = 100, arthropod = 100}, - collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.89, 0.7}, + collisionbox = {-0.45, 0, -0.45, 0.45, 0.9, 0.45}, visual = "mesh", mesh = "mobs_mc_spider.b3d", textures = { @@ -44,7 +49,7 @@ local spider = { distance = 16, }, walk_velocity = 1.3, - run_velocity = 2.8, + run_velocity = 2.75, --spider can become extremely difficult if any higher jump = true, jump_height = 4, view_range = 16, diff --git a/mods/ENTITIES/mobs_mc/squid.lua b/mods/ENTITIES/mobs_mc/squid.lua index 0c425bb51..55d4b05c3 100644 --- a/mods/ENTITIES/mobs_mc/squid.lua +++ b/mods/ENTITIES/mobs_mc/squid.lua @@ -17,6 +17,8 @@ mobs:register_mob("mobs_mc:squid", { xp_min = 1, xp_max = 3, armor = 100, + rotate = 270, + tilt_swim = true, -- FIXME: If the squid is near the floor, it turns black collisionbox = {-0.4, 0.0, -0.4, 0.4, 0.9, 0.4}, visual = "mesh", @@ -48,8 +50,7 @@ mobs:register_mob("mobs_mc:squid", { }, visual_size = {x=3, y=3}, makes_footstep_sound = false, - fly = true, - fly_in = { mobs_mc.items.water_source, mobs_mc.items.river_water_source }, + swim = true, breathes_in_water = true, jump = false, view_range = 16, diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_chest.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_chest.png new file mode 100644 index 0000000000000000000000000000000000000000..e0715af9f02aa63fd68ee71dd0cdaa7fc5e32e1c GIT binary patch literal 20594 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 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_cyan.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_cyan.png new file mode 100644 index 0000000000000000000000000000000000000000..83f7a8faa17d54d5e7402e7d6e94e18f50e27401 GIT binary patch literal 7612 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 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_green.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_green.png new file mode 100644 index 0000000000000000000000000000000000000000..c3297ce9424cbcc9d6f40928e2c1f6ad9e6f13a2 GIT binary patch literal 5809 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 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_blue.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..71eabea5365dd02619695bfe447b7a327758b534 GIT binary patch literal 7643 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 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_gray.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..929a6095072b637a445ab8dc122209208b262619 GIT binary patch literal 6354 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 DvSSw9 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_lime.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_lime.png new file mode 100644 index 0000000000000000000000000000000000000000..1507d6d7956e15fe5190684a3a34df54e1db2444 GIT binary patch literal 7388 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 Lid3zHX~_QoDQo#C literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_magenta.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_magenta.png new file mode 100644 index 0000000000000000000000000000000000000000..809e645fb6a872106d5ffdd1a731c564bc79756a GIT binary patch literal 7352 zcmb7og;N~N6XgQSvbbc?0KqkAaCiG~Su_Mm2*G6u1YO)67I$|D?rwn~!JXjl68!jG z)%^iiQ{7YbrfRyTW_tR)4pmo`$HpMT0002kiV8BCuQUABB*36o|7X_6=M|rH*Vcn+ znz~XsIN4i#v-v^=`{D3~>WkYq3jn}vaXVQb!P<;1^U{pL;Y%yQ9=s{oj>54J!9h` zX_LJ(BZOSZX6jPs;qZR!{K7e#vxCz0+J#|uPNM3KJqm+|)90^VnRJ7j&LV9V8;joG z^L3s?X7IC)J=2_?+!))XJ8{j{R(4VJL;tWCC7LZW)A@)We(?W%8Y8qc`c*mQP|E7a zInrD!uFXP9qT~Ik?cvidzzh9iDf5By>7KDW`pHH1p6I_H{UI5jGQrz(-JR6WSL;_| zdH=3uhVAd}NVlA!qF=?!4)sHd+witm3}HuQn-vqtr@1={p7CN4P2@OUj|veOl&A4ifpPJa^q?eS?-u@V`px(c{B_0|#MUd^3CcWTBb>EEa^h(_=G!hXm~vrkozE->oG#yA-NVCC*4hP79+5)uwfVgv( z;J%u;?6J`bJ`gFmps%0KTvai5N-s||&4Xvz+B}rtm~&Z%hABILD=78#5X5JB&3-w? zn!^PUW`k1J3YcPCK}bkgtkGP)et1|Z)OOLjv>CyoV_i{kLuBZO@?U&mMZ>Inbme9C zm|n)Au)G}kw=InzEDD#pNyf939|&fxuNk&Cgt`V3eQ^b4l@0eecD)ec)1O}sD_f7f zyA~B0vz)f}N{TX`GwXGsK5fsEvpuZV=N7*zr*6v~r%O7p@gr2jwj(0?$%mQ@Kmb@> z`W=~56hd$$#XdHdDOQnaB+{^(TMpwArzZU@vo(733A$=j(wW%!&o#vv(efg@LtgTb z()j7KZOYj1w3;Fewn8xtuk^M0R=ws81<*m{;uT>6P4sbjg%M}LsS^CVp<|tkr&;mw zZM9U8nywJze>8G}MFpl-UxRGXEbtzOw>hnD)2^y!mIUkf#yC?%!?>5!=ZzVQ7ae+9 zC?xiCX^&|!R2s}&lA#q(`JPgO_0fNzWFI)_fA;wtnVJ8dSqL{(LT_%)I21|P2XER0 z-~jOO>MqjV#BBjp@&`EW1WI73L6W}6etvqlyqy%I)l^+}>r<~Ay~U-ABD=t#W+pCG z0dB@ii$pC$K@ZoD9+?^7B@u2q%8bf{j(kSuSk&@*HS77b77O!5Z@bMbxe(o(3P~q_2rgaa`V>=>59O<+Fs^%qJ3+Q3#K8IB3lGzpOxxTI9qGwFA@0$yeg_PJcI`{ zgTe}E!|-Q@KHZ9Hp5JWdZ{8ti zXf8E0#Quh1A(9O&A3oE2>^WF|wKCyT;yhjN=vip!g-vxhhlQ6klsLI-5Lx!Sw=I_q znf{H8jGe?HoAP%j&}?jC{yt2yUHKNED#az_8)i=1f2qC1|M;>!`?LW(Y+R@8)Pc6l z%O+w^dm}bn?(2I$JAN#Wn5}j`$xOh5>rvtO-){wF=u?agK^8}2dcJLf$o9r&4pi_* zd2hA&o&-n}IFf5};nGS+rEH`Js$5$&eD5qU-N1Ws*U|2~L(~?t(=5eR(<^=EaEfX{ zD}{U}6*s(Jp?7`nsYH=HDkg4>Vm^u^3|8|fF(#Pgvx`qaQz)kscNgk(^@PEV1-r1& zTv>vk4HD;r8|!VP=7u)Y9LrS;_K~E1ra_uF0y8SuB>R$2E{wmZdZU0mQO1a0eAV0g zt^(+p9C2nAl$B+KK)#V$XLK-4MiQIqvoQT4!4Ma9aLkXUf(LvI9W42&MyEF#*FWPf zgGlfDNf4~Bv|4gmE_9Z0jl&JxC!01!UcLF{eClXn_}pS-%)Xg(h*{FB||WzyOCants5|eiMZ#_xs1iZr-H9 zL*w^G$#+pz1~}rkh31Z4QNzBBC^V#^bjpQg8@EUAIRJma?RbQ1S#&kyBDMk(Io7F) z61kGyl_3@Z8uxN?XyX%Y1q@Im6nTXXgCB}67O0wfvK1^^2WANoDbayKilcE|-62r> z1RSPW74|u>`UOvKH?7X%_Zjnx$*!7U`rECOewzY3kxQtDY61_W_DgF{Nd`y~e-U`5 zeivwlDZ3LO>1xdoDS8m<+XGamm@!w?-oV@YA>kUscwS~(UfC2dtQtw=2&ddnw+>-{{{{Y4q?h&~OEWcK5rpvqKDN=ELT zDV`|}pqZfVGn{6=EL9N5l$Ia|0hg}@!W`51X?Y>c*IKsssH4eh%yP@4nfw?fA$ooz zoX!-OK^#D9wBGLsA$nlZdYJ>WvfU8~@(+^=sTHMhLn??oAz4T(|Dx-@Pga(y=oi}# zOOmu_ak4CZrTGZ4L^F#_#0fm!cV4|87KWM9MK`HI*<4dj$6!vxfNg!L>U6C~w=(QT zpdA~?W|}l=f~7@bXply`sZ(;jc-)*^AWD}*t9zaMURR}U${e?nbQI*#gl?o90JSD) zxc|${Oy`O3M#3MnZdQjNul^Jn-%?E?87XB$5)xt{!5Q1s8=D&vEPeSQ7VC~UY- zm$30Wf281*5M;iQBUYH5*d-C0m8%LC-km6#c~IcaY`}XC=0d(woblg0-!uja63vwp z*cY@;FK|mvR1msjM2#fDp)Gj~qy8(U9mB%vmaGWb5c5&m17NvSmuVt_*N`qW; zu@8a2DnG6?t@P|795_wdZpV~QLs4g(>=72c!P~oVJO>(=!2c9I)+ok4wF(+GAn71g znoN?)^LGY40^h~i;1Bze&H0Vj1Icx+$GoR#|BT{+p(Gd~*DaQ0?32c005PM7y~ih; zUGF^HIyt!U7Odqc+8=bCH+L6mFlZ)FzQbN#ukyD3D9?NrV^b2!(?ViErry*?dirH^ zL#}Map;k@=_9zhk0E2(#>=gf(KQ|>V>Zyy^QH+;ni*?>em7wyxck?troi*pd(n_fg~hz4MNh|)D12!&rUx%ICL&CWm5Ac%1bEt?mtsA`LJV=~m!km(%jb!ch- z@UfX+-J+AMcsyzVplZ_jPX)e~g0}om-60`E6=?-Q7E~&jDyPv&MV*GC{^U6_jhh5b z`T~6A6_R6)8W5Ypz8r_q6H;yaejG{qVoNUEW3HRuP<4niRkzR(%sTGInn%EXsfw#K}2o~{!54bB76(P*oP2s**S@jgmf zD{yYTZQo~yJelv~&D$mlgymU;^mP{6uHP^-HMwtjG-0fDN&k>bvy>p#H4*FOd?Q+E zA#ZJvsqPL=@fzDoWK%8glU5_(tuEITi6T`v7Hm!`PqNlH<>5I?-8n@YATpeFyx2_P z69IF+(Xu~ILazjQ|EH-i8bY*ih~toY#`|JI$7vQwj#M$BfeUBz z6=o_A9W#5BpLKV4bbqOTcx@$4r61Klq>Y`O{5=}_XAb7Nkn8oPcc&+!C#y(O?V~)b zoH&*(wuJ?YNe1|_C^7ZQB|tMEn9PgOu4lN- z-l0Yq%}OR)dJ?E)pXYF&(K=h}FKQGym`TuDjLCP+fqSc{WW0lSV&BsT(ARxHl~;&P zO*9KJ#j5(cA^eF>Y$Kyao-epf%Sb(HK{mfCw~CmzF1sE`y|jo(no!;6+E!B^1iS!$ zrgbhr0s=re%!KyUzbm50?N1(s3v0NWs!r1slz%y2H8;rYKY1Cz%l}4pdr|x=g6^Q8 z?+gH7zWJXa0aDXRUO_aNqKYiqHjspvKyZ4m4i^Bxnpc#O)OK4uHad-48o+)*qDrEn z7o18NyW%A)I(-4ET#`SjGuF^+{^#WDt%oE}AL(`TZ*f1R3AZE9MMNtwFw2bO3k|S$Tul@>CTm*8bp??D!!ss`#N~A8vT(Vwf3f zzf#)*;2`Z6dOyaP(}0RSiOb^#X)gGzxjBn;VcFOk{KHRJyhvhyDf#QBlD zKl=3h;wq#&OuaR*a$HA&8dB4#Ymsk*k!RvOeezI|TYRv&J#XSKF=`jX(pDYTQGkAF ztMG^Wj4f?qJ$JB`te&mxf3`=Syk1Rw`vHhWuj{NO^J47Ls>`1gau zs|wJO=gIF8ecB{l;}=Ah?jzI*PELjOP@#Y!$6qH=`P)rnkg$1^UF4*(1Aw(-CL3xE z@SxOoWKUIOI#rSpJ;@{__o~j-!%s)U8YsN|D)s`u@G)dZY~kWGeyM&EOi&5!%ZaiH zU)=Mjn^bX&=&uZ2vxC8+*2i(&EUX2Bhw@xUPIaWBBA{#Q-`1OF7$Zi3;BncM;; z9nwS=p~!TYRPI%m@pr7V2;*hP;F<`9gzEW=iT@k0|1B#0eTO*`Z+|W(h_tIugDU{| z?pH7Xt{h=j@RJBEbb|c$2#Mzqx2)gJ4>gXVC7eT?f$W*zAt|Pc`y_W-M<4fD|qyE;8d!?aPh;U50_H?>|xAIWQ+>$5Xgy zP+(vP9dzgoKXzKa-UJggMnLulEWrnHDet4Nz_}0f_YL*8fBQa0=*{M*kxmxZHTbWf z)TSHLC%6o=`?D{u9t=JG@AmT2YZ`j%`;-VT@!b3529%Ss&4tCVZFU7Kq$@Hi3k8M^ zuTKEkw~>9bvl*(VMs=f+zyXLQre-OEVj=72O$-NJpvQ@1wh4O2o3~beKcAYPE~SS* z+MtVlQa|upNs-NkRBR<(Cl#&YbmwBOR-L{+bycSxvza#}BOyVlCa6~R%U^$YZoV)I z>b!gHEu9qm$C#`m$pAludo-_|r*8UOU<@|qp;AoIvw;1%mdKm_GRZ?c4z^FEoAx#< zhGZ$IOSEGb(Xx6BN&WLKV9UPULx?PyLJw3kvr!@W)*rtMH7@1fdwZw-#;=p=1#3>J z1LP?rsjimMHjHgwGcddJ!;{7UKDc(QhLzA|j$p>)%Wumj#I<#E5GJ@{Jt4H0(55-k z%DlR%F-@0U$AgtqZw7LbJz3@-Zd6urPS)n`8PB7x(6!F=o2}9J#B1=!_&6e#S3V{4 z*OlT?SD)!>Q=ss^HZvs;&x5mb6yJL5Jd!ns*L-WGI)-8$md_(qFNzBrlyiyvAg6o7 z!)N70pyP&b!V_!Tz9ge_l2Ne#?GE@IARr5n!}z-hNQq`vdG5MwT2la}m{Q;_@(Vjq zpxh>T;a?&juK8HbHuFYdx!2Y0zr-E}RW+&@U|~Ir(JxfCSK`3Aq2_qT7IJ?)9;$Uj z)~}WFlrXvR^!*R|f)gj0IMu)^Ps&C=aB9lB8Ojq)AeYdXU9x-{dVt;(wEh7L=lQ1v zY&xfaNT1aZe0}!Zh)ra2n^p#R8J1ZvcI__O=9AE$C2#4HZ%0+C+2q*vgC3|}a-RtQ zsCkX;yVyQmd*0gvDO1WxlRtR}Mt}YB63po|#zmu?B0_U(B6RXM0&ow}uKvu;nct`= z47{rV7`~y`xL+C9znpTL`ABe+0*~&8hI!H2=h`zWk<_yfl{?q@vTfWRva`EPi|(PR zeoSHUK8Nmvx=g(-XEw41#jCz6=&8y@-fHA$h5DJfXg@gInq%}% zzlhp-Ki^fI9t{odH6n-dr%N<>zI1yQeHtM|!F8GR5z?GBxOqblfq*mf_iWcz#*hJB zHXnpea=qMGog|0K{uI-yI$^+fm9kJoi?UZ=W>|hJ$7PnLY+JHbwIK6Mi@bk+xOmq8 za;o+_%VFkF+UNW9(e?^zUTr!GkKJ$jB-jkkeO;sP@u+dbBh~hp(A6v5xw9l z3|y@^mFm3xbKGUcx_d85W+jCUL)TMqNHEvgIuYtErnPhTI3vdbV^?wGs-hIv^0 zel547EY6OfUTFcTL!6dC#+XE#(~k$Y8T9q23@ss!f~?otD=!8zxipR7zbI^RapgI+ z{j13ys|WHo&^a354vO}fGUT;7vy>Ag5#@LJ<5o{d;i_}niJRH7%RxtN>(T7WxyxN2 zGYzaipuE@nG47?^IRm{~?sQ*DZY1}aM72-lAD@mX3$CVEU{Hq_RrI$}Ow8YdGhudP zSIhFu#Br%I9m#xy?B9zVSuqG%XFv^pvWN4o8vzSD!L`W!N+y0~#-sYwyQn){rr`~C%x0# zg@Y&#rkY~I_5JPCQ1gUkj}AuoIDy6Q87Bq|zD<7yc1Ga_x0&}{*tolA9p>V9;nNZ& zi1RXIX{YM|hstA}Zr8TFhhv+}n013nUi_2Mt~cD)IAw0a4m9r*3Dqf7vGa!F0TCMV zSRz!`19}4rQNe$q2U1a#E?6@YGg3a8ReVTLL-Vu0rMl@`+7;`K{FnG;YzjwvVz)kM zD(}fHCiLXUw@GHJIog(bGxdxeA6q!M;W3|aJ&SurSIEge!&6ZIoHq3uS)`|Z07J4r zBoBd}S|g4UoG_(2tvh{lXj3Gi(p)C*0_` z4+GEoo$&i(TRg5;g(=$Y30sZt(FWGF$Gv`tFC5}*d}lwC)Kbv#Q(?|Y@YBT5RI*G3 zl|E395!)h3xa@i+o3rlj#QB#An>dSl&AzhC?1yzVHLnO~+eosnSmvbfw42bBz6E{J z&o0Ho4*^%sv1+?;yl`Xy%t_0_E$&QDDkU$g&m0?!vv!b-lF#+MiaxP-3*ihQq!W-1 z&=lR`@WE4S3=lQ}{#}xbvjA?AizV`12$|Il?)QI-BwcsaJ`++*{tbPfRcbT`8=DOp z#>gM%8*qdEowhjE&J$o{Z=&9!LOpT~PF8L2p3N|SZVQ!|&z!8_!rB0sXI$*u7*Xj0 z-F3#U8BfdUwEBJ?YidU~nl8?3+hW8L*+RciakvH&yBBuWUn;3uz%b^d^&|FGH?!k& zLRR>x_PbQ@XFD?CS+yOTA{Zvi#AUZ~c9h$LWg=r-k}W^X$c8$X1mL){-s)qBz7gTK zt^RoPFAROXK%eSwtFU|Y{;RNn)+`ng8%iajz{`ven-Z_w8rv}C{-%18uPshUykr;o z1}Eb=B~8@$x5hu`Kvu0@H(*=$aXk4wPSo^r!j`8OicXz%cuDlfk+{M^6c=d>;Wjs Ls>)PKnfU!5Wd#{H literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_orange.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_orange.png new file mode 100644 index 0000000000000000000000000000000000000000..ff17ff67c3f1903f27f80c44224f283c98803e23 GIT binary patch literal 7396 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 MtALdo6(O+y1O7G#1ONa4 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_pink.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_pink.png new file mode 100644 index 0000000000000000000000000000000000000000..7009e6efc5d29ab14705578dab4f9cfbc481f759 GIT binary patch literal 7732 zcmb7{WltPVw8nRFDGL-Ywz#{yyKAu)hvII<7h0@9`9pCpy128ryF+oeMT=Xp%YAV_ zz|G{GNuEq{GLz?=%r8n)T>%T@0|o#9z*16_)qdMU-a--$2bdcWhtz zz-1opsoj`8#;W4;&yIgx-M~Y)pI!nE&Rn#Ev9DjYExS&57}ig!Vs-<*X2qZV3OBD3 zaPoX;nM?aTcvG|ca+!}aBk4*-iRuNbQ50sN(RxuG(#`vw? zF|GFcR)vQIG_}X?Tm@iF`AEI^5(WJTdX+m*?5G-&=&NnF?91qUqMq*ry0;|^;idO9*|b)UaP?aK+Mhhdvv8yB zET7c}{gbganv|j;v+3EVGKG5$)0bhI%$=Ip>98f!8jDZEEGgE$`%k~h6ct6!+WwGk z#t(`-Pp0(b>kgZ>oBwsx%z5}=F@ImtcscH|-!gLXEt=S>6BR5w_Q_Cn%xcq)YhiJl zhDqs1Uri#|dM_?k3B{tqu5L(|I~}xr*_Lr*Y{!N{XX+E<4L9rIfgrqI1j|s!dbeLBqSG;D$DasAwg`dJ7$;JmQNJA1w=L+tJ1B$q$O^ThljI|x- z=umGH76jBM~w=VMoF*S0tvI|sOhr!&rt@J2S!gkXlr@6L$Z zKdP8;$!$k7{1-pJa<#^v7K-R<%6=R}lKmyphIk!qvX}%=?w`cbx)v&7>7sKblVpLy zVYBxUYUgXaeR7U2B!B7$4yl!weD~42?aUW=nfA76{Mxl^|0|ut!1Vs` z(wt4$e+VM6tp~Z6K$S^bwxD*NP(l^m71q{Ci>n7&x$HT*a&*qoFJlIYU(8gBdTU_z z1>E2YZ$reVEPjv|Pp#fmr=@dS&j%f)-w6wca;`Ety=2F35bL_~171dl6I-Lqq*gh$ zx~6gY(!u#I)s;b-MCdIK13n@4J3FDpek?~pWOqR=5k9oxrWzD~Fk3OhY9&Ta4@R(>6+sMl=n>N+t;HF1bqLisgY9>S7{?qN%jfU?cgj(Ew(xB|dE~kN z-Eh(+8Wl~cvd3z6MgsX_3`E24Rt&EVT{jbIH~nfTa<#ATzR}2(pkKenX61T)ja54R z{o(wJnax}X%N8N?pfIVjWm5;^9W}z_{IsR6rSD&`qtklu%0{lB z&oW?I^@ie>pY+w2Jb$PG8>fxC=ErJsVrf_pJ8hLrXE^&GM}mTeIHcr-S`>S)%kTZP z9R5J21`FYrpX=WX!z=(tp;HJT)t=lCWMIi;o54zY=sYeM0-5_%Y#{{5@T2Y`zM@$w zmKv^Djq5U@w=XZnvEy`8!FgZb{Q1Tt{8HRGT;YXb#Tg9a-9G6R5q-rdf{-LB%jIe0I;+ z>?}4xP1hmm&)^U(@RD6f&^bo>*6MxQTHP3{+TZhPG?xJpJ55UthR{uiO zWzQ}_D(m<|{9ib24Y&jYEuYaqO=+*$FqKM=$`mufO5zYLphDfEoKVMyKBeXCKjFLX zOumzmqU0Lv@eJpp3Y=)MbsIYY2M=o;G=~`R@5XA8Y?&?jbw6XAjP&S#E&B*8wg6w3 zd9|xz4jsB!q@6tC)WW#=CVv|bA-)hC6LcplStHc|jE$xuJ(XWX=MZ)bmq)3BR8YDfdB0CLm~Q5>W8z%oSQm$WX@6Jn z_^$GY?}xO$Uy5v;Y00FahV5q69diiAh&{6-nbU)(=dsk}xm9`62PEACWxsiwTMiPw zmDD&yb{L{hYie$XlP(e_>2=cZ(G*Ha)MCPecDePWl1=yZ#86MQr0@ zMMlyQb&S;b14)Pu4hN>}CYNlpamc-yTX>JT0UHjDu)c-)c&ctB0meuH7%?HRe%f

`hXTeEBkp~gOh=j|UVsMC=p68Fk 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 F@;?IJlnnp? literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_white.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_white.png new file mode 100644 index 0000000000000000000000000000000000000000..c6ae669dd830fe5a581a46f6dc7d3f07494b9748 GIT binary patch literal 6866 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 x#<<0c0CfxOfJ(VdIP5a0Sb-{{j9sLxTVS literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_yellow.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..6318e163d74b28c3aa5247821c0ebffa5cdbf140 GIT binary patch literal 7571 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 LNkvXXu0mjfiR>Ik literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/vex.lua b/mods/ENTITIES/mobs_mc/vex.lua index a72827d5d..c23643cda 100644 --- a/mods/ENTITIES/mobs_mc/vex.lua +++ b/mods/ENTITIES/mobs_mc/vex.lua @@ -15,7 +15,7 @@ mobs:register_mob("mobs_mc:vex", { spawn_class = "hostile", pathfinding = 1, passive = false, - attack_type = "dogfight", + attack_type = "punch", physical = false, hp_min = 14, hp_max = 14, diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index db9cf3b19..154e9411f 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -962,14 +962,18 @@ mobs:register_mob("mobs_mc:villager", { }, }, visual_size = {x=2.75, y=2.75}, + rotate = 270, + skittish = true, makes_footstep_sound = true, walk_velocity = 1.2, - run_velocity = 2.4, + run_velocity = 3, drops = {}, can_despawn = false, -- TODO: sounds sounds = { random = "mobs_mc_villager", + damage = "mobs_mc_villager_hurt", + death = "mobs_mc_villager_hurt", distance = 10, }, animation = { diff --git a/mods/ENTITIES/mobs_mc/villager_evoker.lua b/mods/ENTITIES/mobs_mc/villager_evoker.lua index 04c95b88f..f87483e2b 100644 --- a/mods/ENTITIES/mobs_mc/villager_evoker.lua +++ b/mods/ENTITIES/mobs_mc/villager_evoker.lua @@ -35,7 +35,7 @@ mobs:register_mob("mobs_mc:evoker", { walk_velocity = 0.2, run_velocity = 1.4, group_attack = true, - attack_type = "dogfight", + attack_type = "punch", -- Summon vexes custom_attack = function(self, to_attack) local r = pr:next(2,4) diff --git a/mods/ENTITIES/mobs_mc/villager_illusioner.lua b/mods/ENTITIES/mobs_mc/villager_illusioner.lua index 496f08fc6..46b8760a1 100644 --- a/mods/ENTITIES/mobs_mc/villager_illusioner.lua +++ b/mods/ENTITIES/mobs_mc/villager_illusioner.lua @@ -10,7 +10,7 @@ mobs:register_mob("mobs_mc:illusioner", { description = S("Illusioner"), type = "monster", spawn_class = "hostile", - attack_type = "shoot", + attack_type = "projectile", shoot_interval = 2.5, shoot_offset = 1.5, arrow = "mcl_bows:arrow_entity", @@ -18,7 +18,7 @@ mobs:register_mob("mobs_mc:illusioner", { if mod_bows then -- 1-4 damage per arrow local dmg = math.random(1, 4) - mcl_bows.shoot_arrow("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) + mobs.shoot_projectile_handling("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) end end, hp_min = 32, diff --git a/mods/ENTITIES/mobs_mc/villager_vindicator.lua b/mods/ENTITIES/mobs_mc/villager_vindicator.lua index 276f80011..7df54ef58 100644 --- a/mods/ENTITIES/mobs_mc/villager_vindicator.lua +++ b/mods/ENTITIES/mobs_mc/villager_vindicator.lua @@ -37,7 +37,7 @@ mobs:register_mob("mobs_mc:vindicator", { reach = 2, walk_velocity = 1.2, run_velocity = 2.4, - attack_type = "dogfight", + attack_type = "punch", drops = { {name = mobs_mc.items.emerald, chance = 1, diff --git a/mods/ENTITIES/mobs_mc/villager_zombie.lua b/mods/ENTITIES/mobs_mc/villager_zombie.lua index 1948b693d..450710c49 100644 --- a/mods/ENTITIES/mobs_mc/villager_zombie.lua +++ b/mods/ENTITIES/mobs_mc/villager_zombie.lua @@ -29,6 +29,9 @@ mobs:register_mob("mobs_mc:villager_zombie", { description = S("Zombie Villager"), type = "monster", spawn_class = "hostile", + hostile = true, + rotate = 270, + eye_height = 1.65, hp_min = 20, hp_max = 20, xp_min = 5, @@ -51,8 +54,8 @@ mobs:register_mob("mobs_mc:villager_zombie", { damage = 3, reach = 2, walk_velocity = 1.2, - run_velocity = 2.4, - attack_type = "dogfight", + run_velocity = 3.5, + attack_type = "punch", group_attack = true, drops = { {name = mobs_mc.items.rotten_flesh, diff --git a/mods/ENTITIES/mobs_mc/witch.lua b/mods/ENTITIES/mobs_mc/witch.lua index 8ebe71fc0..0c72d0018 100644 --- a/mods/ENTITIES/mobs_mc/witch.lua +++ b/mods/ENTITIES/mobs_mc/witch.lua @@ -34,7 +34,7 @@ mobs:register_mob("mobs_mc:witch", { run_velocity = 2.4, pathfinding = 1, group_attack = true, - attack_type = "dogshoot", + attack_type = "projectile", arrow = "mobs_mc:potion_arrow", shoot_interval = 2.5, shoot_offset = 1, diff --git a/mods/ENTITIES/mobs_mc/wither.lua b/mods/ENTITIES/mobs_mc/wither.lua index 72459a354..7c9072f43 100644 --- a/mods/ENTITIES/mobs_mc/wither.lua +++ b/mods/ENTITIES/mobs_mc/wither.lua @@ -53,7 +53,7 @@ mobs:register_mob("mobs_mc:wither", { }, lava_damage = 0, fire_damage = 0, - attack_type = "dogshoot", + attack_type = "projectile", explosion_strength = 8, dogshoot_stop = true, arrow = "mobs_mc:wither_skull", diff --git a/mods/ENTITIES/mobs_mc/wolf.lua b/mods/ENTITIES/mobs_mc/wolf.lua index 7f14ac6b0..89a4b4629 100644 --- a/mods/ENTITIES/mobs_mc/wolf.lua +++ b/mods/ENTITIES/mobs_mc/wolf.lua @@ -23,13 +23,31 @@ local wolf = { type = "animal", spawn_class = "passive", can_despawn = true, + neutral = true, hp_min = 8, hp_max = 8, xp_min = 1, xp_max = 3, + rotate = 270, passive = false, group_attack = true, - collisionbox = {-0.3, -0.01, -0.3, 0.3, 0.84, 0.3}, + + --head code + has_head = false, + head_bone = "head", + + swap_y_with_x = false, + reverse_head_yaw = false, + + head_bone_pos_y = 3.6, + head_bone_pos_z = -0.6, + + head_height_offset = 1.0525, + head_direction_offset = 0.5, + head_pitch_modifier = 0, + --end head code + + collisionbox = {-0.3, -0.00, -0.3, 0.3, 0.85, 0.3}, visual = "mesh", mesh = "mobs_mc_wolf.b3d", textures = { @@ -53,7 +71,7 @@ local wolf = { run_velocity = 3, damage = 4, reach = 2, - attack_type = "dogfight", + attack_type = "punch", fear_height = 4, follow = mobs_mc.follow.wolf, on_rightclick = function(self, clicker) @@ -75,6 +93,7 @@ local wolf = { dog:set_yaw(yaw) ent = dog:get_luaentity() ent.owner = clicker:get_player_name() + ent.tamed = true -- cornfirm taming minetest.sound_play("mobs_mc_wolf_bark", {object=dog, max_hear_distance=16}, true) -- Replace wolf @@ -142,17 +161,29 @@ dog.owner_loyal = true dog.follow_velocity = 3.2 -- Automatically teleport dog to owner dog.do_custom = mobs_mc.make_owner_teleport_function(12) -dog.follow = mobs_mc.follow.dog dog.attack_animals = nil dog.specific_attack = nil +dog.breed_distance = 1.5 +dog.baby_size = 0.5 +dog.follow_distance = 2 +dog.follow = "mcl_mobitems:beef" + dog.on_rightclick = function(self, clicker) local item = clicker:get_wielded_item() - if mobs:protect(self, clicker) then + --owner is broken for this + --attempt to enter breed state + if mobs.enter_breed_state(self,clicker) then return - elseif item:get_name() ~= "" and mobs:capture_mob(self, clicker, 0, 2, 80, false, nil) then + end + + --make baby grow faster + if self.baby then + mobs.make_baby_grow_faster(self,clicker) return - elseif is_food(item:get_name()) then + end + + if is_food(item:get_name()) then -- Feed to increase health local hp = self.health local hp_add = 0 diff --git a/mods/ENTITIES/mobs_mc/zombie.lua b/mods/ENTITIES/mobs_mc/zombie.lua index 4ae5796b3..7d0fb1491 100644 --- a/mods/ENTITIES/mobs_mc/zombie.lua +++ b/mods/ENTITIES/mobs_mc/zombie.lua @@ -49,6 +49,8 @@ local zombie = { description = S("Zombie"), type = "monster", spawn_class = "hostile", + hostile = true, + rotate = 270, hp_min = 20, hp_max = 20, xp_min = 5, @@ -74,8 +76,25 @@ local zombie = { damage = "mobs_mc_zombie_hurt", distance = 16, }, - walk_velocity = .8, - run_velocity = 1.6, + + --head code + has_head = false, + head_bone = "Head", + + swap_y_with_x = true, + reverse_head_yaw = true, + + head_bone_pos_y = 2.4, + head_bone_pos_z = 0, + + head_height_offset = 1.1, + head_direction_offset = 0, + head_pitch_modifier = 0, + --end head code + + eye_height = 1.65, + walk_velocity = 1, + run_velocity = 3.5, damage = 3, reach = 2, fear_height = 4, @@ -93,7 +112,8 @@ local zombie = { ignited_by_sunlight = true, sunlight_damage = 2, view_range = 16, - attack_type = "dogfight", + attack_type = "punch", + punch_timer_cooloff = 0.5, harmed_by_heal = true, } diff --git a/mods/ENTITIES/mobs_mc/zombiepig.lua b/mods/ENTITIES/mobs_mc/zombiepig.lua index 1ea4197c1..72a19f413 100644 --- a/mods/ENTITIES/mobs_mc/zombiepig.lua +++ b/mods/ENTITIES/mobs_mc/zombiepig.lua @@ -15,13 +15,16 @@ local pigman = { -- type="animal", passive=false: This combination is needed for a neutral mob which becomes hostile, if attacked type = "animal", passive = false, + neutral = true, + rotate = 270, spawn_class = "passive", + hostile_cooldown = 15, --seconds hp_min = 20, hp_max = 20, xp_min = 6, xp_max = 6, armor = {undead = 90, fleshy = 90}, - attack_type = "dogfight", + attack_type = "punch", group_attack = { "mobs_mc:pigman", "mobs_mc:baby_pigman" }, damage = 9, reach = 2, @@ -41,6 +44,22 @@ local pigman = { damage = "mobs_mc_zombiepig_hurt", distance = 16, }, + + --head code + has_head = false, + head_bone = "head", + + swap_y_with_x = true, + reverse_head_yaw = true, + + head_bone_pos_y = 2.4, + head_bone_pos_z = 0, + + head_height_offset = 1.1, + head_direction_offset = 0, + head_pitch_modifier = 0, + --end head code + jump = true, makes_footstep_sound = true, walk_velocity = .8, From e0c94ccb8a75ef23ad154fe1b25715b908e0a397 Mon Sep 17 00:00:00 2001 From: jordan4ibanez Date: Wed, 28 Apr 2021 21:58:28 -0400 Subject: [PATCH 04/22] Stop thorns enchant from crashing server when dealing damage to mobs --- mods/ITEMS/mcl_armor/damage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_armor/damage.lua b/mods/ITEMS/mcl_armor/damage.lua index c5023deb5..3732de8e6 100644 --- a/mods/ITEMS/mcl_armor/damage.lua +++ b/mods/ITEMS/mcl_armor/damage.lua @@ -81,7 +81,7 @@ mcl_damage.register_modifier(function(obj, damage, reason) local thorns_damage = thorns_damage_regular + thorns_damage_irregular if thorns_damage > 0 and reason.type ~= "thorns" and reason.source ~= obj then - mcl_util.deal_damage(reason.source, {type = "thorns", direct = obj}) + mcl_util.deal_damage(reason.source, thorns_damage) local thorns_item = thorns_pieces[math.random(#thorns_pieces)] mcl_util.use_item_durability(thorns_item.itemstack, 2) From cf46f0d8b88870170a0a00367601f031499f193a Mon Sep 17 00:00:00 2001 From: jordan4ibanez Date: Thu, 29 Apr 2021 01:32:57 -0400 Subject: [PATCH 05/22] Fix crashing if null itemstack enchant when player is hacking --- mods/ITEMS/mcl_enchanting/engine.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index e5b61d328..89fdc393d 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -6,6 +6,9 @@ function mcl_enchanting.is_book(itemname) end function mcl_enchanting.get_enchantments(itemstack) + if not itemstack then + return({}) + end return minetest.deserialize(itemstack:get_meta():get_string("mcl_enchanting:enchantments")) or {} end From 6fac49550e3a126d48c0d87617698e89bbe2b945 Mon Sep 17 00:00:00 2001 From: Marcin Serwin Date: Thu, 29 Apr 2021 08:18:33 +0200 Subject: [PATCH 06/22] Fix kicking players from bed when it's destroyed --- mods/ITEMS/mcl_beds/functions.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index b1ce06b96..ecd749603 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -88,7 +88,7 @@ local function lay_down(player, pos, bed_pos, state, skip) end for _, other_pos in pairs(mcl_beds.bed_pos) do - if vector.distance(bed_pos, other_pos) < 0.1 then + if vector.distance(bed_pos2, other_pos) < 0.1 then return false, S("This bed is already occupied!") end end @@ -170,7 +170,7 @@ local function lay_down(player, pos, bed_pos, state, skip) mcl_beds.player[name] = 1 mcl_beds.pos[name] = pos - mcl_beds.bed_pos[name] = bed_pos + mcl_beds.bed_pos[name] = bed_pos2 player_in_bed = player_in_bed + 1 -- physics, eye_offset, etc player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0}) From 33c0aa23c5b6023a9a91fe88e8623c52a190ffea Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 10:58:10 +0200 Subject: [PATCH 07/22] Re-add thorns damage type --- mods/ITEMS/mcl_armor/damage.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_armor/damage.lua b/mods/ITEMS/mcl_armor/damage.lua index 3732de8e6..8ad566d18 100644 --- a/mods/ITEMS/mcl_armor/damage.lua +++ b/mods/ITEMS/mcl_armor/damage.lua @@ -81,7 +81,7 @@ mcl_damage.register_modifier(function(obj, damage, reason) local thorns_damage = thorns_damage_regular + thorns_damage_irregular if thorns_damage > 0 and reason.type ~= "thorns" and reason.source ~= obj then - mcl_util.deal_damage(reason.source, thorns_damage) + mcl_util.deal_damage(reason.source, thorns_damage, {type = "thorns", direct = obj}) local thorns_item = thorns_pieces[math.random(#thorns_pieces)] mcl_util.use_item_durability(thorns_item.itemstack, 2) From 199488cc74b8d6f31d901a20d39e52e309499607 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 11:17:52 +0200 Subject: [PATCH 08/22] Add nil check for crash prevention --- mods/CORE/mcl_util/init.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index f619b5465..f976457c0 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -532,6 +532,10 @@ function mcl_util.get_object_name(object) else local luaentity = object:get_luaentity() + if not luaentity then + return "" + end + return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name end end From ec08032b62d6377ef5d94dbba4fdcd923f09d298 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 11:40:09 +0200 Subject: [PATCH 09/22] Add on_break callback --- mods/ITEMS/mcl_armor/api.lua | 2 ++ mods/ITEMS/mcl_armor/damage.lua | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_armor/api.lua b/mods/ITEMS/mcl_armor/api.lua index 2e5ba1112..566ce5c49 100644 --- a/mods/ITEMS/mcl_armor/api.lua +++ b/mods/ITEMS/mcl_armor/api.lua @@ -92,6 +92,7 @@ function mcl_armor.register_set(def) local groups = def.groups or {} local on_equip_callbacks = def.on_equip_callbacks or {} local on_unequip_callbacks = def.on_unequip_callbacks or {} + local on_break_callbacks = def.on_break_callbacks or {} local textures = def.textures or {} local previews = def.previews or {} local durabilities = def.durabilities or {} @@ -125,6 +126,7 @@ function mcl_armor.register_set(def) on_secondary_use = mcl_armor.equip_on_use, _on_equip = on_equip_callbacks[name] or def.on_equip, _on_unequip = on_unequip_callbacks[name] or def.on_unequip, + _on_break = on_break_callbacks[name] or def.on_break, _mcl_armor_element = name, _mcl_armor_texture = textures[name] or modname .. "_" .. itemname .. ".png", _mcl_armor_preview = previews[name] or modname .. "_" .. itemname .. "_preview.png", diff --git a/mods/ITEMS/mcl_armor/damage.lua b/mods/ITEMS/mcl_armor/damage.lua index 8ad566d18..f17033495 100644 --- a/mods/ITEMS/mcl_armor/damage.lua +++ b/mods/ITEMS/mcl_armor/damage.lua @@ -1,3 +1,12 @@ +local function use_durability(obj, inv, index, stack, uses) + local def = stack:get_definition() + mcl_util.use_item_durability(stack, uses) + if stack:is_empty() and def and def._on_break then + stack = def._on_break(obj) or stack + end + inv:set_stack("armor", index, stack) +end + mcl_damage.register_modifier(function(obj, damage, reason) local flags = reason.flags @@ -28,8 +37,7 @@ mcl_damage.register_modifier(function(obj, damage, reason) points = points + minetest.get_item_group(itemname, "mcl_armor_points") toughness = toughness + minetest.get_item_group(itemname, "mcl_armor_toughness") - mcl_util.use_item_durability(itemstack, uses) - inv:set_stack("armor", element.index, itemstack) + use_durability(obj, inv, element.index, itemstack, uses) end if not flags.bypasses_magic then @@ -84,8 +92,8 @@ mcl_damage.register_modifier(function(obj, damage, reason) mcl_util.deal_damage(reason.source, thorns_damage, {type = "thorns", direct = obj}) local thorns_item = thorns_pieces[math.random(#thorns_pieces)] - mcl_util.use_item_durability(thorns_item.itemstack, 2) - inv:set_stack("armor", thorns_item.index, thorns_item.itemstack) + + use_durability(obj, inv, thorns_item.index, thorns_item.itemstack, 2) end mcl_armor.update(obj) From 87e41cc9a939e83c4c287cd6f231a8cc086819f2 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 11:46:27 +0200 Subject: [PATCH 10/22] Add support for armor texture and preview being functions --- mods/ITEMS/mcl_armor/api.lua | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_armor/api.lua b/mods/ITEMS/mcl_armor/api.lua index 566ce5c49..b632eeca7 100644 --- a/mods/ITEMS/mcl_armor/api.lua +++ b/mods/ITEMS/mcl_armor/api.lua @@ -205,12 +205,26 @@ function mcl_armor.update(obj) if not itemstack:is_empty() then local def = itemstack:get_definition() - if def._mcl_armor_texture then - info.texture = "(" .. def._mcl_armor_texture .. ")" .. (info.texture and "^" .. info.texture or "") + local texture = def._mcl_armor_texture + + if texture then + if type(texture) == "function" then + texture = texture(obj, itemstack) + end + if texture then + info.texture = "(" .. texture .. ")" .. (info.texture and "^" .. info.texture or "") + end end - if obj:is_player() and def._mcl_armor_preview then - info.preview = "(player.png^[opacity:0^" .. def._mcl_armor_preview .. ")" .. (info.preview and "^" .. info.preview or "" ) + local preview = def._mcl_armor_preview + + if obj:is_player() and preview then + if type(preview) == "function" then + preview = preview(obj, itemstack) + end + if preview then + info.preview = "(player.png^[opacity:0^" .. def._mcl_armor_preview .. ")" .. (info.preview and "^" .. info.preview or "" ) + end end info.points = info.points + minetest.get_item_group(itemname, "mcl_armor_points") From 6550e3e8e2200099ddc61a1ffccd44013bab8565 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 11:51:06 +0200 Subject: [PATCH 11/22] Add per-element armor groups --- mods/ITEMS/mcl_armor/api.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mods/ITEMS/mcl_armor/api.lua b/mods/ITEMS/mcl_armor/api.lua index b632eeca7..d58b5e666 100644 --- a/mods/ITEMS/mcl_armor/api.lua +++ b/mods/ITEMS/mcl_armor/api.lua @@ -96,6 +96,7 @@ function mcl_armor.register_set(def) local textures = def.textures or {} local previews = def.previews or {} local durabilities = def.durabilities or {} + local element_groups = def.element_groups or {} for name, element in pairs(mcl_armor.elements) do local itemname = element.name .. "_" .. def.name @@ -111,6 +112,10 @@ function mcl_armor.register_set(def) groups.mcl_armor_uses = (durabilities[name] or math.floor(def.durability * element.durability)) + 1 groups.enchantability = def.enchantability + for k, v in pairs(element_groups) do + groups[k] = v + end + minetest.register_tool(itemstring, { description = S(def.description .. " " .. (descriptions[name] or element.description)), _doc_items_longdesc = mcl_armor.longdesc, From fed1410b7f1de50d7fba259e2c2f957f889d7fa9 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 12:28:34 +0200 Subject: [PATCH 12/22] Add set_on_fire to do_env_damage --- mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua index d5b644f73..c7c4ad27c 100644 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua @@ -1646,6 +1646,8 @@ local do_env_damage = function(self) self.health = self.health - self.lava_damage + mcl_burning.set_on_fire(self.object, 15) + effect(pos, 5, "fire_basic_flame.png", nil, nil, 1, nil) if check_for_death(self, "lava", {type = "environment", @@ -1662,6 +1664,8 @@ local do_env_damage = function(self) self.health = self.health - self.fire_damage + mcl_burning.set_on_fire(self.object, 8) + effect(pos, 5, "fire_basic_flame.png", nil, nil, 1, nil) if check_for_death(self, "fire", {type = "environment", From 7be749a1229fce7322850c7fe046cc0fd9d13f25 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 12:40:18 +0200 Subject: [PATCH 13/22] Update mcl_awards translations --- mods/HUD/awards/locale/awards.de.tr | 7 +++++-- mods/HUD/awards/locale/template.txt | 11 ++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/mods/HUD/awards/locale/awards.de.tr b/mods/HUD/awards/locale/awards.de.tr index 2fb04c4ca..489a19683 100644 --- a/mods/HUD/awards/locale/awards.de.tr +++ b/mods/HUD/awards/locale/awards.de.tr @@ -1,7 +1,7 @@ # textdomain:awards @1: @2=@1: @2 @1 (got)=@1 (erhalten) -@1’s awards:=Auszeichnungen von @1: +@1’s awards:=Auszeichnungen von @: (Secret Award)=(Geheime Auszeichnung) Achievement gotten!=Auszeichnung erhalten! Achievement gotten:=Auszeichnung erhalten: @@ -27,7 +27,6 @@ Awards=Auszeichnungen @1/@2 deaths=@1/@2 Tode @1/@2 dug=@1/@2 abgebaut @1/@2 game joins=@1/@2 Spielen beigetreten -@1/@2 lines of chat=@1/@2 Chatzeilen @1/@2 placed=@1/@2 platziert Die @1 times.=Sterben Sie @1 mal. Die.=Sterben Sie. @@ -58,3 +57,7 @@ Invalid action.=Ungültige Aktion. Player is not online.=Spieler ist nicht online. Done.=Fertig. Achievement “@1” does not exist.=Auszeichnung »@1« existiert nicht. +@1 has made the achievement @2=@1 hat die Auszeichnung @2 erhalten +Write something in chat.=Schreiben Sie etwas in den Chat. +Write @1 chat messages.=Schreiben Sie @1 Chatnachrichten. +@1/@2 chat messages=@1/@2 Chatnachrichten diff --git a/mods/HUD/awards/locale/template.txt b/mods/HUD/awards/locale/template.txt index a1505b349..ac6a1d752 100644 --- a/mods/HUD/awards/locale/template.txt +++ b/mods/HUD/awards/locale/template.txt @@ -6,12 +6,11 @@ @1/@2 game joins= @1/@2 placed= @1 (got)= -@1: @1= +@1: @2= @1’s awards:= (Secret Award)= = = -A Cat in a Pop-Tart?!= Achievement gotten!= Achievement gotten:= Achievement gotten: @1= @@ -28,9 +27,9 @@ Join the game.= List awards in chat (deprecated)= Place a block: @1= Place blocks: @1×@2= -Secret Achievement gotten!= -Secret Achievement gotten:= -Secret Achievement gotten: @1= +Secret achievement gotten!= +Secret achievement gotten:= +Secret achievement gotten: @1= Show details of an achievement= Show, clear, disable or enable your achievements= Get this achievement to find out what it is.= @@ -60,3 +59,5 @@ Player is not online.= Done.= Achievement “@1” does not exist.= @1 has made the achievement @2= +Mine a block: @1= +Mine blocks: @1×@2= From db78c1988041f3af0b0dc55a8e8b9691b8de09de Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 12:42:08 +0200 Subject: [PATCH 14/22] Remove legacy mcl_potions translations --- mods/ITEMS/mcl_potions/locale/mcl_potions.de.tr | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/mods/ITEMS/mcl_potions/locale/mcl_potions.de.tr b/mods/ITEMS/mcl_potions/locale/mcl_potions.de.tr index 36f5280b9..34693d531 100644 --- a/mods/ITEMS/mcl_potions/locale/mcl_potions.de.tr +++ b/mods/ITEMS/mcl_potions/locale/mcl_potions.de.tr @@ -112,18 +112,3 @@ No effect=Keine Wirkung A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect.=Ein werfbarer Trank, der bei Kollision zerbrechen wird, wo er allen nahen Spielern und Mobs einen Statuseffekt geben wird. This particular arrow is tipped and will give an effect when it hits a player or mob.=Diese Pfeilspitze dieses Pfeils in einem Trank getränkt und gibt einen Effekt, wenn er einen Spieler oder einen Mob trifft. - - - -##### not used anymore ##### - -Lingering Weakness Potion=Schwächeverweiltrank -Lingering Weakness Potion +=Schwächeverweiltrank + -Lingering Strength Potion=Stärkeverweiltrank -Lingering Strength Potion II=Stärkeverweiltrank II -Lingering Strength Potion +=Stärkeverweiltrank + -Weakness Splash Potion=Schwächewurftrank -Weakness Splash Potion +=Schwächewurftrank + -Strength Splash Potion=Stärkewurftrank -Strength Splash Potion II=Stärkewurftrank II -Strength Splash Potion +=Stärkewurftrank + From 404097dcc0959bfb29f7b1d0784e105e5b9cf6ee Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 12:43:44 +0200 Subject: [PATCH 15/22] Update german mcl_core translations --- mods/ITEMS/mcl_core/locale/mcl_core.de.tr | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/ITEMS/mcl_core/locale/mcl_core.de.tr b/mods/ITEMS/mcl_core/locale/mcl_core.de.tr index 8fbd79722..3d90dd5ae 100644 --- a/mods/ITEMS/mcl_core/locale/mcl_core.de.tr +++ b/mods/ITEMS/mcl_core/locale/mcl_core.de.tr @@ -274,3 +274,4 @@ Slows down movement=Verlangsamt die Fortbewegung 2×2 saplings @= large tree=2×2 Setzlinge @= großer Baum Grows on sand or dirt next to water=Wächst auf Sand oder Erde neben Wasser Stackable=Stapelbar +Needs soil and water to grow=Braucht Nährboden und Wasser zum wachsen From f8b9f16799835f408939b4d3bda6b283156a536d Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 12:45:15 +0200 Subject: [PATCH 16/22] Update mcl_chests translation template --- mods/ITEMS/mcl_chests/locale/template.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_chests/locale/template.txt b/mods/ITEMS/mcl_chests/locale/template.txt index d680c24c9..1d947184b 100644 --- a/mods/ITEMS/mcl_chests/locale/template.txt +++ b/mods/ITEMS/mcl_chests/locale/template.txt @@ -24,7 +24,7 @@ Red Shulker Box= Grey Shulker Box= Black Shulker Box= A shulker box is a portable container which provides 27 inventory slots for any item except shulker boxes. Shulker boxes keep their inventory when broken, so shulker boxes as well as their contents can be taken as a single item. Shulker boxes come in many different colors.= -To access the inventory of a shulker box, place and right-click it. To take a shulker box and its contents with you, just break and collect it, the items will not fall out. Place the shulker box again to be able to retrieve its contents.= +To access the inventory of a shulker box, place and right-click it. To take a shulker box and its contents with you, just break and collect it, the items will not fall out.= Shulker Box= Large Chest= Inventory= From ab4b6d214ea70896bca2fa6cf70408fc96c41b3c Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 29 Apr 2021 12:49:07 +0200 Subject: [PATCH 17/22] Update doc_items translations --- mods/HELP/doc/doc_items/locale/doc_items.de.tr | 9 ++++----- mods/HELP/doc/doc_items/locale/template.txt | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mods/HELP/doc/doc_items/locale/doc_items.de.tr b/mods/HELP/doc/doc_items/locale/doc_items.de.tr index 90747c38a..f14c99314 100644 --- a/mods/HELP/doc/doc_items/locale/doc_items.de.tr +++ b/mods/HELP/doc/doc_items/locale/doc_items.de.tr @@ -10,9 +10,9 @@ # Itemname (ca. 25%) @1 (ca. @2%)=@1 (ca. @2%) # List separator (e.g. “one, two, three”) -, =, +, =, # Final list separator (e.g. “One, two and three”) - and = und + and = und 1 second=1 Sekunde A transparent block, basically empty space. It is usually left behind after digging something.=Ein transparenter Block, praktisch leerer Raum. Er wird üblicherweise hinterlassen, nachdem man etwas ausgegraben hat. Air=Luft @@ -32,7 +32,7 @@ Item reference of items which are neither blocks, tools or weapons (esp. craftin Liquids can flow into this block and destroy it.=Flüssigkeiten können in diesen Block hereinfließen und ihn zerstören. Maximum stack size: @1=Maximale Stapelgröße: @1 Mining level: @1=Grabestufe: @1 -Mining ratings:=Grabewertungen: +Mining ratings:=Grabewertungen: • @1, rating @2: @3 s - @4 s=• @1, Wertung @2: @3 s - @4 s • @1, rating @2: @3 s=• @1, Wertung @2: @3 s Mining times:=Grabezeiten: @@ -76,9 +76,8 @@ This block connects to these blocks: @1.=Dieser Block verbindet sich mit den fol This block connects to this block: @1.=Dieser Block verbindet sich mit diesem Block: @1. This block decreases your breath and causes a drowning damage of @1 hit point every 2 seconds.=Dieser Block reduziert Ihren Atem und verursacht beim Ertrinken einen Schaden von @1 Trefferpunkt alle 2 Sekunden. This block decreases your breath and causes a drowning damage of @1 hit points every 2 seconds.=Dieser Block reduziert Ihren Atem und verursacht beim Ertrinken einen Schaden von @1 Trefferpunkten alle 2 Sekunden. -This block glows faintly. It is barely noticable.=Dieser Block leuchtet schwach. Es ist kaum merklich. This block is a light source with a light level of @1.=Dieser Block ist eine Lichtquelle mit einer Helligkeitsstufe von @1. -This block glows faintly with a light level of @1.=Dieser Block leuchtet schwach mit einer Helligkeitsstufe von @1. +This block glows faintly with a light level of @1.=Dieser Block leuchtet schwach mit einer Helligkeitsstufe von @1. This block is a building block for creating various buildings.=Dieser Block ist für den Bau diverser Gebäude vorgesehen. This block is a liquid with these properties:=Dieser Block ist eine Flüssigkeit mit folgenden Eigenschaften: This block is affected by gravity and can fall.=Dieser Block wird von der Schwerkraft beeinflusst und kann fallen. diff --git a/mods/HELP/doc/doc_items/locale/template.txt b/mods/HELP/doc/doc_items/locale/template.txt index 484e40ec1..77f107863 100644 --- a/mods/HELP/doc/doc_items/locale/template.txt +++ b/mods/HELP/doc/doc_items/locale/template.txt @@ -2,7 +2,7 @@ Using it as fuel turns it into: @1.= @1 seconds= # Item count times item name -%@1×@2= +@1×@2= # Itemname (25%) @1 (@2%)= # Itemname (<0.5%) From b74078a06cd76b3fca66348398dd1f1cdb7cb602 Mon Sep 17 00:00:00 2001 From: jordan4ibanez Date: Thu, 29 Apr 2021 17:42:06 -0400 Subject: [PATCH 18/22] Feature freeze begins here --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 7c3cecece..102912e97 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ +# ______ +# | ___| +# | |_ _ __ ___ _______ _ __ +# | _| '__/ _ \_ / _ \ '_ \ +# | | | | | (_) / / __/ | | | +# \_| |_| \___/___\___|_| |_| + # MineClone 2 An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. Developed by many people. Not developed or endorsed by Mojang AB. From 55177c03ec15f2d4cc4c4144bc72080778b59edf Mon Sep 17 00:00:00 2001 From: jordan4ibanez Date: Thu, 29 Apr 2021 17:42:43 -0400 Subject: [PATCH 19/22] Fix feature freeze text --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index 102912e97..ca4d01959 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,4 @@ -# ______ -# | ___| -# | |_ _ __ ___ _______ _ __ -# | _| '__/ _ \_ / _ \ '_ \ -# | | | | | (_) / / __/ | | | -# \_| |_| \___/___\___|_| |_| +# (Currently in feature freeze) # MineClone 2 An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. From 7e3dd715af7bf7a5781a08234cbcd0c82a5294ad Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 30 Apr 2021 16:51:34 +0400 Subject: [PATCH 20/22] Fix https://git.minetest.land/MineClone2/MineClone2/issues/1681 by @cora --- mods/HUD/mcl_experience/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/HUD/mcl_experience/init.lua b/mods/HUD/mcl_experience/init.lua index 47db77bca..fd78534fc 100644 --- a/mods/HUD/mcl_experience/init.lua +++ b/mods/HUD/mcl_experience/init.lua @@ -263,7 +263,7 @@ function mcl_experience.add_experience(player, experience) local can = final_candidates[math.random(#final_candidates)] local stack, list, index, wear = can.stack, can.list, can.index, can.wear local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking") - local uses = mcl_util.calculate_durability(itemstack) + local uses = mcl_util.calculate_durability(stack) local multiplier = 2 * 65535 / uses local repair = experience * multiplier local new_wear = wear - repair From ae1212be7f7ea9eb517999d40937af0f2abc332e Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 30 Apr 2021 16:29:45 +0200 Subject: [PATCH 21/22] Add anon5's fix to prevent get_light crashes --- .../ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua index c7c4ad27c..76c062a40 100644 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua +++ b/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.lua @@ -1515,9 +1515,9 @@ local is_at_water_danger = function(self) end local function get_light(pos, tod) - if minetest.get_node_or_nil(pos) then - local lightfunc = minetest.get_natural_light or minetest.get_node_light - return lightfunc(pos, tod) + local ok, light = pcall(minetest.get_natural_light or minetest.get_node_light, pos, tod) + if ok then + return light else return 0 end From 8cccbd7caad680cfbe97ef0effd24b07e7fca7c2 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 30 Apr 2021 16:38:53 +0200 Subject: [PATCH 22/22] Fix harming potion crash --- mods/ITEMS/mcl_potions/functions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_potions/functions.lua b/mods/ITEMS/mcl_potions/functions.lua index 9a1e38d99..55a98ba9d 100644 --- a/mods/ITEMS/mcl_potions/functions.lua +++ b/mods/ITEMS/mcl_potions/functions.lua @@ -689,7 +689,7 @@ function mcl_potions.healing_func(player, hp) hp = -1 end - mcl_util.deal_damage(obj, -hp, {type = "magic"}) + mcl_util.deal_damage(player, -hp, {type = "magic"}) end end