diff --git a/.gitignore b/.gitignore index 393885da79..8228ba34ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ # Text Editor TMP Files *.swp +*.blend1 +*.blend2 +*.blend3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a7383df79e..5cbd6bcfc2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -245,13 +245,9 @@ need to state their sources. These PRs also need Fleckenstein's approval before they are merged. You can use these sources: -* Minecraft code (Name the source file and line, however DONT post any -proprietary code). You can use -[MCP](https://minecraft.fandom.com/wiki/Programs_and_editors/Mod_Coder_Pack) -to decompile Minecraft or look at -[Minestorm](https://github.com/Minestom/Minestom) code. * Testing things inside of Minecraft (Attach screenshots / video footage of the results) +* Looking at [Minestom](https://github.com/Minestom/Minestom) code. An open source Minecraft Server implementation * [Official Minecraft Wiki](https://minecraft.fandom.com/wiki/Minecraft_Wiki) (Include a link to the specific page you used) diff --git a/CREDITS.md b/CREDITS.md index 1381b1c373..c1174e797a 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -6,10 +6,14 @@ ## Creator of MineClone2 * Wuzzy + ## Maintainers -* Fleckenstein * Nicu -* kay27 +* cora + +## Previous Maintainers +* Fleckenstein +* jordan4ibanez ## Developers * bzoss @@ -22,8 +26,7 @@ * aligator * Code-Sploit * NO11 -* cora -* jordan4ibanez +* kabou ## Contributors * Laurent Rocher @@ -75,6 +78,16 @@ * epCode * NO11 * j45 +* 3raven +* PrarieWind +* Gustavo1 +* CableGuy67 + +## Mineclonia +* erlehmann +* Li0n +* E +* n_to ## Original Mod Authors * Wuzzy diff --git a/GROUPS.md b/GROUPS.md index 8286b29bc6..b2c009b479 100644 --- a/GROUPS.md +++ b/GROUPS.md @@ -56,6 +56,7 @@ Please read to learn how digging times * `no_eat_delay=1`: Only for foodstuffs. When eating this, all eating delays are ignored. * `can_eat_when_full=1`: Only for foodstuffs. This item can be eaten when the user has a full hunger bar * `attached_node_facedir=1`: Like `attached_node`, but for facedir nodes +* `supported_node=1`: Like `attached_node`, but can be placed on any nodes that do not have the `drawtype="airlike"` attribute. * `cauldron`: Cauldron. 1: Empty. 2-4: Water height * `anvil`: Anvil. 1: No damage. 2-3: Higher damage levels * `no_rename=1`: Item cannot be renamed by anvil @@ -71,6 +72,7 @@ Please read to learn how digging times * `coral_block=X`: Coral block (1 = alive, 2 = dead) * `coral_species=X`: Specifies the species of a coral; equal X means equal species * `set_on_fire=X`: Sets any (not fire-resistant) mob or player on fire for X seconds when touching +* `compostability=X`: Item can be used on a composter block; X (1-100) is the % chance of adding a level of compost #### Footnotes diff --git a/README.md b/README.md index 8f8f0b1e64..555a2f4907 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. Developed by many people. Not developed or endorsed by Mojang AB. -Version: 0.72.0 (in development) +Version: 0.74 (in development) ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore @@ -66,7 +66,7 @@ Use the `/giveme` chat command to obtain them. See the in-game help for an explanation. ## Installation -This game requires [Minetest](http://minetest.net) to run (version 5.3.0 or +This game requires [Minetest](http://minetest.net) to run (version 5.4.1 or later). So you need to install Minetest first. Only stable versions of Minetest are officially supported. There is no support for running MineClone2 in development versions of Minetest. diff --git a/README_locale/README.zh_TW.md b/README_locale/README.zh_TW.md new file mode 100644 index 0000000000..eb75402476 --- /dev/null +++ b/README_locale/README.zh_TW.md @@ -0,0 +1,324 @@ +# MineClone 2 +一個非官方的Minetest遊戲,遊玩方式和Minecraft類似。由davedevils從MineClone分拆。 +由許多人開發。並非由Mojang Studios開發。 + +版本:0.71.0 + +### 遊玩 +你開始在一個完全由方塊隨機生成的世界裡。你可以探索這個世界,挖掘和建造世界上幾乎所有的方塊,以創造新的結構。你可以選擇在「生存模式」中進行遊戲,在這個模式中,你必須與怪物戰鬥,飢餓求生,並在遊戲的其他各個環節中慢慢進步,如採礦、養殖、建造機器等等。 + +或者你也可以在「創造模式」中玩,在這個模式中,你可以瞬間建造大部分東西。 +#### Gameplay summary + +* 沙盒式遊戲,沒有明確目標 +* 生存:與怪物和飢餓搏鬥 +* 挖礦來獲得礦物和寶物 +* 附魔:獲得經驗值並以附魔強化你的工具 +* 使用收集的方塊來創造偉大的建築 +* 收集鮮花(和其他染料來源),令世界多姿多彩 +* 找些種子並開始耕種 +* 尋找或合成數百個物品之一 +* 建立一個鐵路系統,並從礦車中得到樂趣 +* 用紅石電路建造複雜的機器 +* 在創造模式下,你幾乎可以免費建造任何東西,而且沒有限制。 + +## 如何開始 +### 開始生存 +* **挖樹幹**直到其破裂並收集木材 +* 將木頭**放入2×2的格子中**(你的物品欄中的「合成格子」),然後製作4塊木材。 +* 將4塊木材按2×2的形狀擺放在合成格子裡,製作成合成臺。 +* **右鍵單擊製作臺**以獲得3×3製作網格,製作更複雜的東西 +* 使用**合成指南**(書形圖標)了解所有可能的合成方式 +* **製作一個木鎬**,這樣你就可以挖石頭了。 +* 不同的工具可以打破不同種類的方塊。試試吧! +* 繼續玩你想玩的。盡情享受吧! + +### 耕種 +* 找到種子 +* 合成鋤頭 +* 用鋤頭右鍵點擊泥土或類似的方塊,創建農田 +* 將種子放在農田上,看著它們長出來 +* Collect plant when fully grown +* If near water, farmland becomes wet and speeds up growth + +### Furnace +* Craft furnace +* Furnace allows you to obtain more items +* Upper slot must contain a smeltable item (example: iron ore) +* Lower slot must contain a fuel item (example: coal) +* See tooltips in crafting guide to learn about fuels and smeltable items + +### Additional help +More help about the gameplay, blocks items and much more can be found from inside +the game. You can access the help from your inventory menu. + +### Special items +The following items are interesting for Creative Mode and for adventure +map builders. They can not be obtained in-game or in the creative inventory. + +* Barrier: `mcl_core:barrier` + +Use the `/giveme` chat command to obtain them. See the in-game help for +an explanation. + +#### Incomplete items +These items do not work yet, but you can get them with `/giveme` for testing: + +* Minecart with Chest: `mcl_minecarts:chest_minecart` +* Minecart with Furnace: `mcl_minecarts:furnace_minecart` +* Minecart with Hopper: `mcl_minecarts:hopper_minecart` +* Minecart with Command Block: `mcl_minecarts:command_block_minecart` + +## Installation +This game requires [Minetest](http://minetest.net) to run (version 5.0.0 or +later). So you need to install Minetest first. Only stable versions of Minetest +are officially supported. +There is no support for running MineClone 2 in development versions of Minetest. + +To install MineClone 2 (if you haven't already), move this directory into the +“games” directory of your Minetest data directory. Consult the help of +Minetest to learn more. + +## Project description +The main goal of **MineClone 2** is to be a clone of Minecraft and to be released as free software. + +* **開發目標:我的世界, Java版, 版本 1.12** +* MineClone2還包括Minetest支持的Optifine功能。 +* 後期Minecraft版本的功能可能會偷偷加入,但它們的優先級較低。 +* 總的來說,Minecraft的目標是在Minetest目前允許的情況下進行克隆。 +* 克隆Minecraft是最優先的。 +* MineClone2將使用不同的圖形和聲音,但風格相似。 +* 克隆界面沒有優先權。只會被粗略地模仿。 +* 在Minetest中發現的局限性將在開發過程中被記錄和報告。 + +## 完成程度 +該遊戲目前處於**alpha**階段。 +它是可玩的,但尚未完成,預計會出現許多錯誤。 +向後兼容性是**不能保證的**,更新你的世界可能會造成大大小小的bug(比如「缺少節點」的錯誤甚至崩潰)。 + +已經實現以下功能: + +* 工具,武器 +* 盔甲 +* 合成和熔煉系統:2×2 合成格, 合成臺 (3×3 合成格), 熔爐, 合成教學 +* 儲物箱,大型儲物箱,終界箱和界伏盒 +* 熔爐, 漏斗 +* 飢餓和飽食 +* 大多數怪物和動物 +* Minecraft 1.12中的所有礦物 +* 主世界的大部分方塊 +* 水和岩漿 +* 天氣 +* 28個生態域 +* 地獄,熾熱的維度 +* 紅石電路(部分) +* 礦車(部分) +* 狀態效果(部分) +* 經驗系統 +* 附魔 +* 釀造,藥水,藥水箭(部分) +* 船 +* 火 +* 建築方塊:樓梯、半磚、門、地板門、柵欄、柵欄門、牆。 +* 時鐘 +* 指南針 +* 海綿 +* 史萊姆方塊(不與紅石互動) +* 小植物和樹苗 +* 染料 +* 旗幟 +* 裝飾方塊:玻璃、染色玻璃、玻璃片、鐵柵欄、陶土(和染色版本)、頭顱等 +* 物品展示框 +* 唱片機 +* 床 +* 物品欄 +* 創造模式物品欄 +* 生產 +* 書和羽毛筆 +* 一些服務器命令 +* 還有更多! + +以下是不完整的特性: + +* 生成結構(特別是村莊) +* 一些怪物和動物 +* 紅石系統 +* 終界 +* 特殊的礦車 +* 一些不簡單的方塊和物品。 + +額外功能(在Minecraft 1.11中沒有)。 + +* 內置合成指南,向你展示製作和熔煉的配方 +* 遊戲中的幫助系統包含了大量關於遊戲基礎知識、方塊、物品等方面的幫助。 +* 臨時製作配方。它們的存在只是為了在你不在創造模式下時,提供一些其他無法獲得的物品。這些配方將隨著開發的進行和更多功能的出現而被移除。 +* v6地圖生成器中箱子裡的樹苗。 +* 完全可修改(得益於Minetest強大的Lua API)。 +* 新的方塊和物品: + * 查找工具,顯示觸及事物的幫助 + * 更多的半磚和樓梯 + * 地獄磚柵欄門 + * 紅地獄磚柵欄 + * 紅地獄磚柵欄門 + +與Minecraft的技性術差異: + +* 高度限制為31000格(遠高於Minecraft) +* 水平世界大小約為62000×62000格(比Minecraft中的小得多,但仍然非常大)。 +* 仍然非常不完整和有問題 +* 塊、物品、敵人和其他功能缺失。 +* 一些項目的名稱略有不同,以便於區分。 +* 唱片機的音樂不同 +* 不同的材質(像素完美) +* 不同的聲音(各種來源) +* 不同的引擎(Minetest) + +...最後,MineClone2是自由軟件! + +## 錯誤報告 +請在此處報告所有錯誤和缺少的功能: + + + +## Chating with the community +我們有Discord交流羣: + + + + +## Other readme files + +* `LICENSE.txt`:GPLv3許可文本 +* `CONTRIBUTING.md`: 為那些想參與貢獻的人提供資訊 +* `MISSING_ENGINE_FEATURES.md`: MineClone2需要改进,Minetest中缺失的功能列表。 +* `API.md`: 關於MineClone2的API + +## 參與者 +有這麼多人要列出(抱歉)。詳情請查看各mod目錄。本節只是粗略地介紹了本遊戲的核心作者。 + +### 程式碼 +* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082):大多數mod的主要程序員(已退休) +* davedevils:MineClone 2的原型——「MineClone」的創造者 +* [ex-bart](https://github.com/ex-bart):紅石比較器 +* [Rootyjr](https://github.com/Rootyjr):釣竿和錯誤修復 +* [aligator](https://github.com/aligator):改進門 +* [ryvnf](https://github.com/ryvnf):爆炸物理 +* MysticTempest:錯誤修復 +* [bzoss](https://github.com/bzoss):狀態效果,釀造,藥水 +* kay27 :經驗系統,錯誤修復和優化(當前維護者) +* [EliasFleckenstein03](https://github.com/EliasFleckenstein03):終界水晶,附魔,燃燒的怪物/玩家,箱子的動畫和錯誤修復(當前維護者) +* epCode:更好的玩家動畫,新徽標 +* 2mac:修復動力鐵軌的錯誤 +* 更多:待篇寫 (請查看各mod目錄) + +#### Mod(概括) + +* `controls`: Arcelmi +* `flowlib`: Qwertymine13 +* `walkover`: lordfingle +* `drippingwater`: kddekadenz +* `mobs_mc`: maikerumine, 22i and others +* `awards`: rubenwardy +* `screwdriver`: RealBadAngel, Maciej Kastakin, Minetest contributors +* `xpanes`: Minetest contributors +* `mesecons` mods: Jeija and contributors +* `wieldview`: Stuart Jones +* `mcl_meshhand`: Based on `newhand` by jordan4ibanez +* `mcl_mobs`: Based on Mobs Redo [`mobs`] by TenPlus1 and contributors +* 大多其他的Mod: Wuzzy + +每个mod的详细參與者可以在各个mod目录中找到。 + +### 圖形 +* [XSSheep](http://www.minecraftforum.net/members/XSSheep):主要作者;Minecraft 1.11的Pixel Perfection资源包的制作者 +* [Wuzzy](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=3082):主菜單圖像和各種編輯和添加的材質包 +* [kingoscargames](https://github.com/kingoscargames):現有材質的各種編輯和添加 +* [leorockway](https://github.com/leorockway):怪物紋理的一些編輯 +* [xMrVizzy](https://minecraft.curseforge.com/members/xMrVizzy):釉陶(材質以後會被替換) +* yutyo :MineClone2標志 +* 其他:GUI圖片 + +### 翻譯 +* Wuzzy:德語 +* Rocher Laurent :法語 +* wuniversales:西班牙語 +* kay27 :俄語 +* [Emoji](https://toyshost2.ddns.net):繁體中文 + +### 模型 +* [22i](https://github.com/22i):所有模型的作者 +* [tobyplowy](https://github.com/tobyplowy):對上述模型進行UV映射修復 + +### 聲音和音樂 +多種來源。 有關詳細信息,請參見相應的mod目錄。 + +### 特殊感謝 + +* Wuzzy,感謝他啟動和維護MineClone2多年。 +* celeron55,創建Minetest。 +* Minetest的社區提供了大量的mods選擇,其中一些最終被納入MineClone 2。 +* Jordach,為《Big Freaking Dig》的唱片機音樂合輯而來 +* 花了太多時間為Minecraft Wiki寫作的工作狂。它是創建這個遊戲的寶貴資源。 +* Notch和Jeb是Minecraft背后的主要力量 +* XSSheep用於創建Pixel Perfection資源包。 +* [22i](https://github.com/22i) 提供出色的模型和支持 +* [maikerumine](http://github.com/maikerumine) 揭開生物和生物群落的序幕 + +## 給程序員的信息 +你可以在「API.md」中找到有趣和有用的信息。 + +## 法律信息 +這是一款粉絲開發的遊戲,並非由Mojang AB開發或認可。 + +複製是一種愛的行為。請複制和分享! <3 +下面是詳細的法律條文,有需要的朋友可以參考。 + +### License of source code +``` +MineClone 2 (by kay27, EliasFleckenstein, Wuzzy, davedevils and countless others) +is an imitation of Minecraft. + +MineClone 2 is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License (in the LICENSE.txt file) for more +details. + +In the mods you might find in the read-me or license +text files a different license. This counts as dual-licensing. +You can choose which license applies to you: Either the +license of MineClone 2 (GNU GPLv3) or the mod's license. + +MineClone 2 is a direct continuation of the discontinued MineClone +project by davedevils. + +Mod credits: +See `README.txt` or `README.md` in each mod directory for information about other authors. +For mods that do not have such a file, the license is the source code license +of MineClone 2 and the author is Wuzzy. +``` + +### License of media (textures and sounds) +``` +No non-free licenses are used anywhere. + +The textures, unless otherwise noted, are based on the Pixel Perfection resource pack for Minecraft 1.11, +authored by XSSheep. Most textures are verbatim copies, while some textures have been changed or redone +from scratch. +The glazed terracotta textures have been created by (MysticTempest)[https://github.com/MysticTempest]. +Source: +License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/) + +The main menu images are release under: [CC0](https://creativecommons.org/publicdomain/zero/1.0/) + +All other files, unless mentioned otherwise, fall under: +Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) +http://creativecommons.org/licenses/by-sa/3.0/ + +See README.txt in each mod directory for detailed information about other authors. +``` diff --git a/menu/Logo.blend b/menu/Logo.blend new file mode 100644 index 0000000000..08284ef67a Binary files /dev/null and b/menu/Logo.blend differ diff --git a/menu/icon.png b/menu/icon.png index e479dfff5a..46b7475e36 100644 Binary files a/menu/icon.png and b/menu/icon.png differ diff --git a/menu/icon_big.png b/menu/icon_big.png new file mode 100644 index 0000000000..ecdd62b78e Binary files /dev/null and b/menu/icon_big.png differ diff --git a/menu/icon_small.png b/menu/icon_small.png new file mode 100644 index 0000000000..6e4497d32f Binary files /dev/null and b/menu/icon_small.png differ diff --git a/mods/CORE/mcl_attached/init.lua b/mods/CORE/mcl_attached/init.lua index 4f538e104b..c4a7a3337b 100644 --- a/mods/CORE/mcl_attached/init.lua +++ b/mods/CORE/mcl_attached/init.lua @@ -1,29 +1,93 @@ +-- Overrides the builtin minetest.check_single_for_falling. +-- We need to do this in order to handle nodes in mineclone specific groups +-- "supported_node" and "attached_node_facedir". +-- +-- Nodes in group "supported_node" can be placed on any node that does not +-- have the "airlike" drawtype. Carpets are an example of this type. + local vector = vector local facedir_to_dir = minetest.facedir_to_dir local get_item_group = minetest.get_item_group local remove_node = minetest.remove_node local get_node = minetest.get_node +local get_meta = minetest.get_meta +local registered_nodes = minetest.registered_nodes +local get_node_drops = minetest.get_node_drops +local add_item = minetest.add_item +-- drop_attached_node(p) +-- +-- This function is copied verbatim from minetest/builtin/game/falling.lua +-- We need this to do the exact same dropping node handling in our override +-- minetest.check_single_for_falling() function as in the builtin function. +-- +local function drop_attached_node(p) + local n = get_node(p) + local drops = get_node_drops(n, "") + local def = registered_nodes[n.name] + if def and def.preserve_metadata then + local oldmeta = get_meta(p):to_table().fields + -- Copy pos and node because the callback can modify them. + local pos_copy = vector.new(p) + local node_copy = {name=n.name, param1=n.param1, param2=n.param2} + local drop_stacks = {} + for k, v in pairs(drops) do + drop_stacks[k] = ItemStack(v) + end + drops = drop_stacks + def.preserve_metadata(pos_copy, node_copy, oldmeta, drops) + end + if def and def.sounds and def.sounds.fall then + core.sound_play(def.sounds.fall, {pos = p}, true) + end + remove_node(p) + for _, item in pairs(drops) do + local pos = { + x = p.x + math.random()/2 - 0.25, + y = p.y + math.random()/2 - 0.25, + z = p.z + math.random()/2 - 0.25, + } + add_item(pos, item) + end +end + +-- minetest.check_single_for_falling(pos) +-- +-- * causes an unsupported `group:falling_node` node to fall and causes an +-- unattached `group:attached_node` or `group:attached_node_facedir` node +-- or unsupported `group:supported_node` node to drop. +-- * does not spread these updates to neighbours. +-- +-- Returns true if the node at has spawned a falling node or has been +-- dropped as item(s). +-- local original_function = minetest.check_single_for_falling function minetest.check_single_for_falling(pos) - local ret_o = original_function(pos) - local ret = false - local node = minetest.get_node(pos) + if original_function(pos) then + return true + end + + local node = get_node(pos) if get_item_group(node.name, "attached_node_facedir") ~= 0 then local dir = facedir_to_dir(node.param2) if dir then if get_item_group(get_node(vector.add(pos, dir)).name, "solid") == 0 then - remove_node(pos) - local drops = minetest.get_node_drops(node.name, "") - for dr=1, #drops do - minetest.add_item(pos, drops[dr]) - end - ret = true + drop_attached_node(pos) + return true end end end - return ret_o or ret + + if get_item_group(node.name, "supported_node") ~= 0 then + local def = registered_nodes[get_node(vector.offset(pos, 0, -1, 0)).name] + if def and def.drawtype == "airlike" then + drop_attached_node(pos) + return true + end + end + + return false end diff --git a/mods/CORE/mcl_damage/API.md b/mods/CORE/mcl_damage/API.md new file mode 100644 index 0000000000..9ffdcb9f48 --- /dev/null +++ b/mods/CORE/mcl_damage/API.md @@ -0,0 +1,15 @@ +# mcl_damage + +This mod is intended to overall minetest's native damage system, to provide a better integration between features that deals with entities' health. + +WARNING: Not using it inside your mods may cause strange bugs (using the native damage system may cause conflicts with this system). + +## Callbacks + +To modify the amount of damage made by something: + +```lua +--obj: an ObjectRef +mcl_damage.register_modifier(function(obj, damage, reason) +end, 0) +``` \ No newline at end of file diff --git a/mods/CORE/mcl_explosions/locale/mcl_explosions.zh_TW.tr b/mods/CORE/mcl_explosions/locale/mcl_explosions.zh_TW.tr new file mode 100644 index 0000000000..9cac9b4120 --- /dev/null +++ b/mods/CORE/mcl_explosions/locale/mcl_explosions.zh_TW.tr @@ -0,0 +1,2 @@ +# textdomain:mcl_explosions +@1 was caught in an explosion.=@1 被炸飛了 diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index d548f6cac7..0d1cb45dc9 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -357,6 +357,32 @@ function mcl_util.get_first_occupied_inventory_slot(inventory, listname) return mcl_util.get_eligible_transfer_item_slot(inventory, listname) end +local function drop_item_stack(pos, stack) + if not stack or stack:is_empty() then return end + local drop_offset = vector.new(math.random() - 0.5, 0, math.random() - 0.5) + minetest.add_item(vector.add(pos, drop_offset), stack) +end + +function mcl_util.drop_items_from_meta_container(listname) + return function(pos, oldnode, oldmetadata) + if oldmetadata and oldmetadata.inventory then + -- process in after_dig_node callback + local main = oldmetadata.inventory.main + if not main then return end + for _, stack in pairs(main) do + drop_item_stack(pos, stack) + end + else + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + for i = 1, inv:get_size("main") do + drop_item_stack(pos, inv:get_stack("main", i)) + end + meta:from_table() + end + end +end + -- Returns true if item (itemstring or ItemStack) can be used as a furnace fuel. -- Returns false otherwise function mcl_util.is_fuel(item) @@ -571,3 +597,16 @@ function mcl_util.replace_mob(obj, mob) obj:set_yaw(rot) return obj end + +function mcl_util.get_pointed_thing(player, liquid) + local pos = vector.offset(player:get_pos(), 0, player:get_properties().eye_height, 0) + local look_dir = vector.multiply(player:get_look_dir(), 5) + local pos2 = vector.add(pos, look_dir) + local ray = minetest.raycast(pos, pos2, false, liquid) + + if ray then + for pointed_thing in ray do + return pointed_thing + end + end +end diff --git a/mods/CORE/mcl_worlds/init.lua b/mods/CORE/mcl_worlds/init.lua index 203f69401a..4f89145062 100644 --- a/mods/CORE/mcl_worlds/init.lua +++ b/mods/CORE/mcl_worlds/init.lua @@ -153,3 +153,22 @@ minetest.register_globalstep(function(dtime) end end) +function mcl_worlds.get_cloud_parameters() + if minetest.get_mapgen_setting("mg_name") == "valleys" then + return { + height = 384, --valleys has a much higher average elevation thus often "normal" landscape ends up in the clouds + speed = {x=-2, z=0}, + thickness=5, + color="#FFF0FEF", + ambient = "#201060", + } + else + -- MC-style clouds: Layer 127, thickness 4, fly to the “West” + return { + height = mcl_worlds.layer_to_y(127), + speed = {x=-2, z=0}, + thickness = 4, + color = "#FFF0FEF", + } + end +end diff --git a/mods/CORE/tga_encoder/init.lua b/mods/CORE/tga_encoder/init.lua index 39309c9c91..24ec502e1e 100644 --- a/mods/CORE/tga_encoder/init.lua +++ b/mods/CORE/tga_encoder/init.lua @@ -84,7 +84,7 @@ function image:encode() end function image:save(filename) - local f = assert(io.open(filename, "w")) + local f = assert(io.open(filename, "wb")) f:write(self.data) f:close() end diff --git a/mods/CORE/walkover/init.lua b/mods/CORE/walkover/init.lua index 4d712c3085..eb9de42186 100644 --- a/mods/CORE/walkover/init.lua +++ b/mods/CORE/walkover/init.lua @@ -2,47 +2,45 @@ local get_connected_players = minetest.get_connected_players local get_node = minetest.get_node -local vector_add = vector.add +local vector = vector local ceil = math.ceil local pairs = pairs walkover = {} -walkover.registered_globals = {} - -function walkover.register_global(func) - table.insert(walkover.registered_globals, func) -end local on_walk = {} local registered_globals = {} +walkover.registered_globals = registered_globals + +function walkover.register_global(func) + table.insert(registered_globals, func) +end + minetest.register_on_mods_loaded(function() for name,def in pairs(minetest.registered_nodes) do if def.on_walk_over then on_walk[name] = def.on_walk_over end end - for _,func in ipairs(walkover.registered_globals) do --cache registered globals - table.insert(registered_globals, func) - end end) local timer = 0 minetest.register_globalstep(function(dtime) - timer = timer + dtime; + timer = timer + dtime if timer >= 0.3 then - for _,player in pairs(get_connected_players()) do - local pp = player:get_pos() - pp.y = ceil(pp.y) - local loc = vector_add(pp, {x=0,y=-1,z=0}) - if loc then - local nodeiamon = get_node(loc) - if nodeiamon then - if on_walk[nodeiamon.name] then - on_walk[nodeiamon.name](loc, nodeiamon, player) + for _, player in pairs(get_connected_players()) do + local ppos = player:get_pos() + ppos.y = ceil(ppos.y) + local npos = vector.add(ppos, vector.new(0, -1, 0)) + if npos then + local node = get_node(npos) + if node then + if on_walk[node.name] then + on_walk[node.name](npos, node, player) end for i = 1, #registered_globals do - registered_globals[i](loc, nodeiamon, player) + registered_globals[i](npos, node, player) end end end diff --git a/mods/ENTITIES/mcl_boats/init.lua b/mods/ENTITIES/mcl_boats/init.lua index beff5fb52e..72664b1dfb 100644 --- a/mods/ENTITIES/mcl_boats/init.lua +++ b/mods/ENTITIES/mcl_boats/init.lua @@ -267,7 +267,7 @@ function boat.on_step(self, dtime, moveresult) return end local yaw = self.object:get_yaw() - if ctrl.up then + if ctrl and ctrl.up then -- Forwards self._v = self._v + 0.1 * v_factor @@ -276,7 +276,7 @@ function boat.on_step(self, dtime, moveresult) self.object:set_animation({x=0, y=40}, paddling_speed, 0, true) self._animation = 1 end - elseif ctrl.down then + elseif ctrl and ctrl.down then -- Backwards self._v = self._v - 0.1 * v_factor diff --git a/mods/ENTITIES/mcl_boats/locale/mcl_boats.zh_TW.tr b/mods/ENTITIES/mcl_boats/locale/mcl_boats.zh_TW.tr new file mode 100644 index 0000000000..c1c404f2ac --- /dev/null +++ b/mods/ENTITIES/mcl_boats/locale/mcl_boats.zh_TW.tr @@ -0,0 +1,11 @@ +# textdomain: mcl_boats +Acacia Boat=相思木船 +Birch Boat=白樺木船 +Boat=船 +Boats are used to travel on the surface of water.=船是用來在水上行走的交通工具。 +Dark Oak Boat=黑橡木船 +Jungle Boat=叢林木船 +Oak Boat=橡木船 +Rightclick on a water source to place the boat. Rightclick the boat to enter it. Use [Left] and [Right] to steer, [Forwards] to speed up and [Backwards] to slow down or move backwards. Rightclick the boat again to leave it, punch the boat to make it drop as an item.=右鍵單擊水源以放置船。右鍵單擊船以搭乘它。使用[左]和[右]進行轉向,[向前]加快速度,[向後]減速或向後移動。再次右鍵單擊船以離開它,打擊船以使其掉落為物品。 +Spruce Boat=杉木船 +Water vehicle=水上交通工具 diff --git a/mods/ENTITIES/mcl_burning/api.lua b/mods/ENTITIES/mcl_burning/api.lua index 9699852053..885875aca2 100644 --- a/mods/ENTITIES/mcl_burning/api.lua +++ b/mods/ENTITIES/mcl_burning/api.lua @@ -26,20 +26,64 @@ function mcl_burning.get_collisionbox(obj, smaller, storage) end end +local find_nodes_in_area = minetest.find_nodes_in_area + function mcl_burning.get_touching_nodes(obj, nodenames, storage) local pos = obj:get_pos() local minp, maxp = mcl_burning.get_collisionbox(obj, true, storage) - local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames) + local nodes = find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodenames) return nodes end +-- Manages the fire animation on a burning player's HUD +-- +-- Parameters: +-- player - a valid player object; +-- +-- If the player already has a fire HUD, updates the burning animation. +-- If the fire does not have a fire HUD, initializes the HUD. +-- +function mcl_burning.update_hud(player) + local animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8 + local hud_flame_animated = "mcl_burning_hud_flame_animated.png^[opacity:180^[verticalframe:" .. animation_frames .. ":" + + local storage = mcl_burning.get_storage(player) + if not storage.fire_hud_id then + storage.animation_frame = 1 + storage.fire_hud_id = player:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 0.5}, + scale = {x = -100, y = -100}, + text = hud_flame_animated .. storage.animation_frame, + z_index = 1000, + }) + else + storage.animation_frame = storage.animation_frame + 1 + if storage.animation_frame > animation_frames - 1 then + storage.animation_frame = 0 + end + player:hud_change(storage.fire_hud_id, "text", hud_flame_animated .. storage.animation_frame) + end +end + +-- Sets and object state as burning and adds a fire animation to the object. +-- +-- Parameters: +-- obj - may be a player or a lua_entity; +-- burn_time - sets the object's burn duration; +-- +-- If obj is a player, adds a fire animation to the HUD, if obj is a +-- lua_entity, adds an animated fire entity to obj. +-- The effective burn duration is modified by obj's armor protection. +-- If obj was already burning, its burn duration is updated if the current +-- duration is less than burn_time. +-- If obj is dead, fireproof or a creative player, this function does nothing. +-- function mcl_burning.set_on_fire(obj, burn_time) if obj:get_hp() < 0 then return end - local storage = mcl_burning.get_storage(obj) - local luaentity = obj:get_luaentity() if luaentity and luaentity.fire_resistant then return @@ -60,44 +104,32 @@ function mcl_burning.set_on_fire(obj, burn_time) end end end - if max_fire_prot_lvl > 0 then burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15) end end - if not storage.burn_time or burn_time >= storage.burn_time then - if obj:is_player() then - mcl_burning.channels[obj]:send_all(tostring(mcl_burning.animation_frames)) - mcl_burning.channels[obj]:send_all("start") + local storage = mcl_burning.get_storage(obj) + if storage.burn_time then + if burn_time > storage.burn_time then + storage.burn_time = burn_time end - storage.burn_time = burn_time - storage.fire_damage_timer = 0 + return + end + storage.burn_time = burn_time + storage.fire_damage_timer = 0 - local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire") - local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage) - local obj_size = obj:get_properties().visual_size + local minp, maxp = mcl_burning.get_collisionbox(obj, false, storage) + local size = vector.subtract(maxp, minp) + size = vector.multiply(size, vector.new(1.1, 1.2, 1.1)) + size = vector.divide(size, obj:get_properties().visual_size) - local vertical_grow_factor = 1.2 - local horizontal_grow_factor = 1.1 - local grow_vector = vector.new(horizontal_grow_factor, vertical_grow_factor, horizontal_grow_factor) + local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire") + fire_entity:set_properties({visual_size = size}) + fire_entity:set_attach(obj, "", vector.new(0, size.y * 5, 0), vector.new(0, 0, 0)) - local size = vector.subtract(maxp, minp) - size = vector.multiply(size, grow_vector) - size = vector.divide(size, obj_size) - local offset = vector.new(0, size.y * 10 / 2, 0) - - fire_entity:set_properties({visual_size = size}) - fire_entity:set_attach(obj, "", offset, {x = 0, y = 0, z = 0}) - local fire_luaentity = fire_entity:get_luaentity() - - for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do - local other_luaentity = other:get_luaentity() - if other_luaentity and other_luaentity.name == "mcl_burning:fire" and other_luaentity ~= fire_luaentity then - other:remove() - break - end - end + if obj:is_player() then + mcl_burning.update_hud(obj) end end @@ -105,7 +137,9 @@ function mcl_burning.extinguish(obj) if mcl_burning.is_burning(obj) then local storage = mcl_burning.get_storage(obj) if obj:is_player() then - mcl_burning.channels[obj]:send_all("stop") + if storage.fire_hud_id then + obj:hud_remove(storage.fire_hud_id) + end mcl_burning.storage[obj] = {} else storage.burn_time = nil diff --git a/mods/ENTITIES/mcl_burning/init.lua b/mods/ENTITIES/mcl_burning/init.lua index a478245373..039d295b73 100644 --- a/mods/ENTITIES/mcl_burning/init.lua +++ b/mods/ENTITIES/mcl_burning/init.lua @@ -1,18 +1,27 @@ local modpath = minetest.get_modpath(minetest.get_current_modname()) -local pairs = pairs - -local get_connected_players = minetest.get_connected_players -local get_item_group = minetest.get_item_group - mcl_burning = { - storage = {}, - channels = {}, - animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8 + -- the storage table holds a list of objects (players,luaentities) and tables + -- associated with these objects. These tables have the following attributes: + -- burn_time: + -- Remaining time that object will burn. + -- fire_damage_timer: + -- Timer for dealing damage every second while burning. + -- fire_hud_id: + -- HUD id of the flames animation on a burning player's HUD. + -- animation_frame: + -- The HUD's current animation frame, used by update_hud(). + -- collisionbox_cache: + -- Used by mcl_burning.get_collisionbox() to avoid recalculations. + storage = {} } dofile(modpath .. "/api.lua") +local pairs = pairs +local get_connected_players = minetest.get_connected_players +local get_item_group = minetest.get_item_group + minetest.register_globalstep(function(dtime) for _, player in pairs(get_connected_players()) do local storage = mcl_burning.storage[player] @@ -44,25 +53,43 @@ minetest.register_on_respawnplayer(function(player) mcl_burning.extinguish(player) end) -function mcl_burning.init_player(player) - local meta = player:get_meta() - -- NOTE: mcl_burning:data may be "return nil" (which deserialize into nil) for reasons unknown. - if meta:get_string("mcl_burning:data"):find("return nil", 1, true) then - minetest.log("warning", "[mcl_burning] 'mcl_burning:data' player meta field is invalid! Please report this bug") +minetest.register_on_joinplayer(function(player) + local storage = {} + local burn_data = player:get_meta():get_string("mcl_burning:data") + if burn_data ~= "" then + storage = minetest.deserialize(burn_data) or storage end - mcl_burning.storage[player] = meta:contains("mcl_burning:data") and minetest.deserialize(meta:get_string("mcl_burning:data")) or {} - mcl_burning.channels[player] = minetest.mod_channel_join("mcl_burning:" .. player:get_player_name()) + mcl_burning.storage[player] = storage + if storage.burn_time and storage.burn_time > 0 then + mcl_burning.update_hud(player) + end +end) + +local function on_leaveplayer(player) + local storage = mcl_burning.storage[player] + if not storage then + -- For some unexplained reasons, mcl_burning.storage can be `nil` here. + -- Logging this exception to assist in finding the cause of this. + minetest.log("warning", "on_leaveplayer: missing mcl_burning.storage " + .. "for player " .. player:get_player_name()) + storage = {} + end + storage.fire_hud_id = nil + player:get_meta():set_string("mcl_burning:data", minetest.serialize(storage)) + mcl_burning.storage[player] = nil end -minetest.register_on_joinplayer(function(player) - mcl_burning.init_player(player) -end) - minetest.register_on_leaveplayer(function(player) - player:get_meta():set_string("mcl_burning:data", minetest.serialize(mcl_burning.storage[player])) - mcl_burning.storage[player] = nil + on_leaveplayer(player) end) +minetest.register_on_shutdown(function() + for _,player in ipairs(minetest.get_connected_players()) do + on_leaveplayer(player) + end +end) + +local animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8 minetest.register_entity("mcl_burning:fire", { initial_properties = { @@ -70,42 +97,35 @@ minetest.register_entity("mcl_burning:fire", { collisionbox = {0, 0, 0, 0, 0, 0}, visual = "upright_sprite", textures = { - name = "mcl_burning_entity_flame_animated.png", - animation = { - type = "vertical_frames", - aspect_w = 16, - aspect_h = 16, - length = 1.0, - }, + "mcl_burning_entity_flame_animated.png", + "mcl_burning_entity_flame_animated.png" }, - spritediv = {x = 1, y = mcl_burning.animation_frames}, + spritediv = {x = 1, y = animation_frames}, pointable = false, glow = -1, backface_culling = false, }, - animation_frame = 0, - animation_timer = 0, + _mcl_animation_timer = 0, on_activate = function(self) - self.object:set_sprite({x = 0, y = 0}, mcl_burning.animation_frames, 1.0 / mcl_burning.animation_frames) + self.object:set_sprite({x = 0, y = 0}, animation_frames, 1.0 / animation_frames) end, - on_step = function(self) - if not self:sanity_check() then - self.object:remove() - end - end, - sanity_check = function(self) + on_step = function(self, dtime) local parent = self.object:get_attach() - if not parent then - return false + self.object:remove() + return end - local storage = mcl_burning.get_storage(parent) - if not storage or not storage.burn_time then - return false + self.object:remove() + return + end + if parent:is_player() then + self._mcl_animation_timer = self._mcl_animation_timer + dtime + if self._mcl_animation_timer >= 0.1 then + self._mcl_animation_timer = 0 + mcl_burning.update_hud(parent) + end end - - return true end, }) diff --git a/mods/ENTITIES/mcl_falling_nodes/locale/mcl_falling_nodes.zh_TW.tr b/mods/ENTITIES/mcl_falling_nodes/locale/mcl_falling_nodes.zh_TW.tr new file mode 100644 index 0000000000..2772fb357a --- /dev/null +++ b/mods/ENTITIES/mcl_falling_nodes/locale/mcl_falling_nodes.zh_TW.tr @@ -0,0 +1,3 @@ +# textdomain: mcl_falling_nodes +@1 was smashed by a falling anvil.=@1 被鐵砧壓扁了。 +@1 was smashed by a falling block.=@1 被掉下來的方塊壓扁了。 diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 678f8e2b7d..e39e21bfb9 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -110,7 +110,7 @@ minetest.register_globalstep(function(dtime) if tick == true and pool[name] > 0 then minetest.sound_play("item_drop_pickup", { pos = pos, - gain = 0.7, + gain = 0.3, max_hear_distance = 16, pitch = math.random(70,110)/100 }) @@ -256,6 +256,8 @@ function minetest.handle_node_drops(pos, drops, digger) local silk_touch_drop = false local nodedef = minetest.registered_nodes[dug_node.name] + if not nodedef then return end + if shearsy_level and shearsy_level > 0 and nodedef._mcl_shears_drop then if nodedef._mcl_shears_drop == true then drops = { dug_node.name } diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index 119a135230..d894f97226 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -432,7 +432,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o -- Slow down or speed up local acc = dir.y * -1.8 local friction = 0.4 - local speed_mod = minetest.registered_nodes[minetest.get_node(pos).name]._rail_acceleration + local ndef = minetest.registered_nodes[minetest.get_node(pos).name] + local speed_mod = ndef and ndef._rail_acceleration acc = acc - friction @@ -860,4 +861,4 @@ if has_mcl_wip then mcl_wip.register_wip_item("mcl_minecarts:furnace_minecart") mcl_wip.register_wip_item("mcl_minecarts:command_block_minecart") mcl_wip.register_wip_item("mcl_minecarts:hopper_minecart") -end \ No newline at end of file +end diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.txt b/mods/ENTITIES/mcl_mobs/api.lua similarity index 55% rename from mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.txt rename to mods/ENTITIES/mcl_mobs/api.lua index 48233d0b4f..ea92353917 100644 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/backup_code_api.txt +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -1,7 +1,119 @@ -local math = math -local vector = vector -local function disable_physics(object, luaentity, ignore_check, reset_movement) +-- 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 object:set_properties({ @@ -14,912 +126,630 @@ local function disable_physics(object, luaentity, ignore_check, reset_movement) end end -----For Water Flowing: -local function enable_physics(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}) + +-- 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 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 - 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 - 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 - - self.object:remove() - end - }) + local p1, p2 = self.object:get_pos(), object:get_pos() + return p1 and p2 and (vector.distance(p1, p2) <= dist) end --- Spawn a child -function mobs:spawn_child(pos, mob_type) - local child = minetest_add_entity(pos, mob_type) - if not child then +-- attack player/mob +local do_attack = function(self, player) + + if self.state == "attack" or self.state == "die" then return end - local ent = child:get_luaentity() - effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5) + self.attack = player + self.state = "attack" - ent.child = true + -- TODO: Implement war_cry sound without being annoying + --if random(0, 100) < 90 then + --mob_sound(self, "war_cry", true) + --end +end - local textures - -- using specific child texture (if found) - if ent.child_texture then - textures = ent.child_texture[1] + +-- 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 + + local ent = object:get_luaentity() + if object:is_player() or (ent and ent._cmi_is_mob 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 - -- 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({x,z}) +end - return child +-- 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 --- feeding, taming and breeding (thanks blert2112) -function mobs:feed_tame(self, clicker, feed_count, breed, tame) - if not self.follow then - return false +-- 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 - -- can eat/tame with item in hand - if follow_holding(self, clicker) then + return 0 +end - -- if not in creative then take item - if not mobs.is_creative(clicker:get_player_name()) then +local function update_roll(self) + local is_Fleckenstein = self.nametag == "Fleckenstein" + local was_Fleckenstein = false - local item = clicker:get_wielded_item() + local rot = self.object:get_rotation() + rot.z = is_Fleckenstein and pi or 0 + self.object:set_rotation(rot) - item:take_item() + local cbox = table.copy(self.collisionbox) + local acbox = self.object:get_properties().collisionbox - clicker:set_wielded_item(item) + 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 - mob_sound(self, "eat", nil, true) + self.target_yaw = yaw + self.delay = delay - -- increase health - self.health = self.health + 4 + return self.target_yaw +end - if self.health >= self.hp_max then +-- global function to set mob yaw +function mobs:yaw(self, yaw, delay, dtime) + set_yaw(self, yaw, delay, dtime) +end - self.health = self.hp_max - - if self.htimer < 1 then - self.htimer = 5 - 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 - self.object:set_hp(self.health) +-- 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 - update_tag(self) + self.animation.current = self.animation.current or "" - -- make children grow quicker - if self.child == true then + if (anim == self.animation.current + or not self.animation[anim .. "_start"] + or not self.animation[anim .. "_end"]) and self.state ~= "die" then + return + end - -- deduct 10% of the time to adulthood - self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1) + self.animation.current = anim + 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) +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 - -- 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 +-- 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 - if tame then - self.tamed = true +-- check line of sight (BrunoMine) +local line_of_sight = function(self, pos1, pos2, stepsize) - if not self.owner or self.owner == "" then - self.owner = clicker:get_player_name() - end - end + stepsize = stepsize or 1 - -- make sound when fed so many times - mob_sound(self, "random", true) + 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 - return true + -- 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 --- no damage to nodes explosion -function mobs:safe_boom(self, pos, strength) - minetest_sound_play(self.sounds and self.sounds.explode or "tnt_explode", { + +-- 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 + + +-- 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 + +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 = self.sounds and self.sounds.distance or 32 + max_hear_distance = 8, }, 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 +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 - mobs:safe_boom(self, pos, strength) + tag = self.nametag end + self.object:set_properties({ + nametag = tag, + }) + + update_roll(self) end --- falling and fall damage --- returns true if mob died -local falling = function(self, pos) +-- drop items +local item_drop = function(self, cooked, looting_level) - if self.fly and self.state ~= "die" then + -- 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 - 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 + local obj, item, num + local pos = self.object:get_pos() - -- floating in water (or falling) - local v = self.object:get_velocity() + self.drops = self.drops or {} -- nil check - if v.y > 0 then + for n = 1, #self.drops do + local dropdef = self.drops[n] + local chance = 1 / dropdef.chance + local looting_type = dropdef.looting - -- 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 then - player = obj.object - type = obj.type - name = obj.name or "" + 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 - -- 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 * math_pi / 2) - self.rotate - - if lp.x > s.x then - yaw = yaw + math_pi + 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 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 + if do_common_looting then + num = num + math.floor(math.random(0, looting_level) + 0.5) end - end + if num > 0 then + item = dropdef.name - -- follow that thing - if self.following then + -- cook items when true + if cooked then - local s = self.object:get_pos() - local p + local output = minetest.get_craft_result({ + method = "cooking", width = 1, items = {item}}) - 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") + if output and output.item and not output.item:is_empty() then + item = output.item:get_name() 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 + -- add item if it exists + for x = 1, num do + obj = minetest.add_item(pos, ItemStack(item .. " " .. 1)) + end - self.state = "flop" - self.object:set_acceleration({x = 0, y = DEFAULT_FALL_SPEED, z = 0}) + if obj and obj:get_luaentity() then - 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), + obj:set_velocity({ + x = random(-10, 10) / 9, + y = 6, + z = random(-10, 10) / 9, }) + elseif obj then + obj:remove() -- item does not exist 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 + + self.drops = {} 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) @@ -946,7 +776,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 @@ -989,8 +819,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_xp(self.object:get_pos(), math.random(self.xp_min, self.xp_max)) end end end @@ -1055,7 +885,7 @@ local check_for_death = function(self, cause, cmi_cause) set_animation(self, "die") else local rot = self.object:get_rotation() - rot.z = math_pi/2 + rot.z = pi/2 self.object:set_rotation(rot) length = 1 + DEATH_DELAY set_animation(self, "stand", true) @@ -1082,366 +912,34 @@ 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 - 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 +-- 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 end end end - return false + 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 --- 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) @@ -1453,23 +951,23 @@ local is_at_cliff_or_danger = function(self) return false end local yaw = self.object:get_yaw() - local dir_x = -math_sin(yaw) * (self.collisionbox[4] + 0.5) - local dir_z = math_cos(yaw) * (self.collisionbox[4] + 0.5) + local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) + local dir_z = 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 @@ -1488,18 +986,18 @@ local is_at_water_danger = function(self) return false end local yaw = self.object:get_yaw() - local dir_x = -math_sin(yaw) * (self.collisionbox[4] + 0.5) - local dir_z = math_cos(yaw) * (self.collisionbox[4] + 0.5) + local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) + local dir_z = 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 @@ -1507,7 +1005,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 @@ -1517,10 +1015,25 @@ 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) - local ok, light = pcall(minetest.get_natural_light or minetest.get_node_light, pos, tod) - if ok then - return light + if minetest.get_node_or_nil(pos) then + local lightfunc = minetest.get_natural_light or minetest.get_node_light + return lightfunc(pos, tod) else return 0 end @@ -1608,7 +1121,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 @@ -1649,8 +1162,6 @@ 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", @@ -1667,8 +1178,6 @@ 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", @@ -1694,7 +1203,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 @@ -1720,7 +1229,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 @@ -1786,13 +1295,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 = -math_sin(yaw) * (self.collisionbox[4] + 0.5) - local dir_z = math_cos(yaw) * (self.collisionbox[4] + 0.5) + local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) + local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5) -- what is in front of mob? nod = node_ok({ @@ -1810,7 +1319,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 @@ -1819,12 +1328,12 @@ local do_jump = function(self) return false end - if self.walk_chance == 0 - or minetest_registered_items[nod.name].walkable then + local ndef = minetest.registered_nodes[nod.name] + if self.walk_chance == 0 or ndef and ndef.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() @@ -1835,7 +1344,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 @@ -1882,7 +1391,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 @@ -1892,7 +1401,7 @@ local entity_physics = function(pos, radius) dist = vector.distance(pos, obj_pos) if dist < 1 then dist = 1 end - local damage = math_floor((4 / dist) * radius) + local damage = floor((4 / dist) * radius) local ent = objs[n]:get_luaentity() -- punches work on entities AND players @@ -1972,14 +1481,14 @@ local breed = function(self) return end - -- horny animal can mate for BREED_TIME seconds, - -- afterwards horny animal cannot mate again for BREED_TIME_AGAIN seconds + -- horny animal can mate for HORNY_TIME seconds, + -- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds if self.horny == true - and self.hornytimer < BREED_TIME + BREED_TIME_AGAIN then + and self.hornytimer < HORNY_TIME + HORNY_AGAIN_TIME then self.hornytimer = self.hornytimer + 1 - if self.hornytimer >= BREED_TIME + BREED_TIME_AGAIN then + if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then self.hornytimer = 0 self.horny = false end @@ -1987,13 +1496,13 @@ local breed = function(self) -- find another same animal who is also horny and mate if nearby if self.horny == true - and self.hornytimer <= BREED_TIME then + and self.hornytimer <= HORNY_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 @@ -2026,18 +1535,18 @@ local breed = function(self) if ent and canmate == true and ent.horny == true - and ent.hornytimer <= BREED_TIME then + and ent.hornytimer <= HORNY_TIME then num = num + 1 end -- found your mate? then have a baby if num > 1 then - self.hornytimer = BREED_TIME + 1 - ent.hornytimer = BREED_TIME + 1 + self.hornytimer = HORNY_TIME + 1 + ent.hornytimer = HORNY_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 @@ -2047,7 +1556,7 @@ local breed = function(self) -- Give XP if mod_experience then - mcl_experience.throw_experience(pos, math.random(1, 7)) + mcl_experience.throw_xp(pos, math.random(1, 7)) end -- custom breed function @@ -2087,6 +1596,7 @@ local breed = function(self) end end + -- find and replace what mob is looking for (grass, wheat etc.) local replace = function(self, pos) @@ -2094,7 +1604,7 @@ local replace = function(self, pos) or not self.replace_what or self.child == true or self.object:get_velocity().y ~= 0 - or math.random(1, self.replace_rate) > 1 then + or random(1, self.replace_rate) > 1 then return end @@ -2102,7 +1612,7 @@ local replace = function(self, pos) if type(self.replace_what[1]) == "table" then - local num = math.random(#self.replace_what) + local num = random(#self.replace_what) what = self.replace_what[num][1] or "" with = self.replace_what[num][2] or "" @@ -2115,7 +1625,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} @@ -2129,7 +1639,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 @@ -2153,24 +1663,650 @@ local day_docile = function(self) end +local los_switcher = false +local height_switcher = false -local mob_detach_child = function(self, child) +-- 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) - if self.driver == child then - self.driver = nil + 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 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 -function do_states(self) + +-- 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 if self.state == "stand" then - if math.random(1, 4) == 1 then + if 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 @@ -2188,11 +2324,11 @@ function do_states(self) z = lp.z - s.z } - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - if lp.x > s.x then yaw = yaw + math_pi end + if lp.x > s.x then yaw = yaw + pi end else - yaw = yaw + math.random(-0.5, 0.5) + yaw = yaw + random(-0.5, 0.5) end yaw = set_yaw(self, yaw, 8) @@ -2207,7 +2343,7 @@ function do_states(self) if self.walk_chance ~= 0 and self.facing_fence ~= true - and math.random(1, 100) <= self.walk_chance + and random(1, 100) <= self.walk_chance and is_at_cliff_or_danger(self) == false then set_velocity(self, self.walk_velocity) @@ -2226,19 +2362,19 @@ function do_states(self) 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 @@ -2252,12 +2388,12 @@ function do_states(self) -- 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[math.random(#lp)] + lp = #lp > 0 and lp[random(#lp)] -- did we find land? if lp then @@ -2267,10 +2403,10 @@ function do_states(self) z = lp.z - s.z } - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - if lp.x > s.x then yaw = yaw + math_pi end + if lp.x > s.x then yaw = yaw + pi end -- look towards land and move in that direction yaw = set_yaw(self, yaw, 6) @@ -2283,8 +2419,8 @@ function do_states(self) else -- Randomly turn - if math.random(1, 100) <= 30 then - yaw = yaw + math.random(-0.5, 0.5) + if random(1, 100) <= 30 then + yaw = yaw + random(-0.5, 0.5) yaw = set_yaw(self, yaw, 8) end end @@ -2292,9 +2428,9 @@ function do_states(self) yaw = set_yaw(self, yaw, 8) -- otherwise randomly turn - elseif math.random(1, 100) <= 30 then + elseif random(1, 100) <= 30 then - yaw = yaw + math.random(-0.5, 0.5) + yaw = yaw + random(-0.5, 0.5) yaw = set_yaw(self, yaw, 8) end @@ -2305,7 +2441,7 @@ function do_states(self) end if self.facing_fence == true or cliff_or_danger - or math.random(1, 100) <= 30 then + or random(1, 100) <= 30 then set_velocity(self, 0) self.state = "stand" @@ -2380,9 +2516,9 @@ function do_states(self) z = p.z - s.z } - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - if p.x > s.x then yaw = yaw + math_pi end + if p.x > s.x then yaw = yaw + pi end yaw = set_yaw(self, yaw, 0, dtime) @@ -2448,10 +2584,10 @@ function do_states(self) 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 @@ -2476,9 +2612,9 @@ function do_states(self) and dist > self.reach then local p1 = s - local me_y = math_floor(p1.y) + local me_y = floor(p1.y) local p2 = p - local p_y = math_floor(p2.y + 1) + local p_y = floor(p2.y + 1) local v = self.object:get_velocity() if flight_check(self, s) then @@ -2539,7 +2675,7 @@ function do_states(self) return end - if math_abs(p1.x-s.x) + math_abs(p1.z - s.z) < 0.6 then + if abs(p1.x-s.x) + abs(p1.z - s.z) < 0.6 then -- reached waypoint, remove it from queue table.remove(self.path.way, 1) end @@ -2553,9 +2689,9 @@ function do_states(self) z = p.z - s.z } - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - if p.x > s.x then yaw = yaw + math_pi end + if p.x > s.x then yaw = yaw + pi end yaw = set_yaw(self, yaw, 0, dtime) @@ -2605,7 +2741,7 @@ function do_states(self) self.timer = 0 if self.double_melee_attack - and math.random(1, 2) == 1 then + and random(1, 2) == 1 then set_animation(self, "punch2") else set_animation(self, "punch") @@ -2658,9 +2794,9 @@ function do_states(self) z = p.z - s.z } - yaw = (atan(vec.z / vec.x) + math_pi / 2) - self.rotate + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - if p.x > s.x then yaw = yaw + math_pi end + if p.x > s.x then yaw = yaw + pi end yaw = set_yaw(self, yaw, 0, dtime) @@ -2671,8 +2807,8 @@ function do_states(self) if self.shoot_interval and self.timer > self.shoot_interval - and not minetest_raycast(p, self.attack:get_pos(), false, false):next() - and math.random(1, 100) <= 60 then + and not minetest.raycast(p, self.attack:get_pos(), false, false):next() + and random(1, 100) <= 60 then self.timer = 0 set_animation(self, "shoot") @@ -2681,22 +2817,26 @@ function do_states(self) 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 end ent.switch = 1 ent.owner_id = tostring(self.object) -- add unique owner id to arrow + + -- important for mcl_shields + ent._shooter = self.object + ent._saved_shooter_pos = self.object:get_pos() end local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5 @@ -2718,251 +2858,807 @@ function do_states(self) end +-- falling and fall damage +-- returns true if mob died +local falling = function(self, pos) - --- 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 + if self.fly and self.state ~= "die" then return 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 + 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 - self.animation.current = anim + -- floating in water (or falling) + local v = self.object:get_velocity() - local a_start = self.animation[anim .. "_start"] - local a_end - if fixed_frame then - a_end = a_start + 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 - a_end = self.animation[anim .. "_end"] + -- stop accelerating once max fall speed hit + self.object:set_acceleration({x = 0, y = 0, z = 0}) 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 + if minetest.registered_nodes[node_ok(pos).name].groups.lava then + if self.floats_on_lava == 1 then --- Code to execute before custom on_rightclick handling -local function on_rightclick_prefix(self, clicker) - local item = clicker:get_wielded_item() + self.object:set_acceleration({ + x = 0, + y = -self.fall_speed / (max(1, v.y) ^ 2), + z = 0 + }) + end + end - -- Name mob with nametag - if not self.ignores_nametag and item:get_name() == "mcl_mobs:nametag" then + -- in water then float up + if minetest.registered_nodes[node_ok(pos).name].groups.water 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) + 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.nametag = tag - update_tag(self) - - if not mobs.is_creative(clicker:get_player_name()) then - item:take_item() - clicker:set_wielded_item(item) - end - return true + self.old_y = self.object:get_pos().y end - end - return false end ---[[local function create_mob_on_rightclick(on_rightclick) - return function(self, clicker) - local stop = on_rightclick_prefix(self, clicker) - if (not stop) and (on_rightclick) then - on_rightclick(self, clicker) +local teleport = function(self, target) + if self.do_teleport then + if self.do_teleport(self, target) == false then + return end end -end]] - --- set and return valid yaw -local function set_yaw(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.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 +-- deal damage and effects when mob punched +local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) - ---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 - - - - --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 + -- custom punch function + if self.do_punch then -- when false skip going any further - --if self.do_custom(self, dtime) == false then - -- return - --end - --end + 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 + if self.pause_timer > 0 then - -- self.pause_timer = self.pause_timer - dtime + self.pause_timer = self.pause_timer - dtime - -- return - --end + return + end -- attack timer - --self.timer = self.timer + dtime + 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 - ]]-- -- never go over 100 - --if self.timer > 100 then - -- self.timer = 1 - --end + if self.timer > 100 then + self.timer = 1 + end -- mob plays random sound at times - --if math.random(1, 70) == 1 then - -- mob_sound(self, "random", true) - --end + 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 + 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 - --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 + replace(self, pos) + end - --monster_attack(self) + monster_attack(self) - --npc_attack(self) + npc_attack(self) - --breed(self) + breed(self) - --do_jump(self) - - --runaway_from(self) - - - --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 - - - -- 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) + 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" @@ -2991,6 +3687,698 @@ end end 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) + 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 + + 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 + +local create_mob_on_rightclick = function(on_rightclick) + return function(self, clicker) + local stop = on_rightclick_prefix(self, clicker) + if (not stop) and (on_rightclick) then + on_rightclick(self, clicker) + end + end +end + +-- register mob entity +function mobs:register_mob(name, def) + + 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) + 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 + + -- delete the object after it punched the player to avoid nil entities in e.g. mcl_shields!! + self.object:remove() +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 + + 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, + }) + +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 +end + + +-- No-op in MCL2 (protecting mobs is not possible). +function mobs:protect(self, clicker) + return false +end + + +-- feeding, taming and breeding (thanks blert2112) +function mobs:feed_tame(self, clicker, feed_count, breed, tame) + if not self.follow then + return false + end + + -- 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 + + mob_sound(self, "eat", nil, true) + + -- increase health + self.health = self.health + 4 + + if self.health >= self.hp_max then + + self.health = self.hp_max + + if self.htimer < 1 then + self.htimer = 5 + end + end + + 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 + + -- 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 + return + end + + local ent = child:get_luaentity() + effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5) + + ent.child = true + + local textures + -- using specific child texture (if found) + if ent.child_texture then + textures = ent.child_texture[1] + 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 + + 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 + end + end + end + timer = 0 +end) diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index 2d8cef5b0e..eda74aeb42 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -502,6 +502,20 @@ 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 --------------------------- @@ -521,6 +535,19 @@ 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 ----------- @@ -578,7 +605,7 @@ Note: animation names above are from the pre-defined animation lists inside mob registry without extensions. -mobs.set_mob_animation(self, name) +mobs:set_animation(self, name) This function sets the current animation for mob, defaulting to "stand" if not found. @@ -754,5 +781,8 @@ 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 deleted file mode 100644 index 639eb517d4..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/api.lua +++ /dev/null @@ -1,736 +0,0 @@ --- 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_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 = math - --- localize vector functions -local vector = vector - -local string = string - --- 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 MAX_MOB_NAME_LENGTH = 30 - - ---[[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") ---local mod_explosions = minetest_get_modpath("mcl_explosions") -local mod_mobspawners = minetest_get_modpath("mcl_mobspawners") ---local mod_hunger = minetest_get_modpath("mcl_hunger") ---local mod_worlds = minetest_get_modpath("mcl_worlds") ---local mod_armor = minetest_get_modpath("mcl_armor") ---local mod_experience = minetest_get_modpath("mcl_experience") - - --- random locals I found ---local los_switcher = false ---local height_switcher = false - --- Get translator -local S = minetest.get_translator(minetest.get_current_modname()) - --- CMI support check ---local use_cmi = minetest.global_exists("cmi") - --- creative check -function mobs.is_creative(name) - return minetest_is_creative_enabled(name) -end - ---[[local function atan(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 .. "flow_lib.lua") -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 - - --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") 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 deleted file mode 100644 index 88ce3274bb..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/ai.lua +++ /dev/null @@ -1,1128 +0,0 @@ -local math = math -local vector = vector -local string = string - -local tonumber = tonumber - -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 minetest_registered_nodes = minetest.registered_nodes -local flow = mobs.get_flowing_dir - -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 function quick_rotate(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 -local function round2(num, numDecimalPlaces) - return tonumber(string.format("%." .. (numDecimalPlaces or 0) .. "f", num)) -end - - ---[[ - _ _ -| | | | -| | __ _ _ __ __| | -| | / _` | '_ \ / _` | -| |___| (_| | | | | (_| | -\_____/\__,_|_| |_|\__,_| -]]-- - ---this is basically reverse jump_check -local function cliff_check(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 = 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 function land_state_switch(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 function land_state_execution(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) - minetest.add_entity(baby_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 function swim_state_switch(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 function swim_turn_check(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 function swim_physics_swapper(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 function swim_state_execution(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 function fly_state_switch(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 function fly_turn_check(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 function fly_physics_swapper(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 function fly_state_execution(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 function jump_turn_check(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 function jump_state_switch(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 function jump_state_execution(self, dtime) - local node_in_front_of = mobs.jump_check(self) - 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 -function mobs.mob_step(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 then - local light_current, light_day = minetest_get_node_light(pos), minetest_get_node_light(pos, 0.5) - if light_current and light_day and light_current > 12 and light_day == 15 then - mcl_burning.set_on_fire(self.object, 1) - self.burn_timer = 1 --1.7 seconds - self.pause_timer = 0.4 - end - 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 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 - - --mobs flow from Crafter - local pos = self.object:get_pos() - if pos then - local flow_dir = flow(pos) - if flow_dir then - flow_dir = vector.multiply(flow_dir,10) - local vel = self.object:get_velocity() - local acceleration = vector.new(flow_dir.x-vel.x,flow_dir.y-vel.y,flow_dir.z-vel.z) - acceleration = vector.multiply(acceleration, 0.01) - self.object:add_velocity(acceleration) - 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 deleted file mode 100644 index cea6d838b2..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/animation.lua +++ /dev/null @@ -1,257 +0,0 @@ -local math = math -local vector = vector - -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 deleted file mode 100644 index ac10194e58..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/attack_type_instructions.lua +++ /dev/null @@ -1,347 +0,0 @@ -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 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 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/mob_functions/breeding.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/breeding.lua deleted file mode 100644 index c50fb63001..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/breeding.lua +++ /dev/null @@ -1,179 +0,0 @@ -local minetest_get_objects_inside_radius = minetest.get_objects_inside_radius - -local vector = vector - ---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 minetest.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 deleted file mode 100644 index ed9aec6cd4..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/collision.lua +++ /dev/null @@ -1,135 +0,0 @@ -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 deleted file mode 100644 index 4e6b7ca462..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/death_logic.lua +++ /dev/null @@ -1,161 +0,0 @@ -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 - 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) - - --stop crashing game when object is nil - if not self or not self.object or not self.object:get_luaentity() then - return - end - - 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_xp(self.object:get_pos(), math_random(self.xp_min, self.xp_max)) - if self.on_die then - self.on_die(self, self.object:get_pos()) - end - self.object:remove() - return - end - - --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 diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/environment.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/environment.lua deleted file mode 100644 index 5c431135e8..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/environment.lua +++ /dev/null @@ -1,250 +0,0 @@ -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 function do_tnt(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) - local wmin, wmax - 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 - 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/flow_lib.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/flow_lib.lua deleted file mode 100644 index aa64bfb4e6..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/flow_lib.lua +++ /dev/null @@ -1,78 +0,0 @@ ---this is from https://github.com/HybridDog/builtin_item/blob/e6dfd9dce86503b3cbd1474257eca5f6f6ca71c2/init.lua#L50 -local -minetest,vector,math,pairs,minetest_get_node,vector_subtract,minetest_registered_nodes -= -minetest,vector,math,pairs,minetest.get_node,vector.subtract,minetest.registered_nodes - -local tab -local n -local function get_nodes(pos) - tab,n = {},1 - for i = -1,1,2 do - for _,p in pairs({ - {x=pos.x+i, y=pos.y, z=pos.z}, - {x=pos.x, y=pos.y, z=pos.z+i} - }) do - tab[n] = {p, minetest_get_node(p)} - n = n+1 - end - end - return tab -end - - -local data -local param2 -local nd -local par2 -local name -local tmp -local c_node -function mobs.get_flowing_dir(pos) - c_node = minetest_get_node(pos).name - if c_node ~= "mcl_core:water_flowing" and c_node ~= "mcl_core:water" then - return nil - end - data = get_nodes(pos) - param2 = minetest_get_node(pos).param2 - if param2 > 7 then - return nil - end - if c_node == "mcl_core:water" then - for _,i in pairs(data) do - nd = i[2] - name = nd.name - par2 = nd.param2 - if name == "mcl_core:water_flowing" and par2 == 7 then - return(vector_subtract(i[1],pos)) - end - end - end - for _,i in pairs(data) do - nd = i[2] - name = nd.name - par2 = nd.param2 - if name == "mcl_core:water_flowing" and par2 < param2 then - return(vector_subtract(i[1],pos)) - end - end - for _,i in pairs(data) do - nd = i[2] - name = nd.name - par2 = nd.param2 - if name == "mcl_core:water_flowing" and par2 >= 11 then - return(vector_subtract(i[1],pos)) - end - end - for _,i in pairs(data) do - nd = i[2] - name = nd.name - par2 = nd.param2 - tmp = minetest_registered_nodes[name] - if tmp and not tmp.walkable and name ~= "mcl_core:water_flowing" and name ~= "mcl_core:water" then - return(vector_subtract(i[1],pos)) - end - end - - return nil -end diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/head_logic.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/head_logic.lua deleted file mode 100644 index 0f5615504d..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/head_logic.lua +++ /dev/null @@ -1,98 +0,0 @@ -local math = math -local vector = vector - ---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 = 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 deleted file mode 100644 index fa5b312102..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/interaction.lua +++ /dev/null @@ -1,276 +0,0 @@ -local minetest_after = minetest.after -local minetest_sound_play = minetest.sound_play -local minetest_dir_to_yaw = minetest.dir_to_yaw - -local math = math -local vector = vector - -local MAX_MOB_NAME_LENGTH = 30 - -local mod_hunger = minetest.get_modpath("mcl_hunger") - -mobs.feed_tame = function(self) - return nil -end - --- Code to execute before custom on_rightclick handling -local function on_rightclick_prefix(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 {} - - --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 deleted file mode 100644 index 83df809928..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/mob_effects.lua +++ /dev/null @@ -1,150 +0,0 @@ -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 deleted file mode 100644 index d9698a0a75..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/movement.lua +++ /dev/null @@ -1,390 +0,0 @@ --- localize math functions -local math = math -local HALF_PI = math.pi / 2 -local DOUBLE_PI = math.pi * 2 - --- localize vector functions -local vector = vector - -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) - - local acceleration = self.object:get_acceleration() - - if not acceleration then - return - end - - if acceleration.y ~= 0 then - self.object:set_acceleration({x=0, y=0, z=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 - local 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 diff --git a/mods/ENTITIES/mcl_mobs/api/mob_functions/projectile_handling.lua b/mods/ENTITIES/mcl_mobs/api/mob_functions/projectile_handling.lua deleted file mode 100644 index a4b4c075ea..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/projectile_handling.lua +++ /dev/null @@ -1,43 +0,0 @@ -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 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 deleted file mode 100644 index 65ba764f66..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/set_up.lua +++ /dev/null @@ -1,224 +0,0 @@ -local math_random = math.random - -local minetest_settings = minetest.settings - --- CMI support check -local use_cmi = minetest.global_exists("cmi") - --- 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 deleted file mode 100644 index 98d2644e80..0000000000 --- a/mods/ENTITIES/mcl_mobs/api/mob_functions/sound_handling.lua +++ /dev/null @@ -1,59 +0,0 @@ -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/crafts.lua b/mods/ENTITIES/mcl_mobs/crafts.lua index 2b23c6f58b..e8a5b60fc2 100644 --- a/mods/ENTITIES/mcl_mobs/crafts.lua +++ b/mods/ENTITIES/mcl_mobs/crafts.lua @@ -1,5 +1,5 @@ -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mcl_mobs") -- name tag minetest.register_craftitem("mcl_mobs:nametag", { diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index b0daba2c4b..69246b4706 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -1,16 +1,14 @@ local path = minetest.get_modpath(minetest.get_current_modname()) -local api_path = path.."/api" - -- Mob API -dofile(api_path .. "/api.lua") +dofile(path .. "/api.lua") -- Spawning Algorithm -dofile(api_path .. "/spawning.lua") +dofile(path .. "/spawning.lua") -- Rideable Mobs -dofile(api_path .. "/mount.lua") +dofile(path .. "/mount.lua") -- Mob Items dofile(path .. "/crafts.lua") \ No newline at end of file diff --git a/mods/ENTITIES/mcl_mobs/locale/mcl_mobs.pl.tr b/mods/ENTITIES/mcl_mobs/locale/mcl_mobs.pl.tr deleted file mode 100644 index 96dc1ea155..0000000000 --- a/mods/ENTITIES/mcl_mobs/locale/mcl_mobs.pl.tr +++ /dev/null @@ -1,11 +0,0 @@ -# textdomain: mcl_mobs -Peaceful mode active! No monsters will spawn.=Tryb pokojowy aktywowany! Potwory nie będą się pojawiać. -This allows you to place a single mob.=To pozwala na przywołanie jednego moba. -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.=Postaw to w miejscu w którym chcesz aby pojawił się mob. Zwierzęta pojawią się jako oswojone chyba, że będziesz się skradał podczas stawiania. Jeśli postawisz to na spawnerze to zmienisz którego moba przywołuje. -You need the “maphack” privilege to change the mob spawner.=Potrzebujesz przywileju "maphack", aby zmienić spawner. -Name Tag=Znacznik -A name tag is an item to name a mob.=Znacznik jest przedmiotem pozwalającym nazwać moba. -Before you use the name tag, you need to set a name at an anvil. Then you can use the name tag to name a mob. This uses up the name tag.=Zanim użyjesz znacznika musisz wybrać imię przy kowadle. Następnie możesz użyć znacznika by nazwać moba. To zużywa znacznik. -Only peaceful mobs allowed!=Tylko pokojowe moby są dozwolone! -Give names to mobs=Nazwij moby -Set name at anvil=Wybierz imię przy kowadle diff --git a/mods/ENTITIES/mcl_mobs/locale/mcl_mobs.zh_TW.tr b/mods/ENTITIES/mcl_mobs/locale/mcl_mobs.zh_TW.tr new file mode 100644 index 0000000000..90d24fd21f --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/locale/mcl_mobs.zh_TW.tr @@ -0,0 +1,11 @@ +# textdomain: mcl_mobs +Peaceful mode active! No monsters will spawn.=和平模式已啓用!不會生成怪物。 +This allows you to place a single mob.=允許你放置一個生物。 +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.=把它放在你希望生物出現的地方。除非你在放置的時候按住潛行鍵,否則動物會被馴服地產生。如果你把它放在一個生怪磚上,你就會改變它所產的生物。 +You need the “maphack” privilege to change the mob spawner.=你要「maphack」權限來修改生怪磚。 +Name Tag=命名牌 +A name tag is an item to name a mob.=命名牌是一個用於命名生物的物品 +Before you use the name tag, you need to set a name at an anvil. Then you can use the name tag to name a mob. This uses up the name tag.=在使用名字標籤之前,你需要在一個鐵砧上設置一個名字。然後你就可以用名字標籤來給生物命名。這會消耗命名牌。 +Only peaceful mobs allowed!=只允許和平生物! +Give names to mobs=替生物命名 +Set name at anvil=在鐵砧上設置名字 diff --git a/mods/ENTITIES/mcl_mobs/lucky_block.lua b/mods/ENTITIES/mcl_mobs/lucky_block.lua new file mode 100644 index 0000000000..ea90de74ac --- /dev/null +++ b/mods/ENTITIES/mcl_mobs/lucky_block.lua @@ -0,0 +1,8 @@ + +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/mod.conf b/mods/ENTITIES/mcl_mobs/mod.conf index 2a91a7764b..0d622f6a9a 100644 --- a/mods/ENTITIES/mcl_mobs/mod.conf +++ b/mods/ENTITIES/mcl_mobs/mod.conf @@ -2,4 +2,4 @@ name = mcl_mobs author = PilzAdam description = Adds a mob API for mods to add animals or monsters, etc. depends = mcl_particles -optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience +optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience diff --git a/mods/ENTITIES/mcl_mobs/api/mount.lua b/mods/ENTITIES/mcl_mobs/mount.lua similarity index 88% rename from mods/ENTITIES/mcl_mobs/api/mount.lua rename to mods/ENTITIES/mcl_mobs/mount.lua index 0ed54a46e2..9383ee067c 100644 --- a/mods/ENTITIES/mcl_mobs/api/mount.lua +++ b/mods/ENTITIES/mcl_mobs/mount.lua @@ -1,11 +1,8 @@ -- lib_mount by Blert2112 (edited by TenPlus1) ---local enable_crash = false ---local crash_threshold = 6.5 -- ignored if enable_crash=false - -local math = math -local vector = vector +local enable_crash = false +local crash_threshold = 6.5 -- ignored if enable_crash=false ------------------------------------------------------------------------------ @@ -13,7 +10,7 @@ local vector = vector -- Helper functions -- ---[[local function node_ok(pos, fallback) +local node_ok = function(pos, fallback) fallback = fallback or mobs.fallback_node @@ -24,10 +21,10 @@ local vector = vector end return {name = fallback} -end]] +end ---[[local function node_is(pos) +local function node_is(pos) local node = node_ok(pos) @@ -48,7 +45,7 @@ end]] end return "other" -end]] +end local function get_sign(i) @@ -63,11 +60,13 @@ local function get_sign(i) end ---[[local function get_velocity(v, yaw, y) +local function get_velocity(v, yaw, y) + local x = -math.sin(yaw) * v local z = math.cos(yaw) * v + return {x = x, y = y, z = z} -end]] +end local function get_v(v) @@ -173,7 +172,7 @@ function mobs.detach(player, offset) --pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z} - player:add_velocity(vector.new(math.random(-6,6), math.random(5,8), math.random(-6,6))) --throw the rider off + player:add_velocity(vector.new(math.random(-6,6),math.random(5,8),math.random(-6,6))) --throw the rider off --[[ minetest.after(0.1, function(name, pos) @@ -188,13 +187,13 @@ end function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) - --local rot_view = 0 + local rot_view = 0 - --if entity.player_rotation.y == 90 then - -- rot_view = math.pi/2 - --end + if entity.player_rotation.y == 90 then + rot_view = math.pi/2 + end - --local acce_y = 0 + local acce_y = 0 local velo = entity.object:get_velocity() entity.v = get_v(velo) * get_sign(entity.v) @@ -207,30 +206,21 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) -- move forwards if ctrl.up then - mobs.set_velocity(entity, entity.run_velocity) - - mobs.set_mob_animation(entity, moving_anim) + entity.v = entity.v + entity.accel / 10 -- move backwards elseif ctrl.down then - mobs.set_velocity(entity, -entity.run_velocity) + if entity.max_speed_reverse == 0 and entity.v == 0 then + return + end - mobs.set_mob_animation(entity, moving_anim) - - --halt - else - - mobs.set_velocity(entity, 0) - - mobs.set_mob_animation(entity, stand_anim) + entity.v = entity.v - entity.accel / 10 end - -- mob rotation + -- fix 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 @@ -254,21 +244,32 @@ 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 - mobs.jump(entity) 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) + end + + return + end + -- set moving animation if moving_anim then - mobs:set_mob_animation(entity, moving_anim) + mobs:set_animation(entity, moving_anim) end -- Stop! @@ -382,17 +383,13 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) end entity.v2 = v - ]]-- end -- directional flying routine by D00Med (edited by TenPlus1) 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() @@ -443,9 +440,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_mob_animation(entity, stand_anim) + mobs:set_animation(entity, stand_anim) else -- moving animation - mobs:set_mob_animation(entity, moving_anim) + mobs:set_animation(entity, moving_anim) end end diff --git a/mods/ENTITIES/mcl_mobs/README.md b/mods/ENTITIES/mcl_mobs/readme.MD similarity index 100% rename from mods/ENTITIES/mcl_mobs/README.md rename to mods/ENTITIES/mcl_mobs/readme.MD diff --git a/mods/ENTITIES/mcl_mobs/sounds/attributes.txt b/mods/ENTITIES/mcl_mobs/sounds/attributes.txt deleted file mode 100644 index 1228dd9d7d..0000000000 --- a/mods/ENTITIES/mcl_mobs/sounds/attributes.txt +++ /dev/null @@ -1,4 +0,0 @@ - -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 deleted file mode 100644 index 4d7ba8015e..0000000000 Binary files a/mods/ENTITIES/mcl_mobs/sounds/default_punch.1.ogg and /dev/null differ diff --git a/mods/ENTITIES/mcl_mobs/sounds/default_punch.2.ogg b/mods/ENTITIES/mcl_mobs/sounds/default_punch.2.ogg deleted file mode 100644 index c022d94f87..0000000000 Binary files a/mods/ENTITIES/mcl_mobs/sounds/default_punch.2.ogg and /dev/null differ diff --git a/mods/ENTITIES/mcl_mobs/sounds/default_punch.3.ogg b/mods/ENTITIES/mcl_mobs/sounds/default_punch.3.ogg deleted file mode 100644 index 4c5e3f9b30..0000000000 Binary files a/mods/ENTITIES/mcl_mobs/sounds/default_punch.3.ogg and /dev/null differ diff --git a/mods/ENTITIES/mcl_mobs/sounds/default_punch.ogg b/mods/ENTITIES/mcl_mobs/sounds/default_punch.ogg new file mode 100644 index 0000000000..28a500bf57 Binary files /dev/null and b/mods/ENTITIES/mcl_mobs/sounds/default_punch.ogg differ diff --git a/mods/ENTITIES/mcl_mobs/api/spawning.lua b/mods/ENTITIES/mcl_mobs/spawning.lua similarity index 65% rename from mods/ENTITIES/mcl_mobs/api/spawning.lua rename to mods/ENTITIES/mcl_mobs/spawning.lua index bf07ca94d5..2e7f523ba0 100644 --- a/mods/ENTITIES/mcl_mobs/api/spawning.lua +++ b/mods/ENTITIES/mcl_mobs/spawning.lua @@ -1,32 +1,17 @@ --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 get_biome_name = minetest.get_biome_name -local get_objects_inside_radius = minetest.get_objects_inside_radius -local get_connected_players = minetest.get_connected_players - - +local new_vector = vector.new local math_random = math.random -local math_floor = math.floor ---local max = math.max - ---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 - -local pairs = pairs +local get_biome_name = minetest.get_biome_name +local max = math.max +local get_objects_inside_radius = minetest.get_objects_inside_radius +local vector_distance = vector.distance -- range for mob count -local aoc_range = 48 - ---do mobs spawn? -local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false - +local aoc_range = 32 --[[ THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs @@ -168,14 +153,28 @@ Overworld regular: --- count how many mobs are in an area -local function count_mobs(pos) + +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) local num = 0 - 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 + 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 end end + return num end @@ -244,7 +243,8 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh end --[[ - local function spawn_action(pos, node, active_object_count, active_object_count_wider, name) + local spawn_action + spawn_action = function(pos, node, active_object_count, active_object_count_wider, name) local orig_pos = table.copy(pos) -- is mob actually registered? @@ -281,7 +281,7 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh end -- if toggle set to nil then ignore day/night check - if day_toggle then + if day_toggle ~= nil then local tod = (minetest.get_timeofday() or 0) * 24000 @@ -371,7 +371,7 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh if minetest.registered_nodes[node_ok(pos2).name].walkable == true then -- inside block minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") - if ent.spawn_small_alternative and (not minetest.registered_nodes[node_ok(pos).name].walkable) then + if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative) spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative) end @@ -484,26 +484,25 @@ end local axis --inner and outer part of square donut radius -local inner = 15 -local outer = 64 +local inner = 1 +local outer = 65 local int = {-1,1} +local position_calculation = function(pos) -local function position_calculation(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 + return(pos) end --[[ @@ -517,7 +516,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 @@ -540,169 +539,118 @@ if mobs_spawn then local timer = 0 minetest.register_globalstep(function(dtime) timer = timer + dtime - if timer >= 10 then + if timer >= 8 then timer = 0 - for _,player in pairs(get_connected_players()) do - -- 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 + 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() - local player_pos = player:get_pos() - local dimension = mcl_worlds.pos_to_dimension(player_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) - for i = 1, math_random(1,4) do - -- after this line each "break" means "continue" - local do_mob_algorithm = true - repeat + local goal_pos = position_calculation(player_pos) - 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) + 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"}) + --couldn't find node + if #spawning_position_list <= 0 then break - until do_mob_algorithm == false --this is a safety catch - end + end - break - until do_mob_spawning == false --this is a performance catch + 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) + local gotten_node_name = gotten_node.name + local gotten_node_def = minetest.registered_nodes[gotten_node_name] + + if not gotten_node_name or not gotten_node_def or gotten_node_name == "air" then --skip air nodes + break + end + + if gotten_node_def.use_texture_alpha and gotten_node_def.use_texture_alpha ~= "opaque" then + break + end --don't spawn on nonopaque nodes + + local leaf = minetest.get_item_group(gotten_node_name,"leaves") + if leaf ~= 0 then + break end --don't spawn on treetops + + 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_name, "water") ~= 0 + local is_lava = get_item_group(gotten_node_name, "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 end end end) diff --git a/mods/ENTITIES/mcl_mobs/todo.txt b/mods/ENTITIES/mcl_mobs/todo.txt deleted file mode 100644 index 7598b14ed8..0000000000 --- a/mods/ENTITIES/mcl_mobs/todo.txt +++ /dev/null @@ -1 +0,0 @@ ---use vector.distance to count down mob despawn timer \ No newline at end of file diff --git a/mods/ENTITIES/mcl_paintings/locale/mcl_paintings.zh_TW.tr b/mods/ENTITIES/mcl_paintings/locale/mcl_paintings.zh_TW.tr new file mode 100644 index 0000000000..d4b792185d --- /dev/null +++ b/mods/ENTITIES/mcl_paintings/locale/mcl_paintings.zh_TW.tr @@ -0,0 +1,2 @@ +# textdomain:mcl_paintings +Painting=畫 diff --git a/mods/ENTITIES/mobs_mc/0_gameconfig.lua b/mods/ENTITIES/mobs_mc/0_gameconfig.lua index f21d946fef..c92ccbba52 100644 --- a/mods/ENTITIES/mobs_mc/0_gameconfig.lua +++ b/mods/ENTITIES/mobs_mc/0_gameconfig.lua @@ -15,7 +15,7 @@ with name "mobs_mc_gameconfig". ]] -- Set to false in your gameconfig mod if you create your own monster egg nodes. mobs_mc.create_monster_egg_nodes = true ---mobs_mc.items = {} +mobs_mc.items = {} mobs_mc.items = { -- Items defined in mobs_mc @@ -81,9 +81,7 @@ mobs_mc.items = { gunpowder = "tnt:gunpowder", flint_and_steel = "fire:flint_and_steel", water_source = "default:water_source", - water_flowing = "default:water_flowing", river_water_source = "default:river_water_source", - --water_flowing = "default:river_water_flowing", black_dye = "dye:black", poppy = "flowers:rose", dandelion = "flowers:dandelion_yellow", @@ -128,6 +126,7 @@ mobs_mc.items = { nether_portal = "nether:portal", netherrack = "nether:rack", + nether_brick_block = "nether:brick", -- Wool (Minecraft color scheme) wool_white = "wool:white", diff --git a/mods/ENTITIES/mobs_mc/1_items_default.lua b/mods/ENTITIES/mobs_mc/1_items_default.lua index c8ac421cc9..d792af0a26 100644 --- a/mods/ENTITIES/mobs_mc/1_items_default.lua +++ b/mods/ENTITIES/mobs_mc/1_items_default.lua @@ -525,7 +525,7 @@ if c("totem") then inventory_image = "mcl_totems_totem.png", wield_image = "mcl_totems_totem.png", stack_max = 1, - groups = {combat_item=1}, + groups = {combat_item = 1, offhand_item = 1}, }) end diff --git a/mods/ENTITIES/mobs_mc/2_throwing.lua b/mods/ENTITIES/mobs_mc/2_throwing.lua index d97351ac02..23ae86d80a 100644 --- a/mods/ENTITIES/mobs_mc/2_throwing.lua +++ b/mods/ENTITIES/mobs_mc/2_throwing.lua @@ -6,7 +6,7 @@ -- NOTE: Strings intentionally not marked for translation, other mods already have these items. -- TODO: Remove this file eventually, all items here are already outsourced in other mods. ---local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --maikerumines throwing code --arrow (weapon) @@ -83,7 +83,7 @@ THROWING_ARROW_ENTITY.on_step = function(self, dtime) if self.timer>0.2 then local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, 1.5) for k, obj in pairs(objs) do - if obj:get_luaentity() then + if obj:get_luaentity() ~= nil then if obj:get_luaentity().name ~= "mobs_mc:arrow_entity" and obj:get_luaentity().name ~= "__builtin:item" then local damage = 3 minetest.sound_play("damage", {pos = pos}, true) @@ -108,7 +108,7 @@ THROWING_ARROW_ENTITY.on_step = function(self, dtime) if self.lastpos.x~=nil then if node.name ~= "air" then minetest.sound_play("bowhit1", {pos = pos}, true) - minetest.add_item(self.lastpos, "mobs_mc:arrow") + minetest.add_item(self.lastpos, 'mobs_mc:arrow') self.object:remove() end end @@ -155,7 +155,7 @@ end if c("arrow") and c("flint") and c("feather") and c("stick") then minetest.register_craft({ - output = "mobs_mc:arrow 4", + output = 'mobs_mc:arrow 4', recipe = { {mobs_mc.items.flint}, {mobs_mc.items.stick}, @@ -181,11 +181,11 @@ if c("bow") then }) minetest.register_craft({ - output = "mobs_mc:bow_wood", + output = 'mobs_mc:bow_wood', recipe = { - {mobs_mc.items.string, mobs_mc.items.stick, ""}, - {mobs_mc.items.string, "", mobs_mc.items.stick}, - {mobs_mc.items.string, mobs_mc.items.stick, ""}, + {mobs_mc.items.string, mobs_mc.items.stick, ''}, + {mobs_mc.items.string, '', mobs_mc.items.stick}, + {mobs_mc.items.string, mobs_mc.items.stick, ''}, } }) end @@ -259,7 +259,7 @@ if c("egg") then }) -- shoot egg - local function mobs_shoot_egg(item, player, pointed_thing) + local mobs_shoot_egg = function (item, player, pointed_thing) local playerpos = player:get_pos() @@ -349,7 +349,7 @@ mobs:register_arrow("mobs_mc:snowball_entity", { if c("snowball") then -- shoot snowball - local function mobs_shoot_snowball(item, player, pointed_thing) + local mobs_shoot_snowball = function (item, player, pointed_thing) local playerpos = player:get_pos() diff --git a/mods/ENTITIES/mobs_mc/3_shared.lua b/mods/ENTITIES/mobs_mc/3_shared.lua index fce0850b45..e30e41cf3e 100644 --- a/mods/ENTITIES/mobs_mc/3_shared.lua +++ b/mods/ENTITIES/mobs_mc/3_shared.lua @@ -50,8 +50,10 @@ mobs_mc.make_owner_teleport_function = function(dist, teleport_check_interval) local telepos_below = {x=telepos.x, y=telepos.y-1, z=telepos.z} table.remove(check_offsets, r) -- Long story short, spawn on a platform - if minetest.registered_nodes[minetest.get_node(telepos).name].walkable == false and - minetest.registered_nodes[minetest.get_node(telepos_below).name].walkable == true then + local trynode = minetest.registered_nodes[minetest.get_node(telepos).name] + local trybelownode = minetest.registered_nodes[minetest.get_node(telepos_below).name] + if trynode and not trynode.walkable and + trybelownode and trybelownode.walkable then -- Correct position found! Let's teleport. self.object:set_pos(telepos) return diff --git a/mods/ENTITIES/mobs_mc/4_heads.lua b/mods/ENTITIES/mobs_mc/4_heads.lua index ecd09ee021..01b8ee5775 100644 --- a/mods/ENTITIES/mobs_mc/4_heads.lua +++ b/mods/ENTITIES/mobs_mc/4_heads.lua @@ -3,9 +3,8 @@ -- NOTE: Strings intentionally not marked for translation, other mods already have these items. -- TODO: Remove this file eventually, all items here are already outsourced in other mods. --- TODO: Add translation. ---local S = local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") -- Heads system diff --git a/mods/ENTITIES/mobs_mc/LICENSE-media.md b/mods/ENTITIES/mobs_mc/LICENSE-media.md index 3bfe70a151..dad31abb85 100644 --- a/mods/ENTITIES/mobs_mc/LICENSE-media.md +++ b/mods/ENTITIES/mobs_mc/LICENSE-media.md @@ -190,10 +190,9 @@ Origin of those models: * [Spennnyyy](https://freesound.org/people/Spennnyyy/) (CC0) * `mcl_totems_totem.ogg` * Source: -* [Baŝto](https://opengameart.org/users/ba%C5%9Dto) (remixer) and [kantouth](https://freesound.org/people/kantouth/) (original author) +* [Baŝto](https://opengameart.org/users/ba%C5%9Dto) * `mobs_mc_skeleton_random.*.ogg` (CC BY 3.0) * Source: - * Based on: * [spookymodem](https://freesound.org/people/spookymodem/) * `mobs_mc_skeleton_death.ogg` (CC0) * @@ -307,4 +306,4 @@ Origin of those models: Note: Many of these sounds have been more or less modified to fit the game. -Sounds not mentioned here are licensed under CC0. +Sounds not mentioned hre are licensed under CC0. diff --git a/mods/ENTITIES/mobs_mc/agent.lua b/mods/ENTITIES/mobs_mc/agent.lua index 8475f92fce..cc9910ee6d 100644 --- a/mods/ENTITIES/mobs_mc/agent.lua +++ b/mods/ENTITIES/mobs_mc/agent.lua @@ -2,7 +2,7 @@ --################### AGENT - seemingly unused --################### -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:agent", { type = "npc", diff --git a/mods/ENTITIES/mobs_mc/bat.lua b/mods/ENTITIES/mobs_mc/bat.lua index 5492add742..e9e1c1a16e 100644 --- a/mods/ENTITIES/mobs_mc/bat.lua +++ b/mods/ENTITIES/mobs_mc/bat.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:bat", { description = S("Bat"), @@ -8,9 +8,6 @@ mobs:register_mob("mobs_mc:bat", { spawn_class = "ambient", can_despawn = true, passive = true, - rotate = 270, - tilt_fly = true, - fly = true, hp_min = 6, hp_max = 6, collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25}, @@ -48,7 +45,9 @@ mobs:register_mob("mobs_mc:bat", { fall_damage = 0, view_range = 16, fear_height = 0, + jump = false, + fly = true, makes_footstep_sound = false, }) diff --git a/mods/ENTITIES/mobs_mc/blaze.lua b/mods/ENTITIES/mobs_mc/blaze.lua index 0f62c5388d..577ed7107c 100644 --- a/mods/ENTITIES/mobs_mc/blaze.lua +++ b/mods/ENTITIES/mobs_mc/blaze.lua @@ -3,7 +3,9 @@ -- Model and mobs_blaze.png see https://github.com/22i/minecraft-voxel-blender-models -hi 22i ~jordan4ibanez -- blaze.lua partial copy of mobs_mc/ghast.lua -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") + +local mod_target = minetest.get_modpath("mcl_target") --################### --################### BLAZE @@ -18,9 +20,6 @@ mobs:register_mob("mobs_mc:blaze", { hp_max = 20, xp_min = 10, xp_max = 10, - tilt_fly = false, - hostile = true, - --rotate = 270, collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3}, rotate = -180, visual = "mesh", @@ -39,7 +38,7 @@ mobs:register_mob("mobs_mc:blaze", { walk_velocity = .8, run_velocity = 1.6, damage = 6, - reach = 4, -- don't want blaze getting too close + reach = 2, pathfinding = 1, drops = { {name = mobs_mc.items.blaze_rod, @@ -67,7 +66,7 @@ mobs:register_mob("mobs_mc:blaze", { fall_speed = -2.25, light_damage = 0, view_range = 16, - attack_type = "projectile", + attack_type = "dogshoot", arrow = "mobs_mc:blaze_fireball", shoot_interval = 3.5, shoot_offset = 1.0, @@ -79,18 +78,9 @@ mobs:register_mob("mobs_mc:blaze", { fear_height = 0, glow = 14, fire_resistant = true, - eye_height = 0.75, - projectile_cooldown_min = 2, - projectile_cooldown_max = 3, - shoot_arrow = function(self, pos, dir) - -- 2-4 damage per arrow - local dmg = math.random(2,4) - mobs.shoot_projectile_handling("mobs_mc:blaze_fireball", pos, dir, self.object:get_yaw(), self.object, 7, dmg,nil,nil,nil,-0.4) - end, - do_custom = function(self) - if self.attacking and self.state == "attack" and vector.distance(self.object:get_pos(), self.attacking:get_pos()) < 1.2 then - mcl_burning.set_on_fire(self.attacking, 5) + if self.state == "attack" and self.attack:get_pos() and vector.distance(self.object:get_pos(), self.attack:get_pos()) < 1.2 then + mcl_burning.set_on_fire(self.attack, 5) end local pos = self.object:get_pos() minetest.add_particle({ @@ -160,11 +150,6 @@ mobs:register_arrow("mobs_mc:blaze_fireball", { visual_size = {x = 0.3, y = 0.3}, textures = {"mcl_fire_fire_charge.png"}, velocity = 15, - speed = 5, - tail = 1, - tail_texture = "mobs_mc_spit.png^[colorize:black:255", --repurpose spit texture - tail_size = 2, - tail_distance_divider = 3, _is_fireball = true, -- Direct hit, no fire... just plenty of pain @@ -172,7 +157,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", { mcl_burning.set_on_fire(player, 5) player:punch(self.object, 1.0, { full_punch_interval = 1.0, - damage_groups = {fleshy = self._damage}, + damage_groups = {fleshy = 5}, }, nil) end, @@ -180,7 +165,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", { mcl_burning.set_on_fire(mob, 5) mob:punch(self.object, 1.0, { full_punch_interval = 1.0, - damage_groups = {fleshy = self._damage}, + damage_groups = {fleshy = 5}, }, nil) end, @@ -195,19 +180,20 @@ mobs:register_arrow("mobs_mc:blaze_fireball", { -- Node hit, make fire hit_node = function(self, pos, node) - if node.name ~= "air" then - local pos_above = table.copy(pos) - pos_above.y = pos_above.y + 1 - minetest.set_node(pos_above, {name=mobs_mc.items.fire}) + if node == "air" then + minetest.set_node(pos, {name = mobs_mc.items.fire}) else - local v = self.object:get_velocity() - v = vector.normalize(v) + if self._shot_from_dispenser and mod_target and node == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end + local v = vector.normalize(self.object:get_velocity()) local crashpos = vector.subtract(pos, v) local crashnode = minetest.get_node(crashpos) + local cndef = minetest.registered_nodes[crashnode.name] -- Set fire if node is air, or a replacable flammable node (e.g. a plant) if crashnode.name == "air" or - (minetest.registered_nodes[crashnode.name].buildable_to and minetest.get_item_group(crashnode.name, "flammable") >= 1) then - minetest.set_node(crashpos, {name=mobs_mc.items.fire}) + (cndef and cndef.buildable_to and minetest.get_item_group(crashnode.name, "flammable") >= 1) then + minetest.set_node(crashpos, {name = mobs_mc.items.fire}) end end end diff --git a/mods/ENTITIES/mobs_mc/chicken.lua b/mods/ENTITIES/mobs_mc/chicken.lua index ffaebca2be..0b43fca0dd 100644 --- a/mods/ENTITIES/mobs_mc/chicken.lua +++ b/mods/ENTITIES/mobs_mc/chicken.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### CHICKEN @@ -18,8 +18,7 @@ mobs:register_mob("mobs_mc:chicken", { xp_min = 1, xp_max = 3, collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2}, - skittish = true, - fall_slow = true, + runaway = true, floats = 1, visual = "mesh", mesh = "mobs_mc_chicken.b3d", @@ -27,10 +26,9 @@ mobs:register_mob("mobs_mc:chicken", { {"mobs_mc_chicken.png"}, }, visual_size = {x=2.2, y=2.2}, - rotate = 270, + makes_footstep_sound = true, walk_velocity = 1, - run_velocity = 3, drops = { {name = mobs_mc.items.chicken_raw, chance = 1, @@ -66,25 +64,14 @@ mobs:register_mob("mobs_mc:chicken", { run_start = 0, run_end = 40, }, - follow = "mcl_farming:wheat_seeds", - breed_distance = 1.5, - baby_size = 0.5, - follow_distance = 2, + follow = mobs_mc.follow.chicken, view_range = 16, fear_height = 4, - --why do chickend breed if they lay eggs?? on_rightclick = function(self, clicker) - --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 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, 60, 5, false, nil) then return end end, do_custom = function(self, dtime) @@ -111,21 +98,6 @@ mobs:register_mob("mobs_mc:chicken", { }, true) end, - --head code - has_head = true, - head_bone = "head", - - swap_y_with_x = false, - reverse_head_yaw = false, - - head_bone_pos_y = 1.675, - head_bone_pos_z = 0, - - head_height_offset = 0.55, - head_direction_offset = 0.0925, - - head_pitch_modifier = -math.pi/2, - --end head code }) --spawn @@ -134,53 +106,42 @@ mobs:spawn_specific( "overworld", "ground", { - "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", + "flat", "IcePlainsSpikes", - "SunflowerPlains", - "IcePlains", - "RoofedForest", - "ExtremeHills+_snowtop", - "MesaPlateauFM_grasstop", - "JungleEdgeM", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", "ExtremeHillsM", - "JungleM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", "BirchForestM", - "MesaPlateauF", - "MesaPlateauFM", - "MesaPlateauF_grasstop", - "MesaBryce", - "JungleEdge", + "RoofedForest", + "Savanna", + "Savanna_beach", "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua index 17c4e1e620..0b9a7ec71c 100644 --- a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua +++ b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") local cow_def = { description = S("Cow"), @@ -10,7 +10,6 @@ local cow_def = { hp_max = 10, xp_min = 1, xp_max = 3, - rotate = 270, collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.39, 0.45}, visual = "mesh", mesh = "mobs_mc_cow.b3d", @@ -21,7 +20,6 @@ local cow_def = { visual_size = {x=2.8, y=2.8}, makes_footstep_sound = true, walk_velocity = 1, - run_velocity = 3, drops = { {name = mobs_mc.items.beef_raw, chance = 1, @@ -34,7 +32,7 @@ local cow_def = { max = 2, looting = "common",}, }, - skittish = true, + runaway = true, sounds = { random = "mobs_mc_cow", damage = "mobs_mc_cow_hurt", @@ -49,17 +47,12 @@ local cow_def = { walk_end = 40, run_start = 0, run_end = 40, }, - --follow = mobs_mc.follow.cow, + follow = mobs_mc.follow.cow, on_rightclick = function(self, clicker) + 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) + if self.child then return end @@ -78,28 +71,11 @@ local cow_def = { end return end + mobs:capture_mob(self, clicker, 0, 5, 60, false, nil) end, - breed_distance = 1.5, - baby_size = 0.5, - follow_distance = 2, follow = mobs_mc.items.wheat, view_range = 10, fear_height = 4, - - --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 } mobs:register_mob("mobs_mc:cow", cow_def) @@ -110,17 +86,12 @@ mooshroom_def.description = S("Mooshroom") mooshroom_def.mesh = "mobs_mc_cow.b3d" mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, {"mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } } mooshroom_def.on_rightclick = function(self, clicker) - --attempt to enter breed state - if mobs.enter_breed_state(self,clicker) then + if mobs:feed_tame(self, clicker, 1, true, true) then return end + if mobs:protect(self, clicker) then return end + + if self.child then return end - - --make baby grow faster - if self.baby then - mobs.make_baby_grow_faster(self,clicker) - return - end - local item = clicker:get_wielded_item() -- Use shears to get mushrooms and turn mooshroom into cow if item:get_name() == mobs_mc.items.shears then @@ -169,6 +140,7 @@ mooshroom_def.on_rightclick = function(self, clicker) minetest.add_item(pos, {name = mobs_mc.items.mushroom_stew}) end end + mobs:capture_mob(self, clicker, 0, 5, 60, false, nil) end mobs:register_mob("mobs_mc:mooshroom", mooshroom_def) @@ -179,53 +151,42 @@ mobs:spawn_specific( "overworld", "ground", { - "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", + "flat", "IcePlainsSpikes", - "SunflowerPlains", - "IcePlains", - "RoofedForest", - "ExtremeHills+_snowtop", - "MesaPlateauFM_grasstop", - "JungleEdgeM", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", "ExtremeHillsM", - "JungleM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", "BirchForestM", - "MesaPlateauF", - "MesaPlateauFM", - "MesaPlateauF_grasstop", - "MesaBryce", - "JungleEdge", + "RoofedForest", + "Savanna", + "Savanna_beach", "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/creeper.lua b/mods/ENTITIES/mobs_mc/creeper.lua index a7e33d1bd0..827d08aaba 100644 --- a/mods/ENTITIES/mobs_mc/creeper.lua +++ b/mods/ENTITIES/mobs_mc/creeper.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### CREEPER @@ -12,8 +12,6 @@ local S = minetest.get_translator(minetest.get_current_modname()) mobs:register_mob("mobs_mc:creeper", { type = "monster", spawn_class = "hostile", - hostile = true, - rotate = 270, hp_min = 20, hp_max = 20, xp_min = 5, @@ -35,44 +33,28 @@ mobs:register_mob("mobs_mc:creeper", { explode = "tnt_explode", distance = 16, }, - makes_footstep_sound = false, + makes_footstep_sound = true, walk_velocity = 1.05, run_velocity = 2.1, runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" }, attack_type = "explode", - eye_height = 1.25, + --hssssssssssss explosion_strength = 3, - --explosion_radius = 3, - --explosion_damage_radius = 6, - --explosiontimer_reset_radius = 6, + explosion_radius = 3.5, + explosion_damage_radius = 3.5, + explosiontimer_reset_radius = 6, reach = 3, - defuse_reach = 5.2, - explosion_timer = 0.3, + explosion_timer = 1.5, allow_fuse_reset = true, stop_to_explode = true, - --head code - has_head = true, - 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 - -- Force-ignite creeper with flint and steel and explode after 1.5 seconds. -- TODO: Make creeper flash after doing this as well. -- TODO: Test and debug this code. on_rightclick = function(self, clicker) - if self._forced_explosion_countdown_timer then + if self._forced_explosion_countdown_timer ~= nil then return end local item = clicker:get_wielded_item() @@ -92,11 +74,10 @@ mobs:register_mob("mobs_mc:creeper", { end end, do_custom = function(self, dtime) - if self._forced_explosion_countdown_timer then + if self._forced_explosion_countdown_timer ~= nil then self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime if self._forced_explosion_countdown_timer <= 0 then - local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false - mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { griefing = mobs_griefing, drop_chance = 1.0}, self.object) + mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength) end end end, @@ -149,10 +130,9 @@ mobs:register_mob("mobs_mc:creeper", { }) mobs:register_mob("mobs_mc:creeper_charged", { - description = S("Charged Creeper"), + description = S("Creeper"), type = "monster", spawn_class = "hostile", - hostile = true, hp_min = 20, hp_max = 20, xp_min = 5, @@ -169,7 +149,6 @@ mobs:register_mob("mobs_mc:creeper_charged", { "mobs_mc_creeper_charge.png"}, }, visual_size = {x=3, y=3}, - rotate = 270, sounds = { attack = "tnt_ignite", death = "mobs_mc_creeper_death", @@ -178,19 +157,18 @@ mobs:register_mob("mobs_mc:creeper_charged", { explode = "tnt_explode", distance = 16, }, - makes_footstep_sound = false, + makes_footstep_sound = true, walk_velocity = 1.05, run_velocity = 2.1, runaway_from = { "mobs_mc:ocelot", "mobs_mc:cat" }, attack_type = "explode", explosion_strength = 6, - --explosion_radius = 3, - --explosion_damage_radius = 6, - --explosiontimer_reset_radius = 3, + explosion_radius = 8, + explosion_damage_radius = 8, + explosiontimer_reset_radius = 6, reach = 3, - defuse_reach = 5.2, - explosion_timer = 0.3, + explosion_timer = 1.5, allow_fuse_reset = true, stop_to_explode = true, @@ -198,7 +176,7 @@ mobs:register_mob("mobs_mc:creeper_charged", { -- TODO: Make creeper flash after doing this as well. -- TODO: Test and debug this code. on_rightclick = function(self, clicker) - if self._forced_explosion_countdown_timer then + if self._forced_explosion_countdown_timer ~= nil then return end local item = clicker:get_wielded_item() @@ -218,11 +196,10 @@ mobs:register_mob("mobs_mc:creeper_charged", { end end, do_custom = function(self, dtime) - if self._forced_explosion_countdown_timer then + if self._forced_explosion_countdown_timer ~= nil then self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime if self._forced_explosion_countdown_timer <= 0 then - local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false - mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { griefing = mobs_griefing, drop_chance = 1.0}, self.object) + mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength) end end end, diff --git a/mods/ENTITIES/mobs_mc/ender_dragon.lua b/mods/ENTITIES/mobs_mc/ender_dragon.lua index 3634e20f41..0372fbe002 100644 --- a/mods/ENTITIES/mobs_mc/ender_dragon.lua +++ b/mods/ENTITIES/mobs_mc/ender_dragon.lua @@ -2,28 +2,21 @@ --################### ENDERDRAGON --################### -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:enderdragon", { description = S("Ender Dragon"), type = "monster", spawn_class = "hostile", + pathfinding = 1, attacks_animals = true, walk_chance = 100, - rotate = 270, - tilt_fly = true, - hostile = true, - shoot_arrow = function(self, pos, dir) - -- 2-4 damage per arrow - local dmg = math.random(2,4) - mobs.shoot_projectile_handling("mobs_mc:dragon_fireball", pos, dir, self.object:get_yaw(), self.object, nil, dmg) - end, hp_max = 200, hp_min = 200, xp_min = 500, xp_max = 500, - collisionbox = {-2, 0, -2, 2, 2, 2}, - eye_height = 1, + collisionbox = {-2, 3, -2, 2, 5, 2}, + physical = false, visual = "mesh", mesh = "mobs_mc_dragon.b3d", textures = { @@ -31,7 +24,6 @@ mobs:register_mob("mobs_mc:enderdragon", { }, visual_size = {x=3, y=3}, view_range = 35, - reach = 20, walk_velocity = 6, run_velocity = 6, can_despawn = false, @@ -55,10 +47,12 @@ mobs:register_mob("mobs_mc:enderdragon", { lava_damage = 0, fire_damage = 0, on_rightclick = nil, - attack_type = "projectile", + attack_type = "dogshoot", arrow = "mobs_mc:dragon_fireball", shoot_interval = 0.5, shoot_offset = -1.0, + xp_min = 500, + xp_max = 500, animation = { fly_speed = 8, stand_speed = 8, stand_start = 0, stand_end = 20, @@ -111,8 +105,8 @@ mobs:register_mob("mobs_mc:enderdragon", { fire_resistant = true, }) ---TODO: replace this setting by a proper gamerules system -local mobs_griefing = minetest.settings:get_bool("mobs_griefing", true) + +local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false -- dragon fireball (projectile) mobs:register_arrow("mobs_mc:dragon_fireball", { @@ -139,13 +133,10 @@ mobs:register_arrow("mobs_mc:dragon_fireball", { -- node hit, explode hit_node = function(self, pos, node) - --mobs:boom(self, pos, 2) - if mobs_griefing then - mcl_explosions.explode(self.object:get_pos(), 2, { drop_chance = 1.0 }) - end + mobs:boom(self, pos, 2) end }) mobs:register_egg("mobs_mc:enderdragon", S("Ender Dragon"), "mobs_mc_spawn_icon_dragon.png", 0, true) ---mcl_wip.register_wip_item("mobs_mc:enderdragon") +mcl_wip.register_wip_item("mobs_mc:enderdragon") diff --git a/mods/ENTITIES/mobs_mc/enderman.lua b/mods/ENTITIES/mobs_mc/enderman.lua index a821bd7695..2af96b7268 100644 --- a/mods/ENTITIES/mobs_mc/enderman.lua +++ b/mods/ENTITIES/mobs_mc/enderman.lua @@ -24,11 +24,9 @@ -- added rain damage. -- fixed the grass_with_dirt issue. -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") -local vector = vector - -local function telesound(pos, is_source) +local telesound = function(pos, is_source) local snd if is_source then snd = "mobs_mc_enderman_teleport_src" @@ -195,19 +193,18 @@ mobs:register_mob("mobs_mc:enderman", { description = S("Enderman"), type = "monster", spawn_class = "passive", - neutral = true, + passive = true, + pathfinding = 1, hp_min = 40, hp_max = 40, xp_min = 5, xp_max = 5, - rotate = 270, collisionbox = {-0.3, -0.01, -0.3, 0.3, 2.89, 0.3}, visual = "mesh", mesh = "mobs_mc_enderman.b3d", textures = create_enderman_textures(), visual_size = {x=3, y=3}, makes_footstep_sound = true, - eye_height = 2.5, sounds = { -- TODO: Custom war cry sound war_cry = "mobs_sandmonster", @@ -216,8 +213,8 @@ mobs:register_mob("mobs_mc:enderman", { random = {name="mobs_mc_enderman_random", gain=0.5}, distance = 16, }, - walk_velocity = 1, - run_velocity = 4, + walk_velocity = 0.2, + run_velocity = 3.4, damage = 7, reach = 2, drops = { @@ -227,22 +224,6 @@ mobs:register_mob("mobs_mc:enderman", { max = 1, looting = "common"}, }, - - --head code - has_head = false, - head_bone = "head.low", - - 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 - animation = select_enderman_animation("normal"), _taken_node = "", do_custom = function(self, dtime) @@ -301,10 +282,10 @@ mobs:register_mob("mobs_mc:enderman", { --self:teleport(nil) --self.state = "" --else - if self.attacking then - local target = self.attacking + if self.attack then + local target = self.attack local pos = target:get_pos() - if pos then + if pos ~= nil then if vector.distance(self.object:get_pos(), target:get_pos()) > 10 then self:teleport(target) end @@ -320,12 +301,12 @@ mobs:register_mob("mobs_mc:enderman", { for n = 1, #objs do local obj = objs[n] if obj then - --if minetest.is_player(obj) then + if minetest.is_player(obj) then -- Warp from players during day. --if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then -- self:teleport(nil) --end - if not obj:is_player() then + else local lua = obj:get_luaentity() if lua then if lua.name == "mcl_bows:arrow_entity" or lua.name == "mcl_throwing:snowball_entity" then @@ -343,8 +324,8 @@ mobs:register_mob("mobs_mc:enderman", { -- self:teleport(nil) -- self.state = "" --else - if self.attack and not minetest.settings:get_bool("creative_mode") then - self.state = "attack" + if self.attack ~= nil and not minetest.settings:get_bool("creative_mode") then + self.state = 'attack' end --end end @@ -379,16 +360,11 @@ 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.state = "stand" - self.hostile = false + self.attack = minetest.get_player_by_name(obj:get_player_name()) break - --begin attacking the player - else + else -- I'm not sure what this part does, but I don't want to break anything - jordan4ibanez if self.provoked == "staring" then self.provoked = "broke_contact" - self.hostile = true - self.state = "attack" - self.attacking = obj end end @@ -419,8 +395,9 @@ mobs:register_mob("mobs_mc:enderman", { local node = minetest.get_node(take_pos) -- Don't destroy protected stuff. if not minetest.is_protected(take_pos, "") then - local dug = minetest.dig_node(take_pos) - if dug then + minetest.remove_node(take_pos) + local dug = minetest.get_node_or_nil(take_pos) + if dug and dug.name == "air" then if mobs_mc.enderman_replace_on_take[node.name] then self._taken_node = mobs_mc.enderman_replace_on_take[node.name] else @@ -454,14 +431,14 @@ 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_mob_animation(self, self.animation.current) + mobs:set_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 end end end - elseif self._taken_node and self._taken_node ~= "" and self._take_place_timer >= self._next_take_place_time then + elseif self._taken_node ~= nil and self._taken_node ~= "" and self._take_place_timer >= self._next_take_place_time then -- Place taken node self._take_place_timer = 0 self._next_take_place_time = math.random(take_frequency_min, take_frequency_max) @@ -477,7 +454,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_mob_animation(self, self.animation.current) + mobs:set_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 @@ -487,12 +464,12 @@ mobs:register_mob("mobs_mc:enderman", { end end, do_teleport = function(self, target) - if target then + if target ~= nil then local target_pos = target:get_pos() -- Find all solid nodes below air in a 10×10×10 cuboid centered on the target local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(target_pos, 5), vector.add(target_pos, 5), {"group:solid", "group:cracky", "group:crumbly"}) local telepos - if nodes then + if nodes ~= nil then if #nodes > 0 then -- Up to 64 attempts to teleport for n=1, math.min(64, #nodes) do @@ -502,7 +479,8 @@ mobs:register_mob("mobs_mc:enderman", { -- Selected node needs to have 3 nodes of free space above for u=1, 3 do local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z}) - if minetest.registered_nodes[node.name].walkable then + local ndef = minetest.registered_nodes[node.name] + if ndef and ndef.walkable then node_ok = false break end @@ -527,7 +505,7 @@ mobs:register_mob("mobs_mc:enderman", { -- We need to add (or subtract) different random numbers to each vector component, so it couldn't be done with a nice single vector.add() or .subtract(): local randomCube = vector.new( pos.x + 8*(pr:next(0,16)-8), pos.y + 8*(pr:next(0,16)-8), pos.z + 8*(pr:next(0,16)-8) ) local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(randomCube, 4), vector.add(randomCube, 4), {"group:solid", "group:cracky", "group:crumbly"}) - if nodes then + if nodes ~= nil then if #nodes > 0 then -- Up to 8 low-level (in total up to 8*8 = 64) attempts to teleport for n=1, math.min(8, #nodes) do @@ -536,7 +514,8 @@ mobs:register_mob("mobs_mc:enderman", { node_ok = true for u=1, 3 do local node = minetest.get_node({x=nodepos.x, y=nodepos.y+u, z=nodepos.z}) - if minetest.registered_nodes[node.name].walkable then + local ndef = minetest.registered_nodes[node.name] + if ndef and ndef.walkable then node_ok = false break end @@ -559,13 +538,13 @@ mobs:register_mob("mobs_mc:enderman", { end, on_die = function(self, pos) -- Drop carried node on death - if self._taken_node and self._taken_node ~= "" then + if self._taken_node ~= nil and self._taken_node ~= "" then minetest.add_item(pos, self._taken_node) end end, do_punch = function(self, hitter, tflp, tool_caps, dir) -- damage from rain caused by itself so we don't want it to attack itself. - if hitter ~= self.object and hitter then + if hitter ~= self.object and hitter ~= nil then --if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then -- self:teleport(nil) --else @@ -581,7 +560,7 @@ mobs:register_mob("mobs_mc:enderman", { water_damage = 8, view_range = 64, fear_height = 4, - attack_type = "punch", + attack_type = "dogfight", }) diff --git a/mods/ENTITIES/mobs_mc/endermite.lua b/mods/ENTITIES/mobs_mc/endermite.lua index 29a887c067..2bffa83044 100644 --- a/mods/ENTITIES/mobs_mc/endermite.lua +++ b/mods/ENTITIES/mobs_mc/endermite.lua @@ -2,22 +2,19 @@ --################### ENDERMITE --################### -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:endermite", { description = S("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 dc47411fdf..1d71791621 100644 --- a/mods/ENTITIES/mobs_mc/ghast.lua +++ b/mods/ENTITIES/mobs_mc/ghast.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### GHAST @@ -14,17 +14,13 @@ 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, - reach = 20, - eye_height = 2.5, - collisionbox = {-2, 0, -2, 2, 4, 2}, + collisionbox = {-2, 5, -2, 2, 9, 2}, visual = "mesh", mesh = "mobs_mc_ghast.b3d", textures = { @@ -40,10 +36,8 @@ 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}, @@ -54,23 +48,22 @@ mobs:register_mob("mobs_mc:ghast", { walk_start = 0, walk_end = 40, run_start = 0, run_end = 40, }, - fall_damage = 0, - view_range = 28, - attack_type = "projectile", - arrow = "mobs_mc:ghast_fireball", + 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, 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"} @@ -80,7 +73,6 @@ mobs:register_mob("mobs_mc:ghast", { self.object:set_properties({textures=self.base_texture}) end end, - ]]-- }) @@ -100,40 +92,32 @@ mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_max) -- fireball (projectile) -mobs:register_arrow("mobs_mc:ghast_fireball", { +mobs:register_arrow("mobs_mc: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) - mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 }) + mobs:boom(self, self.object:get_pos(), 1, true) end, hit_mob = function(self, mob) mob:punch(self.object, 1.0, { full_punch_interval = 1.0, - damage_groups = {fleshy = self._damage}, + damage_groups = {fleshy = 6}, }, nil) - --mobs:boom(self, self.object:get_pos(), 1, true) - mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 }) + mobs:boom(self, self.object:get_pos(), 1, true) end, hit_node = function(self, pos, node) - --mobs:boom(self, pos, 1, true) - mcl_explosions.explode(self.object:get_pos(), 3,{ drop_chance = 1.0 }) + mobs:boom(self, pos, 1, true) end }) diff --git a/mods/ENTITIES/mobs_mc/guardian.lua b/mods/ENTITIES/mobs_mc/guardian.lua index 3e1a4f8537..06a2ba2e27 100644 --- a/mods/ENTITIES/mobs_mc/guardian.lua +++ b/mods/ENTITIES/mobs_mc/guardian.lua @@ -2,7 +2,7 @@ --################### GUARDIAN --################### -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:guardian", { description = S("Guardian"), @@ -13,8 +13,8 @@ mobs:register_mob("mobs_mc:guardian", { xp_min = 10, xp_max = 10, breath_max = -1, - passive = false, - attack_type = "punch", + passive = false, + attack_type = "dogfight", pathfinding = 1, view_range = 16, walk_velocity = 2, @@ -94,6 +94,7 @@ mobs:register_mob("mobs_mc:guardian", { makes_footstep_sound = false, fly_in = { mobs_mc.items.water_source, mobs_mc.items.river_water_source }, jump = false, + view_range = 16, }) -- Spawning disabled due to size issues diff --git a/mods/ENTITIES/mobs_mc/guardian_elder.lua b/mods/ENTITIES/mobs_mc/guardian_elder.lua index 2bb0e984a8..5b8150dd4c 100644 --- a/mods/ENTITIES/mobs_mc/guardian_elder.lua +++ b/mods/ENTITIES/mobs_mc/guardian_elder.lua @@ -4,7 +4,7 @@ --################### GUARDIAN --################### -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:guardian_elder", { description = S("Elder Guardian"), @@ -15,8 +15,8 @@ mobs:register_mob("mobs_mc:guardian_elder", { xp_min = 10, xp_max = 10, breath_max = -1, - passive = false, - attack_type = "punch", + passive = false, + attack_type = "dogfight", pathfinding = 1, view_range = 16, walk_velocity = 2, @@ -104,6 +104,7 @@ mobs:register_mob("mobs_mc:guardian_elder", { makes_footstep_sound = false, fly_in = { mobs_mc.items.water_source, mobs_mc.items.river_water_source }, jump = false, + view_range = 16, }) -- Spawning disabled due to size issues <- what do you mean? -j4i diff --git a/mods/ENTITIES/mobs_mc/horse.lua b/mods/ENTITIES/mobs_mc/horse.lua index 4b33515d5c..5fe6055733 100644 --- a/mods/ENTITIES/mobs_mc/horse.lua +++ b/mods/ENTITIES/mobs_mc/horse.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### HORSE @@ -38,9 +38,9 @@ end local can_equip_horse_armor = function(entity_id) return entity_id == "mobs_mc:horse" or entity_id == "mobs_mc:skeleton_horse" or entity_id == "mobs_mc:zombie_horse" end ---[[local can_equip_chest = function(entity_id) +local can_equip_chest = function(entity_id) return entity_id == "mobs_mc:mule" or entity_id == "mobs_mc:donkey" -end]] +end local can_breed = function(entity_id) return entity_id == "mobs_mc:horse" or "mobs_mc:mule" or entity_id == "mobs_mc:donkey" end @@ -88,10 +88,6 @@ 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 = { @@ -101,7 +97,7 @@ local horse = { walk_speed = 25, walk_start = 0, walk_end = 40, - run_speed = 120, + run_speed = 60, run_start = 0, run_end = 40, }, @@ -118,8 +114,7 @@ local horse = { fly = false, walk_chance = 60, view_range = 16, - follow = "mcl_farming:wheat_item", - follow_distance = 3, + follow = mobs_mc.follow.horse, passive = true, hp_min = 15, hp_max = 30, @@ -187,7 +182,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, "run", "stand", false, dtime) + mobs.drive(self, "walk", "stand", false, dtime) return false -- skip rest of mob functions end @@ -219,21 +214,6 @@ 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)) @@ -259,7 +239,6 @@ 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 @@ -274,14 +253,6 @@ 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 @@ -311,10 +282,14 @@ 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 - --local inv = clicker:get_inventory() + local inv = clicker:get_inventory() -- detatch player already riding horse if self.driver and clicker == self.driver then @@ -382,6 +357,9 @@ 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, @@ -542,53 +520,42 @@ mobs:spawn_specific( "overworld", "ground", { - "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", + "flat", "IcePlainsSpikes", - "SunflowerPlains", - "IcePlains", - "RoofedForest", - "ExtremeHills+_snowtop", - "MesaPlateauFM_grasstop", - "JungleEdgeM", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", "ExtremeHillsM", - "JungleM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", "BirchForestM", - "MesaPlateauF", - "MesaPlateauFM", - "MesaPlateauF_grasstop", - "MesaBryce", - "JungleEdge", + "RoofedForest", + "Savanna", + "Savanna_beach", "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 0, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/init.lua b/mods/ENTITIES/mobs_mc/init.lua index d7600e927d..58006fe90e 100644 --- a/mods/ENTITIES/mobs_mc/init.lua +++ b/mods/ENTITIES/mobs_mc/init.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local path = minetest.get_modpath(minetest.get_current_modname()) +local path = minetest.get_modpath("mobs_mc") if not minetest.get_modpath("mobs_mc_gameconfig") then mobs_mc = {} diff --git a/mods/ENTITIES/mobs_mc/iron_golem.lua b/mods/ENTITIES/mobs_mc/iron_golem.lua index 939412abbd..0d3e74645f 100644 --- a/mods/ENTITIES/mobs_mc/iron_golem.lua +++ b/mods/ENTITIES/mobs_mc/iron_golem.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### IRON GOLEM @@ -16,11 +16,8 @@ mobs:register_mob("mobs_mc:iron_golem", { type = "npc", spawn_class = "passive", passive = true, - rotate = 270, hp_min = 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", @@ -43,7 +40,7 @@ mobs:register_mob("mobs_mc:iron_golem", { reach = 3, group_attack = true, attacks_monsters = true, - attack_type = "punch", + attack_type = "dogfight", drops = { {name = mobs_mc.items.iron_ingot, chance = 1, @@ -158,11 +155,11 @@ mobs_mc.tools.check_iron_golem_summon = function(pos) if ok then -- Remove the nodes minetest.remove_node(pos) - minetest.check_for_falling(pos) + core.check_for_falling(pos) for i=1, 4 do local cpos = vector.add(pos, checks[c][i]) minetest.remove_node(cpos) - minetest.check_for_falling(cpos) + core.check_for_falling(cpos) end -- Summon iron golem local place diff --git a/mods/ENTITIES/mobs_mc/llama.lua b/mods/ENTITIES/mobs_mc/llama.lua index 9c3f681b18..b6566059a9 100644 --- a/mods/ENTITIES/mobs_mc/llama.lua +++ b/mods/ENTITIES/mobs_mc/llama.lua @@ -1,4 +1,4 @@ -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### LLAMA @@ -28,15 +28,6 @@ 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, @@ -59,11 +50,7 @@ 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, @@ -96,7 +83,7 @@ mobs:register_mob("mobs_mc:llama", { look_start = 78, look_end = 108, }, - follow = mobs_mc.items.hay_bale, + follow = mobs_mc.follow.llama, view_range = 16, do_custom = function(self, dtime) @@ -139,71 +126,30 @@ mobs:register_mob("mobs_mc:llama", { 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 + 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 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 then - + --[[ TODO: Re-enable this code when carpet textures arrived. + if minetest.get_item_group(item:get_name(), "carpet") == 1 and not self.carpet 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({ @@ -224,21 +170,23 @@ mobs:register_mob("mobs_mc:llama", { end end end + ]] - if self.carpet then - -- detatch player already riding llama - if self.driver and clicker == self.driver 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) - end + self.object:set_properties({stepheight = 1.1}) + mobs.attach(self, clicker) 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, @@ -275,12 +223,18 @@ mobs:spawn_specific( "overworld", "ground", { -"Mesa", -"MesaPlateauFM_grasstop", -"MesaPlateauF", -"MesaPlateauFM", -"MesaPlateauF_grasstop", -"MesaBryce", + "Mesa", + "MesaPlateauFM_grasstop", + "MesaPlateauF", + "MesaPlateauFM", + "MesaPlateauF_grasstop", + "MesaBryce", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", }, 0, minetest.LIGHT_MAX+1, @@ -292,38 +246,3 @@ 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 = self._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/locale/mobs_mc.de.tr b/mods/ENTITIES/mobs_mc/locale/mobs_mc.de.tr index 6598cd4819..24d3fa3247 100644 --- a/mods/ENTITIES/mobs_mc/locale/mobs_mc.de.tr +++ b/mods/ENTITIES/mobs_mc/locale/mobs_mc.de.tr @@ -28,7 +28,6 @@ Pig=Schwein Polar Bear=Eisbär Rabbit=Kaninchen Killer Bunny=Killerkaninchen -The Killer Bunny=Das Killerkaninchen Sheep=Schaf Shulker=Shulker Silverfish=Silberfischchen diff --git a/mods/ENTITIES/mobs_mc/locale/mobs_mc.es.tr b/mods/ENTITIES/mobs_mc/locale/mobs_mc.es.tr index c61c09943c..240e7759f0 100644 --- a/mods/ENTITIES/mobs_mc/locale/mobs_mc.es.tr +++ b/mods/ENTITIES/mobs_mc/locale/mobs_mc.es.tr @@ -28,7 +28,6 @@ Pig=Cerdo Polar Bear=Oso polar Rabbit=Conejo Killer Bunny=Conejo asesino -The Killer Bunny=El Conejo asesino Sheep=Oveja Shulker=Shulker Silverfish=Lepisma diff --git a/mods/ENTITIES/mobs_mc/locale/mobs_mc.fr.tr b/mods/ENTITIES/mobs_mc/locale/mobs_mc.fr.tr index 4c8bd562d9..ff1e2b9c0b 100644 --- a/mods/ENTITIES/mobs_mc/locale/mobs_mc.fr.tr +++ b/mods/ENTITIES/mobs_mc/locale/mobs_mc.fr.tr @@ -28,7 +28,6 @@ Pig=Cochon Polar Bear=Ours blanc Rabbit=Lapin Killer Bunny=Lapin tueur -The Killer Bunny=Le Lapin tueur Sheep=Mouton Shulker=Shulker Silverfish=Poisson d'argent diff --git a/mods/ENTITIES/mobs_mc/locale/mobs_mc.pl.tr b/mods/ENTITIES/mobs_mc/locale/mobs_mc.pl.tr deleted file mode 100644 index 06eaa457a6..0000000000 --- a/mods/ENTITIES/mobs_mc/locale/mobs_mc.pl.tr +++ /dev/null @@ -1,75 +0,0 @@ -# textdomain: mobs_mc -Totem of Undying=Token nieśmiertelności -A totem of undying is a rare artifact which may safe you from certain death.=Totem nieśmiertelności to rzadki artefakt, który może uchronić cię przed pewną śmiercią. -The totem only works while you hold it in your hand. If you receive fatal damage, you are saved from death and you get a second chance with 1 HP. The totem is destroyed in the process, however.=Totem działa tylko kiedy trzymasz go w dłoni. Jeśli otrzymasz obrażenia od upadku zostaniesz oszczędzony i pozostanie ci 1 HP, jednak totem zostanie wtedy zniszczony. -Agent=Agent -Bat=Nietoperz -Blaze=Płomyk -Chicken=Kurczak -Cow=Krowa -Mooshroom=Muuuchomor -Creeper=Creeper -Ender Dragon=Smok kresu -Enderman=Enderman -Endermite=Endermit -Ghast=Ghast -Elder Guardian=Prastrażnik -Guardian=Strażnik -Horse=Koń -Skeleton Horse=Koń szkielet -Zombie Horse=Koń zombie -Donkey=Osioł -Mule=Muł -Iron Golem=Żelazny golem -Llama=Lama -Ocelot=Ocelot -Parrot=Papuga -Pig=Świnia -Polar Bear=Niedźwiedź polarny -Rabbit=Królik -Killer Bunny=Królik zabójca -Sheep=Owca -Shulker=Shulker -Silverfish=Rybik cukrowy -Skeleton=Szkielet -Stray=Tułacz -Wither Skeleton=Witherowy szkielet -Magma Cube=Kostka magmy -Slime=Szlam -Snow Golem=Śnieżny golem -Spider=Pająk -Cave Spider=Pająk jaskiniowy -Squid=Kałamarnica -Vex=Dręczyciel -Evoker=Przywoływacz -Illusioner=Iluzjonista -Villager=Osadnik -Vindicator=Obrońca -Zombie Villager=Osadnik zombie -Witch=Wiedźma -Wither=Wither -Wolf=Wilk -Husk=Posuch -Zombie=Zombie -Zombie Pigman=Świniak zombie -Iron Horse Armor=Żelazna zbroja dla konia -Iron horse armor can be worn by horses to increase their protection from harm a bit.=Żelazna zbroja dla konia może być noszona przez konie aby nieco zwiększyć ich odporność na obrażenia. -Golden Horse Armor=Złota zbroja dla konia -Golden horse armor can be worn by horses to increase their protection from harm.=Złota zbroja dla konia może być noszona przez konie aby zwiększyć ich odporność na obrażenia. -Diamond Horse Armor=Diamentowa zbroja dla konia -Diamond horse armor can be worn by horses to greatly increase their protection from harm.=Diamentowa zbroja dla konia może być noszona przez konie aby istotnie zwiększyć ich odporność na obrażenia. -Place it on a horse to put on the horse armor. Donkeys and mules can't wear horse armor.=Połóż ją na koniu aby założyć zbroję dla konia. Osły i muły nie mogą nosić zbroi dla konia. -Farmer=Rolnik -Fisherman=Rybak -Fletcher=Łuczarz -Shepherd=Pasterz -Librarian=Bibliotekarz -Cartographer=Kartograf -Armorer=Płatnerz -Leatherworker=Rymarz -Butcher=Rzeźnik -Weapon Smith=Zbrojmistrz -Tool Smith=Narzędziarz -Cleric=Kapłan -Nitwit=Głupiec -Protects you from death while wielding it=Chroni przed śmiercią gdy go trzymasz diff --git a/mods/ENTITIES/mobs_mc/locale/mobs_mc.ru.tr b/mods/ENTITIES/mobs_mc/locale/mobs_mc.ru.tr index 8857dda970..73807c0019 100644 --- a/mods/ENTITIES/mobs_mc/locale/mobs_mc.ru.tr +++ b/mods/ENTITIES/mobs_mc/locale/mobs_mc.ru.tr @@ -28,7 +28,6 @@ Pig=Свинья Polar Bear=Полярный медведь Rabbit=Кролик Killer Bunny=Кролик-убийца -The Killer Bunny=Кролик-убийца Sheep=Овца Shulker=Шалкер Silverfish=Чешуйница diff --git a/mods/ENTITIES/mobs_mc/locale/template.txt b/mods/ENTITIES/mobs_mc/locale/template.txt index 7b55c1b89e..04ba9e4658 100644 --- a/mods/ENTITIES/mobs_mc/locale/template.txt +++ b/mods/ENTITIES/mobs_mc/locale/template.txt @@ -28,7 +28,6 @@ Pig= Polar Bear= Rabbit= Killer Bunny= -The Killer Bunny= Sheep= Shulker= Silverfish= diff --git a/mods/ENTITIES/mobs_mc/models/attributes.txt b/mods/ENTITIES/mobs_mc/models/attributes.txt deleted file mode 100644 index ec59e0f702..0000000000 --- a/mods/ENTITIES/mobs_mc/models/attributes.txt +++ /dev/null @@ -1 +0,0 @@ -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 ab34f334f8..cebc037c05 100644 Binary files a/mods/ENTITIES/mobs_mc/models/mobs_mc_ghast.b3d and b/mods/ENTITIES/mobs_mc/models/mobs_mc_ghast.b3d differ diff --git a/mods/ENTITIES/mobs_mc/ocelot.lua b/mods/ENTITIES/mobs_mc/ocelot.lua index aea543895e..5a3f135a1c 100644 --- a/mods/ENTITIES/mobs_mc/ocelot.lua +++ b/mods/ENTITIES/mobs_mc/ocelot.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### OCELOT AND CAT @@ -31,8 +31,6 @@ local ocelot = { type = "animal", spawn_class = "passive", can_despawn = true, - rotate = 270, - skittish = true, hp_min = 10, hp_max = 10, xp_min = 1, @@ -45,7 +43,7 @@ local ocelot = { makes_footstep_sound = true, walk_chance = default_walk_chance, walk_velocity = 1, - run_velocity = 10, + run_velocity = 3, follow_velocity = 1, floats = 1, runaway = true, @@ -59,7 +57,7 @@ local ocelot = { }, animation = { speed_normal = 25, - run_speed = 150, + run_speed = 50, stand_start = 0, stand_end = 0, walk_start = 0, @@ -125,6 +123,8 @@ 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 @@ -151,7 +151,7 @@ end mobs:register_mob("mobs_mc:cat", cat) ---local base_spawn_chance = 5000 +local base_spawn_chance = 5000 -- Spawn ocelot --they get the same as the llama because I'm trying to rework so much of this code right now -j4i diff --git a/mods/ENTITIES/mobs_mc/parrot.lua b/mods/ENTITIES/mobs_mc/parrot.lua index affcac4966..c04ea77c6a 100644 --- a/mods/ENTITIES/mobs_mc/parrot.lua +++ b/mods/ENTITIES/mobs_mc/parrot.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### PARROT @@ -20,14 +20,11 @@ mobs:register_mob("mobs_mc:parrot", { hp_max = 6, xp_min = 1, xp_max = 3, - tilt_fly = true, - collisionbox = {-0.25, 0, -0.25, 0.25, 0.9, 0.25}, - eye_height = 0.45, + collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25}, 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 = { @@ -44,7 +41,7 @@ mobs:register_mob("mobs_mc:parrot", { max = 2, looting = "common",}, }, - animation = { + animation = { stand_speed = 50, walk_speed = 50, fly_speed = 50, @@ -88,6 +85,8 @@ 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 84ff996f2e..837d743f0f 100644 --- a/mods/ENTITIES/mobs_mc/pig.lua +++ b/mods/ENTITIES/mobs_mc/pig.lua @@ -1,13 +1,12 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:pig", { description = S("Pig"), type = "animal", spawn_class = "passive", - skittish = true, - rotate = 270, + runaway = true, hp_min = 10, hp_max = 10, xp_min = 1, @@ -20,30 +19,11 @@ 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, @@ -70,7 +50,7 @@ mobs:register_mob("mobs_mc:pig", { run_start = 0, run_end = 40, }, - follow = "mcl_farming:carrot_item", + follow = mobs_mc.follow.pig, view_range = 8, do_custom = function(self, dtime) @@ -111,17 +91,12 @@ mobs:register_mob("mobs_mc:pig", { 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 + 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 end + if mobs:protect(self, clicker) then return end if self.child then return @@ -129,8 +104,6 @@ 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 @@ -163,7 +136,7 @@ mobs:register_mob("mobs_mc:pig", { end -- Mount or detach player - --local name = clicker:get_player_name() + local name = clicker:get_player_name() if self.driver and clicker == self.driver then -- Detach if already attached mobs.detach(clicker, {x=1, y=0, z=0}) @@ -191,6 +164,10 @@ 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, @@ -211,53 +188,42 @@ mobs:spawn_specific( "overworld", "ground", { - "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", + "flat", "IcePlainsSpikes", - "SunflowerPlains", - "IcePlains", - "RoofedForest", - "ExtremeHills+_snowtop", - "MesaPlateauFM_grasstop", - "JungleEdgeM", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", "ExtremeHillsM", - "JungleM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", "BirchForestM", - "MesaPlateauF", - "MesaPlateauFM", - "MesaPlateauF_grasstop", - "MesaBryce", - "JungleEdge", + "RoofedForest", + "Savanna", + "Savanna_beach", "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/polar_bear.lua b/mods/ENTITIES/mobs_mc/polar_bear.lua index 0f5296d351..98268961bd 100644 --- a/mods/ENTITIES/mobs_mc/polar_bear.lua +++ b/mods/ENTITIES/mobs_mc/polar_bear.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### POLARBEAR @@ -31,7 +31,7 @@ mobs:register_mob("mobs_mc:polar_bear", { walk_velocity = 1.2, run_velocity = 2.4, group_attack = true, - attack_type = "punch", + attack_type = "dogfight", 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 51235a3f93..6b47fec706 100644 --- a/mods/ENTITIES/mobs_mc/rabbit.lua +++ b/mods/ENTITIES/mobs_mc/rabbit.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") local rabbit = { description = S("Rabbit"), @@ -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,6 +62,8 @@ 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” @@ -99,7 +101,7 @@ killer_bunny.on_rightclick = nil killer_bunny.run_velocity = 6 killer_bunny.do_custom = function(self) if not self._killer_bunny_nametag_set then - self.nametag = S("The Killer Bunny") + self.nametag = "The Killer Bunny" self._killer_bunny_nametag_set = true end end @@ -114,53 +116,22 @@ mobs:spawn_specific( "overworld", "ground", { - "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", +"FlowerForest", +"Swampland", +"Taiga", +"ExtremeHills", +"BirchForest", +"MegaSpruceTaiga", +"MegaTaiga", +"ExtremeHills+", +"Forest", +"Plains", +"ColdTaiga", +"SunflowerPlains", +"RoofedForest", +"MesaPlateauFM_grasstop", +"ExtremeHillsM", +"BirchForestM", }, 9, minetest.LIGHT_MAX+1, @@ -233,4 +204,4 @@ mobs:spawn(spawn_grass) mobs:register_egg("mobs_mc:rabbit", S("Rabbit"), "mobs_mc_spawn_icon_rabbit.png", 0) -- Note: This spawn egg does not exist in Minecraft -mobs:register_egg("mobs_mc:killer_bunny", S("Killer Bunny"), "mobs_mc_spawn_icon_rabbit_caerbannog.png", 0) +mobs:register_egg("mobs_mc:killer_bunny", S("Killer Bunny"), "mobs_mc_spawn_icon_rabbit.png^[colorize:#FF0000:192", 0) -- TODO: Update inventory image diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 76f933a6b0..f16b64c66f 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### SHEEP @@ -38,7 +38,7 @@ local rainbow_colors = { "unicolor_red_violet" } -if minetest.get_modpath("mcl_wool") then +if minetest.get_modpath("mcl_wool") ~= nil then colors["unicolor_light_blue"] = { mobs_mc.items.wool_light_blue, "#5050FFD0" } end @@ -63,13 +63,8 @@ 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", @@ -78,23 +73,6 @@ 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, @@ -121,6 +99,7 @@ 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 @@ -150,6 +129,7 @@ mobs:register_mob("mobs_mc:sheep", { do_custom = function(self, dtime) if not self.initial_color_set then local r = math.random(0,100000) + local textures if r <= 81836 then -- 81.836% self.color = "unicolor_white" @@ -215,16 +195,8 @@ mobs:register_mob("mobs_mc:sheep", { on_rightclick = function(self, clicker) local item = clicker:get_wielded_item() - --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 mobs:feed_tame(self, clicker, 1, true, true) then return end + if mobs:protect(self, clicker) then return end if item:get_name() == mobs_mc.items.shears and not self.gotten and not self.child then self.gotten = true @@ -280,6 +252,7 @@ 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. @@ -336,53 +309,42 @@ mobs:spawn_specific( "overworld", "ground", { - "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", + "flat", "IcePlainsSpikes", - "SunflowerPlains", - "IcePlains", - "RoofedForest", - "ExtremeHills+_snowtop", - "MesaPlateauFM_grasstop", - "JungleEdgeM", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", "ExtremeHillsM", - "JungleM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", "BirchForestM", - "MesaPlateauF", - "MesaPlateauFM", - "MesaPlateauF_grasstop", - "MesaBryce", - "JungleEdge", + "RoofedForest", + "Savanna", + "Savanna_beach", "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 0, minetest.LIGHT_MAX+1, @@ -394,4 +356,3 @@ 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 1a5c4ec84d..0d5ad880a9 100644 --- a/mods/ENTITIES/mobs_mc/shulker.lua +++ b/mods/ENTITIES/mobs_mc/shulker.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### SHULKER @@ -15,7 +15,7 @@ mobs:register_mob("mobs_mc:shulker", { description = S("Shulker"), type = "monster", spawn_class = "hostile", - attack_type = "projectile", + attack_type = "shoot", 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 ac3991ad1b..5af3c8aa04 100644 --- a/mods/ENTITIES/mobs_mc/silverfish.lua +++ b/mods/ENTITIES/mobs_mc/silverfish.lua @@ -2,7 +2,7 @@ --################### SILVERFISH --################### -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:silverfish", { description = S("Silverfish"), @@ -44,8 +44,9 @@ mobs:register_mob("mobs_mc:silverfish", { run_start = 0, run_end = 20, }, view_range = 16, - attack_type = "punch", + attack_type = "dogfight", damage = 1, + reach = 1, }) mobs:register_egg("mobs_mc:silverfish", S("Silverfish"), "mobs_mc_spawn_icon_silverfish.png", 0) @@ -61,7 +62,7 @@ if minetest.get_modpath("default") and mobs_mc.create_monster_egg_nodes then description = "Stone Monster Egg", tiles = {"default_stone.png"}, groups = {oddly_breakable_by_hand = 2, spawns_silverfish = 1}, - drop = "", + drop = '', is_ground_content = true, sounds = default.node_sound_stone_defaults(), after_dig_node = spawn_silverfish, @@ -72,7 +73,7 @@ if minetest.get_modpath("default") and mobs_mc.create_monster_egg_nodes then tiles = {"default_cobble.png"}, is_ground_content = false, groups = {oddly_breakable_by_hand = 2, spawns_silverfish = 1}, - drop = "", + drop = '', sounds = default.node_sound_stone_defaults(), after_dig_node = spawn_silverfish, }) @@ -82,7 +83,7 @@ if minetest.get_modpath("default") and mobs_mc.create_monster_egg_nodes then tiles = {"default_mossycobble.png"}, is_ground_content = false, groups = {oddly_breakable_by_hand = 2, spawns_silverfish = 1}, - drop = "", + drop = '', sounds = default.node_sound_stone_defaults(), after_dig_node = spawn_silverfish, }) @@ -94,7 +95,7 @@ if minetest.get_modpath("default") and mobs_mc.create_monster_egg_nodes then tiles = {"default_stone_brick.png"}, is_ground_content = false, groups = {oddly_breakable_by_hand = 2, spawns_silverfish = 1}, - drop = "", + drop = '', sounds = default.node_sound_stone_defaults(), after_dig_node = spawn_silverfish, }) @@ -104,7 +105,7 @@ if minetest.get_modpath("default") and mobs_mc.create_monster_egg_nodes then tiles = {"default_stone_block.png"}, is_ground_content = false, groups = {oddly_breakable_by_hand = 2, spawns_silverfish = 1}, - drop = "", + drop = '', sounds = default.node_sound_stone_defaults(), after_dig_node = spawn_silverfish, }) diff --git a/mods/ENTITIES/mobs_mc/skeleton+stray.lua b/mods/ENTITIES/mobs_mc/skeleton+stray.lua index f0e728e083..61e1c6eb25 100644 --- a/mods/ENTITIES/mobs_mc/skeleton+stray.lua +++ b/mods/ENTITIES/mobs_mc/skeleton+stray.lua @@ -3,8 +3,8 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) -local mod_bows = minetest.get_modpath("mcl_bows") +local S = minetest.get_translator("mobs_mc") +local mod_bows = minetest.get_modpath("mcl_bows") ~= nil --################### --################### SKELETON @@ -16,37 +16,21 @@ 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, group_attack = true, visual = "mesh", mesh = "mobs_mc_skeleton.b3d", - - --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 - + textures = { { + "mcl_bows_bow_0.png", -- bow + "mobs_mc_skeleton.png", -- skeleton + } }, visual_size = {x=1, y=1}, makes_footstep_sound = true, textures = { @@ -59,7 +43,7 @@ local skeleton = { walk_velocity = 1.2, run_velocity = 2.4, damage = 2, - reach = 3, + reach = 2, drops = { {name = mobs_mc.items.arrow, chance = 1, @@ -91,8 +75,6 @@ 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, @@ -104,13 +86,13 @@ local skeleton = { ignited_by_sunlight = true, view_range = 16, fear_height = 4, - attack_type = "projectile", + attack_type = "dogshoot", arrow = "mcl_bows:arrow_entity", shoot_arrow = function(self, pos, dir) if mod_bows then -- 2-4 damage per arrow - local dmg = math.random(2,4) - mobs.shoot_projectile_handling("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) + 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) end end, shoot_interval = 2, diff --git a/mods/ENTITIES/mobs_mc/skeleton_wither.lua b/mods/ENTITIES/mobs_mc/skeleton_wither.lua index a6b48d4281..1c0bdbea1b 100644 --- a/mods/ENTITIES/mobs_mc/skeleton_wither.lua +++ b/mods/ENTITIES/mobs_mc/skeleton_wither.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### WITHER SKELETON @@ -87,7 +87,7 @@ mobs:register_mob("mobs_mc:witherskeleton", { fire_damage = 0, light_damage = 0, view_range = 16, - attack_type = "punch", + attack_type = "dogfight", 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 9236b255e3..8d855e7610 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") -- Returns a function that spawns children in a circle around pos. -- To be used as on_die callback. @@ -16,7 +16,8 @@ local spawn_children_on_die = function(child_mob, children_count, spawn_distance if not eject_speed then eject_speed = 1 end - local mother_stuck = minetest.registered_nodes[minetest.get_node(pos).name].walkable + local mndef = minetest.registered_nodes[minetest.get_node(pos).name] + local mother_stuck = mndef and mndef.walkable angle = math.random(0, math.pi*2) local children = {} for i=1,children_count do @@ -26,27 +27,26 @@ local spawn_children_on_die = function(child_mob, children_count, spawn_distance -- If child would end up in a wall, use position of the "mother", unless -- the "mother" was stuck as well local speed_penalty = 1 - if (not mother_stuck) and minetest.registered_nodes[minetest.get_node(newpos).name].walkable then + local cndef = minetest.registered_nodes[minetest.get_node(newpos).name] + if (not mother_stuck) and cndef and cndef.walkable then newpos = pos speed_penalty = 0.5 end local mob = minetest.add_entity(newpos, child_mob) - if mob then - if (not mother_stuck) then - mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty)) - end - mob:set_yaw(angle - math.pi/2) - table.insert(children, mob) - angle = angle + (math.pi*2)/children_count + if (not mother_stuck) then + mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty)) end + mob:set_yaw(angle - math.pi/2) + table.insert(children, mob) + angle = angle + (math.pi*2)/children_count end -- If mother was murdered, children attack the killer after 1 second if self.state == "attack" then minetest.after(1.0, function(children, enemy) - for c = 1, #children do + for c=1, #children do local child = children[c] local le = child:get_luaentity() - if le then + if le ~= nil then le.state = "attack" le.attack = enemy end @@ -66,7 +66,6 @@ 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"}}, @@ -98,9 +97,8 @@ local slime_big = { }, fall_damage = 0, view_range = 16, - attack_type = "jump_punch", + attack_type = "dogfight", passive = false, - jump_only = true, jump = true, walk_velocity = 2.5, run_velocity = 2.5, @@ -313,7 +311,6 @@ local magma_cube_big = { }, walk_velocity = 4, run_velocity = 4, - rotate = 270, damage = 6, reach = 3, armor = 53, @@ -337,13 +334,12 @@ 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 = "jump_punch", + attack_type = "dogfight", passive = false, - jump_only = true, jump = true, jump_height = 8, walk_chance = 0, diff --git a/mods/ENTITIES/mobs_mc/snowman.lua b/mods/ENTITIES/mobs_mc/snowman.lua index 0726b8da0c..a5aaaac0f4 100644 --- a/mods/ENTITIES/mobs_mc/snowman.lua +++ b/mods/ENTITIES/mobs_mc/snowman.lua @@ -3,12 +3,12 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") local snow_trail_frequency = 0.5 -- Time in seconds for checking to add a new snow trail local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false -local mod_throwing = minetest.get_modpath("mcl_throwing") +local mod_throwing = minetest.get_modpath("mcl_throwing") ~= nil local gotten_texture = { "mobs_mc_snowman.png", @@ -124,6 +124,10 @@ mobs:register_mob("mobs_mc:snowman", { local pos = self.object:get_pos() minetest.sound_play("mcl_tools_shears_cut", {pos = pos}, true) + if minetest.registered_items["mcl_farming:pumpkin_face"] then + minetest.add_item({x=pos.x, y=pos.y+1.4, z=pos.z}, "mcl_farming:pumpkin_face") + end + -- Wear out if not minetest.is_creative_enabled(clicker:get_player_name()) then item:add_wear(mobs_mc.misc.shears_wear) @@ -179,9 +183,9 @@ mobs_mc.tools.check_snow_golem_summon = function(pos) minetest.remove_node(pos) minetest.remove_node(b1) minetest.remove_node(b2) - minetest.check_for_falling(pos) - minetest.check_for_falling(b1) - minetest.check_for_falling(b2) + core.check_for_falling(pos) + core.check_for_falling(b1) + core.check_for_falling(b2) local obj = minetest.add_entity(place, "mobs_mc:snowman") if obj then summon_particles(obj) 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 acb236445e..5c9ee492ba 100644 Binary files a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg differ 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 1ef7a52274..acb236445e 100644 Binary files a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg index c2743fbcc6..1ef7a52274 100644 Binary files a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg new file mode 100644 index 0000000000..c2743fbcc6 Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg differ 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 deleted file mode 100644 index 5c9ee492ba..0000000000 Binary files a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager_hurt.1.ogg and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/spider.lua b/mods/ENTITIES/mobs_mc/spider.lua index e1be9c3ed6..c1cb5be4bd 100644 --- a/mods/ENTITIES/mobs_mc/spider.lua +++ b/mods/ENTITIES/mobs_mc/spider.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### SPIDER @@ -17,22 +17,17 @@ local spider = { type = "monster", spawn_class = "hostile", passive = false, - hostile = true, - always_climb = true, docile_by_day = true, - attack_type = "punch", - punch_timer_cooloff = 0.5, - rotate = 270, + attack_type = "dogfight", + pathfinding = 1, 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.45, 0, -0.45, 0.45, 0.9, 0.45}, + collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.89, 0.7}, visual = "mesh", mesh = "mobs_mc_spider.b3d", textures = { @@ -49,7 +44,7 @@ local spider = { distance = 16, }, walk_velocity = 1.3, - run_velocity = 2.75, --spider can become extremely difficult if any higher + run_velocity = 2.8, 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 ccd73296ae..0c425bb515 100644 --- a/mods/ENTITIES/mobs_mc/squid.lua +++ b/mods/ENTITIES/mobs_mc/squid.lua @@ -4,7 +4,7 @@ --################### SQUID --################### -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") mobs:register_mob("mobs_mc:squid", { description = S("Squid"), @@ -17,8 +17,6 @@ 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", @@ -50,7 +48,8 @@ mobs:register_mob("mobs_mc:squid", { }, visual_size = {x=3, y=3}, makes_footstep_sound = false, - swim = true, + fly = true, + fly_in = { mobs_mc.items.water_source, mobs_mc.items.river_water_source }, 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 deleted file mode 100644 index e0715af9f0..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_chest.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_black.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_black.png deleted file mode 100644 index 40c39648f4..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_black.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_blue.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_blue.png deleted file mode 100644 index b02c41b266..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_blue.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_brown.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_brown.png deleted file mode 100644 index 2c7c71c2fa..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_brown.png and /dev/null differ 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 deleted file mode 100644 index 83f7a8faa1..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_cyan.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_gray.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_gray.png deleted file mode 100644 index a4bd9cb1f0..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_gray.png and /dev/null differ 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 deleted file mode 100644 index c3297ce942..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_green.png and /dev/null differ 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 deleted file mode 100644 index 71eabea536..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_blue.png and /dev/null differ 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 deleted file mode 100644 index 929a609507..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_light_gray.png and /dev/null differ 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 deleted file mode 100644 index 1507d6d795..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_lime.png and /dev/null differ 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 deleted file mode 100644 index 809e645fb6..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_magenta.png and /dev/null differ 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 deleted file mode 100644 index ff17ff67c3..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_orange.png and /dev/null differ 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 deleted file mode 100644 index 7009e6efc5..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_pink.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_purple.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_purple.png deleted file mode 100644 index 1de65a407f..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_purple.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_red.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_red.png deleted file mode 100644 index 645df49779..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_red.png and /dev/null differ 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 deleted file mode 100644 index c6ae669dd8..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_white.png and /dev/null differ 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 deleted file mode 100644 index 6318e163d7..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_llama_decor_yellow.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_spawn_icon_rabbit_caerbannog.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_spawn_icon_rabbit_caerbannog.png deleted file mode 100644 index 4244a83c6f..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_spawn_icon_rabbit_caerbannog.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_spit.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_spit.png deleted file mode 100644 index 6cdb3e0b3c..0000000000 Binary files a/mods/ENTITIES/mobs_mc/textures/mobs_mc_spit.png and /dev/null differ diff --git a/mods/ENTITIES/mobs_mc/vex.lua b/mods/ENTITIES/mobs_mc/vex.lua index 22f1e70d23..a72827d5d4 100644 --- a/mods/ENTITIES/mobs_mc/vex.lua +++ b/mods/ENTITIES/mobs_mc/vex.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### VEX @@ -36,6 +36,7 @@ mobs:register_mob("mobs_mc:vex", { view_range = 16, walk_velocity = 3.2, run_velocity = 5.9, + attack_type = "dogfight", sounds = { -- TODO: random death = "mobs_mc_vex_death", diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index ce2e765754..a2b828e091 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -19,7 +19,7 @@ -- TODO: Internal inventory, pick up items, trade with other villagers -- TODO: Farm stuff -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") local N = function(s) return s end local F = minetest.formspec_escape @@ -74,7 +74,7 @@ local professions = { }, { - { { "mcl_farming:pumpkin_face", 8, 13 }, E1 }, + { { "mcl_farming:pumpkin", 8, 13 }, E1 }, { E1, { "mcl_farming:pumpkin_pie", 2, 3} }, }, @@ -195,7 +195,7 @@ local professions = { { -- TODO: replace with empty map - { { "mcl_core:emerald", 7, 11}, { "mcl_maps:empty_map", 1, 1 } }, + { { "mcl_core:emerald", 7, 11}, { "mcl_maps:filled_map", 1, 1 } }, }, -- TODO: special maps @@ -409,7 +409,7 @@ local init_trades = function(self, inv) local offered_stack = ItemStack({name = offered_item, count = offered_count}) if mcl_enchanting.is_enchanted(offered_item) then if mcl_enchanting.is_book(offered_item) then - mcl_enchanting.enchant_uniform_randomly(offered_stack, {"soul_speed"}) + offered_stack = mcl_enchanting.enchant_uniform_randomly(offered_stack, {"soul_speed"}) else mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true) mcl_enchanting.unload_enchantments(offered_stack) @@ -962,18 +962,14 @@ 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 = 3, + run_velocity = 2.4, 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 030da54704..04c95b88f2 100644 --- a/mods/ENTITIES/mobs_mc/villager_evoker.lua +++ b/mods/ENTITIES/mobs_mc/villager_evoker.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### EVOKER @@ -35,7 +35,7 @@ mobs:register_mob("mobs_mc:evoker", { walk_velocity = 0.2, run_velocity = 1.4, group_attack = true, - attack_type = "punch", + attack_type = "dogfight", -- 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 bec5762e5a..496f08fc62 100644 --- a/mods/ENTITIES/mobs_mc/villager_illusioner.lua +++ b/mods/ENTITIES/mobs_mc/villager_illusioner.lua @@ -3,14 +3,14 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) -local mod_bows = minetest.get_modpath("mcl_bows") +local S = minetest.get_translator("mobs_mc") +local mod_bows = minetest.get_modpath("mcl_bows") ~= nil mobs:register_mob("mobs_mc:illusioner", { description = S("Illusioner"), type = "monster", spawn_class = "hostile", - attack_type = "projectile", + attack_type = "shoot", 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) - mobs.shoot_projectile_handling("mcl_bows:arrow", pos, dir, self.object:get_yaw(), self.object, nil, dmg) + mcl_bows.shoot_arrow("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 6a6999b96e..276f800116 100644 --- a/mods/ENTITIES/mobs_mc/villager_vindicator.lua +++ b/mods/ENTITIES/mobs_mc/villager_vindicator.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### VINDICATOR @@ -37,7 +37,7 @@ mobs:register_mob("mobs_mc:vindicator", { reach = 2, walk_velocity = 1.2, run_velocity = 2.4, - attack_type = "punch", + attack_type = "dogfight", 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 088839b659..1948b693d8 100644 --- a/mods/ENTITIES/mobs_mc/villager_zombie.lua +++ b/mods/ENTITIES/mobs_mc/villager_zombie.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### ZOMBIE VILLAGER @@ -29,9 +29,6 @@ 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, @@ -54,8 +51,8 @@ mobs:register_mob("mobs_mc:villager_zombie", { damage = 3, reach = 2, walk_velocity = 1.2, - run_velocity = 3.5, - attack_type = "punch", + run_velocity = 2.4, + attack_type = "dogfight", 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 34492a1b78..8ebe71fc02 100644 --- a/mods/ENTITIES/mobs_mc/witch.lua +++ b/mods/ENTITIES/mobs_mc/witch.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### WITCH @@ -34,7 +34,7 @@ mobs:register_mob("mobs_mc:witch", { run_velocity = 2.4, pathfinding = 1, group_attack = true, - attack_type = "projectile", + attack_type = "dogshoot", 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 22e095d98d..72459a3549 100644 --- a/mods/ENTITIES/mobs_mc/wither.lua +++ b/mods/ENTITIES/mobs_mc/wither.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### WITHER @@ -26,6 +26,7 @@ mobs:register_mob("mobs_mc:wither", { {"mobs_mc_wither.png"}, }, visual_size = {x=4, y=4}, + makes_footstep_sound = true, view_range = 16, fear_height = 4, walk_velocity = 2, @@ -52,7 +53,7 @@ mobs:register_mob("mobs_mc:wither", { }, lava_damage = 0, fire_damage = 0, - attack_type = "projectile", + attack_type = "dogshoot", explosion_strength = 8, dogshoot_stop = true, arrow = "mobs_mc:wither_skull", @@ -80,7 +81,7 @@ mobs:register_mob("mobs_mc:wither", { end, }) ---local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false +local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false mobs:register_arrow("mobs_mc:wither_skull", { visual = "sprite", diff --git a/mods/ENTITIES/mobs_mc/wolf.lua b/mods/ENTITIES/mobs_mc/wolf.lua index 0b685d40f0..7f14ac6b0d 100644 --- a/mods/ENTITIES/mobs_mc/wolf.lua +++ b/mods/ENTITIES/mobs_mc/wolf.lua @@ -1,6 +1,6 @@ --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") local default_walk_chance = 50 @@ -23,31 +23,13 @@ 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, - - --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}, + collisionbox = {-0.3, -0.01, -0.3, 0.3, 0.84, 0.3}, visual = "mesh", mesh = "mobs_mc_wolf.b3d", textures = { @@ -71,7 +53,7 @@ local wolf = { run_velocity = 3, damage = 4, reach = 2, - attack_type = "punch", + attack_type = "dogfight", fear_height = 4, follow = mobs_mc.follow.wolf, on_rightclick = function(self, clicker) @@ -93,7 +75,6 @@ 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 @@ -161,32 +142,20 @@ 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() - --owner is broken for this - --attempt to enter breed state - if mobs.enter_breed_state(self,clicker) then + if mobs:protect(self, clicker) then return - end - - --make baby grow faster - if self.baby then - mobs.make_baby_grow_faster(self,clicker) + elseif item:get_name() ~= "" and mobs:capture_mob(self, clicker, 0, 2, 80, false, nil) then return - end - - if is_food(item:get_name()) then + elseif is_food(item:get_name()) then -- Feed to increase health local hp = self.health - local hp_add + local hp_add = 0 -- Use eatable group to determine health boost local eatable = minetest.get_item_group(item, "eatable") if eatable > 0 then diff --git a/mods/ENTITIES/mobs_mc/zombie.lua b/mods/ENTITIES/mobs_mc/zombie.lua index e1247d8bdd..4ae5796b30 100644 --- a/mods/ENTITIES/mobs_mc/zombie.lua +++ b/mods/ENTITIES/mobs_mc/zombie.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### ZOMBIE @@ -49,8 +49,6 @@ local zombie = { description = S("Zombie"), type = "monster", spawn_class = "hostile", - hostile = true, - rotate = 270, hp_min = 20, hp_max = 20, xp_min = 5, @@ -76,25 +74,8 @@ local zombie = { damage = "mobs_mc_zombie_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 - - eye_height = 1.65, - walk_velocity = 1, - run_velocity = 3.5, + walk_velocity = .8, + run_velocity = 1.6, damage = 3, reach = 2, fear_height = 4, @@ -112,8 +93,7 @@ local zombie = { ignited_by_sunlight = true, sunlight_damage = 2, view_range = 16, - attack_type = "punch", - punch_timer_cooloff = 0.5, + attack_type = "dogfight", harmed_by_heal = true, } diff --git a/mods/ENTITIES/mobs_mc/zombiepig.lua b/mods/ENTITIES/mobs_mc/zombiepig.lua index b4088deef4..1ea4197c16 100644 --- a/mods/ENTITIES/mobs_mc/zombiepig.lua +++ b/mods/ENTITIES/mobs_mc/zombiepig.lua @@ -3,7 +3,7 @@ --made for MC like Survival game --License for code WTFPL and otherwise stated in readmes -local S = minetest.get_translator(minetest.get_current_modname()) +local S = minetest.get_translator("mobs_mc") --################### --################### ZOMBIE PIGMAN @@ -15,16 +15,13 @@ 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 = "punch", + attack_type = "dogfight", group_attack = { "mobs_mc:pigman", "mobs_mc:baby_pigman" }, damage = 9, reach = 2, @@ -44,22 +41,6 @@ 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, diff --git a/mods/ENTITIES/mobs_mc_gameconfig/init.lua b/mods/ENTITIES/mobs_mc_gameconfig/init.lua index 27cb4b4bf3..06d7eb87fa 100644 --- a/mods/ENTITIES/mobs_mc_gameconfig/init.lua +++ b/mods/ENTITIES/mobs_mc_gameconfig/init.lua @@ -200,14 +200,14 @@ end mobs_mc.override.enderman_block_texture_overrides = { ["mcl_core:cactus"] = ctable, -- FIXME: replace colorize colors with colors from palette - ["mcl_core:dirt_with_grass"] = { - "mcl_core_grass_block_top.png^[colorize:green:90", - "default_dirt.png", - "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)", - "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)", - "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)", - "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)", - }, + ["mcl_core:dirt_with_grass"] = + { + "mcl_core_grass_block_top.png^[colorize:green:90", + "default_dirt.png", + "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)", + "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)", + "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)", + "default_dirt.png^(mcl_core_grass_block_side_overlay.png^[colorize:green:90)"} } -- List of nodes on which mobs can spawn diff --git a/mods/ENVIRONMENT/lightning/locale/lightning.zh_TW.tr b/mods/ENVIRONMENT/lightning/locale/lightning.zh_TW.tr new file mode 100644 index 0000000000..0667e8dc80 --- /dev/null +++ b/mods/ENVIRONMENT/lightning/locale/lightning.zh_TW.tr @@ -0,0 +1,4 @@ +# textdomain: lightning +@1 was struck by lightning.=@1 被閃電擊斃。 +Let lightning strike at the specified position or yourself=讓閃電擊中指定位置或自己 +No position specified and unknown player=未指定位置且玩家未知 diff --git a/mods/ENVIRONMENT/mcl_void_damage/locale/mcl_void_damage.zh_TW.tr b/mods/ENVIRONMENT/mcl_void_damage/locale/mcl_void_damage.zh_TW.tr new file mode 100644 index 0000000000..515e83fcc1 --- /dev/null +++ b/mods/ENVIRONMENT/mcl_void_damage/locale/mcl_void_damage.zh_TW.tr @@ -0,0 +1,3 @@ +# textdomain: mcl_void_damage +The void is off-limits to you!=你不可以進入虛空! +@1 fell into the endless void.=@1 掉到世界外面了。 diff --git a/mods/ENVIRONMENT/mcl_weather/locale/mcl_weather.zh_TW.tr b/mods/ENVIRONMENT/mcl_weather/locale/mcl_weather.zh_TW.tr new file mode 100644 index 0000000000..42be7481b3 --- /dev/null +++ b/mods/ENVIRONMENT/mcl_weather/locale/mcl_weather.zh_TW.tr @@ -0,0 +1,8 @@ +# textdomain: mcl_weather +Gives ability to control weather=賦予控制天氣的能力 +Changes the weather to the specified parameter.=將天氣改為指定的參數。 +Error: No weather specified.=錯誤:未指定天氣。 +Error: Invalid parameters.=錯誤:無效參數。 +Error: Duration can't be less than 1 second.=錯誤:延續時間不可以短於1秒。 +Error: Invalid weather specified. Use “clear”, “rain”, “snow” or “thunder”.=錯誤:不明天氣。請使用「clear」、「rain」、「snow」或「thunder」。 +Toggles between clear weather and weather with downfall (randomly rain, thunderstorm or snow)=在晴朗的天氣和降雨天氣之間切換(隨機選擇雨、雷暴或雪)。 diff --git a/mods/ENVIRONMENT/mcl_weather/nether_dust.lua b/mods/ENVIRONMENT/mcl_weather/nether_dust.lua index d328dae214..4ab9e4081d 100644 --- a/mods/ENVIRONMENT/mcl_weather/nether_dust.lua +++ b/mods/ENVIRONMENT/mcl_weather/nether_dust.lua @@ -1,36 +1,66 @@ mcl_weather.nether_dust = {} -mcl_weather.nether_dust.particles_count = 99 +mcl_weather.nether_dust.particlespawners = {} --- calculates coordinates and draw particles for Nether dust -function mcl_weather.nether_dust.add_dust_particles(player) - for i=mcl_weather.nether_dust.particles_count, 1,-1 do - local rpx, rpy, rpz = mcl_weather.get_random_pos_by_player_look_dir(player) - minetest.add_particle({ - pos = {x = rpx, y = rpy - math.random(6, 18), z = rpz}, - velocity = {x = math.random(-30,30)*0.01, y = math.random(-15,15)*0.01, z = math.random(-30,30)*0.01}, - acceleration = {x = math.random(-50,50)*0.02, y = math.random(-20,20)*0.02, z = math.random(-50,50)*0.02}, - expirationtime = 3, - size = math.random(6,20)*0.01, - collisiondetection = false, - object_collision = false, - vertical = false, - glow = math.random(0,minetest.LIGHT_MAX), - texture = "mcl_particles_nether_dust"..tostring(i%3+1)..".png", - playername = player:get_player_name() - }) +local psdef= { + amount = 150, + time = 0, + minpos = vector.new(-15,-15,-15), + maxpos =vector.new(15,15,15), + minvel = vector.new(-0.3,-0.15,-1), + maxvel = vector.new(0.3,0.15,0.3), + minacc = vector.new(-1,-0.4,-1), + maxacc = vector.new(1,0.4,1), + minexptime = 1, + maxexptime = 10, + minsize = 0.2, + maxsize = 0.7, + collisiondetection = false, + collision_removal = false, + object_collision = false, + vertical = false +} + +local function check_player(player) + local name=player:get_player_name() + if mcl_worlds.has_dust(player:get_pos()) and not mcl_weather.nether_dust.particlespawners[name] then + return true + end +end + +mcl_weather.nether_dust.add_particlespawners = function(player) + local name=player:get_player_name(name) + mcl_weather.nether_dust.particlespawners[name]={} + psdef.playername = name + psdef.attached = player + psdef.glow = math.random(0,minetest.LIGHT_MAX) + for i=1,3 do + psdef.texture="mcl_particles_nether_dust"..i..".png" + mcl_weather.nether_dust.particlespawners[name][i]=minetest.add_particlespawner(psdef) end end -local timer = 0 -minetest.register_globalstep(function(dtime) - timer = timer + dtime - if timer < 0.7 then return end - timer = 0 - - for _, player in pairs(minetest.get_connected_players()) do - if not mcl_worlds.has_dust(player:get_pos()) then - return false +mcl_weather.nether_dust.delete_particlespawners = function(player) + local name=player:get_player_name(name) + if mcl_weather.nether_dust.particlespawners[name] then + for i=1,3 do + minetest.delete_particlespawner(mcl_weather.nether_dust.particlespawners[name][i]) end - mcl_weather.nether_dust.add_dust_particles(player) + mcl_weather.nether_dust.particlespawners[name]=nil + end +end + +mcl_worlds.register_on_dimension_change(function(player, dimension) + if check_player(player) then + return mcl_weather.nether_dust.add_particlespawners(player) + end + mcl_weather.nether_dust.delete_particlespawners(player) +end) + +minetest.register_on_joinplayer(function(player) + if check_player(player) then + mcl_weather.nether_dust.add_particlespawners(player) end end) +minetest.register_on_leaveplayer(function(player) + mcl_weather.nether_dust.delete_particlespawners(player) +end) diff --git a/mods/ENVIRONMENT/mcl_weather/rain.lua b/mods/ENVIRONMENT/mcl_weather/rain.lua index 220b610066..0caef5c6f4 100644 --- a/mods/ENVIRONMENT/mcl_weather/rain.lua +++ b/mods/ENVIRONMENT/mcl_weather/rain.lua @@ -1,5 +1,5 @@ -local PARTICLES_COUNT_RAIN = 30 -local PARTICLES_COUNT_THUNDER = 45 +local PARTICLES_COUNT_RAIN = 100 +local PARTICLES_COUNT_THUNDER = 300 local get_connected_players = minetest.get_connected_players @@ -19,6 +19,45 @@ mcl_weather.rain = { init_done = false, } +local update_sound={} +local vel=math.random(0,3) +local falling_speed=math.random(10,15) +local size = math.random(1,3) +local psdef= { + amount = mcl_weather.rain.particles_count, + time=0, + minpos = vector.new(-6,3,-6), + maxpos = vector.new(6,15,6), + minvel = vector.new(-vel,-falling_speed,-vel), + maxvel = vector.new(vel,-falling_speed+vel,vel), + minacc = vector.new(0,0,0), + maxacc = vector.new(0,-0.4,0), + minexptime = 0.5, + maxexptime = 2, + minsize = size, + maxsize= size*2, + collisiondetection = true, + collision_removal = true, + vertical = true, +} +local psdef_backsplash= { + amount = 10, + time=0, + minpos = vector.new(-3,-1,-3), + maxpos = vector.new(3,0,3), + minvel = vector.new(-vel,falling_speed*2,-vel), + maxvel = vector.new(vel,falling_speed*2+vel,vel), + minacc = vector.new(0,0,0), + maxacc = vector.new(0,0,0), + minexptime = 0.1, + maxexptime = 0.2, + minsize = size*0.1, + maxsize= size*0.5, + collisiondetection = true, + collision_removal = true, + vertical = true, +} +local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png", "weather_pack_rain_raindrop_1.png"} function mcl_weather.rain.sound_handler(player) return minetest.sound_play("weather_rain", { @@ -44,42 +83,18 @@ function mcl_weather.rain.set_sky_box() end end --- creating manually parctiles instead of particles spawner because of easier to control --- spawn position. +-- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net. function mcl_weather.rain.add_rain_particles(player) - mcl_weather.rain.last_rp_count = 0 - for i=mcl_weather.rain.particles_count, 1,-1 do - local random_pos_x, random_pos_y, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player) - if mcl_weather.is_outdoor({x=random_pos_x, y=random_pos_y, z=random_pos_z}) then - mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1 - minetest.add_particle({ - pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z}, - velocity = {x=0, y=-10, z=0}, - acceleration = {x=0, y=-30, z=0}, - expirationtime = 1.0, - size = math.random(0.5, 3), - collisiondetection = true, - collision_removal = true, - vertical = true, - texture = mcl_weather.rain.get_texture(), - playername = player:get_player_name() - }) - end + mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count + for k,v in pairs(textures) do + psdef.texture=v + mcl_weather.add_spawner_player(player,"rain"..k,psdef) end -end - --- Simple random texture getter -function mcl_weather.rain.get_texture() - local texture_name - local random_number = math.random() - if random_number > 0.33 then - texture_name = "weather_pack_rain_raindrop_1.png" - elseif random_number > 0.66 then - texture_name = "weather_pack_rain_raindrop_2.png" - else - texture_name = "weather_pack_rain_raindrop_3.png" + psdef_backsplash.texture=textures[math.random(1,#textures)] + local l=mcl_weather.add_spawner_player(player,"rainbacksplash",psdef_backsplash) + if l then + update_sound[player:get_player_name()]=true end - return texture_name; end -- register player for rain weather. @@ -89,6 +104,7 @@ function mcl_weather.rain.add_player(player) local player_meta = {} player_meta.origin_sky = {player:get_sky()} mcl_weather.players[player:get_player_name()] = player_meta + update_sound[player:get_player_name()]=true end end @@ -99,26 +115,15 @@ function mcl_weather.rain.remove_player(player) if player_meta and player_meta.origin_sky then player:set_clouds({color="#FFF0F0E5"}) mcl_weather.players[player:get_player_name()] = nil + update_sound[player:get_player_name()]=true end end -mcl_worlds.register_on_dimension_change(function(player, dimension) - if dimension ~= "overworld" and dimension ~= "void" then - mcl_weather.rain.remove_sound(player) - mcl_weather.rain.remove_player(player) - elseif dimension == "overworld" then - mcl_weather.rain.update_sound(player) - if mcl_weather.rain.raining then - mcl_weather.rain.add_rain_particles(player) - mcl_weather.rain.add_player(player) - end - end -end) - -- adds and removes rain sound depending how much rain particles around player currently exist. -- have few seconds delay before each check to avoid on/off sound too often -- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance. function mcl_weather.rain.update_sound(player) + if not update_sound[player:get_player_name()] then return end local player_meta = mcl_weather.players[player:get_player_name()] if player_meta then if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then @@ -136,6 +141,7 @@ function mcl_weather.rain.update_sound(player) player_meta.sound_updated = minetest.get_gametime() end + update_sound[player:get_player_name()]=false end -- rain sound removed from player. @@ -158,7 +164,8 @@ function mcl_weather.rain.clear() for _, player in pairs(get_connected_players()) do mcl_weather.rain.remove_sound(player) mcl_weather.rain.remove_player(player) - end + mcl_weather.remove_spawners_player(player) + end end minetest.register_globalstep(function(dtime) @@ -177,8 +184,10 @@ function mcl_weather.rain.make_weather() end for _, player in pairs(get_connected_players()) do - if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then + local pos=player:get_pos() + if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(pos) or not mcl_weather.is_outdoor(pos) then mcl_weather.rain.remove_sound(player) + mcl_weather.remove_spawners_player(player) return false end mcl_weather.rain.add_player(player) @@ -190,8 +199,12 @@ end -- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops function mcl_weather.rain.set_particles_mode(mode) if mode == "thunder" then + psdef.amount=PARTICLES_COUNT_THUNDER + psdef_backsplash.amount=PARTICLES_COUNT_THUNDER mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER else + psdef.amount=PARTICLES_COUNT_RAIN + psdef_backsplash.amount=PARTICLES_COUNT_RAIN mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN end end diff --git a/mods/ENVIRONMENT/mcl_weather/skycolor.lua b/mods/ENVIRONMENT/mcl_weather/skycolor.lua index 6b89c33bec..7b6183d447 100644 --- a/mods/ENVIRONMENT/mcl_weather/skycolor.lua +++ b/mods/ENVIRONMENT/mcl_weather/skycolor.lua @@ -240,8 +240,7 @@ local function initsky(player) mcl_weather.skycolor.force_update = true end - -- MC-style clouds: Layer 127, thickness 4, fly to the “West” - player:set_clouds({height=mcl_worlds.layer_to_y(127), speed={x=-2, z=0}, thickness=4, color="#FFF0FEF"}) + player:set_clouds(mcl_worlds:get_cloud_parameters() or {height=mcl_worlds.layer_to_y(127), speed={x=-2, z=0}, thickness=4, color="#FFF0FEF"}) end minetest.register_on_joinplayer(initsky) diff --git a/mods/ENVIRONMENT/mcl_weather/snow.lua b/mods/ENVIRONMENT/mcl_weather/snow.lua index 9f89a3a0ac..b602831278 100644 --- a/mods/ENVIRONMENT/mcl_weather/snow.lua +++ b/mods/ENVIRONMENT/mcl_weather/snow.lua @@ -5,30 +5,25 @@ mcl_weather.snow = {} mcl_weather.snow.particles_count = 15 mcl_weather.snow.init_done = false --- calculates coordinates and draw particles for snow weather -function mcl_weather.snow.add_snow_particles(player) - mcl_weather.rain.last_rp_count = 0 - for i=mcl_weather.snow.particles_count, 1,-1 do - local random_pos_x, _, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player) - local random_pos_y = math.random() + math.random(player:get_pos().y - 1, player:get_pos().y + 7) - if minetest.get_node_light({x=random_pos_x, y=random_pos_y, z=random_pos_z}, 0.5) == 15 then - mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1 - minetest.add_particle({ - pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z}, - velocity = {x = math.random(-100,100)*0.001, y = math.random(-300,-100)*0.004, z = math.random(-100,100)*0.001}, - acceleration = {x = 0, y=0, z = 0}, - expirationtime = 8.0, - size = 1, - collisiondetection = true, - collision_removal = true, - object_collision = false, - vertical = false, - texture = mcl_weather.snow.get_texture(), - playername = player:get_player_name() - }) - end - end -end +local psdef= { + amount = 99, + time = 0, --stay on til we turn it off + minpos = vector.new(-15,-5,-15), + maxpos =vector.new(15,10,15), + minvel = vector.new(0,-1,0), + maxvel = vector.new(0,-4,0), + minacc = vector.new(0,-1,0), + maxacc = vector.new(0,-4,0), + minexptime = 1, + maxexptime = 1, + minsize = 0.5, + maxsize = 5, + collisiondetection = true, + collision_removal = true, + object_collision = true, + vertical = true, + glow = 1 +} function mcl_weather.snow.set_sky_box() mcl_weather.skycolor.add_layer( @@ -48,6 +43,7 @@ end function mcl_weather.snow.clear() mcl_weather.skycolor.remove_layer("weather-pack-snow-sky") mcl_weather.snow.init_done = false + mcl_weather.remove_all_spawners() end -- Simple random texture getter @@ -74,10 +70,14 @@ minetest.register_globalstep(function(dtime) end for _, player in pairs(get_connected_players()) do - if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then + if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos()) or not mcl_weather.is_outdoor(player:get_pos())) then + mcl_weather.remove_spawners_player(player) return false end - mcl_weather.snow.add_snow_particles(player) + for i=1,2 do + psdef.texture="weather_pack_snow_snowflake"..i..".png" + mcl_weather.add_spawner_player(player,"snow"..i,psdef) + end end end) diff --git a/mods/ENVIRONMENT/mcl_weather/weather_core.lua b/mods/ENVIRONMENT/mcl_weather/weather_core.lua index 34f69406df..f7316bcfbe 100644 --- a/mods/ENVIRONMENT/mcl_weather/weather_core.lua +++ b/mods/ENVIRONMENT/mcl_weather/weather_core.lua @@ -47,6 +47,35 @@ local function save_weather() end minetest.register_on_shutdown(save_weather) +local particlespawners={} +function mcl_weather.add_spawner_player(pl,id,ps) + local name=pl:get_player_name() + if not particlespawners[name] then + particlespawners[name] = {} + end + if not particlespawners[name][id] then + ps.playername =name + ps.attached = pl + particlespawners[name][id]=minetest.add_particlespawner(ps) + return particlespawners[name][id] + end +end +function mcl_weather.remove_spawners_player(pl) + local name=pl:get_player_name() + if not particlespawners[name] then return end + for k,v in pairs(particlespawners[name]) do + minetest.delete_particlespawner(v) + end + particlespawners[name] = nil + return true +end + +function mcl_weather.remove_all_spawners() + for k,v in pairs(minetest.get_connected_players()) do + mcl_weather.remove_spawners_player(v) + end +end + function mcl_weather.get_rand_end_time(min_duration, max_duration) local r if min_duration and max_duration then @@ -92,36 +121,6 @@ function mcl_weather.is_underwater(player) return false end --- trying to locate position for particles by player look direction for performance reason. --- it is costly to generate many particles around player so goal is focus mainly on front view. -function mcl_weather.get_random_pos_by_player_look_dir(player) - local look_dir = player:get_look_dir() - local player_pos = player:get_pos() - - local random_pos_x, random_pos_y, random_pos_z - - if look_dir.x > 0 then - if look_dir.z > 0 then - random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5) - random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5) - else - random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5) - random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5) - end - else - if look_dir.z > 0 then - random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5) - random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5) - else - random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5) - random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5) - end - end - - random_pos_y = math.random() + math.random(player_pos.y + 10, player_pos.y + 15) - return random_pos_x, random_pos_y, random_pos_z -end - local t, wci = 0, mcl_weather.check_interval minetest.register_globalstep(function(dtime) diff --git a/mods/HELP/doc/doc_identifier/locale/doc_identifier.zh_TW.tr b/mods/HELP/doc/doc_identifier/locale/doc_identifier.zh_TW.tr new file mode 100644 index 0000000000..727887db91 --- /dev/null +++ b/mods/HELP/doc/doc_identifier/locale/doc_identifier.zh_TW.tr @@ -0,0 +1,18 @@ +# textdomain:doc_identifier +Error: This node, item or object is undefined. This is always an error.=錯誤:該方塊、物品或實體未定義。這總是一個錯誤。 +This can happen for the following reasons:=發生這種情況的原因有機會是: +• The mod which is required for it is not enabled=• 未啟用所需的MOD +• The author of the game or a mod has made a mistake=• 遊戲或mod的作者犯了一個錯誤 +It appears to originate from the mod “@1”, which is enabled.=它似乎來自以啟用的mod「@1」。 +It appears to originate from the mod “@1”, which is not enabled!=它似乎來自沒啟用的mod「@1」! +Its identifier is “@1”.=其標識符為「@1」。 +Lookup Tool=幫助工具 +No help entry for this block could be found.=找不到此方塊的幫助條目。 +No help entry for this item could be found.=找不到此物品的幫助條目。 +No help entry for this object could be found.=找不到此實體的幫助條目。 +OK=OK +Punch any block, item or other thing about you wish to learn more about. This will open up the appropriate help entry. The tool comes in two modes which are changed by using. In liquid mode, this tool points to liquids as well while in solid mode this is not the case.=擊打任何你想了解更多的方塊、物品或其他事情。這將打開相應的幫助條目。該工具有兩種模式,可以通過使用來改變。在液體模式下,這個工具也會指向液體,而在固體模式下則不會這樣。 +This block cannot be identified because the world has not materialized at this point yet. Try again in a few seconds.=方塊所在的區塊未加載,請等一下在試一次。 +This is a player.=這是一個玩家。 +This useful little helper can be used to quickly learn more about about one's closer environment. It identifies and analyzes blocks, items and other things and it shows extensive information about the thing on which it is used.=這個有用的小幫手可以用來快速了解自己所處的近距離環境。它可以識別和分析區塊、物品和其他事物。當你對着一個方塊、物品或實體使用它時,可以顯示出那個事物的大量信息。 +Show help for pointed thing=顯示選中方塊的資訊 diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index 3bc7b705a1..5e36860476 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -548,7 +548,7 @@ local function get_recipe_fs(data, iY) shapeless and "shapeless" or "furnace" if recipe.type == "cooking" then - icon = "default_furnace_front_active.png" + icon = "craftguide_furnace.png" elseif not custom_recipe then icon = fmt("craftguide_%s.png", icon) end diff --git a/mods/HELP/mcl_craftguide/textures/craftguide_furnace.png b/mods/HELP/mcl_craftguide/textures/craftguide_furnace.png new file mode 100644 index 0000000000..c425604d25 Binary files /dev/null and b/mods/HELP/mcl_craftguide/textures/craftguide_furnace.png differ diff --git a/mods/HELP/tt/init.lua b/mods/HELP/tt/init.lua index 819bf7b813..f2b83b612c 100644 --- a/mods/HELP/tt/init.lua +++ b/mods/HELP/tt/init.lua @@ -76,8 +76,6 @@ function tt.reload_itemstack_description(itemstack) orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name")) end local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack) - if desc ~= orig_desc then - meta:set_string("description", desc) - end + meta:set_string("description", desc) end end diff --git a/mods/HUD/hudbars/locale/hudbars.zh_TW.tr b/mods/HUD/hudbars/locale/hudbars.zh_TW.tr new file mode 100644 index 0000000000..2163c659eb --- /dev/null +++ b/mods/HUD/hudbars/locale/hudbars.zh_TW.tr @@ -0,0 +1,6 @@ +# textdomain: hudbars +Health=生命 +Breath=氧氣 + +# Default format string for progress bar-style HUD bars, e.g. “Health 5/20” +@1: @2/@3= diff --git a/mods/HUD/mcl_experience/bottle.lua b/mods/HUD/mcl_experience/bottle.lua index 10e42a57db..17a70054d9 100644 --- a/mods/HUD/mcl_experience/bottle.lua +++ b/mods/HUD/mcl_experience/bottle.lua @@ -1,5 +1,7 @@ local S = minetest.get_translator(minetest.get_current_modname()) +local mod_target = minetest.get_modpath("mcl_target") + minetest.register_entity("mcl_experience:bottle",{ textures = {"mcl_experience_bottle.png"}, hp_max = 1, @@ -30,6 +32,9 @@ minetest.register_entity("mcl_experience:bottle",{ vertical = false, texture = "mcl_particles_effect.png^[colorize:blue:127", }) + if mod_target and n == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end self.object:remove() end end, diff --git a/mods/HUD/mcl_experience/locale/mcl_experience.zh_TW.tr b/mods/HUD/mcl_experience/locale/mcl_experience.zh_TW.tr new file mode 100644 index 0000000000..a10e47e617 --- /dev/null +++ b/mods/HUD/mcl_experience/locale/mcl_experience.zh_TW.tr @@ -0,0 +1,7 @@ +# textdomain: mcl_experience +[[] ]=[[<玩家名字>] <經驗值>] +Gives a player some XP=給予玩家經驗值 +Error: Too many parameters!=錯誤:太多參數! +Error: Incorrect value of XP=錯誤:經驗值數值不當! +Error: Player not found=錯誤:找不到玩家! +Added @1 XP to @2, total: @3, experience level: @4=已給予 @2 @1 點經驗值,共有 @3 點,經驗等級:@4 diff --git a/mods/HUD/mcl_hbarmor/locale/mcl_hbarmor.zh_TW.tr b/mods/HUD/mcl_hbarmor/locale/mcl_hbarmor.zh_TW.tr new file mode 100644 index 0000000000..a0dc8174e0 --- /dev/null +++ b/mods/HUD/mcl_hbarmor/locale/mcl_hbarmor.zh_TW.tr @@ -0,0 +1,2 @@ +# textdomain:hbarmor +Armor=防禦點數 diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index f5a9574eb9..d66aa06d2c 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -363,6 +363,10 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size, armor_slot_imgs = armor_slot_imgs .. "image[5.5,2.75;1,1;mcl_inventory_empty_armor_slot_boots.png]" end + if inv:get_stack("offhand", 1):is_empty() then + armor_slot_imgs = armor_slot_imgs .. "image[1.5,2.025;1,1;mcl_inventory_empty_armor_slot_shield.png]" + end + local stack_size = get_stack_size(player) -- Survival inventory slots @@ -377,6 +381,8 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size, mcl_formspec.get_itemslot_bg(2.5,2.75,1,1).. mcl_formspec.get_itemslot_bg(5.5,1.3,1,1).. mcl_formspec.get_itemslot_bg(5.5,2.75,1,1).. + "list[current_player;offhand;1.5,2.025;1,1]".. + mcl_formspec.get_itemslot_bg(1.5,2.025,1,1).. armor_slot_imgs.. -- player preview player_preview.. diff --git a/mods/HUD/mcl_inventory/init.lua b/mods/HUD/mcl_inventory/init.lua index c197bfdd96..0d411502d1 100644 --- a/mods/HUD/mcl_inventory/init.lua +++ b/mods/HUD/mcl_inventory/init.lua @@ -76,6 +76,10 @@ local function set_inventory(player, armor_change_only) end end + if inv:get_stack("offhand", 1):is_empty() then + armor_slot_imgs = armor_slot_imgs .. "image[3,2;1,1;mcl_inventory_empty_armor_slot_shield.png]" + end + local form = "size[9,8.75]".. "background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]".. player_preview.. @@ -88,6 +92,8 @@ local function set_inventory(player, armor_change_only) mcl_formspec.get_itemslot_bg(0,1,1,1).. mcl_formspec.get_itemslot_bg(0,2,1,1).. mcl_formspec.get_itemslot_bg(0,3,1,1).. + "list[current_player;offhand;3,2;1,1]".. + mcl_formspec.get_itemslot_bg(3,2,1,1).. armor_slot_imgs.. -- craft and inventory "label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))).."]".. @@ -148,8 +154,10 @@ end) minetest.register_on_joinplayer(function(player) --init inventory - player:get_inventory():set_width("main", 9) - player:get_inventory():set_size("main", 36) + local inv = player:get_inventory() + inv:set_width("main", 9) + inv:set_size("main", 36) + inv:set_size("offhand", 1) --set hotbar size player:hud_set_hotbar_itemcount(9) diff --git a/mods/HUD/mcl_inventory/locale/mcl_inventory.zh_TW.tr b/mods/HUD/mcl_inventory/locale/mcl_inventory.zh_TW.tr new file mode 100644 index 0000000000..880d224f2b --- /dev/null +++ b/mods/HUD/mcl_inventory/locale/mcl_inventory.zh_TW.tr @@ -0,0 +1,21 @@ +# textdomain: mcl_inventory +Recipe book=合成教學 +Help=幫助 +Select player skin=選擇玩家皮膚 +Achievements=成就 +Building Blocks=建築方塊 +Decoration Blocks=裝飾性方塊 +Redstone=紅石 +Transportation=交通 +Brewing=釀造 +Miscellaneous=雜項 +Search Items=搜尋 +Foodstuffs=食物 +Tools=工具 +Combat=戰鬥 +Mobs=生物 +Materials=材料 +Survival Inventory=生存模式物品欄 +Crafting=合成 +Inventory=物品欄 +@1/@2= diff --git a/mods/HUD/mcl_offhand/init.lua b/mods/HUD/mcl_offhand/init.lua new file mode 100644 index 0000000000..b0fc223ec2 --- /dev/null +++ b/mods/HUD/mcl_offhand/init.lua @@ -0,0 +1,171 @@ +local minetest, math = minetest, math +mcl_offhand = {} + +local max_offhand_px = 128 +-- only supports up to 128px textures + +function mcl_offhand.get_offhand(player) + return player:get_inventory():get_stack("offhand", 1) +end + +local function offhand_get_wear(player) + return mcl_offhand.get_offhand(player):get_wear() +end + +local function offhand_get_count(player) + return mcl_offhand.get_offhand(player):get_count() +end + +minetest.register_on_joinplayer(function(player, last_login) + mcl_offhand[player] = { + hud = {}, + last_wear = offhand_get_wear(player), + last_count = offhand_get_count(player), + } +end) + +local function remove_hud(player, hud) + local offhand_hud = mcl_offhand[player].hud[hud] + if offhand_hud then + player:hud_remove(offhand_hud) + mcl_offhand[player].hud[hud] = nil + end +end + +function rgb_to_hex(r, g, b) + return string.format("%02x%02x%02x", r, g, b) +end + +local function update_wear_bar(player, itemstack) + local wear_bar_percent = (65535 - offhand_get_wear(player)) / 65535 + + local color = {255, 255, 255} + local wear = itemstack:get_wear() / 65535; + local wear_i = math.min(math.floor(wear * 600), 511); + wear_i = math.min(wear_i + 10, 511); + if wear_i <= 255 then + color = {wear_i, 255, 0} + else + color = {255, 511 - wear_i, 0} + end + local wear_bar = mcl_offhand[player].hud.wear_bar + player:hud_change(wear_bar, "text", "mcl_wear_bar.png^[colorize:#" .. rgb_to_hex(color[1], color[2], color[3])) + player:hud_change(wear_bar, "scale", {x = 40 * wear_bar_percent, y = 3}) + player:hud_change(wear_bar, "offset", {x = -320 - (20 - player:hud_get(wear_bar).scale.x / 2), y = -13}) +end + +minetest.register_globalstep(function(dtime) + for _, player in pairs(minetest.get_connected_players()) do + local itemstack = mcl_offhand.get_offhand(player) + local offhand_item = itemstack:get_name() + local offhand_hud = mcl_offhand[player].hud + if offhand_item ~= "" then + local item_texture = minetest.registered_items[offhand_item].inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px + local position = {x = 0.5, y = 1} + local offset = {x = -320, y = -32} + + if not offhand_hud.slot then + offhand_hud.slot = player:hud_add({ + hud_elem_type = "image", + position = position, + offset = offset, + scale = {x = 2.75, y = 2.75}, + text = "mcl_offhand_slot.png", + z_index = 0, + }) + end + if not offhand_hud.item then + offhand_hud.item = player:hud_add({ + hud_elem_type = "image", + position = position, + offset = offset, + scale = {x = 0.4, y = 0.4}, + text = item_texture, + z_index = 1, + }) + else + player:hud_change(offhand_hud.item, "text", item_texture) + end + if not offhand_hud.wear_bar_bg and minetest.registered_tools[offhand_item] then + if offhand_get_wear(player) > 0 then + local texture = "mcl_wear_bar.png^[colorize:#000000" + offhand_hud.wear_bar_bg = player:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 1}, + offset = {x = -320, y = -13}, + scale = {x = 40, y = 3}, + text = texture, + z_index = 2, + }) + offhand_hud.wear_bar = player:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 1}, + offset = {x = -320, y = -13}, + scale = {x = 10, y = 3}, + text = texture, + z_index = 3, + }) + update_wear_bar(player, itemstack) + end + end + + if not offhand_hud.item_count and offhand_get_count(player) > 1 then + offhand_hud.item_count = player:hud_add({ + hud_elem_type = "text", + position = {x = 0.5, y = 1}, + offset = {x = -298, y = -18}, + scale = {x = 1, y = 1}, + alignment = {x = -1, y = 0}, + text = offhand_get_count(player), + z_index = 4, + number = 0xFFFFFF, + }) + end + + if offhand_hud.wear_bar then + if offhand_hud.last_wear ~= offhand_get_wear(player) then + update_wear_bar(player, itemstack) + offhand_hud.last_wear = offhand_get_wear(player) + end + if offhand_get_wear(player) <= 0 or not minetest.registered_tools[offhand_item] then + remove_hud(player, "wear_bar_bg") + remove_hud(player, "wear_bar") + end + end + + if offhand_hud.item_count then + if offhand_hud.last_count ~= offhand_get_count(player) then + player:hud_change(offhand_hud.item_count, "text", offhand_get_count(player)) + offhand_hud.last_count = offhand_get_count(player) + end + if offhand_get_count(player) <= 1 then + remove_hud(player, "item_count") + end + end + + elseif offhand_hud.slot then + for index, _ in pairs(mcl_offhand[player].hud) do + remove_hud(player, index) + end + end + end +end) + +minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info) + if action == "move" and inventory_info.to_list == "offhand" then + local itemstack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index) + if not (minetest.get_item_group(itemstack:get_name(), "offhand_item") > 0) then + return 0 + else + return itemstack:get_stack_max() + end + end +end) + +minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info) + local from_offhand = inventory_info.from_list == "offhand" + local to_offhand = inventory_info.to_list == "offhand" + if action == "move" and from_offhand or to_offhand then + mcl_inventory.update_inventory_formspec(player) + end +end) diff --git a/mods/HUD/mcl_offhand/mod.conf b/mods/HUD/mcl_offhand/mod.conf new file mode 100644 index 0000000000..f0260f35c3 --- /dev/null +++ b/mods/HUD/mcl_offhand/mod.conf @@ -0,0 +1,3 @@ +name = mcl_offhand +author = NO11 +depends = mcl_inventory diff --git a/mods/HUD/mcl_offhand/textures/mcl_offhand_slot.png b/mods/HUD/mcl_offhand/textures/mcl_offhand_slot.png new file mode 100644 index 0000000000..69ceb5973d Binary files /dev/null and b/mods/HUD/mcl_offhand/textures/mcl_offhand_slot.png differ diff --git a/mods/HUD/mcl_offhand/textures/mcl_wear_bar.png b/mods/HUD/mcl_offhand/textures/mcl_wear_bar.png new file mode 100644 index 0000000000..6fee6bba6d Binary files /dev/null and b/mods/HUD/mcl_offhand/textures/mcl_wear_bar.png differ diff --git a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua index 3517e09cbf..01b42c3403 100644 --- a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua @@ -43,14 +43,20 @@ end local function comparator_activate(pos, node) local def = minetest.registered_nodes[node.name] - minetest.swap_node(pos, { name = def.comparator_onstate, param2 = node.param2 }) + local onstate = def.comparator_onstate + if onstate then + minetest.swap_node(pos, { name = onstate, param2 = node.param2 }) + end minetest.after(0.1, comparator_turnon , {pos = pos, node = node}) end local function comparator_deactivate(pos, node) local def = minetest.registered_nodes[node.name] - minetest.swap_node(pos, { name = def.comparator_offstate, param2 = node.param2 }) + local offstate = def.comparator_offstate + if offstate then + minetest.swap_node(pos, { name = offstate, param2 = node.param2 }) + end minetest.after(0.1, comparator_turnoff, {pos = pos, node = node}) end diff --git a/mods/ITEMS/REDSTONE/mcl_target/init.lua b/mods/ITEMS/REDSTONE/mcl_target/init.lua new file mode 100644 index 0000000000..268c6ebe3f --- /dev/null +++ b/mods/ITEMS/REDSTONE/mcl_target/init.lua @@ -0,0 +1,70 @@ +local S = minetest.get_translator("mcl_target") + +local mod_farming = minetest.get_modpath("mcl_farming") + +mcl_target = {} + +function mcl_target.hit(pos, time) + minetest.set_node(pos, {name="mcl_target:target_on"}) + mesecon.receptor_on(pos, mesecon.rules.alldirs) + + local timer = minetest.get_node_timer(pos) + timer:start(time) +end + +minetest.register_node("mcl_target:target_off", { + description = S("Target"), + _doc_items_longdesc = S("A target is a block that provides a temporary redstone charge when hit by a projectile."), + _doc_items_usagehelp = S("Throw a projectile on the target to activate it."), + tiles = {"mcl_target_target_top.png", "mcl_target_target_top.png", "mcl_target_target_side.png"}, + groups = {hoey = 1}, + sounds = mcl_sounds.node_sound_dirt_defaults({ + footstep = {name="default_grass_footstep", gain=0.1}, + }), + mesecons = { + receptor = { + state = mesecon.state.off, + rules = mesecon.rules.alldirs, + }, + }, + _mcl_blast_resistance = 0.5, + _mcl_hardness = 0.5, +}) + +minetest.register_node("mcl_target:target_on", { + description = S("Target"), + _doc_items_create_entry = false, + tiles = {"mcl_target_target_top.png", "mcl_target_target_top.png", "mcl_target_target_side.png"}, + groups = {hoey = 1, not_in_creative_inventory = 1}, + drop = "mcl_target:target_off", + sounds = mcl_sounds.node_sound_dirt_defaults({ + footstep = {name="default_grass_footstep", gain=0.1}, + }), + on_timer = function(pos, elapsed) + local node = minetest.get_node(pos) + if node.name == "mcl_target:target_on" then --has not been dug + minetest.set_node(pos, {name="mcl_target:target_off"}) + mesecon.receptor_off(pos, mesecon.rules.alldirs) + end + end, + mesecons = { + receptor = { + state = mesecon.state.on, + rules = mesecon.rules.alldirs, + }, + }, + _mcl_blast_resistance = 0.5, + _mcl_hardness = 0.5, +}) + + +if mod_farming then + minetest.register_craft({ + output = "mcl_target:target_off", + recipe = { + {"", "mesecons:redstone", ""}, + {"mesecons:redstone", "mcl_farming:hay_block", "mesecons:redstone"}, + {"", "mesecons:redstone", ""}, + }, + }) +end \ No newline at end of file diff --git a/mods/ITEMS/REDSTONE/mcl_target/locale/mcl_target.fr.tr b/mods/ITEMS/REDSTONE/mcl_target/locale/mcl_target.fr.tr new file mode 100644 index 0000000000..6c558683d6 --- /dev/null +++ b/mods/ITEMS/REDSTONE/mcl_target/locale/mcl_target.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mcl_target +Target=Cible +A target is a block that provides a temporary redstone charge when hit by a projectile.=La cible est un bloc qui se comporte comme une source d'énergie temporaire quand elle est frappée par un projectile. +Throw a projectile on the target to activate it.=Lancer un projectile sur la cible pour l'activer. \ No newline at end of file diff --git a/mods/ITEMS/REDSTONE/mcl_target/locale/template.txt b/mods/ITEMS/REDSTONE/mcl_target/locale/template.txt new file mode 100644 index 0000000000..18bc7708c3 --- /dev/null +++ b/mods/ITEMS/REDSTONE/mcl_target/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mcl_target +Target= +A target is a block that provides a temporary redstone charge when hit by a projectile.= +Throw a projectile on the target to activate it.= \ No newline at end of file diff --git a/mods/ITEMS/REDSTONE/mcl_target/mod.conf b/mods/ITEMS/REDSTONE/mcl_target/mod.conf new file mode 100644 index 0000000000..16f70ed128 --- /dev/null +++ b/mods/ITEMS/REDSTONE/mcl_target/mod.conf @@ -0,0 +1,3 @@ +name = mcl_target +author = AFCMS +depends = mesecons, mcl_sounds \ No newline at end of file diff --git a/mods/ITEMS/REDSTONE/mcl_target/textures/mcl_target_target_side.png b/mods/ITEMS/REDSTONE/mcl_target/textures/mcl_target_target_side.png new file mode 100755 index 0000000000..286f7767ed Binary files /dev/null and b/mods/ITEMS/REDSTONE/mcl_target/textures/mcl_target_target_side.png differ diff --git a/mods/ITEMS/REDSTONE/mcl_target/textures/mcl_target_target_top.png b/mods/ITEMS/REDSTONE/mcl_target/textures/mcl_target_target_top.png new file mode 100755 index 0000000000..b55ef3ec8a Binary files /dev/null and b/mods/ITEMS/REDSTONE/mcl_target/textures/mcl_target_target_top.png differ diff --git a/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua b/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua index ed0e4c6085..129c28eea9 100644 --- a/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua @@ -1,5 +1,69 @@ local S = minetest.get_translator(minetest.get_current_modname()) +local function path_to_sunlight_exists(position, light_level) + local neighbours = { + { x = 0, y = 0, z =-1 }, + { x = 0, y = 0, z = 1 }, + { x = 0, y =-1, z = 0 }, + { x = 0, y = 1, z = 0 }, + { x =-1, y = 0, z = 0 }, + { x = 1, y = 0, z = 0 }, + } + for i=1, #neighbours do + local offset = neighbours[i] + local position_new = vector.add( + position, + offset + ) + local light_level_new = minetest.get_node_light( + position_new, + nil + ) + if 15 == light_level_new then + -- found the sunlight + return true + elseif light_level_new > light_level then + -- search where light is brighter + if path_to_sunlight_exists( + position_new, + light_level_new + ) then + return true + end + end + end +end + +local function sunlight_visible(position) + local light_level + -- Minetest 5.4.0+ can measure the daylight level at a position + if nil ~= minetest.get_natural_light then + light_level = minetest.get_natural_light( + position, + nil + ) + if light_level >= 12 then + return true + end + else -- Minetest 5.3.0 or less can only measure the light level + local time = minetest.get_timeofday() * 24000 + -- only check light level during day + if time > 6000 and time < 18000 then + light_level = minetest.get_node_light( + position, + nil + ) + if light_level >= 12 then + return path_to_sunlight_exists( + position, + 12 + ) + end + end + end + return false +end + local boxes = { -8/16, -8/16, -8/16, 8/16, -2/16, 8/16 } -- Daylight Sensor @@ -95,9 +159,7 @@ minetest.register_abm({ interval = 1, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) - local light = minetest.get_node_light(pos, nil) - - if light >= 12 and minetest.get_timeofday() > 0.2 and minetest.get_timeofday() < 0.8 then + if sunlight_visible(pos) then minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_on", param2=node.param2}) mesecon.receptor_on(pos, mesecon.rules.pplate) end @@ -110,9 +172,7 @@ minetest.register_abm({ interval = 1, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) - local light = minetest.get_node_light(pos, nil) - - if light < 12 then + if not sunlight_visible(pos) then minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_off", param2=node.param2}) mesecon.receptor_off(pos, mesecon.rules.pplate) end @@ -202,9 +262,7 @@ minetest.register_abm({ interval = 1, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) - local light = minetest.get_node_light(pos, nil) - - if light < 12 then + if not sunlight_visible(pos) then minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_inverted_on", param2=node.param2}) mesecon.receptor_on(pos, mesecon.rules.pplate) end @@ -217,9 +275,7 @@ minetest.register_abm({ interval = 1, chance = 1, action = function(pos, node, active_object_count, active_object_count_wider) - local light = minetest.get_node_light(pos, nil) - - if light >= 12 and minetest.get_timeofday() > 0.8 and minetest.get_timeofday() < 0.2 then + if sunlight_visible(pos) then minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_inverted_off", param2=node.param2}) mesecon.receptor_off(pos, mesecon.rules.pplate) end diff --git a/mods/ITEMS/mcl_anvils/locale/mcl_anvils.zh_TW.tr b/mods/ITEMS/mcl_anvils/locale/mcl_anvils.zh_TW.tr new file mode 100644 index 0000000000..8ddf546a90 --- /dev/null +++ b/mods/ITEMS/mcl_anvils/locale/mcl_anvils.zh_TW.tr @@ -0,0 +1,16 @@ +# textdomain: mcl_anvils +Set Name=命名 +Repair and Name=修復與命名 +Inventory=物品欄 +Anvil=鐵砧 +The anvil allows you to repair tools and armor, and to give names to items. It has a limited durability, however. Don't let it fall on your head, it could be quite painful!=鐵砧允許你修理工具和盔甲,並為物品命名。然而,它的耐久性有限。不要讓它落在你的頭上,這可能是相當痛苦的! +To use an anvil, rightclick it. An anvil has 2 input slots (on the left) and one output slot.=要使用一個鐵砧,右擊它。一個鐵砧有兩個輸入槽(在左邊)和一個輸出槽。 +To rename items, put an item stack in one of the item slots while keeping the other input slot empty. Type in a name, hit enter or “Set Name”, then take the renamed item from the output slot.=要重新命名物品,在其中一個物品槽裡放一個物品,同時保持另一個輸入槽為空。鍵入名稱,點擊回車或「設置名稱」,然後從輸出槽中取出重命名後的物品。 +There are two possibilities to repair tools (and armor):=有兩種維修工具(和裝甲)的可能性: +• Tool + Tool: Place two tools of the same type in the input slots. The “health” of the repaired tool is the sum of the “health” of both input tools, plus a 12% bonus.=• 工具+工具。在輸入槽中放置兩個相同類型的工具。修復後的工具的耐久力是兩個輸入工具的耐久力之和,加上12%的獎勵。 +• Tool + Material: Some tools can also be repaired by combining them with an item that it's made of. For example, iron pickaxes can be repaired with iron ingots. This repairs the tool by 25%.=• 工具+材料。有些工具也可以通過與它所製成的物品結合起來進行修理。例如,鐵鎬可以用鐵錠修復。這可以使工具的修復率提高25%。 +Armor counts as a tool. It is possible to repair and rename a tool in a single step.=盔甲算作是一種工具。可以在一個步驟中修復和重命名一個工具。 +The anvil has limited durability and 3 damage levels: undamaged, slightly damaged and very damaged. Each time you repair or rename something, there is a 12% chance the anvil gets damaged. Anvils also have a chance of being damaged when they fall by more than 1 block. If a very damaged anvil is damaged again, it is destroyed.=鐵砧的耐用性有限,有3個損壞等級:未損壞、微損的和耗損的。每次你修復或重命名某物時,有12%的機會使鐵砧受損。當鐵砧跌落超過1塊時,也有機會被損壞。如果一個耗損的鐵砧再次受損,它就會被摧毀。 +Slightly Damaged Anvil=微損的鐵砧 +Very Damaged Anvil=耗損的鐵砧 +Repair and rename items=修復與命名物品 diff --git a/mods/ITEMS/mcl_armor/API.md b/mods/ITEMS/mcl_armor/API.md new file mode 100644 index 0000000000..ede33ebb95 --- /dev/null +++ b/mods/ITEMS/mcl_armor/API.md @@ -0,0 +1,298 @@ +# mcl_armor + +This mod implements the ability of registering armors. + +## Registering an Armor Set + +The `mcl_armor.register_set()` function aims to simplify the process of registering a full set of armor. + +This function register four pieces of armor (head, torso, leggings, feets) based on a definition table: + +```lua +mcl_armor.register_set({ + --name of the armor material (used for generating itemstrings) + name = "dummy_armor", + + --description of the armor material + --do NOT translate this string, it will be concatenated will each piece of armor's description and result will be automatically fetched from your mod's translation files + description = "Dummy Armor", + + --overide description of each armor piece + --do NOT localize this string + descriptions = { + head = "Cap", --default: "Helmet" + torso = "Tunic", --default: "Chestplate" + legs = "Pants", --default: "Leggings" + feet = "Shoes", --default: "Boots" + }, + + --this is used to calculate each armor piece durability with the minecraft algorithm + --head durability = durability * 0.6857 + 1 + --torso durability = durability * 1.0 + 1 + --legs durability = durability * 0.9375 + 1 + --feet durability = durability * 0.8125 + 1 + durability = 80, + + --this is used then you need to specify the durability of each piece of armor + --this field have the priority over the durability one + --if the durability of some pieces of armor isn't specified in this field, the durability field will be used insteed + durabilities = { + head = 200, + torso = 500, + legs = 400, + feet = 300, + }, + + --this define how good enchants you will get then enchanting one piece of the armor in an enchanting table + --if set to zero or nil, the armor will not be enchantable + enchantability = 15, + + --this define how much each piece of armor protect the player + --these points will be shown in the HUD (chestplate bar above the health bar) + points = { + head = 1, + torso = 3, + legs = 2, + feet = 1, + }, + + --this attribute reduce strong damage even more + --See https://minecraft.fandom.com/wiki/Armor#Armor_toughness for more explanations + --default: 0 + toughness = 2, + + --this field is used to specify some items groups that will be added to each piece of armor + --please note that some groups do NOT need to be added by hand, because they are already handeled by the register function: + --(armor, combat_armor, armor_, combat_armor_, mcl_armor_points, mcl_armor_toughness, mcl_armor_uses, enchantability) + groups = {op_armor = 1}, + + --specify textures that will be overlayed on the entity wearing the armor + --these fields have default values and its recommanded to keep the code clean by just using the default name for your textures + textures = { + head = "dummy_texture.png", --default: "_helmet_.png" + torso = "dummy_texture.png", --default: "_chestplate_.png" + legs = "dummy_texture.png", --default: "_leggings_.png" + feet = "dummy_texture.png", --default: "_boots_.png" + }, + --you can also define these fields as functions, that will be called each time the API function mcl_armor.update(obj) is called (every time you equip/unequip some armor piece, take damage, and more) + --note that the enchanting overlay will not appear unless you implement it in the function + --this allow to make armors where the textures change whitout needing to register many other armors with different textures + textures = { + head = function(obj, itemstack) + if mcl_enchanting.is_enchanted(itemstack) then + return "dummy_texture.png^"..mcl_enchanting.overlay + else + return "dummy_texture.png" + end + end, + }, + + --WARNING: 2d preview is deprecated and will be removed soon + --specify textures that will be shown in player inventory then you disabled the 3d player inventory preview + --its similar to how works the textures field + previews = { + head = "dummy_texture.png", --default: "_helmet__preview.png" + torso = "dummy_texture.png", --default: "_chestplate__preview.png" + legs = "dummy_texture.png", --default: "_leggings__preview.png" + feet = "dummy_texture.png", --default: "_boots__preview.png" + }, + + --inventory textures aren't definable using a table similar to textures or previews + --you are forced to use the default texture names which are: + --head: "_inv_helmet_.png + --torso: "_inv_chestplate_.png + --legs: "_inv_leggings_.png + --feet: "_inv_boots_.png + + --this callback table allow you to define functions that will be called each time an entity equip an armor piece or the mcl_armor.on_equip() function is called + --the functions accept two arguments: obj and itemstack + on_equip_callbacks = { + head = function(obj, itemstack) + --do stuff + end, + }, + + --this callback table allow you to define functions that will be called each time an entity unequip an armor piece or the mcl_armor.on_unequip() function is called + --the functions accept two arguments: obj and itemstack + on_unequip_callbacks = { + head = function(obj, itemstack) + --do stuff + end, + }, + + --this callback table allow you to define functions that will be called then an armor piece break + --the functions accept one arguments: obj + --the itemstack isn't sended due to how minetest handle items which have a zero durability + on_break_callbacks = { + head = function(obj) + --do stuff + end, + }, + + --this is used to generate automaticaly armor crafts based on each element type folowing the regular minecraft pattern + --if set to nil no craft will be added + craft_material = "mcl_mobitems:leather", + + --this is used to generate cooking crafts for each piece of armor + --if set to nil no craft will be added + cook_material = "mcl_core:gold_nugget", --cooking any piece of this armor will output a gold nugged + + --this is used for allowing each piece of the armor to be repaired by using an anvil with repair_material as aditionnal material + --it basicaly set the _repair_material item field of each piece of the armor + --if set to nil no repair material will be added + repair_material = "mcl_core:iron_ingot", +}) +``` + +## Creating an Armor Piece + +If you don't want to register a full set of armor, then you will need to manually register your own single item. + +```lua +minetest.register_tool("dummy_mod:random_armor", { + description = S("Random Armor"), + + --these two item fields are used for ingame documentation + --the mcl_armor.longdesc and mcl_armor.usage vars contains the basic usage and purpose of a piece of armor + --these vars may not be enough for that you want to do, so you may add some extra informations like that: + --_doc_items_longdesc = mcl_armor.longdesc.." "..S("Some extra informations.") + _doc_items_longdesc = mcl_armor.longdesc, + _doc_items_usagehelp = mcl_armor.usage, + + --this field is similar to any item definition in minetest + --it just set the image shown then the armor is dropped as an item or inside an inventory + inventory_image = "mcl_armor_inv_elytra.png", + + --this field is used by minetest internally and also by some helper functions + --in order for the tool to be shown is the right creative inventory tab, the right groups should be added + --"mcl_armor_uses" is required to give your armor a durability + --in that case, the armor can be worn by 10 points before breaking + --if you want the armor to be enchantable, you should also add the "enchantability" group, with the highest number the better enchants you can apply + groups = {armor = 1, non_combat_armor = 1, armor_torso = 1, non_combat_torso = 1, mcl_armor_uses = 10}, + + --this table is used by minetest for seraching item specific sounds + --the _mcl_armor_equip and _mcl_armor_unequip are used by the armor implementation to play sounds on equip and unequip + --note that you don't need to provide any file extention + sounds = { + _mcl_armor_equip = "mcl_armor_equip_leather", + _mcl_armor_unequip = "mcl_armor_unequip_leather", + }, + + --these fields should be initialised like that in most cases + --mcl_armor.equip_on_use is a function that try to equip the piece of armor you have in hand inside the right armor slot if the slot is empty + on_place = mcl_armor.equip_on_use, + on_secondary_use = mcl_armor.equip_on_use, + + --this field define that the tool is ACTUALLY an armor piece and in which armor slot you can put it + --it should be set to "head", "torso", "legs" or "feet" + _mcl_armor_element = "torso", + + + --this field is used to provide the texture that will be overlayed on the object (player or mob) skin + --this field can be a texture name or a function that will be called each time the mcl_armor.update(obj) function is called + --see the mcl_armor.register_set() documentation for more explanations + _mcl_armor_texture = "mcl_armor_elytra.png" + + --callbacks + --see the mcl_armor.register_set() documentation for more explanations + + _on_equip = function(obj, itemstack) + end, + _on_unequip = function(obj, itemstack) + end, + _on_break = function(obj) + end, +}) +``` + +## Interacting with Armor of an Entity + +Mods may want to interact with armor of an entity. + +Most global functions not described here may not be stable or may be for internal use only. + +You can equip a piece of armor on an entity inside a mod by using `mcl_armor.equip()`. + +```lua +--itemstack: an itemstack containing the armor piece to equip +--obj: the entity you want to equip the armor on +--swap: boolean, force equiping the armor piece, even if the entity already have one of the same type +mcl_armor.equip(itemstack, obj, swap) +``` + +You can update the entity apparence by using `mcl_armor.update()`. + +This function put the armor overlay on the object's base texture. +If the object is player it will update his displayed armor points count in HUD. + +This function will work both on players and mobs. + +```lua +--obj: the entity you want the apparence to be updated +mcl_armor.update(obj) +``` + +## Handling Enchantments + +Armors can be enchanted in most cases. + +The enchanting part of MineClone2 is separated from the armor part, but closely linked. + +Existing armor enchantments in Minecraft improve most of the time how the armor protect the entity from damage. + +The `mcl_armor.register_protection_enchantment()` function aims to simplificate the creation of such enchants. + +```lua +mcl_armor.register_protection_enchantment({ + --this field is the id that will be used for registering enchanted book and store the enchant inside armor metadata. + --(his internal name) + id = "magic_protection", + + --visible name of the enchant + --this field is used as the name of registered enchanted book and inside armor tooltip + --translation should be added + name = S("Magic Protection"), + + --this field is used to know that the enchant currently do + --translation should be added + description = S("Reduces magic damage."), + + --how many levels can the enchant have + --ex: 4 => I, II, III, IV + --default: 4 + max_level = 4, + + --which enchants this enchant will not be compatible with + --each of these values is a enchant id + incompatible = {blast_protection = true, fire_protection = true, projectile_protection = true}, + + --how much will the enchant consume from the enchantability group of the armor item + --default: 5 + weight = 5, + + --false => the enchant can be obtained in an enchanting table + --true => the enchant isn't obtainable in the enchanting table + --is true, you will probably need to implement some ways to obtain it + --even it the field is named "treasure", it will be no way to find it + --default: false + treasure = false, + + --how much will damage be reduced + --see Minecraft Wiki for more informations + --https://minecraft.gamepedia.com/Armor#Damage_protection + --https://minecraft.gamepedia.com/Armor#Enchantments + factor = 1, + + --restrict damage to one type + --allow the enchant to only protect of one type of damage + damage_type = "magic", + + --restrict damage to one category + --allow to protect from many type of damage at once + --this is much less specific than damage_type and also much more customisable + --the "is_magic" flag is used in the "magic", "dragon_breath", "wither_skull" and "thorns" damage types + --you can checkout the mcl_damage source code for a list of availlable damage types and associated flags + --but be warned that mods can register additionnal damage types + damage_flag = "is_magic", +}) +``` diff --git a/mods/ITEMS/mcl_armor/locale/mcl_armor.zh_TW.tr b/mods/ITEMS/mcl_armor/locale/mcl_armor.zh_TW.tr new file mode 100644 index 0000000000..1dca107573 --- /dev/null +++ b/mods/ITEMS/mcl_armor/locale/mcl_armor.zh_TW.tr @@ -0,0 +1,23 @@ +# textdomain: mcl_armor +This is a piece of equippable armor which reduces the amount of damage you receive.=這是一件可裝備的盔甲,可以減少你受到的傷害。 +To equip it, put it on the corresponding armor slot in your inventory menu.=要裝備它,就把它放在你的物品欄中相應的盔甲插槽上。 +Leather Cap=皮革帽子 +Iron Helmet=鐵製頭盔 +Golden Helmet=黃金頭盔 +Diamond Helmet=鑽石頭盔 +Chain Helmet=鎖鏈頭盔 +Leather Tunic=皮革上衣 +Iron Chestplate=鐵製胸甲 +Golden Chestplate=黃金胸甲 +Diamond Chestplate=鑽石胸甲 +Chain Chestplate=鎖鏈胸甲 +Leather Pants=皮革褲子 +Iron Leggings=鐵製護腿 +Golden Leggings=黃金護腿 +Diamond Leggings=鑽石護腿 +Chain Leggings=鎖鏈護腿 +Leather Boots=皮革靴子 +Iron Boots=鐵製靴子 +Golden Boots=黃金靴子 +Diamond Boots=鑽石靴子 +Chain Boots=鎖鏈靴子 diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend1 b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend1 deleted file mode 100644 index 1a13f1c92e..0000000000 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend1 and /dev/null differ diff --git a/mods/ITEMS/mcl_armor_stand/locale/mcl_armor_stand.zh_TW.tr b/mods/ITEMS/mcl_armor_stand/locale/mcl_armor_stand.zh_TW.tr new file mode 100644 index 0000000000..d5d107e556 --- /dev/null +++ b/mods/ITEMS/mcl_armor_stand/locale/mcl_armor_stand.zh_TW.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_armor_stand +Armor Stand=盔甲座 +An armor stand is a decorative object which can display different pieces of armor. Anything which players can wear as armor can also be put on an armor stand.=盔甲架是一種裝飾實體,可以展示不同的盔甲。玩家可以作為盔甲穿戴的任何東西也都可以放在盔甲架上。 +Just place an armor item on the armor stand. To take the top piece of armor from the armor stand, select your hand and use the place key on the armor stand.=只需将一件盔甲放在盔甲架上。要从盔甲架上取下最上面的一件盔甲,选择你的手并在盔甲架上使用放置键。 +Displays pieces of armor=展示盔甲 diff --git a/mods/ITEMS/mcl_banners/init.lua b/mods/ITEMS/mcl_banners/init.lua index a396caf7d3..cc0e02e665 100644 --- a/mods/ITEMS/mcl_banners/init.lua +++ b/mods/ITEMS/mcl_banners/init.lua @@ -88,6 +88,10 @@ for k,v in pairs(mcl_banners.colors) do colors_reverse["mcl_banners:banner_item_"..v[1]] = k end +function mcl_banners.color_reverse(itemname) + return colors_reverse[itemname] +end + -- Add pattern/emblazoning crafting recipes dofile(modpath.."/patterncraft.lua") @@ -149,7 +153,7 @@ local function on_destruct_hanging_banner(pos) return on_destruct_banner(pos, true) end -local function make_banner_texture(base_color, layers) +function mcl_banners.make_banner_texture(base_color, layers) local colorize if mcl_banners.colors[base_color] then colorize = mcl_banners.colors[base_color][4] @@ -171,11 +175,11 @@ local function make_banner_texture(base_color, layers) finished_banner = finished_banner .. "^" .. layer end - return { finished_banner } + return finished_banner end - return { base } + return base else - return { "mcl_banners_banner_base.png" } + return "mcl_banners_banner_base.png" end end @@ -192,7 +196,7 @@ local function spawn_banner_entity(pos, hanging, itemstack) local imeta = itemstack:get_meta() local layers_raw = imeta:get_string("layers") local layers = minetest.deserialize(layers_raw) - local colorid = colors_reverse[itemstack:get_name()] + local colorid = mcl_banners.color_reverse(itemstack:get_name()) banner:get_luaentity():_set_textures(colorid, layers) local mname = imeta:get_string("name") if mname and mname ~= "" then @@ -604,7 +608,7 @@ local entity_standing = { visual = "mesh", mesh = "amc_banner.b3d", visual_size = { x=2.499, y=2.499 }, - textures = make_banner_texture(), + textures = {mcl_banners.make_banner_texture()}, pointable = false, _base_color = nil, -- base color of banner @@ -624,7 +628,7 @@ local entity_standing = { self._layers = inp._layers self._name = inp._name self.object:set_properties({ - textures = make_banner_texture(self._base_color, self._layers), + textures = {mcl_banners.make_banner_texture(self._base_color, self._layers)}, }) end -- Make banner slowly swing @@ -635,7 +639,7 @@ local entity_standing = { -- Set the banner textures. This function can be used by external mods. -- Meaning of parameters: -- * self: Lua entity reference to entity. - -- * other parameters: Same meaning as in make_banner_texture + -- * other parameters: Same meaning as in mcl_banners.make_banner_texture _set_textures = function(self, base_color, layers) if base_color then self._base_color = base_color @@ -643,7 +647,7 @@ local entity_standing = { if layers then self._layers = layers end - self.object:set_properties({textures = make_banner_texture(self._base_color, self._layers)}) + self.object:set_properties({textures = {mcl_banners.make_banner_texture(self._base_color, self._layers)}}) end, } minetest.register_entity("mcl_banners:standing_banner", entity_standing) diff --git a/mods/ITEMS/mcl_barrels/init.lua b/mods/ITEMS/mcl_barrels/init.lua new file mode 100644 index 0000000000..09b16eee39 --- /dev/null +++ b/mods/ITEMS/mcl_barrels/init.lua @@ -0,0 +1,204 @@ +local S = minetest.get_translator("mcl_barrels") +local F = minetest.formspec_escape +local C = minetest.colorize + +--TODO: fix barrel rotation placement + +local open_barrels = {} + +local drop_content = mcl_util.drop_items_from_meta_container("main") + +local function on_blast(pos) + local node = minetest.get_node(pos) + drop_content(pos, node) + minetest.remove_node(pos) +end + +-- Simple protection checking functions +local function protection_check_move(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end +end + +local function protection_check_put_take(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end +end + +local function barrel_open(pos, node, clicker) + local name = minetest.get_meta(pos):get_string("name") + + if name == "" then + name = S("Barrel") + end + + local playername = clicker:get_player_name() + + minetest.show_formspec(playername, + "mcl_barrels:barrel_"..pos.x.."_"..pos.y.."_"..pos.z, + table.concat({ + "size[9,8.75]", + "label[0,0;"..F(C("#313131", name)).."]", + "list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]", + mcl_formspec.get_itemslot_bg(0, 0.5, 9, 3), + "label[0,4.0;"..F(C("#313131", S("Inventory"))).."]", + "list[current_player;main;0,4.5;9,3;9]", + mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3), + "list[current_player;main;0,7.74;9,1;]", + mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1), + "listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]", + "listring[current_player;main]", + }) + ) + + minetest.swap_node(pos, { name = "mcl_barrels:barrel_open", param2 = node.param2 }) + open_barrels[playername] = pos +end + +local function close_forms(pos) + local players = minetest.get_connected_players() + local formname = "mcl_barrels:barrel_"..pos.x.."_"..pos.y.."_"..pos.z + for p = 1, #players do + if vector.distance(players[p]:get_pos(), pos) <= 30 then + minetest.close_formspec(players[p]:get_player_name(), formname) + end + end +end + +local function update_after_close(pos) + local node = minetest.get_node_or_nil(pos) + if not node then return end + if node.name == "mcl_barrels:barrel_open" then + minetest.swap_node(pos, {name = "mcl_barrels:barrel_closed", param2 = node.param2}) + end +end + +local function close_barrel(player) + local name = player:get_player_name() + local open = open_barrels[name] + if open == nil then + return + end + + update_after_close(open) + + open_barrels[name] = nil +end + +minetest.register_node("mcl_barrels:barrel_closed", { + description = S("Barrel"), + _tt_help = S("27 inventory slots"), + _doc_items_longdesc = S("Barrels are containers which provide 27 inventory slots."), + _doc_items_usagehelp = S("To access its inventory, rightclick it. When broken, the items will drop out."), + tiles = {"mcl_barrels_barrel_top.png^[transformR270", "mcl_barrels_barrel_bottom.png", "mcl_barrels_barrel_side.png"}, + paramtype = "light", + paramtype2 = "facedir", + on_place = function(itemstack, placer, pointed_thing) + minetest.rotate_and_place(itemstack, placer, pointed_thing, minetest.is_creative_enabled(placer:get_player_name()), {}, false) + return itemstack + end, + stack_max = 64, + sounds = mcl_sounds.node_sound_wood_defaults(), + groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1}, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:set_size("main", 9*3) + end, + after_place_node = function(pos, placer, itemstack, pointed_thing) + minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name")) + end, + allow_metadata_inventory_move = protection_check_move, + allow_metadata_inventory_take = protection_check_put_take, + allow_metadata_inventory_put = protection_check_put_take, + on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + minetest.log("action", player:get_player_name().. + " moves stuff in barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " moves stuff to barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_take = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " takes stuff from barrel at "..minetest.pos_to_string(pos)) + end, + after_dig_node = drop_content, + on_blast = on_blast, + on_rightclick = barrel_open, + on_destruct = close_forms, + _mcl_blast_resistance = 2.5, + _mcl_hardness = 2.5, +}) + +minetest.register_node("mcl_barrels:barrel_open", { + description = S("Barrel Open"), + _tt_help = S("27 inventory slots"), + _doc_items_longdesc = S("Barrels are containers which provide 27 inventory slots."), + _doc_items_usagehelp = S("To access its inventory, rightclick it. When broken, the items will drop out."), + _doc_items_create_entry = false, + tiles = {"mcl_barrels_barrel_top_open.png", "mcl_barrels_barrel_bottom.png", "mcl_barrels_barrel_side.png"}, + paramtype = "light", + paramtype2 = "facedir", + drop = "mcl_barrels:barrel_closed", + stack_max = 64, + sounds = mcl_sounds.node_sound_wood_defaults(), + groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1, not_in_creative_inventory = 1}, + allow_metadata_inventory_move = protection_check_move, + allow_metadata_inventory_take = protection_check_put_take, + allow_metadata_inventory_put = protection_check_put_take, + on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + minetest.log("action", player:get_player_name().. + " moves stuff in barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " moves stuff to barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_take = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " takes stuff from barrel at "..minetest.pos_to_string(pos)) + end, + after_dig_node = drop_content, + on_blast = on_blast, + on_rightclick = barrel_open, + on_destruct = close_forms, + _mcl_blast_resistance = 2.5, + _mcl_hardness = 2.5, +}) + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname:find("mcl_barrels:") == 1 and fields.quit then + close_barrel(player) + end +end) + +minetest.register_on_leaveplayer(function(player) + close_barrel(player) +end) + +--Minecraft Java Edition craft +minetest.register_craft({ + output = "mcl_barrels:barrel_closed", + recipe = { + {"group:wood", "group:wood_slab", "group:wood"}, + {"group:wood", "", "group:wood"}, + {"group:wood", "group:wood_slab", "group:wood"}, + } +}) + +minetest.register_craft({ + type = "fuel", + recipe = "mcl_barrels:barrel_closed", + burntime = 15, +}) diff --git a/mods/ITEMS/mcl_barrels/locale/mcl_barrels.de.tr b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.de.tr new file mode 100644 index 0000000000..e1fa1b603a --- /dev/null +++ b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.de.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_barrels +Barrel= +Barrels are containers which provide 27 inventory slots.= +To access its inventory, rightclick it. When broken, the items will drop out.= +27 inventory slots= \ No newline at end of file diff --git a/mods/ITEMS/mcl_barrels/locale/mcl_barrels.es.tr b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.es.tr new file mode 100644 index 0000000000..e1fa1b603a --- /dev/null +++ b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.es.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_barrels +Barrel= +Barrels are containers which provide 27 inventory slots.= +To access its inventory, rightclick it. When broken, the items will drop out.= +27 inventory slots= \ No newline at end of file diff --git a/mods/ITEMS/mcl_barrels/locale/mcl_barrels.fr.tr b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.fr.tr new file mode 100644 index 0000000000..0e93d1ee5a --- /dev/null +++ b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.fr.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_barrels +Barrel=Tonneau +Barrels are containers which provide 27 inventory slots.=Les tonneaux sont des conteneurs qui offrent 27 emplacements d'inventaire. +To access its inventory, rightclick it. When broken, the items will drop out.=Pour accéder à son inventaire, faites un clic droit dessus. Une fois cassés, les articles tomberont. +27 inventory slots=27 emplacements d'inventaire \ No newline at end of file diff --git a/mods/ITEMS/mcl_barrels/locale/mcl_barrels.pl.tr b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.pl.tr new file mode 100644 index 0000000000..e1fa1b603a --- /dev/null +++ b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.pl.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_barrels +Barrel= +Barrels are containers which provide 27 inventory slots.= +To access its inventory, rightclick it. When broken, the items will drop out.= +27 inventory slots= \ No newline at end of file diff --git a/mods/ITEMS/mcl_barrels/locale/mcl_barrels.ru.tr b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.ru.tr new file mode 100644 index 0000000000..e1fa1b603a --- /dev/null +++ b/mods/ITEMS/mcl_barrels/locale/mcl_barrels.ru.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_barrels +Barrel= +Barrels are containers which provide 27 inventory slots.= +To access its inventory, rightclick it. When broken, the items will drop out.= +27 inventory slots= \ No newline at end of file diff --git a/mods/ITEMS/mcl_barrels/locale/template.txt b/mods/ITEMS/mcl_barrels/locale/template.txt new file mode 100644 index 0000000000..e1fa1b603a --- /dev/null +++ b/mods/ITEMS/mcl_barrels/locale/template.txt @@ -0,0 +1,5 @@ +# textdomain: mcl_barrels +Barrel= +Barrels are containers which provide 27 inventory slots.= +To access its inventory, rightclick it. When broken, the items will drop out.= +27 inventory slots= \ No newline at end of file diff --git a/mods/ITEMS/mcl_barrels/mod.conf b/mods/ITEMS/mcl_barrels/mod.conf new file mode 100644 index 0000000000..2b0088b79d --- /dev/null +++ b/mods/ITEMS/mcl_barrels/mod.conf @@ -0,0 +1,3 @@ +name = mcl_barrels +depends = mcl_util, mcl_formspec, mcl_sounds +author = AFCMS \ No newline at end of file diff --git a/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_bottom.png b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_bottom.png new file mode 100755 index 0000000000..9c57880618 Binary files /dev/null and b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_bottom.png differ diff --git a/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_side.png b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_side.png new file mode 100755 index 0000000000..8a01cc4a9d Binary files /dev/null and b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_side.png differ diff --git a/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_top.png b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_top.png new file mode 100755 index 0000000000..8af5a5c902 Binary files /dev/null and b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_top.png differ diff --git a/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_top_open.png b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_top_open.png new file mode 100755 index 0000000000..1d3a02be17 Binary files /dev/null and b/mods/ITEMS/mcl_barrels/textures/mcl_barrels_barrel_top_open.png differ diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index 85873f3c69..86cc079fe6 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -248,7 +248,7 @@ function mcl_beds.register_bed(name, def) paramtype2 = "facedir", is_ground_content = false, -- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks! - groups = {handy = 1, flammable = 3, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1}, + groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1}, _mcl_hardness = 0.2, _mcl_blast_resistance = 1, sounds = def.sounds or default_sounds, diff --git a/mods/ITEMS/mcl_beds/locale/mcl_beds.zh_TW.tr b/mods/ITEMS/mcl_beds/locale/mcl_beds.zh_TW.tr new file mode 100644 index 0000000000..fd0a586293 --- /dev/null +++ b/mods/ITEMS/mcl_beds/locale/mcl_beds.zh_TW.tr @@ -0,0 +1,41 @@ +# textdomain: mcl_beds +Beds allow you to sleep at night and make the time pass faster.=床可以讓你在晚上睡覺,讓時間過得更快。 +To use a bed, stand close to it and right-click the bed to sleep in it. Sleeping only works when the sun sets, at night or during a thunderstorm. The bed must also be clear of any danger.=要使用床,站在靠近床的地方,右鍵點擊床,就可以在床上睡覺。只有在太陽落山、晚上或雷雨時才能睡覺。床也必須遠離任何危險。 +You have heard of other worlds in which a bed would set the start point for your next life. But this world is not one of them.=你聽說過其他的世界,在這個世界裡,一張床會成為你的重生點。但這個世界並不是其中之一。 +By using a bed, you set the starting point for your next life. If you die, you will start your next life at this bed, unless it is obstructed or destroyed.=通過使用一張床,你設定了重生點。如果你死了,你將在這張床上重生,除非它被阻礙或破壞。 +In this world, going to bed won't skip the night, but it will skip thunderstorms.=在這個世界上,上床睡覺不會跳過夜晚,但是會跳過雷暴。 +Sleeping allows you to skip the night. The night is skipped when all players in this world went to sleep. The night is skipped after sleeping for a few seconds. Thunderstorms can be skipped in the same manner.=睡覺可以跳過夜晚。當這個世界的所有玩家都進入睡眠狀態幾秒後,夜晚就會被跳過。雷雨也可以用同樣的方式跳過。 +Bed=床 +Red Bed=紅色床 +Blue Bed=藍色床 +Cyan Bed=青色床 +Grey Bed=灰色床 +Light Grey Bed=淺灰色床 +Black Bed=黑色床 +Yellow Bed=黃色床 +Green Bed=綠色床 +Magenta Bed=洋紅色床 +Orange Bed=橙色床 +Purple Bed=紫色床 +Brown Bed=棕色床 +Pink Bed=粉紅色床 +Lime Bed=淺綠色床 +Light Blue Bed=淺藍色床 +White Bed=白色床 +You can't sleep, the bed's too far away!=你無法休息,床離你太遠了! +This bed is already occupied!=這張床已被佔用! +You have to stop moving before going to bed!=在睡覺前,你必須停下! +You can't sleep now, monsters are nearby!=你無法休息,有怪物在附近遊蕩! +You can't sleep, the bed is obstructed!=你無法休息,床已被阻擋! +It's too dangerous to sleep here!=在這裏睡太危險了! +New respawn position set! But you can only sleep at night or during a thunderstorm.=你設定了重生點,但你只能在晚上或雷雨時才能睡覺。 +You can only sleep at night or during a thunderstorm.=你只能在晚上或雷雨時才能睡覺。 +New respawn position set!=你設定了重生點! +Leave bed=起來 +Abort sleep=醒來 +Players in bed: @1/@2=@2位玩家中的@1位在床上 +Note: Night skip is disabled.=注意:睡覺以跳過夜晚被停用 +You're sleeping.=你睡着了。 +You will fall asleep when all players are in bed.=你會在所有玩家在床上時睡着 +You're in bed.=你在床上。 +Allows you to sleep=允許你睡覺 diff --git a/mods/ITEMS/mcl_books/locale/mcl_books.zh_TW.tr b/mods/ITEMS/mcl_books/locale/mcl_books.zh_TW.tr new file mode 100644 index 0000000000..eb3ab51a73 --- /dev/null +++ b/mods/ITEMS/mcl_books/locale/mcl_books.zh_TW.tr @@ -0,0 +1,27 @@ +# textdomain: mcl_books +Book=書 +Books are used to make bookshelves and book and quills.=書籍用於製作書櫃以及書和羽毛筆。 +“@1”=「@1」 +Copy of “@1”=「@1」的複本 +Copy of Copy of “@1”=「@1」的複本的複本 +Tattered Book=破舊的書 +by @1=由 @1 篇寫 +# as in “to sign a book” +Sign=署名 +Done=退出 +This item can be used to write down some notes.=這個物品可以用來寫下一些筆記。 +Hold it in the hand, then rightclick to read the current notes and edit then. You can edit the text as often as you like. You can also sign the book which turns it into a written book which you can stack, but it can't be edited anymore.=把它拿在手裡,然後右鍵閱讀當前的筆記,然後進行編輯。你可以隨心所欲地編輯文字。你也可以在書上署名名,這就把它變成了一本完成的書,你可以把它疊起來,但它不能再被編輯了。 +A book can hold up to 4500 characters. The title length is limited to 64 characters.=一本書最多可以容納4500個字符。標題長度限制為64個字符。 +Enter book title:=輸入書本標題: +Note: The book will no longer be editable after signing=注意:在署名後,它不能再被編輯了。 +Sign and Close=署名並退出 +Cancel=取消 +Nameless Book=未命名的書 +Written Book=完成的書 +Written books contain some text written by someone. They can be read and copied, but not edited.=完成的書包含一些由玩家寫的文字。它們可以被閱讀和復制,但不能被編輯。 +Hold it in your hand, then rightclick to read the book.=把書放在手裏,右鍵閱讀它。 +To copy the text of the written book, place it into the crafting grid together with a book and quill (or multiple of those) and craft. The written book will not be consumed. Copies of copies can not be copied.=要復製完成的書的文本,請將其與書和羽毛筆(或多個)一起放入製作網格,然後製作。完成的書不會被消耗掉。複本的複本不能被複製。 +Bookshelf=書櫃 +Bookshelves are used for decoration.=書櫃是一種裝飾行方塊 +Book and Quill=書和羽毛筆 +Write down some notes=寫下一些筆記 diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index 3437076173..cda8dcc6d6 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -1,5 +1,7 @@ local S = minetest.get_translator(minetest.get_current_modname()) +local mod_target = minetest.get_modpath("mcl_target") + local math = math local vector = vector @@ -73,7 +75,8 @@ local ARROW_ENTITY={ _stuckin=nil, --Position of node in which arow is stuck. _shooter=nil, -- ObjectRef of player or mob who shot it _is_arrow = true, - + _in_player = false, + _blocked = false, _viscosity=0, -- Viscosity of node the arrow is currently in _deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession } @@ -82,7 +85,7 @@ local ARROW_ENTITY={ local function spawn_item(self, pos) if not minetest.is_creative_enabled("") then local item = minetest.add_item(pos, "mcl_bows:arrow") - item:set_velocity({x=0, y=0, z=0}) + item:set_velocity(vector.new(0, 0, 0)) item:set_yaw(self.object:get_yaw()) end mcl_burning.extinguish(self.object) @@ -94,12 +97,10 @@ local function damage_particles(pos, is_critical) minetest.add_particlespawner({ amount = 15, time = 0.1, - minpos = {x=pos.x-0.5, y=pos.y-0.5, z=pos.z-0.5}, - maxpos = {x=pos.x+0.5, y=pos.y+0.5, z=pos.z+0.5}, - minvel = {x=-0.1, y=-0.1, z=-0.1}, - maxvel = {x=0.1, y=0.1, z=0.1}, - minacc = {x=0, y=0, z=0}, - maxacc = {x=0, y=0, z=0}, + minpos = vector.offset(pos, -0.5, -0.5, -0.5), + maxpos = vector.offset(pos, 0.5, 0.5, 0.5), + minvel = vector.new(-0.1, -0.1, -0.1), + maxvel = vector.new(0.1, 0.1, 0.1), minexptime = 1, maxexptime = 2, minsize = 1.5, @@ -117,8 +118,7 @@ function ARROW_ENTITY.on_step(self, dtime) self._time_in_air = self._time_in_air + .001 local pos = self.object:get_pos() - local dpos = table.copy(pos) -- digital pos - dpos = vector.round(dpos) + local dpos = vector.round(vector.new(pos)) -- digital pos local node = minetest.get_node(dpos) if self._stuck then @@ -248,50 +248,59 @@ function ARROW_ENTITY.on_step(self, dtime) -- Punch target object but avoid hurting enderman. if not lua or lua.name ~= "mobs_mc:enderman" then - if self._in_player == false then + if not self._in_player then damage_particles(self.object:get_pos(), self._is_critical) end if mcl_burning.is_burning(self.object) then mcl_burning.set_on_fire(obj, 5) end - if self._in_player == false then + if not self._in_player and not self._blocked then obj:punch(self.object, 1.0, { full_punch_interval=1.0, damage_groups={fleshy=self._damage}, }, self.object:get_velocity()) if obj:is_player() then - local placement - self._placement = math.random(1, 2) - if self._placement == 1 then - placement = "front" + if not mcl_shields.is_blocking(obj) then + local placement + self._placement = math.random(1, 2) + if self._placement == 1 then + placement = "front" + else + placement = "back" + end + self._in_player = true + if self._placement == 2 then + self._rotation_station = 90 + else + self._rotation_station = -90 + end + self._y_position = random_arrow_positions("y", placement) + self._x_position = random_arrow_positions("x", placement) + if self._y_position > 6 and self._x_position < 2 and self._x_position > -2 then + self._attach_parent = "Head" + self._y_position = self._y_position - 6 + elseif self._x_position > 2 then + self._attach_parent = "Arm_Right" + self._y_position = self._y_position - 3 + self._x_position = self._x_position - 2 + elseif self._x_position < -2 then + self._attach_parent = "Arm_Left" + self._y_position = self._y_position - 3 + self._x_position = self._x_position + 2 + else + self._attach_parent = "Body" + end + self._z_rotation = math.random(-30, 30) + self._y_rotation = math.random( -30, 30) + self.object:set_attach( + obj, self._attach_parent, + vector.new(self._x_position, self._y_position, random_arrow_positions("z", placement)), + vector.new(0, self._rotation_station + self._y_rotation, self._z_rotation) + ) else - placement = "back" + self._blocked = true + self.object:set_velocity(vector.multiply(self.object:get_velocity(), -0.25)) end - self._in_player = true - if self._placement == 2 then - self._rotation_station = 90 - else - self._rotation_station = -90 - end - self._y_position = random_arrow_positions("y", placement) - self._x_position = random_arrow_positions("x", placement) - if self._y_position > 6 and self._x_position < 2 and self._x_position > -2 then - self._attach_parent = "Head" - self._y_position = self._y_position - 6 - elseif self._x_position > 2 then - self._attach_parent = "Arm_Right" - self._y_position = self._y_position - 3 - self._x_position = self._x_position - 2 - elseif self._x_position < -2 then - self._attach_parent = "Arm_Left" - self._y_position = self._y_position - 3 - self._x_position = self._x_position + 2 - else - self._attach_parent = "Body" - end - self._z_rotation = math.random(-30, 30) - self._y_rotation = math.random( -30, 30) - self.object:set_attach(obj, self._attach_parent, {x=self._x_position,y=self._y_position,z=random_arrow_positions("z", placement)}, {x=0,y=self._rotation_station + self._y_rotation,z=self._z_rotation}) minetest.after(150, function() self.object:remove() end) @@ -301,7 +310,7 @@ function ARROW_ENTITY.on_step(self, dtime) if is_player then - if self._shooter and self._shooter:is_player() and self._in_player == false then + if self._shooter and self._shooter:is_player() and not self._in_player and not self._blocked then -- “Ding” sound for hitting another player minetest.sound_play({name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true) end @@ -318,7 +327,7 @@ function ARROW_ENTITY.on_step(self, dtime) end end end - if self._in_player == false then + if not self._in_player and not self._blocked then minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true) end end @@ -344,9 +353,9 @@ function ARROW_ENTITY.on_step(self, dtime) local dir if math.abs(vel.y) < 0.00001 then if self._lastpos.y < pos.y then - dir = {x=0, y=1, z=0} + dir = vector.new(0, 1, 0) else - dir = {x=0, y=-1, z=0} + dir = vector.new(0, -1, 0) end else dir = minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(self.object:get_yaw()-YAW_OFFSET))) @@ -374,8 +383,8 @@ function ARROW_ENTITY.on_step(self, dtime) self._stucktimer = 0 self._stuckrechecktimer = 0 - self.object:set_velocity({x=0, y=0, z=0}) - self.object:set_acceleration({x=0, y=0, z=0}) + self.object:set_velocity(vector.new(0, 0, 0)) + self.object:set_acceleration(vector.new(0, 0, 0)) minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true) @@ -383,6 +392,11 @@ function ARROW_ENTITY.on_step(self, dtime) tnt.ignite(self._stuckin) end + -- Activate target + if mod_target and snode.name == "mcl_target:target_off" then + mcl_target.hit(self._stuckin, 1) --10 redstone ticks + end + -- Push the button! Push, push, push the button! if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then local bdir = minetest.wallmounted_to_dir(node.param2) @@ -420,7 +434,7 @@ function ARROW_ENTITY.on_step(self, dtime) end -- Update internal variable - self._lastpos={x=pos.x, y=pos.y, z=pos.z} + self._lastpos = pos end -- Force recheck of stuck arrows when punched. @@ -439,6 +453,7 @@ function ARROW_ENTITY.get_staticdata(self) is_critical = self._is_critical, stuck = self._stuck, stuckin = self._stuckin, + stuckin_player = self._in_player, } if self._stuck then -- If _stucktimer is missing for some reason, assume the maximum @@ -455,7 +470,6 @@ end function ARROW_ENTITY.on_activate(self, staticdata, dtime_s) self._time_in_air = 1.0 - self._in_player = false local data = minetest.deserialize(staticdata) if data then self._stuck = data.stuck @@ -488,10 +502,23 @@ function ARROW_ENTITY.on_activate(self, staticdata, dtime_s) self._shooter = shooter end end + + if data.stuckin_player then + self.object:remove() + end end self.object:set_armor_groups({ immortal = 1 }) end +minetest.register_on_respawnplayer(function(player) + for _, obj in pairs(player:get_children()) do + local ent = obj:get_luaentity() + if ent and ent.name and string.find(ent.name, "mcl_bows:arrow_entity") then + obj:remove() + end + end +end) + minetest.register_entity("mcl_bows:arrow_entity", ARROW_ENTITY) if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_mobitems") then diff --git a/mods/ITEMS/mcl_bows/crossbow.lua b/mods/ITEMS/mcl_bows/crossbow.lua index 5ae21a1f3e..b211f6b399 100644 --- a/mods/ITEMS/mcl_bows/crossbow.lua +++ b/mods/ITEMS/mcl_bows/crossbow.lua @@ -116,7 +116,7 @@ end -- Bow item, uncharged state minetest.register_tool("mcl_bows:crossbow", { - description = S("Corssbow"), + description = S("Crossbow"), _tt_help = S("Launches arrows"), _doc_items_longdesc = S("Bows are ranged weapons to shoot arrows at your foes.").."\n".. S("The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead."), diff --git a/mods/ITEMS/mcl_bows/locale/mcl_bows.zh_TW.tr b/mods/ITEMS/mcl_bows/locale/mcl_bows.zh_TW.tr new file mode 100644 index 0000000000..6b59895d3e --- /dev/null +++ b/mods/ITEMS/mcl_bows/locale/mcl_bows.zh_TW.tr @@ -0,0 +1,14 @@ +# textdomain: mcl_bows +Arrow=箭 +Arrows are ammunition for bows and dispensers.=箭頭是弓箭和發射器的彈藥。 +An arrow fired from a bow has a regular damage of 1-9. At full charge, there's a 20% chance of a critical hit dealing 10 damage instead. An arrow fired from a dispenser always deals 3 damage.=從弓上射出的箭有1-9的常規傷害。在最大能量的情況下,有20%的機會暴擊,造成10的傷害。從發射器中發射的箭總是造成3點傷害。 +Arrows might get stuck on solid blocks and can be retrieved again. They are also capable of pushing wooden buttons.=箭頭可能會卡在固體方塊上,可以再次取回。他們也能按下木質按鈕。 +To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory. To retrieve an arrow that sticks in a block, simply walk close to it.=要把箭作為弓的彈藥,只需把它們放在你物品欄的任何地方,它們就會被自動使用。要使用箭作為發射器的彈藥,把它們放在發射器的物品欄中。要取回插在方塊上的箭,只需走到它附近。 +Bow=弓 +Bows are ranged weapons to shoot arrows at your foes.=弓是遠程武器,可以向敵人發射箭頭。 +The speed and damage of the arrow increases the longer you charge. The regular damage of the arrow is between 1 and 9. At full charge, there's also a 20% of a critical hit, dealing 10 damage instead.=拉弓時間越長,箭的速度和傷害越大。箭的常規傷害在1到9之間。在拉滿弓的情況下,20%的機會暴擊,造成10的傷害。 +To use the bow, you first need to have at least one arrow anywhere in your inventory (unless in Creative Mode). Hold down the right mouse button to charge, release to shoot.=要使用這把弓,你首先需要在你物品欄的任何地方至少有一支箭(除非在創造模式下)。按住鼠標右鍵充電,鬆開即可射擊。 +Ammunition=彈藥 +Damage from bow: 1-10=從弓發射時的傷害:1-10 +Damage from dispenser: 3=從發射器發射時的傷害:3 +Launches arrows=發射箭 diff --git a/mods/ITEMS/mcl_bows/mod.conf b/mods/ITEMS/mcl_bows/mod.conf index 79ae42436d..7b174826a5 100644 --- a/mods/ITEMS/mcl_bows/mod.conf +++ b/mods/ITEMS/mcl_bows/mod.conf @@ -1,6 +1,6 @@ name = mcl_bows author = Arcelmi description = This mod adds bows and arrows for MineClone 2. -depends = controls, mcl_particles, mcl_enchanting, mcl_init +depends = controls, mcl_particles, mcl_enchanting, mcl_init, mcl_util, mcl_shields optional_depends = awards, mcl_achievements, mcl_core, mcl_mobitems, playerphysics, doc, doc_identifier, mesecons_button diff --git a/mods/ITEMS/mcl_bows/rocket.lua b/mods/ITEMS/mcl_bows/rocket.lua index 678aba4d42..2c1d30dcd4 100644 --- a/mods/ITEMS/mcl_bows/rocket.lua +++ b/mods/ITEMS/mcl_bows/rocket.lua @@ -18,20 +18,6 @@ local function dir_to_pitch(dir) return -math.atan2(-dir.y, xz) end -local function random_arrow_positions(positions, placement) - if positions == "x" then - return math.random(-4, 4) - elseif positions == "y" then - return math.random(0, 10) - end - if placement == "front" and positions == "z" then - return 3 - elseif placement == "back" and positions == "z" then - return -3 - end - return 0 -end - local function damage_explosion(self, damagemulitplier) mcl_explosions.explode(self.object:get_pos(), 3, {}) local objects = minetest.get_objects_inside_radius(self.object:get_pos(), 8) @@ -49,10 +35,10 @@ end local function particle_explosion(self) local particle_pattern = math.random(1, 3) - local fpitch = 0 - local true_type = "" - local type = math.random(1,2) - local size = math.random(1,3) + local fpitch + --local true_type + local type = math.random(1, 2) + local size = math.random(1, 3) local colors = {"red", "yellow", "blue", "green", "white"} local this_colors = {colors[math.random(#colors)], colors[math.random(#colors)], colors[math.random(#colors)]} @@ -64,11 +50,11 @@ local function particle_explosion(self) fpitch = math.random(60, 70) end - if type == 1 then + --[[if type == 1 then true_type = "Popper" else true_type = "Floof" - end + end]] if type == 1 then minetest.sound_play("mcl_bows_firework", { @@ -243,6 +229,7 @@ end local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements") local mod_button = minetest.get_modpath("mesecons_button") +local mod_target = minetest.get_modpath("mcl_target") minetest.register_craftitem("mcl_bows:rocket", { description = S("Arrow"), @@ -578,6 +565,11 @@ function ARROW_ENTITY.on_step(self, dtime) tnt.ignite(self._stuckin) end + -- Activate target + if mod_target and snode.name == "mcl_target:target_off" then + mcl_target.hit(self._stuckin, 1) --10 redstone ticks + end + -- Push the button! Push, push, push the button! if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then local bdir = minetest.wallmounted_to_dir(node.param2) diff --git a/mods/ITEMS/mcl_brewing/locale/mcl_brewing.zh_TW.tr b/mods/ITEMS/mcl_brewing/locale/mcl_brewing.zh_TW.tr new file mode 100644 index 0000000000..da4b70890a --- /dev/null +++ b/mods/ITEMS/mcl_brewing/locale/mcl_brewing.zh_TW.tr @@ -0,0 +1,10 @@ +# textdomain: mcl_brewing +Brewing Stand=釀造台 +Inventory=物品欄 +To use a brewing stand, rightclick it.=右鍵點擊以使用釀造台。 +To brew, you need blaze powder as fuel, a brewing material and at least 1 glass bottle filled with a liquid.=釀造時,你需要烈焰粉作為燃料,一個釀造材料和至少1個裝滿液體的玻璃瓶。 +Place the blaze powder in the left slot, the brewing material in the middle slot and 1-3 bottles in the remaining slots.=將烈焰粉放在左邊的槽中,將釀造材料放在中間的槽中,將1-3個瓶子放在其餘的槽中。 +When you have found a good combination, the brewing will commence automatically and steam starts to appear, using up the fuel and brewing material. The potions will soon be ready.=當你找到一個好的組合時,釀造將自動開始,並開始出現蒸汽,耗盡燃料和釀造材料。藥水很快就會準備好。 +Different combinations of brewing materials and liquids will give different results. Try to experiment!=釀造材料和液體的不同組合會產生不同的結果。試著去實驗吧! +The stand allows you to brew potions!=釀造台可以讓你釀製藥水! +Brew Potions=釀造藥水 diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index 931214b95c..ff0b866dab 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -19,9 +19,15 @@ local string = string local raycast = minetest.raycast local get_node = minetest.get_node +local set_node = minetest.set_node local add_node = minetest.add_node local add_item = minetest.add_item +local registered_nodes = minetest.registered_nodes +local get_item_group = minetest.get_item_group +local is_creative_enabled = minetest.is_creative_enabled +local is_protected = minetest.is_protected +local record_protection_violation = minetest.record_protection_violation if mod_mcl_core then minetest.register_craft({ @@ -33,33 +39,35 @@ if mod_mcl_core then }) end -mcl_buckets = {} -mcl_buckets.liquids = {} +mcl_buckets = { + liquids = {}, + buckets = {}, +} -- Sound helper functions for placing and taking liquids local function sound_place(itemname, pos) - local def = minetest.registered_nodes[itemname] + local def = registered_nodes[itemname] if def and def.sounds and def.sounds.place then minetest.sound_play(def.sounds.place, {gain=1.0, pos = pos, pitch = 1 + math.random(-10, 10)*0.005}, true) end end local function sound_take(itemname, pos) - local def = minetest.registered_nodes[itemname] + local def = registered_nodes[itemname] if def and def.sounds and def.sounds.dug then minetest.sound_play(def.sounds.dug, {gain=1.0, pos = pos, pitch = 1 + math.random(-10, 10)*0.005}, true) end end local function place_liquid(pos, itemstring) - local fullness = minetest.registered_nodes[itemstring].liquid_range + local fullness = registered_nodes[itemstring].liquid_range sound_place(itemstring, pos) - minetest.add_node(pos, {name=itemstring, param2=fullness}) + add_node(pos, {name=itemstring, param2=fullness}) end local function give_bucket(new_bucket, itemstack, user) local inv = user:get_inventory() - if minetest.is_creative_enabled(user:get_player_name()) then + if is_creative_enabled(user:get_player_name()) then --TODO: is a full bucket added if inv doesn't contain one? return itemstack else @@ -126,7 +134,7 @@ end local function get_bucket_drop(itemstack, user, take_bucket) -- Handle bucket item and inventory stuff - if take_bucket and not minetest.is_creative_enabled(user:get_player_name()) then + if take_bucket and not is_creative_enabled(user:get_player_name()) then -- Add empty bucket and put it into inventory, if possible. -- Drop empty bucket otherwise. local new_bucket = ItemStack("mcl_buckets:bucket_empty") @@ -147,6 +155,169 @@ local function get_bucket_drop(itemstack, user, take_bucket) end end +local function on_place_bucket(itemstack, user, pointed_thing, def) + -- Must be pointing to node + if pointed_thing.type ~= "node" then + return + end + -- Call on_rightclick if the pointed node defines it + local new_stack = mcl_util.call_on_rightclick(itemstack, user, pointed_thing) + if new_stack then + return new_stack + end + + local undernode = get_node(pointed_thing.under) + local abovenode = get_node(pointed_thing.above) + + if registered_nodes[undernode.name] and registered_nodes[undernode.name].buildable_to or get_item_group(undernode.name, "cauldron") == 1 then + local result, take_bucket = get_extra_check(def.extra_check, pointed_thing.under, user) + if result then + local node_place = get_node_place(def.source_place, pointed_thing.under) + local pns = user:get_player_name() + + -- Check protection + if is_protected(pointed_thing.under, pns) then + record_protection_violation(pointed_thing.under, pns) + return itemstack + end + + -- Place liquid + place_liquid(pointed_thing.under, node_place) + + -- Update doc mod + if mod_doc and doc.entry_exists("nodes", node_place) then + doc.mark_entry_as_revealed(user:get_player_name(), "nodes", node_place) + end + end + return get_bucket_drop(itemstack, user, take_bucket) + elseif registered_nodes[abovenode.name] and registered_nodes[abovenode.name].buildable_to or get_item_group(abovenode.name, "cauldron") == 1 then + local result, take_bucket = get_extra_check(def.extra_check, pointed_thing.above, user) + if result then + local node_place = get_node_place(def.source_place, pointed_thing.above) + local pns = user:get_player_name() + + -- Check protection + if is_protected(pointed_thing.above, pns) then + record_protection_violation(pointed_thing.above, pns) + return itemstack + end + + -- Place liquid + place_liquid(pointed_thing.above, node_place) + + -- Update doc mod + if mod_doc and doc.entry_exists("nodes", node_place) then + doc.mark_entry_as_revealed(user:get_player_name(), "nodes", node_place) + end + end + return get_bucket_drop(itemstack, user, take_bucket) + else + return itemstack + end +end + + +local function on_place_bucket_empty(itemstack, user, pointed_thing) + -- Must be pointing to node + if pointed_thing.type ~= "node" then + return itemstack + end + + -- Call on_rightclick if the pointed node defines it + local new_stack = mcl_util.call_on_rightclick(itemstack, user, pointed_thing) + if new_stack then + return new_stack + end + + local node = get_node(pointed_thing.under) + local nn = node.name + + local new_bucket + local liquid_node = bucket_raycast(user) + if liquid_node then + if is_protected(liquid_node.above, user:get_player_name()) then + record_protection_violation(liquid_node.above, user:get_player_name()) + end + local liquid_name = get_node(liquid_node.above).name + if liquid_name then + local liquid_def = mcl_buckets.liquids[liquid_name] + if liquid_def then + --minetest.chat_send_all("test") + -- Fill bucket, but not in Creative Mode + -- FIXME: remove this line + --if not is_creative_enabled(user:get_player_name()) then + if not false then + new_bucket = ItemStack({name = liquid_def.bucketname}) + if liquid_def.on_take then + liquid_def.on_take(user) + end + end + add_node(liquid_node.above, {name="air"}) + sound_take(nn, liquid_node.above) + + if mod_doc and doc.entry_exists("nodes", liquid_name) then + doc.mark_entry_as_revealed(user:get_player_name(), "nodes", liquid_name) + end + if new_bucket then + return give_bucket(new_bucket, itemstack, user) + end + else + minetest.log("error", string.format("[mcl_buckets] Node [%s] has invalid group [_mcl_bucket_pointable]!", liquid_name)) + end + end + return itemstack + else + -- FIXME: replace this ugly code by cauldrons API + if nn == "mcl_cauldrons:cauldron_3" then + -- Take water out of full cauldron + set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) + if not is_creative_enabled(user:get_player_name()) then + new_bucket = ItemStack("mcl_buckets:bucket_water") + end + sound_take("mcl_core:water_source", pointed_thing.under) + elseif nn == "mcl_cauldrons:cauldron_3r" then + -- Take river water out of full cauldron + set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) + if not is_creative_enabled(user:get_player_name()) then + new_bucket = ItemStack("mcl_buckets:bucket_river_water") + end + sound_take("mclx_core:river_water_source", pointed_thing.under) + end + if new_bucket then + return give_bucket(new_bucket, itemstack, user) + end + end + return itemstack +end + +controls.register_on_press(function(player, key) + if key ~= "RMB" then + return + end + + local wielded_item = player:get_wielded_item() + local itemname = wielded_item:get_name() + local def = mcl_buckets.buckets[itemname] + + if itemname == "mcl_buckets:bucket_empty" then + local pointed_thing = mcl_util.get_pointed_thing(player, true) + + if not pointed_thing then + return + end + wielded_item = on_place_bucket_empty(wielded_item, player, pointed_thing) + elseif def then + local pointed_thing = mcl_util.get_pointed_thing(player, false) + + if not pointed_thing then + return + end + wielded_item = on_place_bucket(wielded_item, player, pointed_thing, def) + end + + player:set_wielded_item(wielded_item) +end) + function mcl_buckets.register_liquid(def) for _,source in ipairs(def.source_take) do mcl_buckets.liquids[source] = { @@ -161,6 +332,8 @@ function mcl_buckets.register_liquid(def) end end + mcl_buckets.buckets[def.bucketname] = def + if def.bucketname == nil or def.bucketname == "" then error(string.format("[mcl_bucket] Invalid itemname then registering [%s]!", def.name)) end @@ -173,71 +346,8 @@ function mcl_buckets.register_liquid(def) inventory_image = def.inventory_image, stack_max = 1, groups = def.groups, - on_place = function(itemstack, user, pointed_thing) - -- Must be pointing to node - if pointed_thing.type ~= "node" then - return - end - -- Call on_rightclick if the pointed node defines it - local new_stack = mcl_util.call_on_rightclick(itemstack, user, pointed_thing) - if new_stack then - return new_stack - end - - local undernode = get_node(pointed_thing.under) - local abovenode = get_node(pointed_thing.above) - local buildable1 = minetest.registered_nodes[undernode.name] and minetest.registered_nodes[undernode.name].buildable_to - local buildable2 = minetest.registered_nodes[abovenode.name] and minetest.registered_nodes[abovenode.name].buildable_to - if not buildable1 and not buildable2 then return itemstack end --if both nodes aren't buildable_to, skip - - if buildable1 then - local result, take_bucket = get_extra_check(def.extra_check, pointed_thing.under, user) - if result then - local node_place = get_node_place(def.source_place, pointed_thing.under) - local pns = user:get_player_name() - - -- Check protection - if minetest.is_protected(pointed_thing.under, pns) then - minetest.record_protection_violation(pointed_thing.under, pns) - return itemstack - end - - -- Place liquid - place_liquid(pointed_thing.under, node_place) - - -- Update doc mod - if mod_doc and doc.entry_exists("nodes", node_place) then - doc.mark_entry_as_revealed(user:get_player_name(), "nodes", node_place) - end - end - return get_bucket_drop(itemstack, user, take_bucket) - elseif buildable2 then - local result, take_bucket = get_extra_check(def.extra_check, pointed_thing.above, user) - if result then - local node_place = get_node_place(def.source_place, pointed_thing.above) - local pns = user:get_player_name() - - -- Check protection - if minetest.is_protected(pointed_thing.above, pns) then - minetest.record_protection_violation(pointed_thing.above, pns) - return itemstack - end - - -- Place liquid - place_liquid(pointed_thing.above, node_place) - - -- Update doc mod - if mod_doc and doc.entry_exists("nodes", node_place) then - doc.mark_entry_as_revealed(user:get_player_name(), "nodes", node_place) - end - end - return get_bucket_drop(itemstack, user, take_bucket) - else - return itemstack - end - end, _on_dispense = function(stack, pos, droppos, dropnode, dropdir) - local buildable = minetest.registered_nodes[dropnode.name].buildable_to or dropnode.name == "mcl_portals:portal" + local buildable = registered_nodes[dropnode.name].buildable_to or dropnode.name == "mcl_portals:portal" if not buildable then return stack end local result, take_bucket = get_extra_check(def.extra_check, droppos, nil) if result then -- Fail placement of liquid if result is false @@ -259,78 +369,6 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { --liquids_pointable = true, inventory_image = "bucket.png", stack_max = 16, - on_place = function(itemstack, user, pointed_thing) - -- Must be pointing to node - if pointed_thing.type ~= "node" then - return itemstack - end - - -- Call on_rightclick if the pointed node defines it - local new_stack = mcl_util.call_on_rightclick(itemstack, user, pointed_thing) - if new_stack then - return new_stack - end - - local node = minetest.get_node(pointed_thing.under) - local nn = node.name - - local new_bucket - local liquid_node = bucket_raycast(user) - if liquid_node then - if minetest.is_protected(liquid_node.above, user:get_player_name()) then - minetest.record_protection_violation(liquid_node.above, user:get_player_name()) - end - local liquid_name = get_node(liquid_node.above).name - if liquid_name then - local liquid_def = mcl_buckets.liquids[liquid_name] - if liquid_def then - --minetest.chat_send_all("test") - -- Fill bucket, but not in Creative Mode - -- FIXME: remove this line - --if not minetest.is_creative_enabled(user:get_player_name()) then - if not false then - new_bucket = ItemStack({name = liquid_def.bucketname}) - if liquid_def.on_take then - liquid_def.on_take(user) - end - end - add_node(liquid_node.above, {name="air"}) - sound_take(nn, liquid_node.above) - - if mod_doc and doc.entry_exists("nodes", liquid_name) then - doc.mark_entry_as_revealed(user:get_player_name(), "nodes", liquid_name) - end - if new_bucket then - return give_bucket(new_bucket, itemstack, user) - end - else - minetest.log("error", string.format("[mcl_buckets] Node [%s] has invalid group [_mcl_bucket_pointable]!", liquid_name)) - end - end - return itemstack - else - -- FIXME: replace this ugly code by cauldrons API - if nn == "mcl_cauldrons:cauldron_3" then - -- Take water out of full cauldron - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) - if not minetest.is_creative_enabled(user:get_player_name()) then - new_bucket = ItemStack("mcl_buckets:bucket_water") - end - sound_take("mcl_core:water_source", pointed_thing.under) - elseif nn == "mcl_cauldrons:cauldron_3r" then - -- Take river water out of full cauldron - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) - if not minetest.is_creative_enabled(user:get_player_name()) then - new_bucket = ItemStack("mcl_buckets:bucket_river_water") - end - sound_take("mclx_core:river_water_source", pointed_thing.under) - end - if new_bucket then - return give_bucket(new_bucket, itemstack, user) - end - end - return itemstack - end, _on_dispense = function(stack, pos, droppos, dropnode, dropdir) -- Fill empty bucket with liquid or drop bucket if no liquid local collect_liquid = false @@ -344,13 +382,13 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { collect_liquid = true end if collect_liquid then - minetest.set_node(droppos, {name="air"}) + set_node(droppos, {name="air"}) -- Fill bucket with liquid stack = new_bucket else -- No liquid found: Drop empty bucket - minetest.add_item(droppos, stack) + add_item(droppos, stack) stack:take_item() end return stack diff --git a/mods/ITEMS/mcl_buckets/locale/mcl_buckets.zh_TW.tr b/mods/ITEMS/mcl_buckets/locale/mcl_buckets.zh_TW.tr new file mode 100644 index 0000000000..a9db929b26 --- /dev/null +++ b/mods/ITEMS/mcl_buckets/locale/mcl_buckets.zh_TW.tr @@ -0,0 +1,17 @@ +# textdomain: mcl_buckets +Empty Bucket=空桶 +A bucket can be used to collect and release liquids.=桶可以用來收集和倒出液體。 +Punch a liquid source to collect it. You can then use the filled bucket to place the liquid somewhere else.=擊打一個液體源頭來收集它。然後你可以用裝滿的桶把液體放在其他地方。 +Lava Bucket=熔岩桶 +A bucket can be used to collect and release liquids. This one is filled with hot lava, safely contained inside. Use with caution.=桶可以用來收集和釋放液體。這個桶裡裝的是熱的熔岩,安全地裝在裡面。使用時要小心! +Get in a safe distance and place the bucket to empty it and create a lava source at this spot. Don't burn yourself!=在安全距離內,將熔岩倒出,在這個地方創造一個熔岩源頭。不要燒到自己! +Water Bucket=水桶 +A bucket can be used to collect and release liquids. This one is filled with water.=桶可以用來收集和倒出液體。這個桶裡裝的是水。 +Place it to empty the bucket and create a water source.=放置它以清空水桶並創建水源。 +River Water Bucket=河水桶 +A bucket can be used to collect and release liquids. This one is filled with river water.=桶可以用來收集和倒出液體。這個桶裡裝的是河水。 +Place it to empty the bucket and create a river water source.=放置它以清空水桶並創建河水源。 +Collects liquids=攜帶流體 +Places a lava source=放置熔岩源頭 +Places a water source=放置水源 +Places a river water source=放置河水源頭 diff --git a/mods/ITEMS/mcl_buckets/mod.conf b/mods/ITEMS/mcl_buckets/mod.conf index 0d7b764b87..ba945b033b 100644 --- a/mods/ITEMS/mcl_buckets/mod.conf +++ b/mods/ITEMS/mcl_buckets/mod.conf @@ -1,6 +1,6 @@ name = mcl_buckets author = Kahrl description = -depends = mcl_worlds, mcl_util +depends = mcl_worlds, mcl_util, controls optional_depends = mcl_core, mclx_core, doc diff --git a/mods/ITEMS/mcl_cake/init.lua b/mods/ITEMS/mcl_cake/init.lua index 1040710645..f3a69f4131 100644 --- a/mods/ITEMS/mcl_cake/init.lua +++ b/mods/ITEMS/mcl_cake/init.lua @@ -52,7 +52,10 @@ minetest.register_node("mcl_cake:cake", { fixed = full_cake }, stack_max = 1, - groups = {handy=1, cake=7, food=2,no_eat_delay=1, attached_node=1, dig_by_piston=1, comparator_signal=14}, + groups = { + handy = 1, attached_node = 1, dig_by_piston = 1, comparator_signal = 14, + cake = 7, food = 2, no_eat_delay = 1, compostability = 100 + }, drop = "", on_rightclick = function(pos, node, clicker, itemstack) -- Cake is subject to protection @@ -125,7 +128,11 @@ local register_slice = function(level, nodebox, desc) type = "fixed", fixed = nodebox, }, - groups = {handy=1, cake=level, food=2,no_eat_delay=1,attached_node=1,not_in_creative_inventory=1,dig_by_piston=1,comparator_signal=level*2}, + groups = { + handy = 1, attached_node = 1, not_in_creative_inventory = 1, + dig_by_piston = 1, cake = level, comparator_signal = level * 2, + food = 2, no_eat_delay = 1 + }, drop = "", on_rightclick = on_rightclick, sounds = mcl_sounds.node_sound_leaves_defaults(), diff --git a/mods/ITEMS/mcl_cake/locale/mcl_cake.zh_TW.tr b/mods/ITEMS/mcl_cake/locale/mcl_cake.zh_TW.tr new file mode 100644 index 0000000000..702791b495 --- /dev/null +++ b/mods/ITEMS/mcl_cake/locale/mcl_cake.zh_TW.tr @@ -0,0 +1,12 @@ +# textdomain: mcl_cake +Cake=蛋糕 +Cakes can be placed and eaten to restore hunger points. A cake has 7 slices. Each slice restores 2 hunger points and 0.4 saturation points. Cakes will be destroyed when dug or when the block below them is broken.=蛋糕可以被放置和食用,以恢復飢餓值。一個蛋糕有7片。每片可以恢復2個飢餓值和0.4個飽食度。蛋糕在被挖掘或其下面的方塊被打破時將被摧毀。 +Place the cake anywhere, then rightclick it to eat a single slice. You can't eat from the cake when your hunger bar is full.=將蛋糕放在任何地方,然後右鍵單擊以吃一小片。 當您的飢餓條已滿時,您不能從蛋糕上吃東西。 +Cake (6 Slices Left)=蛋糕(還剩6片) +Cake (5 Slices Left)=蛋糕(還剩5片) +Cake (4 Slices Left)=蛋糕(還剩4片) +Cake (3 Slices Left)=蛋糕(還剩3片) +Cake (2 Slices Left)=蛋糕(還剩2片) +Cake (1 Slice Left)=蛋糕(還剩1片) +With 7 tasty slices!=有七塊美味的蛋糕! +Hunger points: +@1 per slice=飢餓值:每片 +@1 diff --git a/mods/ITEMS/mcl_cauldrons/locale/mcl_cauldrons.zh_TW.tr b/mods/ITEMS/mcl_cauldrons/locale/mcl_cauldrons.zh_TW.tr new file mode 100644 index 0000000000..ea3b97c416 --- /dev/null +++ b/mods/ITEMS/mcl_cauldrons/locale/mcl_cauldrons.zh_TW.tr @@ -0,0 +1,11 @@ +# textdomain: mcl_cauldron +Cauldron=鍋釜 +Cauldrons are used to store water and slowly fill up under rain. They can also be used to wash off banners.=鍋釜是用來儲水的,在雨水的作用下慢慢填滿。它們也可以用來清洗旗幟。 +Place a water pucket into the cauldron to fill it with water. Place an empty bucket on a full cauldron to retrieve the water. Place a water bottle into the cauldron to fill the cauldron to one third with water. Place a glass bottle in a cauldron with water to retrieve one third of the water. Use an emblazoned banner on a cauldron with water to wash off its top layer.=將水桶放入鍋釜中,使其充滿水。將一個空桶放在裝滿水的大鍋上,以取回水。將一個水瓶放入鍋釜內,使大鍋內增加三分之一的水。將一個玻璃瓶放在有水的鍋釜裡,取回三分之一的水。在有水的鍋釜上使用印有圖案的旗幟,以洗掉其上層。 +Cauldron (1/3 Water)=鍋釜(1/3 水) +Cauldron (2/3 Water)=鍋釜(2/3 水) +Cauldron (3/3 Water)=鍋釜(3/3 水) +Cauldron (1/3 River Water)=鍋釜(1/3 河水) +Cauldron (2/3 River Water)=鍋釜(2/3 河水) +Cauldron (3/3 River Water)=鍋釜(3/3 河水) +Stores water=儲存水 diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index ad5c781f74..35712dfd16 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -291,22 +291,7 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile end end - local function drop_items_chest(pos, oldnode, oldmetadata) - local meta = minetest.get_meta(pos) - local meta2 = meta:to_table() - if oldmetadata then - meta:from_table(oldmetadata) - end - local inv = meta:get_inventory() - for i=1,inv:get_size("main") do - local stack = inv:get_stack("main", i) - if not stack:is_empty() then - local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5} - minetest.add_item(p, stack) - end - end - meta:from_table(meta2) - end + local drop_items_chest = mcl_util.drop_items_from_meta_container("main") local function on_chest_blast(pos) local node = minetest.get_node(pos) diff --git a/mods/ITEMS/mcl_clock/locale/mcl_clock.zh_TW.tr b/mods/ITEMS/mcl_clock/locale/mcl_clock.zh_TW.tr new file mode 100644 index 0000000000..c6834373f1 --- /dev/null +++ b/mods/ITEMS/mcl_clock/locale/mcl_clock.zh_TW.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_clock +Clocks are tools which shows the current time of day in the Overworld.=時鐘顯示世界上當前時間的工具。 +The clock contains a rotating disc with a sun symbol (yellow disc) and moon symbol and a little “pointer” which shows the current time of day by estimating the real position of the sun and the moon in the sky. Noon is represented by the sun symbol and midnight is represented by the moon symbol.=時鐘包含一個帶有太陽符號(黃色圓盤)和月亮符號的旋轉圓盤,以及一個小「指針」,通過估計太陽和月亮在天空中的實際位置來顯示當前的時間。正午由太陽符號表示,午夜由月亮符號表示。 +Clock=時鐘 +Displays the time of day in the Overworld=顯示世界上當前的時間 diff --git a/mods/ITEMS/mcl_cocoas/locale/mcl_cocoas.zh_TW.tr b/mods/ITEMS/mcl_cocoas/locale/mcl_cocoas.zh_TW.tr new file mode 100644 index 0000000000..d71e2b11b1 --- /dev/null +++ b/mods/ITEMS/mcl_cocoas/locale/mcl_cocoas.zh_TW.tr @@ -0,0 +1,6 @@ +# textdomain: mcl_cocoas +Premature Cocoa Pod=成長中的可可豆莢(第1階段) +Cocoa pods grow on the side of jungle trees in 3 stages.=可可莢果分3個階段生長在叢林樹的側面。 +Medium Cocoa Pod=成長中的可可豆莢(第2階段) +Mature Cocoa Pod=成熟的可可豆莢 +A mature cocoa pod grew on a jungle tree to its full size and it is ready to be harvested for cocoa beans. It won't grow any further.=一個成熟的可可豆莢在叢林樹上成熟,它已經準備好被收穫成可可豆了。它不會再長了。 diff --git a/mods/ITEMS/mcl_compass/locale/mcl_compass.zh_TW.tr b/mods/ITEMS/mcl_compass/locale/mcl_compass.zh_TW.tr new file mode 100644 index 0000000000..b4a8126599 --- /dev/null +++ b/mods/ITEMS/mcl_compass/locale/mcl_compass.zh_TW.tr @@ -0,0 +1,4 @@ +# textdomain: mcl_compass +Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=指南針是指向世界原點(X@=0,Z@=0)或主世界的出生點的工具。 +Compass=指南針 +Points to the world origin=指向世界原點 diff --git a/mods/ITEMS/mcl_composters/init.lua b/mods/ITEMS/mcl_composters/init.lua new file mode 100644 index 0000000000..56422d8b5e --- /dev/null +++ b/mods/ITEMS/mcl_composters/init.lua @@ -0,0 +1,276 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- +-- Composter mod, adds composters. +-- +-- Copyleft 2022 by kabou +-- GNU General Public Licence 3.0 +-- + +local composter_description = S( + "Composter" +) +local composter_longdesc = S( + "Composters can convert various organic items into bonemeal." +) +local composter_usagehelp = S( + "Use organic items on the composter to fill it with layers of compost. " .. + "Every time an item is put in the composter, there is a chance that the " .. + "composter adds another layer of compost. Some items have a bigger chance " .. + "of adding an extra layer than other items. After filling up with 7 layers " .. + "of compost, the composter is full. After a delay of approximately one " .. + "second the composter becomes ready and bone meal can be retrieved from it. " .. + "Right-clicking the composter takes out the bone meal empties the composter." +) + +minetest.register_craft({ + output = "mcl_composters:composter", + recipe = { + {"group:wood_slab", "", "group:wood_slab"}, + {"group:wood_slab", "", "group:wood_slab"}, + {"group:wood_slab", "group:wood_slab", "group:wood_slab"}, + } +}) + +minetest.register_craft({ + type = "fuel", + recipe = "mcl_composters:composter", + burntime = 15, +}) + +local get_item_group = minetest.get_item_group +local is_creative_enabled = minetest.is_creative_enabled +local registered_nodes = minetest.registered_nodes +local swap_node = minetest.swap_node +local get_node_timer = minetest.get_node_timer +local add_item = minetest.add_item +local vector_offset = vector.offset +local is_protected = minetest.is_protected +local record_protection_violation = minetest.record_protection_violation + +--- Fill the composter when rightclicked. +-- +-- `on_rightclick` handler for composter blocks of all fill levels except +-- for the "ready" composter (see: composter_harvest). +-- If the item used on the composter block is compostable, there is a chance +-- that the level of the composter may increase, depending on the value of +-- compostability of the item. +-- +-- parameters are the standard parameters passed to `on_rightclick`. +-- returns the remaining itemstack. +-- +local function composter_add_item(pos, node, player, itemstack, pointed_thing) + if not player or (player:get_player_control() and player:get_player_control().sneak) then + return itemstack + end + local name = player:get_player_name() + if is_protected(pos, name) then + record_protection_violation(pos, name) + return itemstack + end + if not itemstack or itemstack:is_empty() then + return itemstack + end + local itemname = itemstack:get_name() + local chance = get_item_group(itemname, "compostability") + if chance > 0 then + if not is_creative_enabled(player:get_player_name()) then + itemstack:take_item() + end + -- calculate leveling up chance + local rand = math.random(0,100) + if chance >= rand then + -- get current compost level + local level = registered_nodes[node.name]["_mcl_compost_level"] + -- spawn green particles above new layer + mcl_dye.add_bone_meal_particle(vector_offset(pos, 0, level/8, 0)) + -- TODO: play some sounds + -- update composter block + if level < 7 then + level = level + 1 + else + level = "ready" + end + swap_node(pos, {name = "mcl_composters:composter_" .. level}) + -- a full composter becomes ready for harvest after one second + -- the block will get updated by the node timer callback set in node reg def + if level == 7 then + local timer = get_node_timer(pos) + timer:start(1) + end + end + end + return itemstack +end + +--- Update a full composter block to ready for harvesting. +-- +-- `on_timer` handler. The timer is set in function 'composter_add_item' +-- when the composter level has reached 7. +-- +-- pos: position of the composter block. +-- returns false, thereby cancelling further activity of the timer. +-- +local function composter_ready(pos) + swap_node(pos, {name = "mcl_composters:composter_ready"}) + -- maybe spawn particles again? + -- TODO: play some sounds + return false +end + +--- Spawn bone meal item and reset composter block. +-- +-- `on_rightclick` handler for the "ready" composter block. Causes a +-- bone meal item to be spawned from the composter and resets the +-- composter block to an empty composter block. +-- +-- parameterss are the standard parameters passed to `on_rightclick`. +-- returns itemstack (unchanged in this function). +-- +local function composter_harvest(pos, node, player, itemstack, pointed_thing) + if not player or (player:get_player_control() and player:get_player_control().sneak) then + return itemstack + end + local name = player:get_player_name() + if is_protected(pos, name) then + record_protection_violation(pos, name) + return itemstack + end + -- reset ready type composter to empty type + swap_node(pos, {name="mcl_composters:composter"}) + -- spawn bone meal item (wtf dye?! is this how they make white cocoa) + add_item(pos, "mcl_dye:white") + -- TODO play some sounds + return itemstack +end + +--- Construct composter nodeboxes with varying levels of compost. +-- +-- level: compost level in the composter +-- returns a nodebox definition table. +-- +local function composter_get_nodeboxes(level) + local top_y_tbl = {[0]=-7, -5, -3, -1, 1, 3, 5, 7} + local top_y = top_y_tbl[level] / 16 + return { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, -0.375, 0.5, 0.5}, -- Left wall + { 0.375, -0.5, -0.5, 0.5, 0.5, 0.5}, -- Right wall + {-0.375, -0.5, 0.375, 0.375, 0.5, 0.5}, -- Back wall + {-0.375, -0.5, -0.5, 0.375, 0.5, -0.375}, -- Front wall + {-0.5, -0.5, -0.5, 0.5, top_y, 0.5}, -- Bottom level + } + } +end + +--- Register empty composter node. +-- +-- This is the craftable base model that can be placed in an inventory. +-- +minetest.register_node("mcl_composters:composter", { + description = composter_description, + _tt_help = S("Converts organic items into bonemeal"), + _doc_items_longdesc = composter_longdesc, + _doc_items_usagehelp = composter_usagehelp, + paramtype = "light", + drawtype = "nodebox", + node_box = composter_get_nodeboxes(0), + selection_box = {type = "regular"}, + tiles = { + "mcl_composter_bottom.png^mcl_composter_top.png", + "mcl_composter_bottom.png", + "mcl_composter_side.png" + }, + is_ground_content = false, + groups = { + handy=1, material_wood=1, deco_block=1, dirtifier=1, + flammable=2, fire_encouragement=3, fire_flammability=4, + }, + sounds = mcl_sounds.node_sound_wood_defaults(), + _mcl_hardness = 0.6, + _mcl_blast_resistance = 0.6, + _mcl_compost_level = 0, + on_rightclick = composter_add_item +}) + +--- Template function for composters with compost. +-- +-- For each fill level a custom node is registered. +-- +local function register_filled_composter(level) + local id = "mcl_composters:composter_"..level + minetest.register_node(id, { + description = S("Composter") .. " (" .. level .. "/7 " .. S("filled") .. ")", + _doc_items_create_entry = false, + paramtype = "light", + drawtype = "nodebox", + node_box = composter_get_nodeboxes(level), + selection_box = {type = "regular"}, + tiles = { + "mcl_composter_compost.png^mcl_composter_top.png", + "mcl_composter_bottom.png", + "mcl_composter_side.png" + }, + is_ground_content = false, + groups = { + handy=1, material_wood=1, deco_block=1, dirtifier=1, + not_in_creative_inventory=1, not_in_craft_guide=1, + flammable=2, fire_encouragement=3, fire_flammability=4, + comparator_signal=level + }, + sounds = mcl_sounds.node_sound_wood_defaults(), + drop = "mcl_composters:composter", + _mcl_hardness = 0.6, + _mcl_blast_resistance = 0.6, + _mcl_compost_level = level, + on_rightclick = composter_add_item, + on_timer = composter_ready + }) + + -- Add entry aliases for the Help + if minetest.get_modpath("doc") then + doc.add_entry_alias("nodes", "mcl_composters:composter", "nodes", id) + end +end + +--- Register filled composters (7 levels). +-- +for level = 1, 7 do + register_filled_composter(level) +end + +--- Register composter that is ready to be harvested. +-- +minetest.register_node("mcl_composters:composter_ready", { + description = S("Composter") .. "(" .. S("ready for harvest") .. ")", + _doc_items_create_entry = false, + paramtype = "light", + drawtype = "nodebox", + node_box = composter_get_nodeboxes(7), + selection_box = {type = "regular"}, + tiles = { + "mcl_composter_ready.png^mcl_composter_top.png", + "mcl_composter_bottom.png", + "mcl_composter_side.png" + }, + is_ground_content = false, + groups = { + handy=1, material_wood=1, deco_block=1, dirtifier=1, + not_in_creative_inventory=1, not_in_craft_guide=1, + flammable=2, fire_encouragement=3, fire_flammability=4, + comparator_signal=8 + }, + sounds = mcl_sounds.node_sound_wood_defaults(), + drop = "mcl_composters:composter", + _mcl_hardness = 0.6, + _mcl_blast_resistance = 0.6, + _mcl_compost_level = 7, + on_rightclick = composter_harvest +}) + +-- Add entry aliases for the Help +if minetest.get_modpath("doc") then + doc.add_entry_alias("nodes", "mcl_composters:composter", + "nodes", "mcl_composters:composter_ready" ) +end diff --git a/mods/ITEMS/mcl_composters/locale/template.txt b/mods/ITEMS/mcl_composters/locale/template.txt new file mode 100644 index 0000000000..c5f9bb858e --- /dev/null +++ b/mods/ITEMS/mcl_composters/locale/template.txt @@ -0,0 +1,7 @@ +# textdomain: mcl_composters +Composter= +Composters can convert various organic items into bonemeal.= +Use organic items on the composter to fill it with layers of compost. Every time an item is put in the composter, there is a chance that the composter adds another layer of compost. Some items have a bigger chance of adding an extra layer than other items. After filling up with 7 layers of compost, the composter is full. After a delay of approximately one second the composter becomes ready and bone meal can be retrieved from it. Right-clicking the composter takes out the bone meal empties the composter."= +filled= +ready for harvest= +Converts organic items into bonemeal= diff --git a/mods/ITEMS/mcl_composters/mod.conf b/mods/ITEMS/mcl_composters/mod.conf new file mode 100644 index 0000000000..86d7298875 --- /dev/null +++ b/mods/ITEMS/mcl_composters/mod.conf @@ -0,0 +1,5 @@ +name = mcl_composters +author = kabou +description = Composters can convert various organic items into bonemeal. +depends = mcl_core, mcl_sounds, mcl_dye +optional_depends = doc diff --git a/mods/ITEMS/mcl_composters/textures/mcl_composter_bottom.png b/mods/ITEMS/mcl_composters/textures/mcl_composter_bottom.png new file mode 100644 index 0000000000..cfed3a8a5c Binary files /dev/null and b/mods/ITEMS/mcl_composters/textures/mcl_composter_bottom.png differ diff --git a/mods/ITEMS/mcl_composters/textures/mcl_composter_compost.png b/mods/ITEMS/mcl_composters/textures/mcl_composter_compost.png new file mode 100644 index 0000000000..afda87c716 Binary files /dev/null and b/mods/ITEMS/mcl_composters/textures/mcl_composter_compost.png differ diff --git a/mods/ITEMS/mcl_composters/textures/mcl_composter_ready.png b/mods/ITEMS/mcl_composters/textures/mcl_composter_ready.png new file mode 100644 index 0000000000..7caf79f96e Binary files /dev/null and b/mods/ITEMS/mcl_composters/textures/mcl_composter_ready.png differ diff --git a/mods/ITEMS/mcl_composters/textures/mcl_composter_side.png b/mods/ITEMS/mcl_composters/textures/mcl_composter_side.png new file mode 100644 index 0000000000..c9e5a6fe3c Binary files /dev/null and b/mods/ITEMS/mcl_composters/textures/mcl_composter_side.png differ diff --git a/mods/ITEMS/mcl_composters/textures/mcl_composter_top.png b/mods/ITEMS/mcl_composters/textures/mcl_composter_top.png new file mode 100644 index 0000000000..fc6e202d3c Binary files /dev/null and b/mods/ITEMS/mcl_composters/textures/mcl_composter_top.png differ diff --git a/mods/ITEMS/mcl_core/craftitems.lua b/mods/ITEMS/mcl_core/craftitems.lua index 85a078766f..fc84c50f54 100644 --- a/mods/ITEMS/mcl_core/craftitems.lua +++ b/mods/ITEMS/mcl_core/craftitems.lua @@ -139,7 +139,7 @@ minetest.register_craftitem("mcl_core:apple", { stack_max = 64, on_place = minetest.item_eat(4), on_secondary_use = minetest.item_eat(4), - groups = { food = 2, eatable = 4 }, + groups = { food = 2, eatable = 4, compostability = 65 }, _mcl_saturation = 2.4, }) diff --git a/mods/ITEMS/mcl_core/functions.lua b/mods/ITEMS/mcl_core/functions.lua index d2ff3690aa..fc08a0957c 100644 --- a/mods/ITEMS/mcl_core/functions.lua +++ b/mods/ITEMS/mcl_core/functions.lua @@ -210,7 +210,8 @@ minetest.register_abm({ end local posses = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } } for _, p in pairs(posses) do - if minetest.registered_nodes[minetest.get_node(vector.new(pos.x + p[1], pos.y, pos.z + p[2])).name].walkable then + local ndef = minetest.registered_nodes[minetest.get_node(vector.new(pos.x + p[1], pos.y, pos.z + p[2])).name] + if ndef and ndef.walkable then local posy = pos.y while minetest.get_node(vector.new(pos.x, posy, pos.z)).name == "mcl_core:cactus" do local pos = vector.new(pos.x, posy, pos.z) @@ -619,6 +620,30 @@ function mcl_core.generate_spruce_tree(pos) minetest.place_schematic({ x = pos.x - 3, y = pos.y - 1, z = pos.z - 3 }, path, "0", nil, false) end +local function find_necorner(p) + local n=minetest.get_node_or_nil(vector.offset(p,0,1,1)) + local e=minetest.get_node_or_nil(vector.offset(p,1,1,0)) + if n and n.name == "mcl_core:sprucetree" then + p=vector.offset(p,0,0,1) + end + if e and e.name == "mcl_core:sprucetree" then + p=vector.offset(p,1,0,0) + end + return p +end + +local function generate_spruce_podzol(ps) + local pos=find_necorner(ps) + local pos1=vector.offset(pos,-6,-6,-6) + local pos2=vector.offset(pos,6,6,6) + local nn=minetest.find_nodes_in_area_under_air(pos1, pos2, {"group:dirt"}) + for k,v in pairs(nn) do + if math.random(vector.distance(pos,v)) < 4 and not (math.abs(pos.x-v.x) == 6 and math.abs(pos.z-v.z) == 6) then --leave out the corners + minetest.set_node(v,{name="mcl_core:podzol"}) + end + end +end + function mcl_core.generate_huge_spruce_tree(pos) local r1 = math.random(1, 2) local r2 = math.random(1, 4) @@ -635,6 +660,7 @@ function mcl_core.generate_huge_spruce_tree(pos) path = modpath.."/schematics/mcl_core_spruce_huge_up_"..r2..".mts" end minetest.place_schematic(vector.add(pos, offset), path, "0", nil, false) + generate_spruce_podzol(pos) end -- END of spruce tree functions -- @@ -841,7 +867,7 @@ minetest.register_abm({ -- If this was mycelium, uproot plant above if n2.name == "mcl_core:mycelium" then local tad = minetest.registered_nodes[minetest.get_node(above).name] - if tad.groups and tad.groups.non_mycelium_plant then + if tad and tad.groups and tad.groups.non_mycelium_plant then minetest.dig_node(above) end end @@ -1333,7 +1359,7 @@ minetest.register_abm({ function mcl_core.supports_vines(nodename) local def = minetest.registered_nodes[nodename] -- Rules: 1) walkable 2) full cube - return def.walkable and + return def and def.walkable and (def.node_box == nil or def.node_box.type == "regular") and (def.collision_box == nil or def.collision_box.type == "regular") end @@ -1672,4 +1698,3 @@ function mcl_core.after_snow_destruct(pos) local node = minetest.get_node(npos) mcl_core.clear_snow_dirt(npos, node) end - diff --git a/mods/ITEMS/mcl_core/locale/mcl_core.zh_TW.tr b/mods/ITEMS/mcl_core/locale/mcl_core.zh_TW.tr new file mode 100644 index 0000000000..1773418462 --- /dev/null +++ b/mods/ITEMS/mcl_core/locale/mcl_core.zh_TW.tr @@ -0,0 +1,257 @@ +# textdomain: mcl_core +@1 could not survive in lava.=@1試圖在熔岩中游泳 +@1 died in lava.=@1試圖在熔岩中游泳 +@1 melted in lava.=@1試圖在熔岩中游泳 +@1 took a bath in a hot lava tub.=@1試圖在熔岩中游泳 +A block of diamond is mostly a shiny decorative block but also useful as a compact storage of diamonds.=鑽石磚主要是一種閃亮的裝飾方塊,但也可以作為鑽石的省位存儲方式。 +A block of emerald is mostly a shiny decorative block but also useful as a compact storage of emeralds.=綠寶石磚主要是一種閃亮的裝飾方塊,但也可以作為綠寶石的省位存儲方式。 +A block of gold is mostly a shiny decorative block but also useful as a compact storage of gold ingots.=金磚主要是一種閃亮的裝飾方塊,但也可以作為黃金的省位存儲方式。 +A block of iron is mostly a decorative block but also useful as a compact storage of iron ingots.=鐵磚主要是一種裝飾方塊,但也可以作為鐵的省位存儲方式。 +A cactus can only be placed on top of another cactus or any sand.=仙人掌只可以拜擺放在其他仙人掌或沙上。 +A decorative and mostly transparent block.=一種用於裝飾並且基本上是透明的方塊。 +A grass block is dirt with a grass cover. Grass blocks are resourceful blocks which allow the growth of all sorts of plants. They can be turned into farmland with a hoe and turned into grass paths with a shovel. In light, the grass slowly spreads onto dirt nearby. Under an opaque block or a liquid, a grass block may turn back to dirt.=草方塊是有草覆蓋的泥土。草方塊是重要的方塊,是各種植物生長的基礎。它們可以用鋤頭變成農田,用鐵鍬變成草徑。在光照下,草會慢慢蔓延到附近的泥土上。在不透明的方塊或液體下,草方塊可能會變回泥土。 +A lapis lazuli block is mostly a decorative block but also useful as a compact storage of lapis lazuli.=青金石磚主要是一種裝飾方塊,但也可以作為青金石的省位存儲方式。 +A lava source sets fire to a couple of air blocks above when they're next to a flammable block.=當熔岩源與易燃方塊相鄰時,會將附近點燃。 +A piece of ladder which allows you to climb vertically. Ladders can only be placed on the side of solid blocks and not on glass, leaves, ice, slabs, glowstone, nor sea lanterns.=一塊可以讓你垂直攀爬的梯子。梯子只能放在不透明方塊的側面,不能放在玻璃、樹葉、冰塊、石板、螢石、海燈龍等透明方塊上。 +Acacia Leaves=相思木葉 +Acacia Sapling=相思木樹苗 +Acacia Wood=相思木原木 +Acacia Wood Planks=相思木木材 +Acacia leaves are grown from acacia trees.=相思木葉是由相思木樹生長出來的。 +Andesite=安山岩 +Andesite is an igneous rock.=安山岩是一種火成岩。 +Apple=蘋果 +Apples are food items which can be eaten.=蘋果是一種可以被食用的食物 +Barrier=屏障 +Barriers are invisble walkable blocks. They are used to create boundaries of adventure maps and the like. Monsters and animals won't appear on barriers, and fences do not connect to barriers. Other blocks can be built on barriers like on any other block.=屏障是看不見但可行走的方塊。它們通常被用來創建冒險地圖的邊界。怪物和動物不會出現在屏障上,柵欄也不會連接到屏障上。其他方塊可以像在其他方塊上一樣被放置在屏障上。 +Bedrock=基岩 +Bedrock is a very hard type of rock. It can not be broken, destroyed, collected or moved by normal means, unless in Creative Mode.=基岩是一種堅實無比的石頭。除了創造模式的玩家,沒有人可以以正常方式破壞、銷毀、收集或移動它。 +Birch Bark=白樺樹皮 +Birch Leaves=白樺樹葉 +Birch Sapling=白樺樹樹苗 +Birch Wood=白樺樹原木 +Birch Wood Planks=白樺樹木材 +Birch leaves are grown from birch trees.=白樺樹葉是由白樺樹樹生長出來的。 +Black Stained Glass=黑色玻璃 +Block of Coal=煤炭磚 +Block of Diamond=鑽石磚 +Block of Emerald=綠寶石磚 +Block of Gold=金磚 +Block of Iron=鐵磚 +Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=煤炭磚作為煤炭的省位存儲方式,作為熔爐燃料非常有用。一個煤炭磚的燃燒時間相當於10塊煤炭。 +Blue Stained Glass=藍色玻璃 +Bone Block=骨塊 +Bone blocks are decorative blocks and a compact storage of bone meal.=骨粉塊是一個裝飾方塊,也是骨粉的省位存儲方式。 +Bowl=碗 +Bowls are mainly used to hold tasty soups.=碗主要用來盛湯。 +Brick=紅磚頭 +Brick Block=紅磚 +Brick blocks are a good building material for building solid houses and can take quite a punch.=紅磚是一種很好的建築材料,可以用來建造堅固的房屋,並可以承受相當大的壓力。 +Bricks are used to craft brick blocks.=紅磚頭是用來合成紅磚的原料。 +Brown Stained Glass=棕色玻璃 +Cactus=仙人掌 +Charcoal=木炭 +Charcoal is an alternative furnace fuel created by cooking wood in a furnace. It has the same burning time as coal and also shares many of its crafting recipes, but it can not be used to create coal blocks.=木炭可作爲煤炭的替代,通過在熔爐中烹飪原木而產生的。它的燃燒時間與煤炭相同,也也可用來合成許多煤炭可合成的東西,但它不能用來製作煤炭磚。 +Chiseled Stone Bricks=鏨制石磚 +Chiseled Red Sandstone=鏨制紅砂岩 +Chiseled Sandstone=鏨制砂岩 +Chiseled red sandstone is a decorative building block.=鏨制紅砂岩是一個裝飾方塊。 +Chiseled sandstone is a decorative building block.=鏨制砂岩是一個裝飾方塊。 +Clay=黏土 +Clay Ball=黏土球 +Clay balls are a raw material, mainly used to create bricks in the furnace.=黏土球是一種原料,主要用於製磚。 +Clay is a versatile kind of earth commonly found at beaches underwater.=黏土是一種多功能的土,常見於岸邊。 +Coal=煤炭 +Coal Ore=煤礦 +Coarse Dirt=粗泥 +Coarse dirt acts as a soil for some plants and is similar to dirt, but it will never grow a cover.=粗粗泥作為一些植物的土壤,與泥土相似,但它永遠不會長草。 +Cobblestone=鵝卵石 +Cobweb=蜘蛛網 +Cobwebs can be walked through, but significantly slow you down.=蜘蛛網可以穿過,但它會大大降低你的速度。 +Cracked Stone Bricks=裂紋石磚 +Cut Red Sandstone=切製紅砂岩 +Cut Sandstone=切製砂岩 +Cut red sandstone is a decorative building block.=切製紅砂岩是裝飾性的方塊。 +Cut sandstone is a decorative building block.=切製砂岩是裝飾性的方塊。 +Cyan Stained Glass=青色玻璃 +Dark Oak Bark=黑橡木樹皮 +Dark Oak Leaves=黑橡木樹葉 +Dark Oak Sapling=黑橡木樹苗 +Dark Oak Wood=黑橡木原木 +Dark Oak Wood Planks=黑橡木木材 +Dark oak leaves are grown from dark oak trees.=黑橡木樹葉是由黑橡樹生長出來的。 +Dark oak saplings can grow into dark oaks, but only in groups. A lonely dark oak sapling won't grow. A group of four dark oak saplings grows into a dark oak after some time when they are placed on soil (such as dirt) in a 2×2 square and exposed to light.=黑橡木樹苗可以長成黑橡樹,但只能成群生長。單獨的黑橡木樹苗是長不出來的。四棵黑橡木樹苗以2×2的形態放在土壤(如泥土)上,並暴露在光照下,一段時間後就會長成一棵黑橡樹。 +Dead Bush=枯灌木 +Dead bushes are unremarkable plants often found in dry areas. They can be harvested for sticks.=枯灌木是一種不起眼的植物,經常在乾旱地區發現。它們可以被收割成木棒。 +Diamond=鑽石 +Diamond Ore=鑽石礦 +Diamond ore is rare and can be found in clusters near the bottom of the world.=鑽石礦非常稀少,可以在接近世界底部的地方找到它們。 +Diamonds are precious minerals and useful to create the highest tier of armor and tools.=鑽石是珍貴的礦物,可用於製造最高等級的裝甲和工具 +Diorite=閃長岩 +Diorite is an igneous rock.=閃長岩是一種火成岩。 +Dirt=泥土 +Dirt acts as a soil for a few plants. When in light, this block may grow a grass or mycelium cover if such blocks are nearby.=泥土可以作为一些植物的土壤。在光照下,如果附近有草方塊或菌絲土,草或菌絲可呢會蔓延到這裏。 +Emerald=綠寶石 +Emerald Ore=綠寶石礦 +Emerald ore is the ore of emeralds. It is very rare and can be found alone, not in clusters.=綠寶石礦是綠寶石的礦石。它非常稀少,只可以單獨出現,不會成堆出現。 +Emeralds are not very useful on their own, but they can exchanged for gold ingots by crafting.=綠寶石本身用途不太多,但可以通過合成來得到金錠。 +Flint=燧石 +Flint is a raw material.=燧石是原材料。 +Flowing Lava=流動的熔岩 +Flowing Water=流動的水 +Frosted Ice=霜冰 +Frosted ice is a short-lived solid block. It melts into a water source within a few seconds.=霜冰是一種壽命很短的固體方塊。它在幾秒鐘內就會融化,成爲水源。 +Glass=草 +Gold Ingot=金錠 +Gold Nugget=金粒 +Gold Ore=金礦 +Gold nuggets are very small pieces of molten gold; the main purpose is to create gold ingots.=金粒是非常小塊的金,主要用來合成金錠。 +Golden Apple=進蘋果 +Golden apples are precious food items which can be eaten.=金蘋果是可以吃的珍貴食品。 +Granite=花崗岩 +Grass Block=草方塊 +Grass Path=草徑 +Grass paths are a decorative variant of grass blocks. Their top has a different color and they are a bit lower than grass blocks, making them useful to build footpaths. Grass paths can be created with a shovel. A grass path turns into dirt when it is below a solid block.=草徑是草方塊的一種裝飾變種。它們的頂部顏色和草方塊不同,而且它們比草方塊低一些,因此它們對建造人行道很有用。草徑可以用鏟子來創造。當草徑位於不透明方塊下時,它就會變成泥土。 +Gravel=礫石 +Green Stained Glass=綠色玻璃 +Grey Stained Glass=灰色玻璃 +Ice=冰 +Ice is a solid block usually found in cold areas. It melts near block light sources at a light level of 12 or higher. When it melts or is broken while resting on top of another block, it will turn into a water source.=冰是一種通常在寒冷地區發現的不透明方塊。它在光照度為12或更高的方塊光源附近會融化。當它融化或被打破時,如果它當時在另一個方塊的頂部,它將變成一個水源。 +In the End dimension, starting a fire on this block will create an eternal fire.=在終界,在此方塊上點火將產生永恆之火。 +Iron Ingot=鐵錠 +Iron Nugget=鐵粒 +Iron Ore=鐵礦 +Iron nuggets are very small pieces of molten iron; the main purpose is to create iron ingots.=鐵粒是非常小塊的鐵,主要用來合成鐵錠。 +Jungle Bark=叢林樹皮 +Jungle Leaves=叢林輸葉 +Jungle Sapling=叢林樹苗 +Jungle Wood=叢林原木 +Jungle Wood Planks=叢林木材 +Jungle leaves are grown from jungle trees.=叢林樹葉是由叢林樹生長出來的。 +Ladder=梯子 +Lapis Lazuli Block=青金石磚 +Lapis Lazuli Ore=青金石礦 +Lapis lazuli ore is the ore of lapis lazuli. It can be rarely found in clusters near the bottom of the world.=青金石礦是青金石的礦石。在世界底部附近能發現成群的和稀有的青金石礦。 +Lava Source=熔岩源 +Lava is hot and rather dangerous. Don't touch it, it will hurt you a lot and it is hard to get out.=熔岩很熱並相當危險。不要碰它,它會對你造成很大的傷害,而且很難脫身。 +Light Blue Stained Glass=淺藍色玻璃 +Light Grey Stained Glass=淺灰色玻璃 +Lime Stained Glass=淺綠色玻璃 +Lit Redstone Ore=被點亮的紅石礦 +Magenta Stained Glass=洋紅色玻璃 +Molten gold. It is used to craft armor, tools, and whatnot.=融化的金。用來製作盔甲、工具等等。 +Molten iron. It is used to craft armor, tools, and whatnot.=融化的鐵。用來製作盔甲、工具等等。 +Mossy Cobblestone=青苔鵝卵石 +Mossy Stone Bricks=青苔石磚 +Mycelium=菌絲土 +Mycelium is a type of dirt and the ideal soil for mushrooms. Unlike other dirt-type blocks, it can not be turned into farmland with a hoe. In light, mycelium slowly spreads over nearby dirt. Under an opaque block or a liquid, it eventually turns back into dirt.=菌絲是泥土的一種,也是蘑菇的理想土壤。與其他泥土類方塊不同,它不能用鋤頭把它變成農田。在光照之下,菌絲會在附近的泥土上慢慢蔓延。在不透明方塊或液體下,它最終會變回泥土。 +Oak Bark=橡樹皮 +Oak Leaves=橡樹葉 +Oak Sapling=橡樹樹苗 +Oak Wood=橡樹原木 +Oak Wood Planks=橡樹木材 +Oak leaves are grown from oak trees.=橡樹樹葉是由橡樹生長出來的。 +Obsidian=黑曜石 +Obsidian is an extremely hard mineral with an enourmous blast-resistance. Obsidian is formed when water meets lava.=黑曜石是一種極其堅硬的礦物,具有極強的抗爆性。黑曜石是由水與熔岩源相遇而形成的。 +One of the most common blocks in the world, almost the entire underground consists of stone. It sometimes contains ores. Stone may be created when water meets lava.=世界上最常見的方塊之一,幾乎整個地下都由石頭組成。它有時也包含礦石。當水與流動的熔岩相遇時,可能會產生石頭。 +Orange Stained Glass=橙色玻璃 +Packed Ice=冰磚 +Packed ice is a compressed form of ice. It is opaque and solid.=冰塊是冰的壓縮形式。它是不透明的固體方塊。 +Paper=紙 +Paper is used to craft books and maps.=紙是用來合成書和地圖的物品。 +Pink Stained Glass=粉紅色玻璃 +Podzol=灰壤 +Podzol is a type of dirt found in taiga forests. Only a few plants are able to survive on it.=灰壤是一種在針葉林中發現的泥土。只有少數植物能在上面生存。 +Polished Andesite=拋光安山岩 +Polished Diorite=拋光閃長岩 +Polished Granite=拋光花崗岩 +Polished Stone=拋光石頭 +Polished andesite is a decorative building block made from andesite.=拋光閃長岩是由閃長岩製成的裝飾性方塊。 +Polished diorite is a decorative building block made from diorite.=拋光安山岩是由安山岩製成的裝飾性方塊。 +Polished granite is a decorative building block made from granite.=拋光花崗岩是由花崗岩製成的裝飾性方塊。 +Purple Stained Glass=紫色玻璃 +Realm Barrier=維度分割屏障 +Red Sand=紅沙 +Red Sandstone=紅砂岩 +Red Stained Glass=紅色玻璃 +Red sand is found in large quantities in mesa biomes.=红沙在山地生態域中大量存在。 +Red sandstone is compressed red sand and is a rather soft kind of stone.=紅砂岩是壓縮的紅砂,是一種比較軟的石頭。 +Redstone Ore=紅石礦 +Redstone ore is commonly found near the bottom of the world. It glows when it is punched or walked upon.=紅石礦可以在距離世界底部比較近的地方生成。它會在受到壓力或被擊打時發光。 +Sand=沙 +Sand is found in large quantities at beaches and deserts.=沙大量存在於海灘和沙漠中。 +Sandstone=砂岩 +Sandstone is compressed sand and is a rather soft kind of stone.=砂岩是壓縮的沙,是一種比較軟的石頭。 +Slime Block=史萊姆方塊 +Slime blocks are very bouncy and prevent fall damage.=史萊姆方塊擁有驚人的彈性,正因如此,它可以防止掉落傷害。 +Smooth Red Sandstone=平滑紅砂岩 +Smooth Sandstone=平滑砂岩 +Smooth red sandstone is a decorative building block.=平滑紅砂岩是一種裝飾性建築材料。 +Smooth sandstone is compressed sand and is a rather soft kind of stone.=平滑砂岩是一種裝飾性建築材料。 +Snow=雪 +Some coal contained in stone, it is very common and can be found inside stone in medium to large clusters at nearly every height.=煤礦在石頭中非常常見,幾乎在任何高度的石頭中也可以找到中小形的煤礦。 +Some iron contained in stone, it is prety common and can be found below sea level.=鐵礦的稀有度比煤礦小一點,可以在海平面下找到。 +Spruce Bark=杉木樹皮 +Spruce Leaves=杉木樹葉 +Spruce Sapling=杉木樹苗 +Spruce Wood=杉木原木 +Spruce Wood Planks=杉木木材 +Spruce leaves are grown from spruce trees.=杉木樹葉是由杉樹生長出來的。 +Stained glass is a decorative and mostly transparent block which comes in various different colors.=染色玻璃是一種大多是透明的裝飾性方塊,有各種不同的顏色。 +Stick=木棒 +Sticks are a very versatile crafting material; used in countless crafting recipes.=木棒是一種非常通用的製作材料;使用它的合成配方不計其數。 +Stone=石頭 +Stone Bricks=石磚 +Sugar=糖 +Sugar Canes=甘蔗 +Sugar canes are a plant which has some uses in crafting. Sugar canes will slowly grow up to 3 blocks when they are next to water and are placed on a grass block, dirt, sand, red sand, podzol or coarse dirt. When a sugar cane is broken, all sugar canes connected above will break as well.=甘蔗是一種植物,在合成上有一定的用途。當甘蔗在水旁邊而且放在草塊、泥土、沙子、紅沙、豆莢或粗土上的時候,會慢慢長到3格高。當一根甘蔗被折斷時,上面連接的所有甘蔗也會折斷。 +Sugar canes can only be placed top of other sugar canes and on top of blocks on which they would grow.=甘蔗只能放在其他甘蔗或會讓它生長的方塊的上面。 +Sugar comes from sugar canes and is used to make sweet foods.=糖來自甘蔗,用於製作甜食。 +The trunk of a birch tree.=白樺樹的樹幹。 +The trunk of a dark oak tree.=黑橡樹的樹幹。 +The trunk of a jungle tree.=叢林木的樹幹。 +The trunk of a spruce tree.=杉木的樹幹。 +The trunk of an acacia.=相思木的樹幹。 +The trunk of an oak tree.=黑橡木的樹幹。 +This block consists of a couple of loose stones and can't support itself.=這塊石頭由一些鬆散的石頭組成,無法支撐自己。 +This is a decorative block surrounded by the bark of a tree trunk.=這是一個由樹皮包圍的裝飾方塊。 +This is a full block of snow. Snow of this thickness is usually found in areas of extreme cold.=這是一整塊的雪。這種厚度的雪通常出現在極寒地區。 +This is a piece of cactus commonly found in dry areas, especially deserts. Over time, cacti will grow up to 3 blocks high on sand or red sand. A cactus hurts living beings touching it with a damage of 1 HP every half second. When a cactus block is broken, all cactus blocks connected above it will break as well.=這是一片常見於乾燥地區(尤其是沙漠)的仙人掌。隨著時間的推移,仙人掌會在沙子或紅沙上長到3塊高。當有生物接觸它時,該生物會每半秒受到1HP的傷害。當一個仙​​人掌塊被打破時,它上面連接的所有仙人掌塊也會被打破。 +This stone contains pure gold, a rare metal.=這塊石頭含有一種稀有金屬——純金。 +Top Snow=雪 +Top snow is a layer of snow. It melts near light sources other than the sun with a light level of 12 or higher.=頂雪是一層雪。它會在光照度為12或更高的非太陽光源附近融化。 +Vines=藤蔓 +Vines are climbable blocks which can be placed on the sides of solid full-cube blocks. Vines slowly grow and spread.=藤蔓是可以攀爬的方塊,可以放在不透明方塊的側面。藤蔓會慢慢生長和蔓延。 +Void=虛空 +Water=水 +Water Source=水源 +Water is abundant in oceans and also appears in a few springs in the ground. You can swim easily in water, but you need to catch your breath from time to time.=水是海洋的主要構成部分,也出現在地下水中。在水中可以輕鬆地游泳,但需要時常透氣。 +When placed on soil (such as dirt) and exposed to light, a birch sapling will grow into a birch after some time.=將白樺樹苗放在土壤(如泥土)上並接受光照,一段時間後就會長成白樺樹。 +When placed on soil (such as dirt) and exposed to light, a jungle sapling will grow into a jungle tree after some time. When there are 4 jungle saplings in a 2×2 square, they will grow to a huge jungle tree.=將叢林樹苗放在土壤(如泥土)上並接受光照,一段時間後就會長成叢林樹。當2×2的正方形裡有4棵叢林樹苗時,它們會長成一棵巨大的叢林樹。 +When placed on soil (such as dirt) and exposed to light, a spruce sapling will grow into a spruce after some time. When there are 4 spruce saplings in a 2×2 square, they will grow to a huge spruce.=將杉木樹苗放在土壤(如泥土)上並接受光照,一段時間後就會長成杉木樹。當2×2的正方形裡有4棵杉木樹苗時,它們會長成一棵巨大的杉木樹。 +When placed on soil (such as dirt) and exposed to light, an acacia sapling will grow into an acacia after some time.=將相思木樹苗放在土壤(如泥土)上並接受光照,一段時間後就會長成相思木樹。 +When placed on soil (such as dirt) and exposed to light, an oak sapling will grow into an oak after some time.=將黑橡木樹苗放在土壤(如泥土)上並接受光照,一段時間後就會長成黑橡樹。 +When you hold a barrier in hand, you reveal all placed barriers in a short distance around you.=當你手握一個屏障時,你會看到附近所有放置的屏障。 +White Stained Glass=白色玻璃 +Yellow Stained Glass=黃色玻璃 +“Coal” refers to coal lumps obtained by digging coal ore which can be found underground. Coal is your standard furnace fuel, but it can also be used to make torches, coal blocks and a few other things.=「煤」指的是通過挖掘地下可以找到的煤礦而得到的煤塊。煤是標準的燃料,但也可以用來製作火把、煤塊和其他一些東西。 +Water interacts with lava in various ways:=水與熔岩的相互作用如下: +• When water is directly above or horizontally next to a lava source, the lava turns into obsidian.=• 當水在熔岩源的正上方或水平旁邊時,熔岩就會變成黑曜石。 +• When flowing water touches flowing lava either from above or horizontally, the lava turns into cobblestone.=• 當流水從上方或水平方向接觸到流動的熔岩時,熔岩就會變成鵝卵石。 +• When water is directly below lava, the water turns into stone.=• 當水位於熔岩下時,水就會變成石頭。 +Lava interacts with water various ways:=熔岩與水的相互作用如下: +• When a lava source is directly below or horizontally next to water, the lava turns into obsidian.=• 當水在熔岩源的正上方或水平旁邊時,熔岩就會變成黑曜石。 +• When lava is directly above water, the water turns into stone.=• 當熔岩位於水上時,水就會變成石頭。 +Stained Glass=染色玻璃 +Granite is an igneous rock.=花崗岩是火成岩。 +Top snow can be stacked and has one of 8 different height levels. At levels 2-8, top snow is collidable. Top snow drops 2-9 snowballs, depending on its height.=雪可以疊加,並有8個不同的高度等級。在2-8級時,頂雪是不可穿過的。雪會根據其高度掉落2-9個雪球。 +This block can only be placed on full solid blocks and on another top snow (which increases its height).=此方塊只能放在完整的不透明方塊上或另一個雪上。如果它被放置在另一個雪上,會增加其高度。 +Needs soil and water to grow=需要泥土和水來生長 +Needs soil and light to grow=需要泥土和光照來生長 +Grows on sand=在沙上生長 +Contact damage: @1 per half second=接触伤害:每半秒@1次 +Slows down movement=減低行走速度 +2×2 saplings required=必須以2×2的形態擺放樹苗 +2×2 saplings @= large tree=以2×2的形態可長成大形樹木 +Grows on sand or dirt next to water=在靠近水的沙或泥土上生長 +Stackable=可堆疊 diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index fe1ee58c29..b4edc50456 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -368,7 +368,12 @@ minetest.register_node("mcl_core:dirt_with_grass", { color = "#8EB971", is_ground_content = true, stack_max = 64, - groups = {handy=1,shovely=1,dirt=2,grass_block=1, grass_block_no_snow=1, soil=1, soil_sapling=2, soil_sugarcane=1, cultivatable=2, spreading_dirt_type=1, enderman_takable=1, building_block=1}, + groups = { + handy = 1, shovely = 1, dirt = 2, grass_block = 1, grass_block_no_snow = 1, + soil = 1, soil_sapling = 2, soil_sugarcane = 1, cultivatable = 2, + spreading_dirt_type = 1, enderman_takable = 1, building_block = 1, + compostability = 30 + }, drop = "mcl_core:dirt", sounds = mcl_sounds.node_sound_dirt_defaults({ footstep = {name="default_grass_footstep", gain=0.1}, diff --git a/mods/ITEMS/mcl_core/nodes_cactuscane.lua b/mods/ITEMS/mcl_core/nodes_cactuscane.lua index e61d6df803..62d5cc2b5f 100644 --- a/mods/ITEMS/mcl_core/nodes_cactuscane.lua +++ b/mods/ITEMS/mcl_core/nodes_cactuscane.lua @@ -12,7 +12,10 @@ minetest.register_node("mcl_core:cactus", { tiles = {"mcl_core_cactus_top.png", "mcl_core_cactus_bottom.png", "mcl_core_cactus_side.png"}, is_ground_content = true, stack_max = 64, - groups = {handy=1, attached_node=1, plant=1, deco_block=1, dig_by_piston=1, enderman_takable=1}, + groups = { + handy = 1, attached_node = 1, deco_block = 1, dig_by_piston = 1, + plant = 1, enderman_takable = 1, compostability = 50 + }, sounds = mcl_sounds.node_sound_wood_defaults(), paramtype = "light", sunlight_propagates = true, @@ -54,7 +57,7 @@ minetest.register_node("mcl_core:reeds", { _doc_items_usagehelp = S("Sugar canes can only be placed top of other sugar canes and on top of blocks on which they would grow."), drawtype = "plantlike", paramtype2 = "color", - tiles = {"default_papyrus.png"}, + tiles = {"mcl_core_papyrus.png"}, palette = "mcl_core_palette_grass.png", palette_index = 0, inventory_image = "mcl_core_reeds.png", @@ -79,7 +82,10 @@ minetest.register_node("mcl_core:reeds", { }, }, stack_max = 64, - groups = {dig_immediate=3, craftitem=1, deco_block=1, plant=1, non_mycelium_plant=1, dig_by_piston=1}, + groups = { + dig_immediate = 3, craftitem = 1, deco_block = 1, dig_by_piston = 1, + plant = 1, non_mycelium_plant = 1, compostability = 50 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), node_placement_prediction = "", drop = "mcl_core:reeds", -- to prevent color inheritation diff --git a/mods/ITEMS/mcl_core/nodes_climb.lua b/mods/ITEMS/mcl_core/nodes_climb.lua index 9505bb19ab..1a6780618f 100644 --- a/mods/ITEMS/mcl_core/nodes_climb.lua +++ b/mods/ITEMS/mcl_core/nodes_climb.lua @@ -104,7 +104,11 @@ minetest.register_node("mcl_core:vine", { type = "wallmounted", }, stack_max = 64, - groups = {handy=1,axey=1,shearsy=1,swordy=1, flammable=2,deco_block=1,destroy_by_lava_flow=1,dig_by_piston=1, fire_encouragement=15, fire_flammability=100}, + groups = { + handy = 1, axey = 1, shearsy = 1, swordy = 1, deco_block = 1, + dig_by_piston = 1, destroy_by_lava_flow = 1, compostability = 50, + flammable = 2, fire_encouragement = 15, fire_flammability = 100 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), drop = "", _mcl_shears_drop = true, diff --git a/mods/ITEMS/mcl_core/nodes_glass.lua b/mods/ITEMS/mcl_core/nodes_glass.lua index 6e7ab350b7..8b3aea6891 100644 --- a/mods/ITEMS/mcl_core/nodes_glass.lua +++ b/mods/ITEMS/mcl_core/nodes_glass.lua @@ -5,10 +5,11 @@ local mod_doc = minetest.get_modpath("doc") minetest.register_node("mcl_core:glass", { description = S("Glass"), _doc_items_longdesc = S("A decorative and mostly transparent block."), - drawtype = "glasslike", + drawtype = "glasslike_framed_optional", is_ground_content = false, - tiles = {"default_glass.png"}, + tiles = {"default_glass.png", "default_glass_detail.png"}, paramtype = "light", + paramtype2 = "glasslikeliquidlevel", sunlight_propagates = true, stack_max = 64, groups = {handy=1, glass=1, building_block=1, material_glass=1}, @@ -39,10 +40,11 @@ function mcl_core.add_stained_glass(desc, recipeitem, colorgroup, color) _doc_items_create_entry = create_entry, _doc_items_entry_name = entry_name, _doc_items_longdesc = longdesc, - drawtype = "glasslike", + drawtype = "glasslike_framed_optional", is_ground_content = false, - tiles = {"mcl_core_glass_"..color..".png"}, + tiles = {"mcl_core_glass_"..color..".png", "mcl_core_glass_"..color.."_detail.png"}, paramtype = "light", + paramtype2 = "glasslikeliquidlevel", sunlight_propagates = true, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "blend" or true, stack_max = 64, diff --git a/mods/ITEMS/mcl_core/nodes_trees.lua b/mods/ITEMS/mcl_core/nodes_trees.lua index a5ef7aa97d..e4903958ef 100644 --- a/mods/ITEMS/mcl_core/nodes_trees.lua +++ b/mods/ITEMS/mcl_core/nodes_trees.lua @@ -152,17 +152,10 @@ local function register_leaves(subname, description, longdesc, tiles, sapling, d paramtype = "light", stack_max = 64, groups = { - handy=1, - hoey=1, - shearsy=1, - swordy=1, - leafdecay=leafdecay_distance, - flammable=2, - leaves=1, - deco_block=1, - dig_by_piston=1, - fire_encouragement=30, - fire_flammability=60 + handy = 1, hoey = 1, shearsy = 1, swordy = 1, dig_by_piston = 1, + leaves = 1, leafdecay = leafdecay_distance, deco_block = 1, + flammable = 2, fire_encouragement = 30, fire_flammability = 60, + compostability = 30 }, drop = get_drops(0), _mcl_shears_drop = true, @@ -194,7 +187,11 @@ local function register_sapling(subname, description, longdesc, tt_help, texture fixed = selbox }, stack_max = 64, - groups = {dig_immediate=3, plant=1,sapling=1,non_mycelium_plant=1,attached_node=1,dig_by_water=1,dig_by_piston=1,destroy_by_lava_flow=1,deco_block=1}, + groups = { + plant = 1, sapling = 1, non_mycelium_plant = 1, attached_node = 1, + deco_block = 1, dig_immediate = 3, dig_by_water = 1, dig_by_piston = 1, + destroy_by_lava_flow = 1, compostability = 30 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), on_construct = function(pos) local meta = minetest.get_meta(pos) @@ -275,4 +272,4 @@ register_leaves("birchleaves", S("Birch Leaves"), S("Birch leaves are grown from -- Node aliases minetest.register_alias("default:acacia_tree", "mcl_core:acaciatree") -minetest.register_alias("default:acacia_leaves", "mcl_core:acacialeaves") \ No newline at end of file +minetest.register_alias("default:acacia_leaves", "mcl_core:acacialeaves") diff --git a/mods/ITEMS/mcl_core/textures/default_glass_detail.png b/mods/ITEMS/mcl_core/textures/default_glass_detail.png new file mode 100644 index 0000000000..6205f84a58 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/default_glass_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_black_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_black_detail.png new file mode 100644 index 0000000000..9dac71149d Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_black_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_blue_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_blue_detail.png new file mode 100644 index 0000000000..13d0e83b2f Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_blue_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_brown_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_brown_detail.png new file mode 100644 index 0000000000..d342045b14 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_brown_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_cyan_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_cyan_detail.png new file mode 100644 index 0000000000..6b907f54d3 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_cyan_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_gray_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_gray_detail.png new file mode 100644 index 0000000000..4dbc15680b Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_gray_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_green_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_green_detail.png new file mode 100644 index 0000000000..03b9943f12 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_green_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_light_blue_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_light_blue_detail.png new file mode 100644 index 0000000000..842441a2c6 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_light_blue_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_lime_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_lime_detail.png new file mode 100644 index 0000000000..8b80407d3c Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_lime_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_magenta_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_magenta_detail.png new file mode 100644 index 0000000000..cd2d234587 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_magenta_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_orange_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_orange_detail.png new file mode 100644 index 0000000000..930992769a Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_orange_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_pink_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_pink_detail.png new file mode 100644 index 0000000000..d06f90f6b5 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_pink_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_purple_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_purple_detail.png new file mode 100644 index 0000000000..a5685731ff Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_purple_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_red_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_red_detail.png new file mode 100644 index 0000000000..587fbdbdd4 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_red_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_silver_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_silver_detail.png new file mode 100644 index 0000000000..49d444b80f Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_silver_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_white_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_white_detail.png new file mode 100644 index 0000000000..e7e0db92d0 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_white_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/mcl_core_glass_yellow_detail.png b/mods/ITEMS/mcl_core/textures/mcl_core_glass_yellow_detail.png new file mode 100644 index 0000000000..b3fc7c8933 Binary files /dev/null and b/mods/ITEMS/mcl_core/textures/mcl_core_glass_yellow_detail.png differ diff --git a/mods/ITEMS/mcl_core/textures/default_papyrus.png b/mods/ITEMS/mcl_core/textures/mcl_core_papyrus.png similarity index 100% rename from mods/ITEMS/mcl_core/textures/default_papyrus.png rename to mods/ITEMS/mcl_core/textures/mcl_core_papyrus.png diff --git a/mods/ITEMS/mcl_crafting_table/locale/mcl_crafting_table.zh_TW.tr b/mods/ITEMS/mcl_crafting_table/locale/mcl_crafting_table.zh_TW.tr new file mode 100644 index 0000000000..b393d5a48f --- /dev/null +++ b/mods/ITEMS/mcl_crafting_table/locale/mcl_crafting_table.zh_TW.tr @@ -0,0 +1,8 @@ +# textdomain: mcl_crafting_table +Crafting Table=合成台 +A crafting table is a block which grants you access to a 3×3 crafting grid which allows you to perform advanced crafts.=合成台是一個塊狀物,可以讓你進入一個3×3的合成網格,讓你進行高級合成。 +Rightclick the crafting table to access the 3×3 crafting grid.=右鍵點擊合成台以進入3×3合成網格。 +Recipe book=合成教學 +Crafting=合成 +Inventory=物品欄 +3×3 crafting grid=3×3合成網格 diff --git a/mods/ITEMS/mcl_doors/locale/mcl_doors.zh_TW.tr b/mods/ITEMS/mcl_doors/locale/mcl_doors.zh_TW.tr new file mode 100644 index 0000000000..62e2761d7d --- /dev/null +++ b/mods/ITEMS/mcl_doors/locale/mcl_doors.zh_TW.tr @@ -0,0 +1,24 @@ +# textdomain: mcl_doors +Wooden doors are 2-block high barriers which can be opened or closed by hand and by a redstone signal.=木門是2格高的障礙物,可以用手和紅石信號來打開或關閉。 +To open or close a wooden door, rightclick it or supply its lower half with a redstone signal.=要打開或關閉一扇木門,請右擊它或在其下半部分提供紅石信號。 +Oak Door=橡木門 +Acacia Door=相思木門 +Birch Door=樺木門 +Dark Oak Door=黑橡木門 +Jungle Door=叢林木門 +Spruce Door=杉木門 +Iron Door=鐵門 +Iron doors are 2-block high barriers which can only be opened or closed by a redstone signal, but not by hand.=鐵門是2格高的障礙物,能通過紅石信號打開或關閉,但不能用手。 +To open or close an iron door, supply its lower half with a redstone signal.=要打開或關閉鐵門,請在其下半部分提供紅石信號。 +Oak Trapdoor=橡木地板門 +Acacia Trapdoor=相思木地板門 +Birch Trapdoor=樺木地板門 +Spruce Trapdoor=杉木地板門 +Dark Oak Trapdoor=黑橡木地板門 +Jungle Trapdoor=叢林木地板門 +Wooden trapdoors are horizontal barriers which can be opened and closed by hand or a redstone signal. They occupy the upper or lower part of a block, depending on how they have been placed. When open, they can be climbed like a ladder.=木質地板門是水平的障礙物,可以用手或紅石信號來打開和關閉。它們佔據一個方塊的上部或下部,這取決於它們被放置的方式。當打開時,它們可以像梯子一樣被爬上去。 +To open or close the trapdoor, rightclick it or send a redstone signal to it.=要打開或關閉活板門,請右擊它或向它發送紅石信號。 +Iron Trapdoor=鐵製地板門 +Iron trapdoors are horizontal barriers which can only be opened and closed by redstone signals, but not by hand. They occupy the upper or lower part of a block, depending on how they have been placed. When open, they can be climbed like a ladder.=木質地板門是水平的障礙物,能通過紅石信號打開或關閉,但不能用手。它們佔據一個方塊的上部或下部,這取決於它們被放置的方式。當打開時,它們可以像梯子一樣被爬上去。 +Openable by players and redstone power=可以用手和紅石信號來打開 +Openable by redstone power=能通過紅石信號打開 diff --git a/mods/ITEMS/mcl_dye/init.lua b/mods/ITEMS/mcl_dye/init.lua index dfb9624463..727a784601 100644 --- a/mods/ITEMS/mcl_dye/init.lua +++ b/mods/ITEMS/mcl_dye/init.lua @@ -78,7 +78,7 @@ dyelocal.dyes = { {"dark_green", "dye_dark_green", S("Cactus Green"),{dye=1, craftitem=1, basecolor_green=1, excolor_green=1, unicolor_dark_green=1}}, {"green", "mcl_dye_lime", S("Lime Dye"), {dye=1, craftitem=1, basecolor_green=1, excolor_green=1, unicolor_green=1}}, {"yellow", "dye_yellow", S("Dandelion Yellow"), {dye=1, craftitem=1, basecolor_yellow=1, excolor_yellow=1, unicolor_yellow=1}}, - {"brown", "mcl_dye_brown", S("Cocoa Beans"), {dye=1, craftitem=1, basecolor_brown=1, excolor_orange=1, unicolor_dark_orange=1}}, + {"brown", "mcl_dye_brown", S("Cocoa Beans"), {dye=1, craftitem=1, basecolor_brown=1, excolor_orange=1, unicolor_dark_orange=1, compostability = 65}}, {"orange", "dye_orange", S("Orange Dye"), {dye=1, craftitem=1, basecolor_orange=1, excolor_orange=1, unicolor_orange=1}}, {"red", "dye_red", S("Rose Red"), {dye=1, craftitem=1, basecolor_red=1, excolor_red=1, unicolor_red=1}}, {"magenta", "dye_magenta", S("Magenta Dye"), {dye=1, craftitem=1, basecolor_magenta=1, excolor_red_violet=1,unicolor_red_violet=1}}, @@ -561,5 +561,3 @@ minetest.register_craft({ output = "mcl_dye:white 3", recipe = {{"mcl_mobitems:bone"}}, }) - - diff --git a/mods/ITEMS/mcl_dye/locale/mcl_dye.zh_TW.tr b/mods/ITEMS/mcl_dye/locale/mcl_dye.zh_TW.tr new file mode 100644 index 0000000000..23d2face21 --- /dev/null +++ b/mods/ITEMS/mcl_dye/locale/mcl_dye.zh_TW.tr @@ -0,0 +1,25 @@ +# textdomain: mcl_dye +Bone Meal=骨粉 +Light Grey Dye=淺灰色染料 +Grey Dye=灰色染料 +Ink Sac=墨囊 +Purple Dye=紫色染料 +Lapis Lazuli=青金石 +Light Blue Dye=淺藍色染料 +Cyan Dye=青色染料 +Cactus Green=仙人掌綠 +Lime Dye=淺綠色染料 +Dandelion Yellow=蒲公英黃 +Cocoa Beans=可可豆 +Orange Dye=橙色染料 +Rose Red=玫瑰紅 +Magenta Dye=洋紅色染料 +Pink Dye=粉紅色染料 +This item is a dye which is used for dyeing and crafting.=這個物品是一種用於染色和合成的染料。 +Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=右鍵單擊綿羊以染它的毛。其他東西是通過合成染色的。 +Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=骨粉是一種白色染料,也可作為肥料,加速許多植物的生長。 +Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=右鍵點擊一隻羊,使其羊毛變白。右鍵點擊一株植物以加快其生長速度。注意,不是所有的植物都能像這樣施肥。當你右鍵點擊一個草方時,高高的草和花會到處生長。 +Cocoa beans are a brown dye and can be used to plant cocoas.=可可豆是一種棕色染料,也可用於種植可可。 +Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=右鍵點擊一隻羊,使其羊毛變成褐色。右鍵點擊叢林木的一側,可以種植一個可可。 +Grows at the side of jungle trees=在叢林木側生長 +Speeds up plant growth=加速植物生長 diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index e876baf317..f137b42304 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -97,8 +97,9 @@ mcl_enchanting.enchantments.efficiency = { weight = 10, description = S("Increases mining speed."), curse = false, - on_enchant = function(itemstack, level) - mcl_enchanting.update_groupcaps(itemstack) + on_enchant = function() + -- Updating digging speed is handled by update_groupcaps which + -- is called from load_enchantments. end, requires_tool = false, treasure = false, @@ -388,6 +389,7 @@ mcl_experience.register_on_add_xp(function(player, xp) {list = "armor", index = 3}, {list = "armor", index = 4}, {list = "armor", index = 5}, + {list = "offhand", index = 1}, } local final_candidates = {} @@ -671,8 +673,8 @@ mcl_enchanting.enchantments.unbreaking = { tool_capabilities.punch_attack_uses = tool_capabilities.punch_attack_uses * (1 + level) itemstack:get_meta():set_tool_capabilities(tool_capabilities) - -- Unbreaking for groupcaps is handled in this function. - mcl_enchanting.update_groupcaps(itemstack) + -- Updating digging durability is handled by update_groupcaps + -- which is called from load_enchantments. end, requires_tool = true, treasure = false, diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 97a176b971..f505c055e0 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -14,10 +14,11 @@ end function mcl_enchanting.unload_enchantments(itemstack) local itemdef = itemstack:get_definition() - if itemdef.tool_capabilities then - itemstack:get_meta():set_tool_capabilities(nil) - end local meta = itemstack:get_meta() + if itemdef.tool_capabilities then + meta:set_tool_capabilities(nil) + meta:set_string("groupcaps_hash", "") + end if meta:get_string("name") == "" then meta:set_string("description", "") meta:set_string("groupcaps_hash", "") @@ -33,6 +34,7 @@ function mcl_enchanting.load_enchantments(itemstack, enchantments) enchantment_def.on_enchant(itemstack, level) end end + mcl_enchanting.update_groupcaps(itemstack) end tt.reload_itemstack_description(itemstack) end @@ -72,8 +74,12 @@ function mcl_enchanting.is_enchanted(itemname) return minetest.get_item_group(itemname, "enchanted") > 0 end +function mcl_enchanting.not_enchantable_on_enchanting_table(itemname) + return mcl_enchanting.get_enchantability(itemname) == -1 +end + function mcl_enchanting.is_enchantable(itemname) - return mcl_enchanting.get_enchantability(itemname) > 0 + return mcl_enchanting.get_enchantability(itemname) > 0 or mcl_enchanting.not_enchantable_on_enchanting_table(itemname) end function mcl_enchanting.can_enchant_freshly(itemname) @@ -326,7 +332,7 @@ end function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr) local itemname = itemstack:get_name() - if not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted then + if (not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted) or mcl_enchanting.not_enchantable_on_enchanting_table(itemname) then return end @@ -452,7 +458,7 @@ function mcl_enchanting.generate_random_table_slots(itemstack, num_bookshelves) end function mcl_enchanting.get_table_slots(player, itemstack, num_bookshelves) - if not mcl_enchanting.can_enchant_freshly(itemstack:get_name()) then + if (not mcl_enchanting.can_enchant_freshly(itemstack:get_name())) or mcl_enchanting.not_enchantable_on_enchanting_table(itemname) then return {false, false, false} end local itemname = itemstack:get_name() diff --git a/mods/ITEMS/mcl_enchanting/groupcaps.lua b/mods/ITEMS/mcl_enchanting/groupcaps.lua index a445b73f21..2a83727729 100644 --- a/mods/ITEMS/mcl_enchanting/groupcaps.lua +++ b/mods/ITEMS/mcl_enchanting/groupcaps.lua @@ -2,10 +2,7 @@ local groupcaps_cache = {} -- Compute a hash value. function compute_hash(value) - -- minetest.get_password_hash is quite fast, even if it uses a - -- cryptographic hashing function (SHA-1). It is written in C++ and it - -- is probably hard to write a faster hashing function in Lua. - return string.sub(minetest.get_password_hash("ryvnf", minetest.serialize(value)), 1, 8) + return string.sub(minetest.sha1(minetest.serialize(value)), 1, 8) end -- Get the groupcaps and hash for an enchanted tool. If this function is called @@ -46,7 +43,7 @@ end -- the tool needs to be updated. function mcl_enchanting.update_groupcaps(itemstack) local name = itemstack:get_name() - if not minetest.registered_tools[name].tool_capabilities then + if not minetest.registered_tools[name] or not minetest.registered_tools[name].tool_capabilities then return end diff --git a/mods/ITEMS/mcl_end/building.lua b/mods/ITEMS/mcl_end/building.lua index 3c8f7f66c8..06c6722c4d 100644 --- a/mods/ITEMS/mcl_end/building.lua +++ b/mods/ITEMS/mcl_end/building.lua @@ -166,18 +166,20 @@ minetest.register_node("mcl_end:dragon_egg", { selection_box = { type = "regular", }, - groups = {handy=1, falling_node = 1, deco_block = 1, not_in_creative_inventory = 1, dig_by_piston = 1 }, + groups = {handy = 1, falling_node = 1, deco_block = 1, not_in_creative_inventory = 1, dig_by_piston = 1 }, sounds = mcl_sounds.node_sound_stone_defaults(), _mcl_blast_resistance = 9, _mcl_hardness = 3, - on_punch = function(pos, node) - local max_dist = vector.new(15, 7, 15) - local positions = minetest.find_nodes_in_area(vector.subtract(pos, max_dist), vector.add(pos, max_dist), "air", false) - if #positions > 0 then - local tpos = positions[math.random(#positions)] - minetest.remove_node(pos) - minetest.set_node(tpos, node) - minetest.check_for_falling(tpos) + on_punch = function(pos, node, puncher) + if not minetest.is_protected(pos, puncher:get_player_name()) then + local max_dist = vector.new(15, 7, 15) + local positions = minetest.find_nodes_in_area(vector.subtract(pos, max_dist), vector.add(pos, max_dist), "air", false) + if #positions > 0 then + local tpos = positions[math.random(#positions)] + minetest.remove_node(pos) + minetest.set_node(tpos, node) + minetest.check_for_falling(tpos) + end end end, }) diff --git a/mods/ITEMS/mcl_end/textures/mcl_end_crystal_beam.png b/mods/ITEMS/mcl_end/textures/mcl_end_crystal_beam.png index 1259a5d0ec..b1b74265d4 100644 Binary files a/mods/ITEMS/mcl_end/textures/mcl_end_crystal_beam.png and b/mods/ITEMS/mcl_end/textures/mcl_end_crystal_beam.png differ diff --git a/mods/ITEMS/mcl_farming/beetroot.lua b/mods/ITEMS/mcl_farming/beetroot.lua index e312aa262e..21096042b8 100644 --- a/mods/ITEMS/mcl_farming/beetroot.lua +++ b/mods/ITEMS/mcl_farming/beetroot.lua @@ -5,7 +5,7 @@ minetest.register_craftitem("mcl_farming:beetroot_seeds", { _tt_help = S("Grows on farmland"), _doc_items_longdesc = S("Grows into a beetroot plant. Chickens like beetroot seeds."), _doc_items_usagehelp = S("Place the beetroot seeds on farmland (which can be created with a hoe) to plant a beetroot plant. They grow in sunlight and grow faster on hydrated farmland. Rightclick an animal to feed it beetroot seeds."), - groups = { craftitem=1 }, + groups = {craftitem = 1, compostability = 30}, inventory_image = "mcl_farming_beetroot_seeds.png", wield_image = "mcl_farming_beetroot_seeds.png", on_place = function(itemstack, placer, pointed_thing) @@ -133,7 +133,7 @@ minetest.register_craftitem("mcl_farming:beetroot_item", { wield_image = "mcl_farming_beetroot.png", on_place = minetest.item_eat(1), on_secondary_use = minetest.item_eat(1), - groups = { food = 2, eatable = 1 }, + groups = {food = 2, eatable = 1, compostability = 65}, _mcl_saturation = 1.2, }) diff --git a/mods/ITEMS/mcl_farming/carrots.lua b/mods/ITEMS/mcl_farming/carrots.lua index 7983c58a2f..1c3ebcdfa5 100644 --- a/mods/ITEMS/mcl_farming/carrots.lua +++ b/mods/ITEMS/mcl_farming/carrots.lua @@ -86,7 +86,7 @@ minetest.register_craftitem("mcl_farming:carrot_item", { _doc_items_longdesc = S("Carrots can be eaten and planted. Pigs and rabbits like carrots."), _doc_items_usagehelp = S("Hold it in your hand and rightclick to eat it. Place it on top of farmland to plant the carrot. It grows in sunlight and grows faster on hydrated farmland. Rightclick an animal to feed it."), inventory_image = "farming_carrot.png", - groups = { food = 2, eatable = 3 }, + groups = {food = 2, eatable = 3, compostability = 65}, _mcl_saturation = 3.6, on_secondary_use = minetest.item_eat(3), on_place = function(itemstack, placer, pointed_thing) diff --git a/mods/ITEMS/mcl_farming/locale/mcl_farming.zh_TW.tr b/mods/ITEMS/mcl_farming/locale/mcl_farming.zh_TW.tr new file mode 100644 index 0000000000..7017f78521 --- /dev/null +++ b/mods/ITEMS/mcl_farming/locale/mcl_farming.zh_TW.tr @@ -0,0 +1,99 @@ +# textdomain: mcl_farming +Beetroot Seeds=甜菜種子 +Grows into a beetroot plant. Chickens like beetroot seeds.=長成甜菜根。雞喜歡甜菜種子。 +Place the beetroot seeds on farmland (which can be created with a hoe) to plant a beetroot plant. They grow in sunlight and grow faster on hydrated farmland. Rightclick an animal to feed it beetroot seeds.=將甜菜種子放在農田上(可以用鋤頭創造)種植甜菜。它們在陽光下生長,在有水分的農田上生長更快。右鍵點擊一個動物來餵牠甜菜種子。 +Premature Beetroot Plant (Stage 1)=未熟的甜菜植物(第1階段) +Beetroot plants are plants which grow on farmland under sunlight in 4 stages. On hydrated farmland, they grow a bit faster. They can be harvested at any time but will only yield a profit when mature.=甜菜根植物是在農田裡陽光下生長的植物,分為4個階段。在有水分的農田裡,它們生長得更快一些。它們可以在任何時候被收割,但只有在成熟時才會產生利潤。 +Premature Beetroot Plant=未熟的甜菜 +Premature Beetroot Plant (Stage 2)=未熟的甜菜(第2階段) +Premature Beetroot Plant (Stage 3)=未熟的甜菜(第3階段) +Mature Beetroot Plant=成熟的甜菜 +A mature beetroot plant is a farming plant which is ready to be harvested for a beetroot and some beetroot seeds. It won't grow any further.=成熟的甜菜是一種隨時可以收穫甜菜根和一些甜菜種子的植物。它不會再增長了。 +Beetroot=甜菜根 +Beetroots are both used as food item and a dye ingredient. Pigs like beetroots, too.=甜菜根既用作食品又用作染料成分。豬也喜歡甜菜根。 +Hold it in your hand and right-click to eat it. Rightclick an animal to feed it.=把它拿在手裡,右鍵點擊以吃掉它。右鍵點擊一個動物來餵牠。 +Beetroot Soup=甜菜根湯 +Beetroot soup is a food item.=甜菜根湯是一種食物。 +Premature Carrot Plant=成長中的胡蘿蔔 +Carrot plants are plants which grow on farmland under sunlight in 8 stages, but only 4 stages can be visually told apart. On hydrated farmland, they grow a bit faster. They can be harvested at any time but will only yield a profit when mature.=胡蘿蔔是在農田中陽光下生長的植物,分為8個階段,但只有4個階段可以從視覺上區​​分。在水分充足的農田裡,它們生長得更快一些。它們可以在任何時候收割,但只有在成熟時才會有收益。 +Premature Carrot Plant (Stage @1)=成長中的胡蘿蔔(第@1階段) +Mature Carrot Plant=成熟的胡蘿蔔 +Mature carrot plants are ready to be harvested for carrots. They won't grow any further.=成熟的胡蘿蔔是一種隨時可以收穫胡蘿蔔的植物。它不會再增長了。 +Carrot=胡蘿蔔 +Carrots can be eaten and planted. Pigs and rabbits like carrots.=胡蘿蔔既可以吃又可以種植。豬和兔子都喜款胡蘿蔔。 +Hold it in your hand and rightclick to eat it. Place it on top of farmland to plant the carrot. It grows in sunlight and grows faster on hydrated farmland. Rightclick an animal to feed it.=把它拿在手裡,右鍵點擊以吃掉它;把它放置在農田上種植它。在水分充足的農田裡,它們生長得更快一些。右鍵點擊一個動物來餵牠。 +Golden Carrot=金胡蘿蔔 +A golden carrot is a precious food item which can be eaten. It is really, really filling!=金胡蘿蔔是一種可以吃的珍貴食品。它真的非常、非常的有營養! +Hoes are essential tools for growing crops. They are used to create farmland in order to plant seeds on it. Hoes can also be used as very weak weapons in a pinch.=鋤頭是種植農作物的基本工具。它們被用來開闢農田,以便在上面種植種子。在緊要關頭,鋤頭也可以作為非常薄弱的​​武器使用。 +Use the hoe on a cultivatable block (by rightclicking it) to turn it into farmland. Dirt, grass blocks and grass paths are cultivatable blocks. Using a hoe on coarse dirt turns it into dirt.=在可耕地塊上使用鋤頭(通過右鍵點擊),將其變成農田。泥土、草塊和草路都是可耕地塊。在粗泥上使用鋤頭可以將其變成泥土。 +Wood Hoe=木鋤 +Stone Hoe=石鋤 +Iron Hoe=鐵鋤 +Golden Hoe=金鋤 +Diamond Hoe=鑽石鋤 +Melon Seeds=西瓜種子 +Grows into a melon stem which in turn grows melons. Chickens like melon seeds.=長成可長出西瓜的瓜莖。雞喜歡西瓜種子。 +Place the melon seeds on farmland (which can be created with a hoe) to plant a melon stem. Melon stems grow in sunlight and grow faster on hydrated farmland. When mature, the stem will attempt to grow a melon at the side. Rightclick an animal to feed it melon seeds.=將西瓜種子放在農田上(可以用鋤頭打造)以種植西瓜莖。瓜莖在陽光下生長,在水分充足的農田上生長更快。成熟後,莖會試圖在邊上長出一個西瓜。右鍵點擊動物以餵食西瓜種子。 +Melon=西瓜 +A melon is a block which can be grown from melon stems, which in turn are grown from melon seeds. It can be harvested for melon slices.=西瓜是一種方塊,可以從西瓜莖中生長出來,而西瓜莖又是從西瓜種子中生長出來的。它可以收穫西瓜片。 +Premature Melon Stem=成長中的西瓜莖 +Melon stems grow on farmland in 8 stages. On hydrated farmland, the growth is a bit quicker. Mature melon stems are able to grow melons.=西瓜莖是在農田中陽光下生長的植物,分為8個階段。在水分充足的農田裡,它們生長得更快一些。成熟的西瓜莖能夠長出西瓜。 +Premature Melon Stem (Stage @1)=成長中的西瓜莖(第@1階段) +Mature Melon Stem=成熟的西瓜莖 +A mature melon stem attempts to grow a melon at one of its four adjacent blocks. A melon can only grow on top of farmland, dirt, or a grass block. When a melon is next to a melon stem, the melon stem immediately bends and connects to the melon. While connected, a melon stem can't grow another melon. As soon all melons around the stem have been removed, it loses the connection and is ready to grow another melon.=一個成熟的西瓜莖試圖在其四個相鄰的區塊中的一個長出西瓜。西瓜只能在農田、泥土或草塊上面生長。當西瓜挨著西瓜莖時,西瓜莖會立即彎曲並與該西瓜連接。在連接時,瓜莖不能再長出另一個西瓜。一旦西瓜莖周圍的所有西瓜都被移走,它就失去了連接,並準備好長出另一個西瓜。 +Melon Slice=西瓜片 +This is a food item which can be eaten.=這是一種可以吃的食物 +Premature Potato Plant=成長中的馬鈴薯 +Potato plants are plants which grow on farmland under sunlight in 8 stages, but only 4 stages can be visually told apart. On hydrated farmland, they grow a bit faster. They can be harvested at any time but will only yield a profit when mature.=馬鈴薯是在農田中陽光下生長的植物,分為8個階段,但只有4個階段可以從視覺上區​​分。在水分充足的農田裡,它們生長得更快一些。它們可以在任何時候收割,但只有在成熟時才會有收益。 +Premature Potato Plant (Stage @1)=成長中的馬鈴薯(第@1階段) +Mature Potato Plant=成熟的馬鈴薯 +Mature potato plants are ready to be harvested for potatoes. They won't grow any further.=成熟的馬鈴薯是一種隨時可以收穫馬鈴薯的植物。它不會再增長了。 +Potato=馬鈴薯 +Potatoes are food items which can be eaten, cooked in the furnace and planted. Pigs like potatoes.=馬鈴薯是可以食用、在熔爐中烹調和種植的食品。豬喜歡馬鈴薯。 +Hold it in your hand and rightclick to eat it. Place it on top of farmland to plant it. It grows in sunlight and grows faster on hydrated farmland. Rightclick an animal to feed it.=把它拿在手裡,點擊右鍵就可以吃掉它。把它放在農田上面來種植。它在陽光下生長,在有水分的農田上生長得更快。右鍵點擊一個動物來餵牠。 +Baked Potato=烤馬鈴薯 +Baked potatoes are food items which are more filling than the unbaked ones.=烤馬鈴薯是比未烤過的馬鈴薯更有營養的食物。 +Poisonous Potato=毒馬鈴薯 +This potato doesn't look too healthy. You can eat it to restore hunger points, but there's a 60% chance it will poison you briefly.=這個馬鈴薯看起來不是很健康。你可以吃它來恢復飢餓值,但有60%的可能性會讓你短暫中毒。 +Pumpkin Seeds=南瓜種子 +Grows into a pumpkin stem which in turn grows pumpkins. Chickens like pumpkin seeds.=長成可以長出南瓜的南瓜莖。雞喜歡南瓜種子。 +Place the pumpkin seeds on farmland (which can be created with a hoe) to plant a pumpkin stem. Pumpkin stems grow in sunlight and grow faster on hydrated farmland. When mature, the stem attempts to grow a pumpkin next to it. Rightclick an animal to feed it pumpkin seeds.=將南瓜種子放在農田上(可以用鋤頭打造)以種植南瓜莖。南瓜莖在陽光下生長,在水分充足的農田裡生長得更快。成熟後,莖會試圖在它旁邊長出一個南瓜。右鍵點擊動物以給它餵食南瓜種子。 +Premature Pumpkin Stem=成長中的南瓜莖 +Pumpkin stems grow on farmland in 8 stages. On hydrated farmland, the growth is a bit quicker. Mature pumpkin stems are able to grow pumpkins.=南瓜莖在農田上的生長分為8個階段,在水分充足的農田裡生長得更快。成熟的南瓜莖能夠長出南瓜。 +Premature Pumpkin Stem (Stage @1)=成長中的南瓜莖(第@1階段) +Mature Pumpkin Stem=成熟的南瓜莖 +A mature pumpkin stem attempts to grow a pumpkin at one of its four adjacent blocks. A pumpkin can only grow on top of farmland, dirt or a grass block. When a pumpkin is next to a pumpkin stem, the pumpkin stem immediately bends and connects to the pumpkin. A connected pumpkin stem can't grow another pumpkin. As soon all pumpkins around the stem have been removed, it loses the connection and is ready to grow another pumpkin.=一個成熟的南瓜莖試圖在其四個相鄰的區塊之一長出一個南瓜。南瓜只能生長在農田、泥土或草塊的上面。當南瓜挨著南瓜莖時,南瓜莖會立即彎曲並連接到該南瓜上。連接的南瓜莖不能再長出另一個南瓜。只要南瓜莖周圍的所有南瓜都被移走,它就失去了連接,可以再長出一個南瓜。 +Faceless Pumpkin=南瓜 +A faceless pumpkin is a decorative block. It can be carved with shears to obtain pumpkin seeds.=南瓜是一種裝飾方塊。它可以用剪刀進行雕刻,以獲得南瓜種子。 +Pumpkin=雕刻過的南瓜 +A pumpkin can be worn as a helmet. Pumpkins grow from pumpkin stems, which in turn grow from pumpkin seeds.=南瓜可以作為頭盔佩戴。南瓜由南瓜莖生長,而南瓜莖又由南瓜種子生長。 +Jack o'Lantern=南瓜燈 +A jack o'lantern is a traditional Halloween decoration made from a pumpkin. It glows brightly.=南瓜燈是由南瓜製成的傳統萬聖節裝飾。它發出明亮的光芒。 +Pumpkin Pie=南瓜派 +A pumpkin pie is a tasty food item which can be eaten.=南瓜派是可以吃的美味食品。 +Farmland=農田 +Farmland is used for farming, a necessary surface to plant crops. It is created when a hoe is used on dirt or a similar block. Plants are able to grow on farmland, but slowly. Farmland will become hydrated farmland (on which plants grow faster) when it rains or a water source is nearby. This block will turn back to dirt when a solid block appears above it or a piston arm extends above it.=農田用於耕作,是種植農作物的必要表面。它是在泥土類方塊上使用鋤頭時形成的。植物能夠在農田上生長,但速度很慢。當下雨或附近有水源時,農田會變成濕潤的耕地(植物在上面生長更快)。當上面出現固體方塊或活塞臂延伸到上面時,這個方塊會變回泥土。 +Hydrated Farmland=濕潤的耕地 +Hydrated farmland is used in farming, this is where you can plant and grow some plants. It is created when farmland is under rain or near water. Without water, this block will dry out eventually. This block will turn back to dirt when a solid block appears above it or a piston arm extends above it.=濕潤的耕地用於耕作,這是你可以種植和生長一些植物的地方。它是在農田被雨水沖刷或靠近水的情況下形成的。如果沒有水,這個方塊最終會變乾。當上面出現固體方塊或活塞臂延伸到上面時,這個方塊會變回泥土。 +Wheat Seeds=小麥種子 +Grows into a wheat plant. Chickens like wheat seeds.=長成小麥。雞喜歡小麥種子。 +Place the wheat seeds on farmland (which can be created with a hoe) to plant a wheat plant. They grow in sunlight and grow faster on hydrated farmland. Rightclick an animal to feed it wheat seeds.=將小麥種子放在農田上(可以用鋤頭製造)以種植一株小麥。它們在陽光下生長,在有水的農田裡生長得更快。右鍵點擊一個動物以給它餵食小麥種子。 +Premature Wheat Plant=成長中的小麥 +Premature wheat plants grow on farmland under sunlight in 8 stages. On hydrated farmland, they grow faster. They can be harvested at any time but will only yield a profit when mature.=小麥是在農田中陽光下生長的植物,分為8個階段。在水分充足的農田裡,它們生長得更快一些。它們可以在任何時候收割,但只有在成熟時才會有收益。 +Premature Wheat Plant (Stage @1)=成長中的小麥(第@1階段) +Mature Wheat Plant=成熟的小麥 +Mature wheat plants are ready to be harvested for wheat and wheat seeds. They won't grow any further.=成熟的小麥是一種隨時可以收穫小麥的植物。它不會再增長了。 +Wheat=小麥 +Wheat is used in crafting. Some animals like wheat.=小麥主要用於合成。有些動物喜歡小麥。 +Cookie=餅乾 +Bread=面包 +Hay Bale=乾草捆 +Hay bales are decorative blocks made from wheat.=乾草捆是用小麥製成的裝飾方塊。 +To carve a face into the pumpkin, use the shears on the side you want to carve.=要在南瓜上雕刻,請將剪刀放在你要雕刻的一側。 +Use the “Place” key on an animal to try to feed it wheat.=在動物身上使用「放置」鍵以嘗試給它餵食小麥。 +Grows on farmland=在農田上生長 +Turns block into farmland=把方塊變成農田 +60% chance of poisoning=有60%的可能性會讓你中毒 +Surface for crops=種植農作物的表面 +Can become wet=可以變溼 +Uses: @1=使用:@1 diff --git a/mods/ITEMS/mcl_farming/melon.lua b/mods/ITEMS/mcl_farming/melon.lua index b3e49a61f3..6bbc507ec9 100644 --- a/mods/ITEMS/mcl_farming/melon.lua +++ b/mods/ITEMS/mcl_farming/melon.lua @@ -7,7 +7,7 @@ minetest.register_craftitem("mcl_farming:melon_seeds", { _doc_items_longdesc = S("Grows into a melon stem which in turn grows melons. Chickens like melon seeds."), _doc_items_usagehelp = S("Place the melon seeds on farmland (which can be created with a hoe) to plant a melon stem. Melon stems grow in sunlight and grow faster on hydrated farmland. When mature, the stem will attempt to grow a melon at the side. Rightclick an animal to feed it melon seeds."), stack_max = 64, - groups = { craftitem=1 }, + groups = {craftitem = 1, compostability = 30}, inventory_image = "mcl_farming_melon_seeds.png", on_place = function(itemstack, placer, pointed_thing) return mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:melontige_1") @@ -21,7 +21,10 @@ local melon_base_def = { _doc_items_longdesc = S("A melon is a block which can be grown from melon stems, which in turn are grown from melon seeds. It can be harvested for melon slices."), stack_max = 64, tiles = {"farming_melon_top.png", "farming_melon_top.png", "farming_melon_side.png", "farming_melon_side.png", "farming_melon_side.png", "farming_melon_side.png"}, - groups = {handy=1,axey=1, plant=1,building_block=1,enderman_takable=1,dig_by_piston=1}, + groups = { + handy = 1, axey = 1, plant = 1, building_block = 1, dig_by_piston = 1, + enderman_takable = 1, compostability = 65 + }, drop = { max_items = 1, items = { @@ -134,7 +137,7 @@ minetest.register_craftitem("mcl_farming:melon_item", { inventory_image = "farming_melon.png", on_place = minetest.item_eat(2), on_secondary_use = minetest.item_eat(2), - groups = { food = 2, eatable = 2 }, + groups = {food = 2, eatable = 2, compostability = 50}, _mcl_saturation = 1.2, }) diff --git a/mods/ITEMS/mcl_farming/potatoes.lua b/mods/ITEMS/mcl_farming/potatoes.lua index 79cd13115e..04a971de88 100644 --- a/mods/ITEMS/mcl_farming/potatoes.lua +++ b/mods/ITEMS/mcl_farming/potatoes.lua @@ -91,7 +91,7 @@ minetest.register_craftitem("mcl_farming:potato_item", { _doc_items_longdesc = S("Potatoes are food items which can be eaten, cooked in the furnace and planted. Pigs like potatoes."), _doc_items_usagehelp = S("Hold it in your hand and rightclick to eat it. Place it on top of farmland to plant it. It grows in sunlight and grows faster on hydrated farmland. Rightclick an animal to feed it."), inventory_image = "farming_potato.png", - groups = { food = 2, eatable = 1 }, + groups = {food = 2, eatable = 1, compostability = 65}, _mcl_saturation = 0.6, stack_max = 64, on_secondary_use = minetest.item_eat(1), @@ -112,7 +112,7 @@ minetest.register_craftitem("mcl_farming:potato_item_baked", { inventory_image = "farming_potato_baked.png", on_place = minetest.item_eat(5), on_secondary_use = minetest.item_eat(5), - groups = { food = 2, eatable = 5 }, + groups = {food = 2, eatable = 5, compostability = 85}, _mcl_saturation = 6.0, }) diff --git a/mods/ITEMS/mcl_farming/pumpkin.lua b/mods/ITEMS/mcl_farming/pumpkin.lua index 1d9ca012cf..45ac2f6119 100644 --- a/mods/ITEMS/mcl_farming/pumpkin.lua +++ b/mods/ITEMS/mcl_farming/pumpkin.lua @@ -15,7 +15,7 @@ minetest.register_craftitem("mcl_farming:pumpkin_seeds", { _doc_items_usagehelp = S("Place the pumpkin seeds on farmland (which can be created with a hoe) to plant a pumpkin stem. Pumpkin stems grow in sunlight and grow faster on hydrated farmland. When mature, the stem attempts to grow a pumpkin next to it. Rightclick an animal to feed it pumpkin seeds."), stack_max = 64, inventory_image = "mcl_farming_pumpkin_seeds.png", - groups = { craftitem=1 }, + groups = {craftitem=1, compostability = 30}, on_place = function(itemstack, placer, pointed_thing) return mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:pumpkin_1") end @@ -99,13 +99,15 @@ local pumpkin_base_def = { stack_max = 64, paramtype2 = "facedir", tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png"}, - groups = {handy=1,axey=1, plant=1,building_block=1, dig_by_piston=1, enderman_takable=1}, + groups = { + handy = 1, axey = 1, plant = 1, building_block = 1, dig_by_piston = 1, + enderman_takable = 1, compostability = 65 + }, sounds = mcl_sounds.node_sound_wood_defaults(), on_rotate = on_rotate, _mcl_blast_resistance = 1, _mcl_hardness = 1, } -minetest.register_node("mcl_farming:pumpkin", pumpkin_base_def) local pumpkin_face_base_def = table.copy(pumpkin_base_def) pumpkin_face_base_def.description = S("Pumpkin") @@ -118,10 +120,17 @@ pumpkin_face_base_def.groups.armor_head=1 pumpkin_face_base_def.groups.non_combat_armor_head=1 pumpkin_face_base_def._mcl_armor_mob_range_factor = 0 pumpkin_face_base_def._mcl_armor_mob_range_mob = "mobs_mc:enderman" + pumpkin_face_base_def._mcl_armor_element = "head" pumpkin_face_base_def._mcl_armor_texture = "mcl_farming_pumpkin_face.png" pumpkin_face_base_def._mcl_armor_preview = "mcl_farming_pumpkin_face_preview.png" +pumpkin_face_base_def.on_construct = function(pos) + -- Attempt to spawn iron golem or snow golem + mobs_mc.tools.check_iron_golem_summon(pos) + mobs_mc.tools.check_snow_golem_summon(pos) +end + if minetest.get_modpath("mcl_armor") then local pumpkin_hud = {} local function add_pumpkin_hud(player) @@ -129,7 +138,7 @@ if minetest.get_modpath("mcl_armor") then pumpkin_blur = player:hud_add({ hud_elem_type = "image", position = {x = 0.5, y = 0.5}, - scale = {x = -100, y = -100}, + scale = {x = -101, y = -101}, text = "mcl_farming_pumpkin_hud.png", z_index = -200 }), @@ -175,12 +184,11 @@ end mcl_farming:add_plant("plant_pumpkin_stem", "mcl_farming:pumpkintige_unconnect", {"mcl_farming:pumpkin_1", "mcl_farming:pumpkin_2", "mcl_farming:pumpkin_3", "mcl_farming:pumpkin_4", "mcl_farming:pumpkin_5", "mcl_farming:pumpkin_6", "mcl_farming:pumpkin_7"}, 30, 5) -- Register actual pumpkin, connected stems and stem-to-pumpkin growth -mcl_farming:add_gourd("mcl_farming:pumpkintige_unconnect", "mcl_farming:pumpkintige_linked", "mcl_farming:pumpkintige_unconnect", stem_def, stem_drop, "mcl_farming:pumpkin_face", pumpkin_face_base_def, 30, 15, "mcl_farming_pumpkin_stem_connected.png^[colorize:#FFA800:127", -function(pos) - -- Attempt to spawn iron golem or snow golem - mobs_mc.tools.check_iron_golem_summon(pos) - mobs_mc.tools.check_snow_golem_summon(pos) -end) +mcl_farming:add_gourd("mcl_farming:pumpkintige_unconnect", "mcl_farming:pumpkintige_linked", "mcl_farming:pumpkintige_unconnect", stem_def, stem_drop, "mcl_farming:pumpkin", pumpkin_base_def, 30, 15, "mcl_farming_pumpkin_stem_connected.png^[colorize:#FFA800:127") + +-- Steal function to properly disconnect a carved pumpkin +pumpkin_face_base_def.after_destruct = minetest.registered_nodes["mcl_farming:pumpkin"].after_destruct +minetest.register_node("mcl_farming:pumpkin_face", pumpkin_face_base_def) -- Jack o'Lantern minetest.register_node("mcl_farming:pumpkin_face_light", { @@ -217,11 +225,6 @@ minetest.register_craft({ recipe = {{"mcl_farming:pumpkin"}} }) -minetest.register_craft({ - output = "mcl_farming:pumpkin_seeds 4", - recipe = {{"mcl_farming:pumpkin_face"}} -}) - minetest.register_craftitem("mcl_farming:pumpkin_pie", { description = S("Pumpkin Pie"), _doc_items_longdesc = S("A pumpkin pie is a tasty food item which can be eaten."), @@ -230,7 +233,7 @@ minetest.register_craftitem("mcl_farming:pumpkin_pie", { wield_image = "mcl_farming_pumpkin_pie.png", on_place = minetest.item_eat(8), on_secondary_use = minetest.item_eat(8), - groups = { food = 2, eatable = 8 }, + groups = {food = 2, eatable = 8, compostability = 100}, _mcl_saturation = 4.8, }) @@ -239,11 +242,6 @@ minetest.register_craft({ output = "mcl_farming:pumpkin_pie", recipe = {"mcl_farming:pumpkin", "mcl_core:sugar", "mcl_throwing:egg"}, }) -minetest.register_craft({ - type = "shapeless", - output = "mcl_farming:pumpkin_pie", - recipe = {"mcl_farming:pumpkin_face", "mcl_core:sugar", "mcl_throwing:egg"}, -}) if minetest.get_modpath("doc") then diff --git a/mods/ITEMS/mcl_farming/shared_functions.lua b/mods/ITEMS/mcl_farming/shared_functions.lua index e942415f50..7b9784503a 100644 --- a/mods/ITEMS/mcl_farming/shared_functions.lua +++ b/mods/ITEMS/mcl_farming/shared_functions.lua @@ -185,7 +185,7 @@ end - stem_def: Partial node definition of the fully-grown unconnected stem node. Many fields are already defined. You need to add `tiles` and `description` at minimum. Don't define on_construct without good reason - stem_drop: Drop probability table for all stem - gourd_itemstring: Desired itemstring of the full gourd node -- gourd_def: (almost) full definition of the gourd node. This function will add on_construct and after_dig_node to the definition for unconnecting any connected stems +- gourd_def: (almost) full definition of the gourd node. This function will add on_construct and after_destruct to the definition for unconnecting any connected stems - grow_interval: Will attempt to grow a gourd periodically at this interval in seconds - grow_chance: Chance of 1/grow_chance to grow a gourd next to the full unconnected stem after grow_interval has passed. Must be a natural number - connected_stem_texture: Texture of the connected stem @@ -235,8 +235,8 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s end -- Register gourd - if not gourd_def.after_dig_node then - function gourd_def.after_dig_node(blockpos, oldnode, oldmetadata, user) + if not gourd_def.after_destruct then + gourd_def.after_destruct = function(blockpos, oldnode) -- Disconnect any connected stems, turning them back to normal stems for n=1, #neighbors do local offset = neighbors[n] diff --git a/mods/ITEMS/mcl_farming/wheat.lua b/mods/ITEMS/mcl_farming/wheat.lua index da1b84b2d4..a254ed36c6 100644 --- a/mods/ITEMS/mcl_farming/wheat.lua +++ b/mods/ITEMS/mcl_farming/wheat.lua @@ -9,7 +9,7 @@ minetest.register_craftitem("mcl_farming:wheat_seeds", { Place the wheat seeds on farmland (which can be created with a hoe) to plant a wheat plant. They grow in sunlight and grow faster on hydrated farmland. Rightclick an animal to feed it wheat seeds. ]]), - groups = { craftitem=1 }, + groups = {craftitem = 1, compostability = 30}, inventory_image = "mcl_farming_wheat_seeds.png", on_place = function(itemstack, placer, pointed_thing) return mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:wheat_1") @@ -104,7 +104,7 @@ minetest.register_craftitem("mcl_farming:wheat_item", { _doc_items_longdesc = S("Wheat is used in crafting. Some animals like wheat."), _doc_items_usagehelp = S("Use the “Place” key on an animal to try to feed it wheat."), inventory_image = "farming_wheat_harvested.png", - groups = { craftitem = 1 }, + groups = {craftitem = 1, compostability = 65}, }) minetest.register_craft({ @@ -125,7 +125,7 @@ minetest.register_craftitem("mcl_farming:cookie", { description = S("Cookie"), _doc_items_longdesc = S("This is a food item which can be eaten."), inventory_image = "farming_cookie.png", - groups = {food=2, eatable=2}, + groups = {food = 2, eatable = 2, compostability = 85}, _mcl_saturation = 0.4, on_place = minetest.item_eat(2), on_secondary_use = minetest.item_eat(2), @@ -136,7 +136,7 @@ minetest.register_craftitem("mcl_farming:bread", { description = S("Bread"), _doc_items_longdesc = S("This is a food item which can be eaten."), inventory_image = "farming_bread.png", - groups = {food=2, eatable=5}, + groups = {food = 2, eatable = 5, compostability = 85}, _mcl_saturation = 6.0, on_place = minetest.item_eat(5), on_secondary_use = minetest.item_eat(5), @@ -156,8 +156,11 @@ minetest.register_node("mcl_farming:hay_block", { stack_max = 64, paramtype2 = "facedir", on_place = mcl_util.rotate_axis, - groups = {handy=1, hoey=1, flammable=2, fire_encouragement=60, - fire_flammability=20, building_block=1, fall_damage_add_percent=-80}, + groups = { + handy = 1, hoey = 1, building_block = 1, fall_damage_add_percent = -80, + flammable = 2, fire_encouragement = 60, fire_flammability = 20, + compostability = 85 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), on_rotate = on_rotate, _mcl_blast_resistance = 0.5, diff --git a/mods/ITEMS/mcl_fences/locale/mcl_fences.zh_TW.tr b/mods/ITEMS/mcl_fences/locale/mcl_fences.zh_TW.tr new file mode 100644 index 0000000000..5f360245c5 --- /dev/null +++ b/mods/ITEMS/mcl_fences/locale/mcl_fences.zh_TW.tr @@ -0,0 +1,18 @@ +# textdomain: mcl_fences +Fences are structures which block the way. Fences will connect to each other and solid blocks. They cannot be jumped over with a simple jump.=柵欄是阻擋道路的結構。柵欄會連接到彼此和固體方塊。它們不能用簡單的跳躍方式跳過去。 +Fence gates can be opened or closed and can't be jumped over. Fences will connect nicely to fence gates.=柵欄門可以打開或關閉,並且不能跳過。 柵欄將很好地連接到柵欄門。 +Right-click the fence gate to open or close it.=右鍵單擊柵欄門以將其打開或關閉。 +Oak Fence=橡木柵欄 +Oak Fence Gate=橡木柵欄門 +Spruce Fence=杉木柵欄 +Spruce Fence Gate=杉木柵欄門 +Birch Fence=樺木柵欄 +Birch Fence Gate=樺木柵欄門 +Jungle Fence=叢林木柵欄 +Jungle Fence Gate=叢林木柵欄門 +Dark Oak Fence=黑橡木柵欄 +Dark Oak Fence Gate=黑橡木柵欄門 +Acacia Fence=相思木柵欄 +Acacia Fence Gate=相思木柵欄門 +Nether Brick Fence=地獄磚柵欄 +Openable by players and redstone power=可被紅石或玩家打開 diff --git a/mods/ITEMS/mcl_fire/init.lua b/mods/ITEMS/mcl_fire/init.lua index 9f1337a5db..79b46a7013 100644 --- a/mods/ITEMS/mcl_fire/init.lua +++ b/mods/ITEMS/mcl_fire/init.lua @@ -24,29 +24,33 @@ local get_connected_players = minetest.get_connected_players local vector = vector local math = math --- inverse pyramid pattern above lava source, floor 1 of 2: -local lava_fire= -{ - { x =-1, y = 1, z =-1}, - { x =-1, y = 1, z = 0}, - { x =-1, y = 1, z = 1}, - { x = 0, y = 1, z =-1}, - { x = 0, y = 1, z = 0}, - { x = 0, y = 1, z = 1}, - { x = 1, y = 1, z =-1}, - { x = 1, y = 1, z = 0}, - { x = 1, y = 1, z = 1} -} -local alldirs= -{ - { x =-1, y = 0, z = 0}, - { x = 1, y = 0, z = 0}, - { x = 0, y =-1, z = 0}, - { x = 0, y = 1, z = 0}, - { x = 0, y = 0, z =-1}, - { x = 0, y = 0, z = 1} +local adjacents = { + { x =-1, y = 0, z = 0 }, + { x = 1, y = 0, z = 0 }, + { x = 0, y = 1, z = 0 }, + { x = 0, y =-1, z = 0 }, + { x = 0, y = 0, z =-1 }, + { x = 0, y = 0, z = 1 }, } +local function shuffle_table(t) + for i = #t, 1, -1 do + local r = math.random(i) + t[i], t[r] = t[r], t[i] + end +end +shuffle_table(adjacents) + +local function has_flammable(pos) + for k,v in pairs(adjacents) do + local p=vector.add(pos,v) + local n=minetest.get_node_or_nil(p) + if n and minetest.get_item_group(n.name, "flammable") ~= 0 then + return p + end + end +end + local smoke_pdef = { amount = 0.009, maxexptime = 4.0, @@ -86,10 +90,6 @@ else eternal_fire_help = S("Eternal fire is a damaging block. Eternal fire can be extinguished by punches and nearby water blocks. Other than (normal) fire, eternal fire does not get extinguished on its own and also continues to burn under rain. Punching eternal fire is safe, but it hurts if you stand inside.") end -local function fire_timer(pos) - minetest.get_node_timer(pos):start(math.random(3, 7)) -end - local function spawn_fire(pos, age) set_node(pos, {name="mcl_fire:fire", param2 = age}) minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z}) @@ -124,82 +124,6 @@ minetest.register_node("mcl_fire:fire", { minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true) end end, - on_timer = function(pos) - local node = get_node(pos) - -- Age is a number from 0 to 15 and is increased every timer step. - -- "old" fire is more likely to be extinguished - local age = node.param2 - local flammables = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"}) - local below = get_node({x=pos.x, y=pos.z-1, z=pos.z}) - local below_is_flammable = get_item_group(below.name, "flammable") > 0 - -- Extinguish fire - if (not fire_enabled) and (math.random(1,3) == 1) then - remove_node(pos) - return - end - if age == 15 and not below_is_flammable then - remove_node(pos) - return - elseif age > 3 and #flammables == 0 and not below_is_flammable and math.random(1,4) == 1 then - remove_node(pos) - return - end - local age_add = 1 - -- If fire spread is disabled, we have to skip the "destructive" code - if (not fire_enabled) then - if age + age_add <= 15 then - node.param2 = age + age_add - set_node(pos, node) - end - -- Restart timer - fire_timer(pos) - return - end - -- Spawn fire to nearby flammable nodes - local is_next_to_flammable = find_node_near(pos, 2, {"group:flammable"}) ~= nil - if is_next_to_flammable and math.random(1,2) == 1 then - -- The fire we spawn copies the age of this fire. - -- This prevents fire from spreading infinitely far as the fire fire dies off - -- quicker the further it has spreaded. - local age_next = math.min(15, age + math.random(0, 1)) - -- Select random type of fire spread - local burntype = math.random(1,2) - if burntype == 1 then - -- Spawn fire in air - local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"}) - while #nodes > 0 do - local r = math.random(1, #nodes) - if find_node_near(nodes[r], 1, {"group:flammable"}) then - spawn_fire(nodes[r], age_next) - break - else - table.remove(nodes, r) - end - end - else - -- Burn flammable block - local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"}) - if #nodes > 0 then - local r = math.random(1, #nodes) - local nn = get_node(nodes[r]).name - local ndef = minetest.registered_nodes[nn] - local fgroup = get_item_group(nn, "flammable") - if ndef and ndef._on_burn then - ndef._on_burn(nodes[r]) - elseif fgroup ~= -1 then - spawn_fire(nodes[r], age_next) - end - end - end - end - -- Regular age increase - if age + age_add <= 15 then - node.param2 = age + age_add - set_node(pos, node) - end - -- Restart timer - fire_timer(pos) - end, drop = "", sounds = {}, -- Turn into eternal fire on special blocks, light Nether portal (if possible), start burning timer @@ -216,7 +140,6 @@ minetest.register_node("mcl_fire:fire", { mcl_portals.light_nether_portal(pos) end - fire_timer(pos) mcl_particles.spawn_smoke(pos, "fire", smoke_pdef) end, on_destruct = function(pos) @@ -254,29 +177,8 @@ minetest.register_node("mcl_fire:eternal_fire", { minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true) end end, - on_timer = function(pos) - if fire_enabled then - local airs = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"}) - while #airs > 0 do - local r = math.random(1, #airs) - if find_node_near(airs[r], 1, {"group:flammable"}) then - local node = get_node(airs[r]) - local age = node.param2 - local age_next = math.min(15, age + math.random(0, 1)) - spawn_fire(airs[r], age_next) - break - else - table.remove(airs, r) - end - end - end - -- Restart timer - fire_timer(pos) - end, -- Start burning timer and light Nether portal (if possible) on_construct = function(pos) - fire_timer(pos) - if has_mcl_portals then --Calling directly minetest.get_modpath consumes 4x more compute time mcl_portals.light_nether_portal(pos) end @@ -400,6 +302,25 @@ if flame_sound then end) end +-- [...]a fire that is not adjacent to any flammable block does not spread, even to another flammable block within the normal range. +-- https://minecraft.fandom.com/wiki/Fire#Spread + +local function check_aircube(p1,p2) + local nds=minetest.find_nodes_in_area(p1,p2,{"air"}) + shuffle_table(nds) + for k,v in pairs(nds) do + if has_flammable(v) then return v end + end +end + +-- [...] a fire block can turn any air block that is adjacent to a flammable block into a fire block. This can happen at a distance of up to one block downward, one block sideways (including diagonals), and four blocks upward of the original fire block (not the block the fire is on/next to). +local function get_ignitable(pos) + return check_aircube(vector.add(pos,vector.new(-1,-1,-1)),vector.add(pos,vector.new(1,4,1))) +end +-- Fire spreads from a still lava block similarly: any air block one above and up to one block sideways (including diagonals) or two above and two blocks sideways (including diagonals) that is adjacent to a flammable block may be turned into a fire block. +local function get_ignitable_by_lava(pos) + return check_aircube(vector.add(pos,vector.new(-1,1,-1)),vector.add(pos,vector.new(1,1,1))) or check_aircube(vector.add(pos,vector.new(-2,2,-2)),vector.add(pos,vector.new(2,2,2))) or nil +end -- -- ABMs @@ -415,27 +336,13 @@ minetest.register_abm({ chance = 1, catch_up = false, action = function(pos, node, active_object_count, active_object_count_wider) - remove_node(pos) + minetest.remove_node(pos) minetest.sound_play("fire_extinguish_flame", {pos = pos, max_hear_distance = 16, gain = 0.15}, true) end, }) - -- Enable the following ABMs according to 'enable fire' setting - -local function has_flammable(pos) - local npos, node - for n, v in ipairs(alldirs) do - npos = vector.add(pos, v) - node = get_node_or_nil(npos) - if node and node.name and get_item_group(node.name, "flammable") ~= 0 then - return npos - end - end - return false -end - if not fire_enabled then -- Occasionally remove fire if fire disabled @@ -446,67 +353,88 @@ if not fire_enabled then interval = 10, chance = 10, catch_up = false, - action = remove_node, + action = minetest.remove_node, }) else -- Fire enabled - -- Set fire to air nodes + -- Fire Spread + minetest.register_abm({ + label = "Ignite flame", + nodenames ={"mcl_fire:fire","mcl_fire:eternal_fire"}, + interval = 7, + chance = 12, + catch_up = false, + action = function(pos) + local p = get_ignitable(pos) + if p then + spawn_fire(p) + shuffle_table(adjacents) + end + end + }) + + --lava fire spread minetest.register_abm({ label = "Ignite fire by lava", - nodenames = {"group:lava"}, - neighbors = {"air"}, + nodenames = {"mcl_core:lava_source","mcl_nether:nether_lava_source"}, + neighbors = {"air","group:flammable"}, interval = 7, chance = 3, catch_up = false, action = function(pos) - local i, dir, target, node, i2, f - i = math.random(1,9) - dir = lava_fire[i] - target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z} - node = get_node(target) - if not node or node.name ~= "air" then - i = ((i + math.random(0,7)) % 9) + 1 - dir = lava_fire[i] - target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z} - node = get_node(target) - if not node or node.name ~= "air" then - return - end - end - i2 = math.random(1,15) - if i2 < 10 then - local dir2, target2, node2 - dir2 = lava_fire[i2] - target2 = {x=target.x+dir2.x, y=target.y+dir2.y, z=target.z+dir2.z} - node2 = get_node(target2) - if node2 and node2.name == "air" then - f = has_flammable(target2) - if f then - minetest.after(1, spawn_fire, {x=target2.x, y=target2.y, z=target2.z}) - minetest.add_particle({ - pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}), - velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.7), z=f.z-pos.z}, - expirationtime=1, size=1.5, collisiondetection=false, - glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png" - }) - return - end - end - end - f = has_flammable(target) - if f then - minetest.after(1, spawn_fire, {x=target.x, y=target.y, z=target.z}) - minetest.add_particle({ - pos = vector.new({x=pos.x, y=pos.y+0.5, z=pos.z}), - velocity={x=f.x-pos.x, y=math.max(f.y-pos.y,0.25), z=f.z-pos.z}, - expirationtime=1, size=1, collisiondetection=false, - glow=minetest.LIGHT_MAX, texture="mcl_particles_flame.png" - }) + local p=get_ignitable_by_lava(pos) + if p then + spawn_fire(p) end end, }) + minetest.register_abm({ + label = "Remove fires", + nodenames = {"mcl_fire:fire"}, + interval = 7, + chance = 3, + catch_up = false, + action = function(pos) + local p=has_flammable(pos) + if p then + local n=minetest.get_node_or_nil(p) + if n and minetest.get_item_group(n.name, "flammable") < 1 then + minetest.remove_node(pos) + end + else + minetest.remove_node(pos) + end + end, + }) + + -- Remove flammable nodes around basic flame + minetest.register_abm({ + label = "Remove flammable nodes", + nodenames = {"mcl_fire:fire","mcl_fire:eternal_fire"}, + neighbors = {"group:flammable"}, + interval = 5, + chance = 18, + catch_up = false, + action = function(pos) + local p = has_flammable(pos) + if not p then + return + end + + local nn = minetest.get_node(p).name + local def = minetest.registered_nodes[nn] + local fgroup = minetest.get_item_group(nn, "flammable") + + if def and def._on_burn then + def._on_burn(p) + elseif fgroup ~= -1 then + spawn_fire(p) + minetest.check_for_falling(p) + end + end + }) end -- Set pointed_thing on (normal) fire. diff --git a/mods/ITEMS/mcl_fire/locale/mcl_fire.zh_TW.tr b/mods/ITEMS/mcl_fire/locale/mcl_fire.zh_TW.tr new file mode 100644 index 0000000000..74394be6da --- /dev/null +++ b/mods/ITEMS/mcl_fire/locale/mcl_fire.zh_TW.tr @@ -0,0 +1,19 @@ +# textdomain: mcl_fire +Fire Charge=火焰彈 +Fire charges are primarily projectiles which can be launched from dispensers, they will fly in a straight line and burst into a fire on impact. Alternatively, they can be used to ignite fires directly.=火焰彈主要是可以從發射器中發射的投射物,它們會沿直線飛行,並在撞擊時爆裂成火。另外,它們也可以用來直接點燃火焰。 +Put the fire charge into a dispenser and supply it with redstone power to launch it. To ignite a fire directly, simply place the fire charge on the ground, which uses it up.=將火藥放入發射器中,並為其提供紅石動力以發射火藥。要直接點火,只需將火藥放在地上,這樣就能用完。 +Flint and Steel=打火機 +Flint and steel is a tool to start fires and ignite blocks.=燧石和鋼是一種用來起火和點燃木塊的工具。 +Rightclick the surface of a block to attempt to light a fire in front of it or ignite the block. A few blocks have an unique reaction when ignited.=右鍵點擊方塊的表面,可以在它面前點火或點燃方塊。有幾種方塊在被點燃時會有獨特的反應。 +Fire is a damaging and destructive but short-lived kind of block. It will destroy and spread towards near flammable blocks, but fire will disappear when there is nothing to burn left. It will be extinguished by nearby water and rain. Fire can be destroyed safely by punching it, but it is hurtful if you stand directly in it. If a fire is started above netherrack or a magma block, it will immediately turn into an eternal fire.=火是一種具有傷害性和破壞性的方塊,但持續時間很短。它將破壞並向附近的易燃區塊蔓延,但當沒有什麼可燃燒的東西時,火就會消失。它將被附近的水和雨所熄滅。火可以通過打它來安全地摧毀,但如果你直接站在它裡面,它是有傷害的。如果火是在地獄石或岩漿塊上面點燃的,它將立即變成永恆的火。 +Fire is a damaging but non-destructive short-lived kind of block. It will disappear when there is no flammable block around. Fire does not destroy blocks, at least not in this world. It will be extinguished by nearby water and rain. Fire can be destroyed safely by punching it, but it is hurtful if you stand directly in it. If a fire is started above netherrack or a magma block, it will immediately turn into an eternal fire.=火是一種具有傷害性但無破壞性的短命方塊。當周圍沒有可燃方塊的時候,它就會消失。火不會破壞方塊,至少在這個世界上不會。它將被附近的水和雨所熄滅。火可以通過打它來安全地摧毀,但如果你直接站在它裡面,它是有傷害的。如果火是在地獄石或岩漿塊上面點燃的,它將立即變成永恆的火。 +Eternal fire is a damaging block that might create more fire. It will create fire around it when flammable blocks are nearby. Eternal fire can be extinguished by punches and nearby water blocks. Other than (normal) fire, eternal fire does not get extinguished on its own and also continues to burn under rain. Punching eternal fire is safe, but it hurts if you stand inside.=永恆之火是一個具有破壞性的方塊,可能會產生更多的火。當附近有易燃塊方塊時,它將在周圍產生火焰。永恆之火可以被拳頭和附近的水所熄滅。和(普通)火不同,永恆之火不會自行熄滅,而且在雨中也會繼續燃燒。擊打永恆之火是安全的,但如果你站在裡面就會受傷。 +Eternal fire is a damaging block. Eternal fire can be extinguished by punches and nearby water blocks. Other than (normal) fire, eternal fire does not get extinguished on its own and also continues to burn under rain. Punching eternal fire is safe, but it hurts if you stand inside.=永恆之火是一種破壞性的方塊。永恆之火可以被拳頭和附近的水塊所熄滅。和(普通)火不同,永恆之火不會自行熄滅,而且在雨中也會繼續燃燒。擊打永恆之火是安全的,但如果你站在裡面就會受傷。 +@1 has been cooked crisp.=@1 被燒死了 +@1 felt the burn.=@1 被燒死了 +@1 died in the flames.=@1 在火焰中昇天 +@1 died in a fire.=@1 在火焰中昇天 +Fire=火 +Eternal Fire=永恆之火 +Dispenser projectile=發射器投射物 +Starts fires and ignites blocks=點火和點燃方塊 diff --git a/mods/ITEMS/mcl_fishing/locale/mcl_fishing.zh_TW.tr b/mods/ITEMS/mcl_fishing/locale/mcl_fishing.zh_TW.tr new file mode 100644 index 0000000000..a0710f3abe --- /dev/null +++ b/mods/ITEMS/mcl_fishing/locale/mcl_fishing.zh_TW.tr @@ -0,0 +1,18 @@ +# textdomain: mcl_fishing +Fishing Rod=釣竿 +Fishing rods can be used to catch fish.=釣竿是用來取得魚的工具。 +Rightclick to launch the bobber. When it sinks right-click again to reel in an item. Who knows what you're going to catch?=右鍵單擊以啟動浮標。當它下沉時,再次點擊右鍵來釣起一個物品。誰知道你會抓到什麼? +Raw Fish=生鱈魚 +Raw fish is obtained by fishing and is a food item which can be eaten safely. Cooking it improves its nutritional value.=生鱈魚是通過捕魚獲得的,是一種可以安全食用的食品。烹飪可以提高其營養價值。 +Cooked Fish=熟鱈魚 +Mmh, fish! This is a healthy food item.=嗯,魚! 這是一種健康的食品。 +Raw Salmon=生鮭魚 +Raw salmon is obtained by fishing and is a food item which can be eaten safely. Cooking it improves its nutritional value.=生鮭魚是通過捕魚獲得的,是一種可以安全食用的食品。烹飪可以提高其營養價值。 +Cooked Salmon=熟鮭魚 +This is a healthy food item which can be eaten.=這是一種健康的可食用食品。 +Clownfish=熱帶魚 +Clownfish may be obtained by fishing (and luck) and is a food item which can be eaten safely.=熱帶魚可以通過釣魚(和運氣)獲得,是一種可以安全食用的食物。 +Pufferfish=河豚 +Pufferfish are a common species of fish and can be obtained by fishing. They can technically be eaten, but they are very bad for humans. Eating a pufferfish only restores 1 hunger point and will poison you very badly (which drains your health non-fatally) and causes serious food poisoning (which increases your hunger).=河豚是一種常見的魚種,可以通過釣魚獲得。嚴格來說,它們可以被吃掉,但對人類非常不利。吃了河豚只能恢復1點飢餓感,而且會讓你中毒非常嚴重(非致命性地消耗你的健康),並導致嚴重的食物中毒(會增加你的飢餓感)。 +Catches fish in water=在水中取得魚 +Very poisonous=有劇毒 diff --git a/mods/ITEMS/mcl_flowerpots/locale/mcl_flowerpots.zh_TW.tr b/mods/ITEMS/mcl_flowerpots/locale/mcl_flowerpots.zh_TW.tr new file mode 100644 index 0000000000..78ee96e8a3 --- /dev/null +++ b/mods/ITEMS/mcl_flowerpots/locale/mcl_flowerpots.zh_TW.tr @@ -0,0 +1,26 @@ +# textdomain: mcl_flowerpots +Dandelion Flower Pot=蒲公英盆栽 +Poppy Flower Pot=罌粟盆栽 +Blue Orchid Flower Pot=藍色蝴蝶蘭盆栽 +Allium Flower Pot=紫紅球花盆栽 +Azure Bluet Flower Pot=雛草盆栽 +Red Tulip Flower Pot=紅色鬱金香盆栽 +Pink Tulip Flower Pot=粉色鬱金香盆栽 +White Tulip Flower Pot=白色鬱金香盆栽 +Orange Tulip Flower Pot=橙色鬱金香盆栽 +Oxeye Daisy Flower Pot=雛菊盆栽 +Brown Mushroom Flower Pot=棕色蘑菇盆栽 +Red Mushroom Flower Pot=紅色蘑菇盆栽 +Oak Sapling Flower Pot=橡木樹苗盆栽 +Acacia Sapling Flower Pot=相思木樹苗盆栽 +Jungle Sapling Flower Pot=叢林木樹苗盆栽 +Dark Oak Sapling Flower Pot=黑橡木樹苗盆栽 +Spruce Sapling Flower Pot=杉木樹苗盆栽 +Birch Sapling Flower Pot=樺木樹苗盆栽 +Dead Bush Flower Pot=枯灌木盆栽 +Fern Flower Pot=蕨盆栽 +Cactus Flower Pot=仙人掌盆栽 +Flower Pot=花盆 +Flower pots are decorative blocks in which flowers and other small plants can be placed.=花盆是可以放置鮮花和其他小植物的裝飾方塊。 +Just place a plant on the flower pot. Flower pots can hold small flowers (not higher than 1 block), saplings, ferns, dead bushes, mushrooms and cacti. Rightclick a potted plant to retrieve the plant.=只需在花盆上放置一株植物即可。花盆可以放置小花(不高於1格)、樹苗、蕨類植物、枯樹叢、蘑菇和仙人掌。右鍵點擊盆栽即可取回植物。 +Can hold a small flower or plant=放置鮮花和其他小植物 diff --git a/mods/ITEMS/mcl_flowers/init.lua b/mods/ITEMS/mcl_flowers/init.lua index 14e0df5cb4..d5112a36dd 100644 --- a/mods/ITEMS/mcl_flowers/init.lua +++ b/mods/ITEMS/mcl_flowers/init.lua @@ -80,7 +80,13 @@ function mcl_flowers.register_simple_flower(name, def) walkable = false, stack_max = 64, drop = def.drop, - groups = {dig_immediate=3,flammable=2,fire_encouragement=60,fire_flammability=100,plant=1,flower=1,place_flowerlike=1,non_mycelium_plant=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1,enderman_takable=1,deco_block=1}, + groups = { + attached_node = 1, deco_block = 1, dig_by_piston = 1, dig_immediate = 3, + dig_by_water = 1, destroy_by_lava_flow = 1, enderman_takable = 1, + plant = 1, flower = 1, place_flowerlike = 1, non_mycelium_plant = 1, + flammable = 2, fire_encouragement = 60, fire_flammability = 100, + compostability = 65 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), node_placement_prediction = "", on_place = on_place_flower, @@ -143,7 +149,12 @@ local def_tallgrass = { walkable = false, buildable_to = true, is_ground_content = true, - groups = {handy=1,shearsy=1, flammable=3,fire_encouragement=60,fire_flammability=100,attached_node=1,plant=1,place_flowerlike=2,non_mycelium_plant=1,dig_by_water=1,destroy_by_lava_flow=1,deco_block=1}, + groups = { + handy = 1, shearsy = 1, attached_node = 1, deco_block = 1, + plant = 1, place_flowerlike = 2, non_mycelium_plant = 1, + flammable = 3, fire_encouragement = 60, fire_flammability = 100, + dig_by_water = 1, destroy_by_lava_flow = 1, compostability = 30 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), drop = wheat_seed_drop, _mcl_shears_drop = true, @@ -167,6 +178,7 @@ def_fern.selection_box = { type = "fixed", fixed = { -6/16, -0.5, -6/16, 6/16, 5/16, 6/16 }, } +def_fern.groups.compostability = 65 minetest.register_node("mcl_flowers:fern", def_fern) @@ -187,7 +199,15 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im is_flower = true end - local bottom_groups = {flammable=2, fire_encouragement=60, fire_flammability=100, non_mycelium_plant=1, attached_node=1, dig_by_water=1, destroy_by_lava_flow=1, dig_by_piston=1, plant=1, double_plant=1, deco_block=1} + local bottom_groups = { + attached_node = 1, deco_block = 1, + dig_by_water = 1, destroy_by_lava_flow = 1, dig_by_piston = 1, + flammable = 2, fire_encouragement = 60, fire_flammability = 100, + plant = 1, double_plant = 1, non_mycelium_plant = 1, compostability = 65 + } + if name == "double_grass" then + bottom_groups.compostability = 50 + end if is_flower then bottom_groups.flower = 1 bottom_groups.place_flowerlike = 1 @@ -410,7 +430,10 @@ minetest.register_node("mcl_flowers:waterlily", { liquids_pointable = true, walkable = true, sunlight_propagates = true, - groups = {dig_immediate = 3, plant=1, dig_by_water = 1,destroy_by_lava_flow=1, dig_by_piston = 1, deco_block=1, dig_by_boat=1}, + groups = { + deco_block = 1, plant = 1, compostability = 65, destroy_by_lava_flow = 1, + dig_immediate = 3, dig_by_water = 1, dig_by_piston = 1, dig_by_boat = 1, + }, sounds = mcl_sounds.node_sound_leaves_defaults(), node_placement_prediction = "", node_box = { diff --git a/mods/ITEMS/mcl_flowers/locale/mcl_flowers.zh_TW.tr b/mods/ITEMS/mcl_flowers/locale/mcl_flowers.zh_TW.tr new file mode 100644 index 0000000000..b8fb0cbe4c --- /dev/null +++ b/mods/ITEMS/mcl_flowers/locale/mcl_flowers.zh_TW.tr @@ -0,0 +1,32 @@ +# textdomain: mcl_flowers +This is a small flower. Small flowers are mainly used for dye production and can also be potted.= +It can only be placed on a block on which it would also survive.= +Poppy=罌粟 +Dandelion=蒲公英 +Oxeye Daisy=雛菊 +Orange Tulip=橙色鬱金香 +Pink Tulip=粉紅色鬱金香 +Red Tulip=紅色鬱金香 +White Tulip=白色鬱金香 +Allium=紫紅球花 +Azure Bluet=藍花美耳草 +Blue Orchid=藍色蝴蝶蘭 +Tall Grass=草 +Tall grass is a small plant which often occurs on the surface of grasslands. It can be harvested for wheat seeds. By using bone meal, tall grass can be turned into double tallgrass which is two blocks high.=草是一種小植物,經常出現在草原的表面。它可以收穫小麥的種子。通過使用骨粉,高草可以變成兩塊高的芒草。 +Fern=蕨 +Ferns are small plants which occur naturally in jungles and taigas. They can be harvested for wheat seeds. By using bone meal, a fern can be turned into a large fern which is two blocks high.=蕨是自然存在於叢林和台地的小型植物。它們可以被收割為小麥種子。通過使用骨粉,可以把蕨變成兩塊高的高蕨。 +(Top Part)=(上部分) +Peony=牡丹花 +A peony is a large plant which occupies two blocks. It is mainly used in dye production.=牡丹花是一種大型植物,共有兩格高。它主要用於染料生產。 +Rose Bush=玫瑰叢 +A rose bush is a large plant which occupies two blocks. It is safe to touch it. Rose bushes are mainly used in dye production.=玫瑰叢是一種大型植物,共有兩格高。觸摸它是安全的。玫瑰叢主要用於染料生產。 +Lilac=紫丁香 +A lilac is a large plant which occupies two blocks. It is mainly used in dye production.=紫丁香是一種大型植物,共有兩格高。它主要用於染料生產。 +Sunflower=向日葵 +A sunflower is a large plant which occupies two blocks. It is mainly used in dye production.=向日葵是一種大型植物,共有兩格高。它主要用於染料生產。 +Double tallgrass a variant of tall grass and occupies two blocks. It can be harvested for wheat seeds.=芒草是草的兩格高變種。可以收割小麥種子。 +Large fern is a variant of fern and occupies two blocks. It can be harvested for wheat seeds.=高蕨是蕨的兩格高變種。可以收割小麥種子。 +Double Tallgrass=芒草 +Large Fern=高蕨 +Lily Pad=荷葉 +A lily pad is a flat plant block which can be walked on. They can be placed on water sources, ice and frosted ice.=荷葉是一種平坦的植物方塊,可以在上面行走。它們可以放在水源、冰面和結霜的冰面上。 diff --git a/mods/ITEMS/mcl_furnaces/locale/mcl_furnaces.zh_TW.tr b/mods/ITEMS/mcl_furnaces/locale/mcl_furnaces.zh_TW.tr new file mode 100644 index 0000000000..447fb835c4 --- /dev/null +++ b/mods/ITEMS/mcl_furnaces/locale/mcl_furnaces.zh_TW.tr @@ -0,0 +1,9 @@ +# textdomain: mcl_furnaces +Furnace=熔爐 +Furnaces cook or smelt several items, using a furnace fuel, into something else.=熔爐用一種爐子燃料將幾種物品烹飪或熔煉成其他東西。 +Use the furnace to open the furnace menu. Place a furnace fuel in the lower slot and the source material in the upper slot. The furnace will slowly use its fuel to smelt the item. The result will be placed into the output slot at the right side.=使用熔爐打開爐子菜單。將熔爐燃料放在下槽,將源材料放在上槽。熔爐將慢慢地使用它的燃料來熔煉或烹飪物品。其結果將被放入右側的輸出槽中。 +Use the recipe book to see what you can smelt, what you can use as fuel and how long it will burn.=使用合成教學來查看您可以冶煉的東西,可以用作燃料的物品以及可燃燒時間。 +Burning Furnace=燃燒的熔爐 +Recipe book=合成教學 +Inventory=物品欄 +Uses fuel to smelt or cook items=使用燃料來熔煉或烹飪物品 diff --git a/mods/ITEMS/mcl_heads/locale/mcl_heads.zh_TW.tr b/mods/ITEMS/mcl_heads/locale/mcl_heads.zh_TW.tr new file mode 100644 index 0000000000..3164d3831c --- /dev/null +++ b/mods/ITEMS/mcl_heads/locale/mcl_heads.zh_TW.tr @@ -0,0 +1,11 @@ +# textdomain: mcl_heads +Zombie Head=殭屍頭 +A zombie head is a small decorative block which resembles the head of a zombie. It can also be worn as a helmet, which reduces the detection range of zombies by 50%.=殭屍頭是一個小的裝飾方塊,類似於殭屍的頭。它也可以作為頭盔佩戴,可以使殭屍的探測範圍減少50%。 +Creeper Head=苦力怕頭 +A creeper head is a small decorative block which resembles the head of a creeper. It can also be worn as a helmet, which reduces the detection range of creepers by 50%.=苦力怕頭是一個小的裝飾方塊,類似於苦力怕的頭。它也可以作為頭盔佩戴,可以使苦力怕的探測範圍減少50%。 +Human Head=玩家頭 +A human head is a small decorative block which resembles the head of a human (i.e. a player character). It can also be worn as a helmet for fun, but does not offer any protection.=玩家頭是一個小的裝飾塊,類似於玩家的頭部。它也可以作為頭盔戴著玩,但不提供任何保護。 +Skeleton Skull=骷髏頭 +A skeleton skull is a small decorative block which resembles the skull of a skeleton. It can also be worn as a helmet, which reduces the detection range of skeletons by 50%.=骷髏頭是一個小的裝飾方塊,類似於骷髏的頭。它也可以作為頭盔佩戴,可以使骷髏的探測範圍減少50%。 +Wither Skeleton Skull=凋零骷髏頭 +A wither skeleton skull is a small decorative block which resembles the skull of a wither skeleton. It can also be worn as a helmet for fun, but does not offer any protection.=凋零骷髏頭是一個小的裝飾塊,類似於凋零骷髏的頭部。它也可以作為頭盔戴著玩,但不提供任何保護。 diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index 36a21ad957..87831490f7 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -343,7 +343,7 @@ minetest.register_abm({ local abovenode = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}) if not minetest.registered_items[abovenode.name] then return end -- Don't bother checking item enties if node above is a container (should save some CPU) - if minetest.registered_items[abovenode.name].groups.container then + if minetest.get_item_group(abovenode.name, "container") ~= 0 then return end local meta = minetest.get_meta(pos) @@ -397,7 +397,7 @@ minetest.register_abm({ -- Suck an item from the container above into the hopper local upnode = minetest.get_node(uppos) if not minetest.registered_nodes[upnode.name] then return end - local g = minetest.registered_nodes[upnode.name].groups.container + local g = minetest.get_item_group(upnode.name, "container") local sucked = mcl_util.move_item_container(uppos, pos) -- Also suck in non-fuel items from furnace fuel slot @@ -442,7 +442,7 @@ minetest.register_abm({ -- Suck an item from the container above into the hopper local abovenode = minetest.get_node(above) if not minetest.registered_nodes[abovenode.name] then return end - local g = minetest.registered_nodes[abovenode.name].groups.container + local g = minetest.get_item_group(abovenode.name, "container") local sucked = mcl_util.move_item_container(above, pos) -- Also suck in non-fuel items from furnace fuel slot @@ -454,7 +454,7 @@ minetest.register_abm({ end -- Move an item from the hopper into the container to which the hopper points to - local g = minetest.registered_nodes[frontnode.name].groups.container + local g = minetest.get_item_group(frontnode.name, "container") if g == 2 or g == 3 or g == 5 or g == 6 then mcl_util.move_item_container(pos, front) elseif g == 4 then diff --git a/mods/ITEMS/mcl_hoppers/locale/mcl_hoppers.zh_TW.tr b/mods/ITEMS/mcl_hoppers/locale/mcl_hoppers.zh_TW.tr new file mode 100644 index 0000000000..f3e8be8abb --- /dev/null +++ b/mods/ITEMS/mcl_hoppers/locale/mcl_hoppers.zh_TW.tr @@ -0,0 +1,16 @@ +# textdomain: mcl_hoppers +Hopper=漏斗 +Hoppers are containers with 5 inventory slots. They collect dropped items from above, take items from a container above and attempt to put its items it into an adjacent container. Hoppers can go either downwards or sideways. Hoppers interact with chests, droppers, dispensers, shulker boxes, furnaces and hoppers.=漏斗是有5個物品槽的容器。它們從上面收集掉落的物品,從上面的容器中取出物品,並試圖把它的物品放到鄰近的容器中。漏斗可以向下或向側面移動。漏斗與箱子、投擲器、發射器、界伏盒、熔爐和漏斗相互作用。 +Hoppers interact with containers the following way:=漏斗會對容器做以下事情: +• Furnaces: Hoppers from above will put items into the source slot. Hoppers from below take items from the output slot. They also take items from the fuel slot when they can't be used as a fuel. Sideway hoppers that point to the furnace put items into the fuel slot=• 熔爐:從上面的漏斗會將物品放入源料槽。下方的漏斗從輸出槽中取出物品。當物品不能作為燃料使用時,它們也會從燃料槽中取出物品。指向熔爐的側邊漏斗將物品放入燃料槽。 +• Ender chests: No interaction.=• 終界箱:不會有任何動作。 +• Other containers: Normal interaction.=• 其他容器:正常動作。 +Hoppers can be disabled when supplied with redstone power. Disabled hoppers don't move items.=供給紅石電源時,可以禁用漏斗。被禁用的漏斗不會移動物品。 +To place a hopper vertically, place it on the floor or a ceiling. To place it sideways, place it at the side of a block. Use the hopper to access its inventory.=要垂直放置漏斗,可將其放在地板或天花板上。要想把它放在側面,就把它放在一個方塊的側面。使用漏斗來訪問其庫存。 +Disabled Hopper=被禁用的漏斗 +Side Hopper=側面漏斗 +Disabled Side Hopper=被禁用的側面漏斗 +Inventory=物品欄 +5 inventory slots=5個物品槽 +Collects items from above, moves items to container below=從上面收集物品,並把物品放到下面的容器中 +Can be disabled with redstone power=可被紅石電源禁用 diff --git a/mods/ITEMS/mcl_itemframes/locale/mcl_itemframes.zh_TW.tr b/mods/ITEMS/mcl_itemframes/locale/mcl_itemframes.zh_TW.tr new file mode 100644 index 0000000000..d45c14d74b --- /dev/null +++ b/mods/ITEMS/mcl_itemframes/locale/mcl_itemframes.zh_TW.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_itemframes +Item Frame=物品展示框 +Item frames are decorative blocks in which items can be placed.=物品展示框是可以展示物品的裝飾方塊。 +Just place any item on the item frame. Use the item frame again to retrieve the item.=只需將物品放在物品展示框上即可。再次使用物品展示框來提出物品。 +Can hold an item=可以展示物品 diff --git a/mods/ITEMS/mcl_jukebox/locale/mcl_jukebox.zh_TW.tr b/mods/ITEMS/mcl_jukebox/locale/mcl_jukebox.zh_TW.tr new file mode 100644 index 0000000000..ba48ae9de7 --- /dev/null +++ b/mods/ITEMS/mcl_jukebox/locale/mcl_jukebox.zh_TW.tr @@ -0,0 +1,10 @@ +# textdomain: mcl_jukebox +Music Disc=唱片 +A music disc holds a single music track which can be used in a jukebox to play music.=一張唱片可容納單一的音樂曲目,可在唱片機中用於播放音樂。 +Place a music disc into an empty jukebox to play the music. Use the jukebox again to retrieve the music disc. The music can only be heard by you, not by other players.=將唱片放入空的唱片機中播放音樂。再次使用唱片機取出唱片。音樂只能由您自己聽,而不能由其他玩家聽。 +@1—@2= +Jukebox=唱片機 +Jukeboxes play music when they're supplied with a music disc.=唱片機在提供唱片的情况下播放音樂。 +Place a music disc into an empty jukebox to insert the music disc and play music. If the jukebox already has a music disc, you will retrieve this music disc first. The music can only be heard by you, not by other players.=將音樂光盤放入空的點唱機,插入音樂光盤並播放音樂。如果點唱機已經有一張音樂光盤,你要先取回這張音樂光盤。音樂只能被你聽到,不能被其他玩家聽到。 +Now playing: @1—@2=正在播放:@1—@2 +Uses music discs to play music=使用唱片播放音樂 diff --git a/mods/ITEMS/mcl_lanterns/init.lua b/mods/ITEMS/mcl_lanterns/init.lua new file mode 100644 index 0000000000..65faa5e8c6 --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/init.lua @@ -0,0 +1,284 @@ +local S = minetest.get_translator("mcl_lanterns") +local modpath = minetest.get_modpath("mcl_lanterns") + +mcl_lanterns = {} + +--[[ +TODO: +- add lantern specific sounds +- remove the hack arround walmounted nodes +]] + +local allowed_non_solid_nodes_floor = { + "mcl_core:ice", + "mcl_nether:soul_sand", + "mcl_mobspawners:spawner", + "mcl_core:barrier", + "mcl_end:chorus_flower", + "mcl_end:chorus_flower_dead", + "mcl_end:end_rod", + "mcl_end:dragon_egg", + "mcl_portals:end_portal_frame_eye", + "mcl_lanterns:chain" +} + +local allowed_non_solid_groups_floor = {"anvil", "wall", "glass", "fence", "fence_gate", "pane"} + +local allowed_non_solid_nodes_ceiling = { + "mcl_core:ice", + "mcl_nether:soul_sand", + "mcl_mobspawners:spawner", + "mcl_core:barrier", + "mcl_end:chorus_flower", + "mcl_end:chorus_flower_dead", + "mcl_end:end_rod", + "mcl_core:grass_path", + "mcl_lanterns:chain" +} + +local allowed_non_solid_groups_ceiling = {"anvil", "wall", "glass", "fence", "fence_gate", "soil", "pane", "end_portal_frame"} + +local function check_placement(node, wdir) + local nn = node.name + local def = minetest.registered_nodes[nn] + + if not def then + return false + else + --wdir: + --0: ceiling + --1: floor + if wdir == 0 then + if def.groups.solid or def.groups.opaque then + return true + else + for _,i in ipairs(allowed_non_solid_nodes_ceiling) do + if nn == i then + return true + end + end + for _,j in ipairs(allowed_non_solid_groups_ceiling) do + if def.groups[j] then + return true + end + end + return false + end + else --assuming wdir == 1 + if def.groups.solid or def.groups.opaque then + return true + else + for _,i in ipairs(allowed_non_solid_nodes_floor) do + if nn == i then + return true + end + end + for _,j in ipairs(allowed_non_solid_groups_floor) do + if def.groups[j] then + return true + end + end + return false + end + end + end +end + +function mcl_lanterns.register_lantern(name, def) + local itemstring_floor = "mcl_lanterns:"..name.."_floor" + local itemstring_ceiling = "mcl_lanterns:"..name.."_ceiling" + + local sounds = mcl_sounds.node_sound_metal_defaults() + + minetest.register_node(itemstring_floor, { + description = def.description, + _doc_items_longdesc = def.longdesc, + drawtype = "mesh", + mesh = "mcl_lanterns_lantern_floor.obj", + inventory_image = def.texture_inv, + wield_image = def.texture_inv, + tiles = { + { + name = def.texture, + animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 3.3} + } + }, + use_texture_alpha = "clip", + paramtype = "light", + paramtype2 = "wallmounted", + place_param2 = 1, + node_placement_prediction = "", + sunlight_propagates = true, + light_source = def.light_level, + groups = {pickaxey = 1, attached_node = 1, deco_block = 1, lantern = 1}, + selection_box = { + type = "fixed", + fixed = { + {-0.1875, -0.5, -0.1875, 0.1875, -0.0625, 0.1875}, + {-0.125, -0.0625, -0.125, 0.125, 0.0625, 0.125}, + {-0.0625, -0.5, -0.0625, 0.0625, 0.1875, 0.0625}, + }, + }, + collision_box = { + type = "fixed", + fixed = { + {-0.1875, -0.5, -0.1875, 0.1875, -0.0625, 0.1875}, + {-0.125, -0.0625, -0.125, 0.125, 0.0625, 0.125}, + {-0.0625, -0.5, -0.0625, 0.0625, 0.1875, 0.0625}, + }, + }, + sounds = sounds, + on_place = function(itemstack, placer, pointed_thing) + local new_stack = mcl_util.call_on_rightclick(itemstack, placer, pointed_thing) + if new_stack then + return new_stack + end + + local under = pointed_thing.under + local above = pointed_thing.above + local node = minetest.get_node(under) + + local wdir = minetest.dir_to_wallmounted(vector.subtract(under, above)) + local fakestack = itemstack + + if check_placement(node, wdir) == false then + return itemstack + end + + if wdir == 0 then + fakestack:set_name(itemstring_ceiling) + elseif wdir == 1 then + fakestack:set_name(itemstring_floor) + end + + local success + itemstack, success = minetest.item_place(fakestack, placer, pointed_thing, wdir) + itemstack:set_name(itemstring_floor) + + if success then + minetest.sound_play(sounds.place, {pos = under, gain = 1}, true) + end + + return itemstack + end, + on_rotate = false, + _mcl_hardness = 3.5, + _mcl_blast_resistance = 3.5, + }) + + minetest.register_node(itemstring_ceiling, { + description = def.description, + _doc_items_create_entry = false, + drawtype = "mesh", + mesh = "mcl_lanterns_lantern_ceiling.obj", + tiles = { + { + name = def.texture, + animation = {type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 3.3} + } + }, + use_texture_alpha = "clip", + paramtype = "light", + paramtype2 = "wallmounted", + place_param2 = 0, + node_placement_prediction = "", + sunlight_propagates = true, + light_source = def.light_level, + groups = {pickaxey = 1, attached_node = 1, deco_block = 1, lantern = 1, not_in_creative_inventory = 1}, + drop = itemstring_floor, + selection_box = { + type = "fixed", + fixed = { + {-0.1875, 0, -0.1875, 0.1875, 0.4375, 0.1875}, + {-0.125, -0.125, -0.125, 0.125, 0, 0.125}, + {-0.0625, -0.5, -0.0625, 0.0625, -0.125, 0.0625}, + }, + }, + collision_box = { + type = "fixed", + fixed = { + {-0.1875, 0, -0.1875, 0.1875, 0.4375, 0.1875}, + {-0.125, -0.125, -0.125, 0.125, 0, 0.125}, + {-0.0625, -0.5, -0.0625, 0.0625, -0.125, 0.0625}, + }, + }, + sounds = sounds, + on_rotate = false, + _mcl_hardness = 3.5, + _mcl_blast_resistance = 3.5, + }) +end + +minetest.register_node("mcl_lanterns:chain", { + description = S("Chain"), + _doc_items_longdesc = S("Chains are metallic decoration blocks."), + inventory_image = "mcl_lanterns_chain_inv.png", + tiles = {"mcl_lanterns_chain.png"}, + drawtype = "mesh", + paramtype = "light", + paramtype2 = "facedir", + use_texture_alpha = "clip", + mesh = "mcl_lanterns_chain.obj", + is_ground_content = false, + sunlight_propagates = true, + collision_box = { + type = "fixed", + fixed = { + {-0.0625, -0.5, -0.0625, 0.0625, 0.5, 0.0625}, + } + }, + selection_box = { + type = "fixed", + fixed = { + {-0.0625, -0.5, -0.0625, 0.0625, 0.5, 0.0625}, + } + }, + groups = {pickaxey = 1, deco_block = 1}, + sounds = mcl_sounds.node_sound_metal_defaults(), + on_place = function(itemstack, placer, pointed_thing) + if pointed_thing.type ~= "node" then + return itemstack + end + + local p0 = pointed_thing.under + local p1 = pointed_thing.above + local param2 = 0 + + local placer_pos = placer:get_pos() + if placer_pos then + local dir = { + x = p1.x - placer_pos.x, + y = p1.y - placer_pos.y, + z = p1.z - placer_pos.z + } + param2 = minetest.dir_to_facedir(dir) + end + + if p0.y - 1 == p1.y then + param2 = 20 + elseif p0.x - 1 == p1.x then + param2 = 16 + elseif p0.x + 1 == p1.x then + param2 = 12 + elseif p0.z - 1 == p1.z then + param2 = 8 + elseif p0.z + 1 == p1.z then + param2 = 4 + end + + return minetest.item_place(itemstack, placer, pointed_thing, param2) + end, + _mcl_blast_resistance = 6, + _mcl_hardness = 5, +}) + +minetest.register_craft({ + output = "mcl_lanterns:chain", + recipe = { + {"mcl_core:iron_nugget"}, + {"mcl_core:iron_ingot"}, + {"mcl_core:iron_nugget"}, + }, +}) + +dofile(modpath.."/register.lua") \ No newline at end of file diff --git a/mods/ITEMS/mcl_lanterns/locale/mcl_lanterns.fr.tr b/mods/ITEMS/mcl_lanterns/locale/mcl_lanterns.fr.tr new file mode 100644 index 0000000000..b28822b75b --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/locale/mcl_lanterns.fr.tr @@ -0,0 +1,6 @@ +# textdomain: mcl_lanterns +Lantern=Lanterne +Soul Lantern=Lanterne des âmes +Lanterns are light sources which can be placed on the top or the bottom of most blocks.=Les lanternes sont des blocs lumineux qui peuvent être placés au dessus ou en dessous de la plupart des blocs. +Chain=Chaîne +Chains are metallic decoration blocks.=La chaîne est un bloc de décoration métalique. \ No newline at end of file diff --git a/mods/ITEMS/mcl_lanterns/locale/template.txt b/mods/ITEMS/mcl_lanterns/locale/template.txt new file mode 100644 index 0000000000..545118b54a --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/locale/template.txt @@ -0,0 +1,6 @@ +# textdomain: mcl_lanterns +Lantern= +Soul Lantern= +Lanterns are light sources which can be placed on the top or the bottom of most blocks.= +Chain= +Chains are metallic decoration blocks.= \ No newline at end of file diff --git a/mods/ITEMS/mcl_lanterns/mod.conf b/mods/ITEMS/mcl_lanterns/mod.conf new file mode 100644 index 0000000000..746ffcb158 --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/mod.conf @@ -0,0 +1,6 @@ +name = mcl_lanterns +description = Add lanterns and chains to MineClone2 +depends = mcl_sounds +optional_depends = +author = AFCMS +title = MineClone2 Lanterns \ No newline at end of file diff --git a/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_chain.obj b/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_chain.obj new file mode 100644 index 0000000000..94a7b8971f --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_chain.obj @@ -0,0 +1,24 @@ +# Blender v3.0.1 OBJ File: 'chain.blend' +# www.blender.org +o Plane +v 0.066291 0.500000 0.066291 +v 0.066291 -0.500000 0.066291 +v -0.066291 0.500000 -0.066291 +v -0.066291 -0.500000 -0.066291 +v -0.066291 0.500000 0.066291 +v -0.066291 -0.500000 0.066291 +v 0.066291 0.500000 -0.066291 +v 0.066291 -0.500000 -0.066291 +vt -0.000000 1.000000 +vt 0.000000 -0.000000 +vt 0.187500 0.000000 +vt 0.187500 1.000000 +vt 0.187500 1.000000 +vt 0.187500 -0.000000 +vt 0.375000 -0.000000 +vt 0.375000 1.000000 +vn 0.7071 0.0000 -0.7071 +vn 0.7071 0.0000 0.7071 +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 5/5/2 6/6/2 8/7/2 7/8/2 diff --git a/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_lantern_ceiling.obj b/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_lantern_ceiling.obj new file mode 100644 index 0000000000..7079aa7cb2 --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_lantern_ceiling.obj @@ -0,0 +1,104 @@ +# Blender v3.0.1 OBJ File: 'lantern.blend' +# www.blender.org +o Lantern_Ceiling +v 0.187500 -0.000000 0.187500 +v 0.187500 0.437500 0.187500 +v 0.187500 0.000000 -0.187500 +v 0.187500 0.437500 -0.187500 +v -0.187500 -0.000000 0.187500 +v -0.187500 0.437500 0.187500 +v -0.187500 0.000000 -0.187500 +v -0.187500 0.437500 -0.187500 +v 0.125000 -0.125000 0.125000 +v 0.125000 -0.000000 0.125000 +v 0.125000 -0.125000 -0.125000 +v 0.125000 0.000000 -0.125000 +v -0.125000 -0.125000 0.125000 +v -0.125000 -0.000000 0.125000 +v -0.125000 -0.125000 -0.125000 +v -0.125000 0.000000 -0.125000 +v 0.066291 -0.500000 -0.066291 +v 0.066291 -0.125000 -0.066291 +v -0.066291 -0.500000 0.066291 +v -0.066291 -0.125000 0.066291 +v -0.066291 -0.500000 -0.066291 +v -0.066291 -0.125000 -0.066291 +v 0.066291 -0.500000 0.066291 +v 0.066291 -0.125000 0.066291 +vt 0.000000 0.062500 +vt 0.375000 0.062500 +vt 0.375000 0.437500 +vt 0.000000 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt -0.000000 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt 0.000000 0.437500 +vt 0.000000 0.062500 +vt 0.375000 0.062500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt 0.000000 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt -0.000000 0.437500 +vt 0.062500 0.125000 +vt 0.312500 0.125000 +vt 0.312500 0.375000 +vt 0.062500 0.375000 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.500000 0.770833 +vt 0.500000 0.770833 +vt 0.500000 0.770833 +vt 0.500000 0.770833 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.687500 0.625000 +vt 0.687500 0.250000 +vt 0.875000 0.250000 +vt 0.875000 0.625000 +vt 0.687500 1.000000 +vt 0.687500 0.625000 +vt 0.875000 0.625000 +vt 0.875000 1.000000 +vn 0.0000 -1.0000 -0.0000 +vn 0.0000 0.0000 -1.0000 +vn -1.0000 -0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -0.0000 1.0000 +vn 0.7071 -0.0000 0.7071 +vn 0.7071 0.0000 -0.7071 +s off +f 1/1/1 5/2/1 7/3/1 3/4/1 +f 4/5/2 3/6/2 7/7/2 8/8/2 +f 8/9/3 7/10/3 5/11/3 6/12/3 +f 6/13/4 2/14/4 4/5/4 8/8/4 +f 2/15/5 1/16/5 3/17/5 4/18/5 +f 6/19/6 5/20/6 1/21/6 2/22/6 +f 9/23/1 13/24/1 15/25/1 11/26/1 +f 12/27/2 11/28/2 15/29/2 16/30/2 +f 16/31/3 15/32/3 13/33/3 14/34/3 +f 14/35/4 10/36/4 12/37/4 16/38/4 +f 10/39/5 9/40/5 11/41/5 12/42/5 +f 14/43/6 13/44/6 9/45/6 10/46/6 +f 17/47/7 18/48/7 20/49/7 19/50/7 +f 21/51/8 22/52/8 24/53/8 23/54/8 diff --git a/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_lantern_floor.obj b/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_lantern_floor.obj new file mode 100644 index 0000000000..c90ece6804 --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/models/mcl_lanterns_lantern_floor.obj @@ -0,0 +1,104 @@ +# Blender v3.0.1 OBJ File: 'lantern.blend' +# www.blender.org +o Lantern_Floor +v 0.187500 -0.062500 -0.187500 +v 0.187500 -0.500000 -0.187500 +v 0.187500 -0.062500 0.187500 +v 0.187500 -0.500000 0.187500 +v -0.187500 -0.062500 -0.187500 +v -0.187500 -0.500000 -0.187500 +v -0.187500 -0.062500 0.187500 +v -0.187500 -0.500000 0.187500 +v 0.125000 0.062500 -0.125000 +v 0.125000 -0.062500 -0.125000 +v 0.125000 0.062500 0.125000 +v 0.125000 -0.062500 0.125000 +v -0.125000 0.062500 -0.125000 +v -0.125000 -0.062500 -0.125000 +v -0.125000 0.062500 0.125000 +v -0.125000 -0.062500 0.125000 +v 0.066291 0.187500 0.066291 +v 0.066291 0.062500 0.066291 +v -0.066291 0.187500 -0.066291 +v -0.066291 0.062500 -0.066291 +v -0.066291 0.187500 0.066291 +v -0.066291 0.062500 0.066291 +v 0.066291 0.187500 -0.066291 +v 0.066291 0.062500 -0.066291 +vt 0.000000 0.062500 +vt 0.375000 0.062500 +vt 0.375000 0.437500 +vt 0.000000 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt -0.000000 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt 0.000000 0.437500 +vt 0.000000 0.062500 +vt 0.375000 0.062500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt 0.000000 0.437500 +vt 0.375000 0.437500 +vt 0.375000 0.875000 +vt -0.000000 0.875000 +vt -0.000000 0.437500 +vt 0.062500 0.125000 +vt 0.312500 0.125000 +vt 0.312500 0.375000 +vt 0.062500 0.375000 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.500000 0.770833 +vt 0.500000 0.770833 +vt 0.500000 0.770833 +vt 0.500000 0.770833 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.312500 0.875000 +vt 0.312500 1.000000 +vt 0.062500 1.000000 +vt 0.062500 0.875000 +vt 0.687500 0.937500 +vt 0.687500 0.812500 +vt 0.875000 0.812500 +vt 0.875000 0.937500 +vt 0.687500 0.937500 +vt 0.687500 0.812500 +vt 0.875000 0.812500 +vt 0.875000 0.937500 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.7071 0.0000 -0.7071 +vn 0.7071 0.0000 0.7071 +s off +f 1/1/1 5/2/1 7/3/1 3/4/1 +f 4/5/2 3/6/2 7/7/2 8/8/2 +f 8/9/3 7/10/3 5/11/3 6/12/3 +f 6/13/4 2/14/4 4/5/4 8/8/4 +f 2/15/5 1/16/5 3/17/5 4/18/5 +f 6/19/6 5/20/6 1/21/6 2/22/6 +f 9/23/1 13/24/1 15/25/1 11/26/1 +f 12/27/2 11/28/2 15/29/2 16/30/2 +f 16/31/3 15/32/3 13/33/3 14/34/3 +f 14/35/4 10/36/4 12/37/4 16/38/4 +f 10/39/5 9/40/5 11/41/5 12/42/5 +f 14/43/6 13/44/6 9/45/6 10/46/6 +f 17/47/7 18/48/7 20/49/7 19/50/7 +f 21/51/8 22/52/8 24/53/8 23/54/8 diff --git a/mods/ITEMS/mcl_lanterns/register.lua b/mods/ITEMS/mcl_lanterns/register.lua new file mode 100644 index 0000000000..efdd1ed98d --- /dev/null +++ b/mods/ITEMS/mcl_lanterns/register.lua @@ -0,0 +1,26 @@ +local S = minetest.get_translator("mcl_lanterns") + +mcl_lanterns.register_lantern("lantern", { + description = S("Lantern"), + longdesc = S("Lanterns are light sources which can be placed on the top or the bottom of most blocks."), + texture = "mcl_lanterns_lantern.png", + texture_inv = "mcl_lanterns_lantern_inv.png", + light_level = 14, +}) + +mcl_lanterns.register_lantern("soul_lantern", { + description = S("Soul Lantern"), + longdesc = S("Lanterns are light sources which can be placed on the top or the bottom of most blocks."), + texture = "mcl_lanterns_soul_lantern.png", + texture_inv = "mcl_lanterns_soul_lantern_inv.png", + light_level = 10, +}) + +minetest.register_craft({ + output = "mcl_lanterns:lantern_floor", + recipe = { + {"mcl_core:iron_nugget", "mcl_core:iron_nugget", "mcl_core:iron_nugget"}, + {"mcl_core:iron_nugget", "mcl_torches:torch" , "mcl_core:iron_nugget"}, + {"mcl_core:iron_nugget", "mcl_core:iron_nugget", "mcl_core:iron_nugget"}, + }, +}) \ No newline at end of file diff --git a/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_chain.png b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_chain.png new file mode 100644 index 0000000000..01725114a6 Binary files /dev/null and b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_chain.png differ diff --git a/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_chain_inv.png b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_chain_inv.png new file mode 100644 index 0000000000..a8c89dab46 Binary files /dev/null and b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_chain_inv.png differ diff --git a/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_lantern.png b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_lantern.png new file mode 100644 index 0000000000..f9936e0fbb Binary files /dev/null and b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_lantern.png differ diff --git a/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_lantern_inv.png b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_lantern_inv.png new file mode 100644 index 0000000000..8bdc8095fc Binary files /dev/null and b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_lantern_inv.png differ diff --git a/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_soul_lantern.png b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_soul_lantern.png new file mode 100644 index 0000000000..6e20058ea3 Binary files /dev/null and b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_soul_lantern.png differ diff --git a/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_soul_lantern_inv.png b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_soul_lantern_inv.png new file mode 100644 index 0000000000..55624c7492 Binary files /dev/null and b/mods/ITEMS/mcl_lanterns/textures/mcl_lanterns_soul_lantern_inv.png differ diff --git a/mods/ITEMS/mcl_maps/colors.json b/mods/ITEMS/mcl_maps/colors.json index 0aa23f0fc3..cd35042527 100644 --- a/mods/ITEMS/mcl_maps/colors.json +++ b/mods/ITEMS/mcl_maps/colors.json @@ -1 +1 @@ -{"player.png": [123, 74, 62], "player_back.png": [114, 68, 56], "mcl_skins_player_dummy.png": [125, 125, 125], "mcl_skins_player_1.png": [103, 100, 86], "mcl_skins_button.png": [121, 95, 85], "mcl_skins_character_1.png": [93, 90, 77], "mcl_hunger_bar_saturation.png": [255, 255, 0], "hbhunger_bar_health_poison.png": [148, 120, 24], "mcl_hunger_bar_exhaustion.png": [255, 255, 255], "mcl_hunger_icon_exhaustion.png": [213, 213, 213], "mcl_hunger_bgicon_exhaustion.png": [25, 25, 26], "mcl_hunger_icon_foodpoison.png": [109, 106, 40], "mcl_hunger_bgicon_saturation.png": [24, 24, 26], "hbhunger_bar.png": [200, 103, 0], "hbhunger_bgicon.png": [24, 24, 26], "hbhunger_icon_health_poison.png": [69, 98, 45], "mcl_hunger_bar_foodpoison.png": [116, 132, 88], "hbhunger_icon.png": [175, 132, 97], "mcl_hunger_icon_saturation.png": [157, 140, 64], "mcl_playerplus_end_sky.png": [14, 14, 14], "mobs_mc_llama_decor_purple.png": [98, 50, 98], "mobs_mc_spawn_icon_illusioner.png": [98, 111, 155], "mobs_mc_llama_gray.png": [195, 188, 175], "mobs_mc_spawn_icon_zombie.png": [64, 136, 112], "mobs_mc_llama_decor_blue.png": [50, 50, 249], "mobs_mc_spawn_icon_skeleton.png": [146, 146, 146], "mobs_mc_shulker_blue.png": [89, 100, 126], "mobs_mc_shulker_black.png": [78, 75, 76], "mobs_mc_wolf_collar.png": [186, 186, 186], "mobs_mc_spawn_icon_bat.png": [130, 63, 13], "mobs_mc_parrot_green.png": [47, 208, 62], "mobs_mc_llama_decor_magenta.png": [249, 50, 249], "mobs_mc_rabbit_black.png": [73, 64, 61], "mobs_mc_vindicator.png": [56, 56, 57], "mobs_mc_polarbear.png": [233, 220, 208], "mobs_mc_magmacube.png": [83, 40, 27], "mobs_mc_chicken.png": [198, 182, 176], "mobs_mc_ghast_firing.png": [198, 198, 198], "mobs_mc_spawn_icon_zombie_pigman.png": [202, 160, 135], "mobs_mc_husk.png": [98, 95, 76], "mobs_mc_villager_librarian.png": [176, 171, 163], "mobs_mc_villager_priest.png": [100, 64, 74], "mobs_mc_villager_smith.png": [76, 76, 63], "mobs_mc_horse_armor_gold.png": [143, 110, 59], "mobs_mc_spawn_icon_dragon.png": [98, 47, 89], "mobs_mc_spawn_icon_donkey.png": [152, 132, 100], "mobs_mc_squid.png": [37, 52, 68], "mobs_mc_villager_farmer.png": [81, 80, 67], "mobs_mc_spawn_icon_horse_skeleton.png": [245, 204, 202], "mobs_mc_horse_markings_blackdots.png": [24, 22, 22], "mobs_mc_zombie_farmer.png": [119, 99, 85], "mobs_mc_spawn_icon_vex.png": [145, 185, 185], "mobs_mc_parrot_blue.png": [43, 58, 148], "mobs_mc_spider_eyes.png": [174, 48, 48], "mobs_mc_zombie.png": [78, 110, 105], "mobs_mc_llama_decor_light_blue.png": [104, 168, 194], "mobs_mc_zombie_priest.png": [120, 104, 110], "mobs_mc_llama_decor_black.png": [50, 50, 50], "mobs_mc_horse_white.png": [190, 173, 154], "mobs_mc_spawn_icon_vindicator.png": [102, 103, 104], "mobs_mc_silverfish.png": [179, 164, 144], "mobs_mc_llama_decor_gray.png": [98, 98, 98], "mobs_mc_spawn_icon_guardian.png": [119, 156, 148], "mobs_mc_creeper.png": [98, 107, 71], "mobs_mc_shulker_purple.png": [135, 87, 99], "mobs_mc_spawn_icon_rabbit.png": [156, 126, 84], "mobs_mc_horse_armor_iron.png": [134, 123, 118], "mobs_mc_sheep.png": [182, 161, 149], "mobs_mc_parrot_grey.png": [33, 178, 173], "mobs_mc_wolf_icon_sit.png": [8, 88, 116], "mobs_mc_gold_horse_armor.png": [140, 106, 67], "mobs_mc_spawn_icon_witch.png": [98, 85, 68], "mobs_mc_shulker_green.png": [89, 122, 84], "mobs_mc_bat.png": [87, 63, 54], "mobs_mc_horse_chestnut.png": [126, 78, 58], "mobs_mc_shulker_yellow.png": [175, 128, 69], "mobs_mc_spawn_icon_creeper.png": [115, 125, 53], "mobs_mc_slime.png": [63, 133, 78], "mobs_mc_evoker.png": [44, 48, 43], "mobs_mc_horse_skeleton.png": [163, 156, 141], "mobs_mc_spawn_icon_blaze.png": [142, 76, 49], "mobs_mc_shulker_light_blue.png": [114, 140, 158], "mobs_mc_shulker_gray.png": [106, 104, 109], "mobs_mc_horse_darkbrown.png": [69, 47, 34], "mobs_mc_stray_overlay.png": [63, 59, 65], "mobs_mc_arrow_particle.png": [218, 171, 136], "mobs_mc_spawn_icon_cat.png": [120, 66, 10], "mobs_mc_stray.png": [155, 157, 161], "mobs_mc_trading_formspec_bg.png": [157, 157, 157], "mobs_mc_llama_chest.png": [70, 53, 36], "mobs_mc_spawn_icon_villager.png": [134, 124, 81], "mobs_mc_pig.png": [228, 175, 165], "mobs_mc_spawn_icon_mooshroom.png": [160, 56, 55], "mobs_mc_wolf_angry.png": [187, 179, 176], "mobs_mc_cat_black.png": [206, 181, 154], "mobs_mc_vex_charging.png": [142, 153, 153], "mobs_mc_llama.png": [207, 189, 155], "mobs_mc_mushroom_brown.png": [122, 81, 58], "mobs_mc_spawn_icon_shulker.png": [170, 117, 130], "mobs_mc_wither_half_health.png": [7, 58, 91], "mobs_mc_spawn_icon_guardian_elder.png": [174, 140, 113], "mobs_mc_enderman_eyes.png": [184, 211, 242], "mobs_mc_horse_creamy.png": [146, 111, 75], "mobs_mc_spawn_icon_zombie_villager.png": [95, 110, 68], "mobs_mc_vex.png": [128, 162, 162], "mobs_mc_iron_golem.png": [47, 44, 44], "mobs_mc_cat_ocelot.png": [163, 111, 52], "mobs_mc_llama_decor_green.png": [50, 98, 50], "mobs_mc_cow.png": [94, 68, 55], "mobs_mc_llama_decor_brown.png": [101, 75, 60], "mobs_mc_villager_butcher.png": [82, 83, 71], "mobs_mc_parrot_yellow_blue.png": [98, 187, 205], "mobs_mc_zombie_pigman.png": [164, 129, 117], "mobs_mc_spawn_icon_wolf.png": [231, 218, 207], "mobs_mc_zombie_villager.png": [112, 108, 90], "mobs_mc_sheep_fur.png": [203, 186, 174], "mobs_mc_spawn_icon_horse_zombie.png": [129, 143, 66], "mobs_mc_blaze.png": [84, 63, 50], "mcl_totems_totem.png": [185, 139, 52], "mobs_mc_rabbit_salt.png": [122, 99, 87], "mobs_mc_rabbit_white_splotched.png": [146, 139, 135], "mobs_mc_horse_brown.png": [115, 84, 61], "mobs_mc_ghast.png": [199, 199, 199], "mobs_mc_horse_markings_white.png": [165, 149, 132], "mobs_mc_horse_markings_whitefield.png": [193, 178, 162], "mobs_mc_spawn_icon_endermite.png": [138, 67, 74], "mobs_mc_shulker_magenta.png": [143, 97, 130], "mobs_mc_snowman.png": [211, 217, 221], "mobs_mc_zombie_smith.png": [71, 59, 54], "mobs_mc_spawn_icon_squid.png": [55, 58, 103], "mobs_mc_dragon_fireball.png": [89, 66, 79], "mobs_mc_horse_armor_diamond.png": [78, 110, 129], "mobs_mc_diamond_horse_armor.png": [67, 95, 112], "mobs_mc_rabbit_toast.png": [130, 123, 119], "mobs_mc_llama_white.png": [207, 199, 184], "mobs_mc_llama_creamy.png": [208, 190, 155], "mobs_mc_pig_saddle.png": [82, 63, 45], "mobs_mc_spawn_icon_cave_spider.png": [23, 43, 57], "mobs_mc_shulker_silver.png": [140, 138, 143], "mobs_mc_trading_formspec_disabled.png": [193, 26, 26], "mobs_mc_spider.png": [41, 38, 37], "mobs_mc_wither.png": [33, 33, 33], "mobs_mc_llama_decor_white.png": [249, 249, 249], "mobs_mc_witch.png": [80, 74, 67], "mobs_mc_wolf_icon_roam.png": [6, 124, 36], "mobs_mc_illusionist.png": [56, 68, 114], "mobs_mc_endermite.png": [55, 20, 65], "mobs_mc_spawn_icon_witherskeleton.png": [71, 71, 71], "mobs_mc_llama_decor_light_gray.png": [185, 185, 185], "mobs_mc_llama_decor_cyan.png": [18, 249, 249], "mobs_mc_skeleton.png": [124, 124, 124], "mobs_mc_spawn_icon_llama.png": [230, 221, 178], "mobs_mc_spawn_icon_chicken.png": [170, 160, 156], "mobs_mc_shulker_pink.png": [173, 127, 160], "mobs_mc_spawn_icon_spider.png": [53, 43, 43], "mobs_mc_shulker_red.png": [146, 77, 71], "mobs_mc_shulker_white.png": [184, 181, 186], "mobs_mc_spawn_icon_magmacube.png": [52, 33, 23], "mobs_mc_spawn_icon_ghast.png": [212, 212, 212], "mobs_mc_rabbit_brown.png": [112, 86, 73], "mobs_mc_spawn_icon_pig.png": [242, 200, 188], "mobs_mc_spawn_icon_horse.png": [44, 36, 25], "mobs_mc_cat_siamese.png": [161, 144, 133], "mobs_mc_mushroom_red.png": [176, 51, 49], "mobs_mc_shulker_brown.png": [94, 81, 70], "mobs_mc_guardian.png": [78, 116, 130], "mobs_mc_creeper_charge.png": [121, 219, 255], "mobs_mc_villager.png": [88, 91, 55], "mobs_mc_llama_decor_lime.png": [50, 249, 50], "mobs_mc_llama_brown.png": [136, 97, 52], "mobs_mc_parrot_red_blue.png": [171, 70, 37], "mobs_mc_spawn_icon_husk.png": [174, 174, 128], "mobs_mc_rabbit_gold.png": [151, 130, 96], "mobs_mc_spawn_icon_evoker.png": [92, 103, 86], "mobs_mc_iron_horse_armor.png": [133, 119, 114], "mobs_mc_llama_decor_red.png": [249, 50, 50], "mobs_mc_enderman.png": [3, 10, 10], "mobs_mc_mooshroom_brown.png": [93, 50, 28], "mobs_mc_llama_decor_pink.png": [249, 161, 175], "mobs_mc_enderman_block.png": [46, 42, 38], "mobs_mc_mooshroom.png": [90, 42, 41], "mobs_mc_cat_red.png": [221, 163, 120], "mobs_mc_spit.png": [221, 218, 246], "mobs_mc_shulkerbullet.png": [216, 190, 153], "mobs_mc_horse_markings_whitedots.png": [230, 220, 207], "mobs_mc_mule.png": [108, 75, 51], "mobs_mc_spawn_icon_iron_golem.png": [122, 72, 41], "mobs_mc_zombie_butcher.png": [107, 98, 87], "mobs_mc_llama_decor_yellow.png": [249, 249, 50], "mobs_mc_wolf_tame.png": [179, 159, 154], "mobs_mc_horse_gray.png": [78, 68, 62], "mobs_mc_shulker_lime.png": [106, 132, 88], "mobs_mc_rabbit_caerbannog.png": [186, 179, 174], "mobs_mc_zombie_librarian.png": [106, 104, 104], "mobs_mc_spawn_icon_silverfish.png": [199, 168, 128], "mobs_mc_spawn_icon_stray.png": [118, 116, 118], "mobs_mc_spawn_icon_polarbear.png": [237, 235, 212], "mobs_mc_guardian_elder.png": [141, 141, 125], "mobs_mc_spawn_icon_slime.png": [76, 130, 33], "mobs_mc_cave_spider.png": [14, 28, 38], "mobs_mc_spawn_icon_cow.png": [162, 118, 72], "mobs_mc_wolf.png": [182, 165, 159], "mobs_mc_wither_skeleton.png": [50, 50, 50], "mobs_mc_endergolem.png": [135, 87, 99], "mobs_mc_spawn_icon_mule.png": [115, 82, 47], "mobs_mc_llama_decor_orange.png": [249, 131, 50], "mobs_chicken_egg.png": [199, 157, 106], "mobs_mc_rabbit_white.png": [161, 153, 149], "mobs_mc_horse_black.png": [49, 42, 39], "mobs_mc_dragon.png": [79, 54, 67], "mobs_mc_spawn_icon_parrot.png": [202, 100, 54], "mobs_mc_spawn_icon_snowman.png": [216, 173, 147], "mobs_mc_donkey.png": [91, 78, 68], "mobs_mc_shulker_cyan.png": [89, 114, 128], "mobs_mc_spawn_icon_sheep.png": [209, 185, 175], "mobs_mc_TEMP_wither_projectile.png": [69, 69, 69], "mobs_mc_spawn_icon_enderman.png": [63, 82, 87], "mobs_mc_shulker_orange.png": [156, 90, 67], "mobs_mc_empty.png": [255, 255, 255], "mobs_mc_spawn_icon_wither.png": [102, 102, 102], "mcl_boats_spruce_boat.png": [72, 61, 51], "mcl_boats_jungle_boat.png": [102, 73, 58], "mcl_boats_texture_birch_boat.png": [131, 105, 83], "mcl_boats_texture_oak_boat.png": [103, 82, 65], "mcl_boats_birch_boat.png": [120, 95, 78], "mcl_boats_texture_jungle_boat.png": [109, 78, 60], "mcl_boats_oak_boat.png": [93, 76, 62], "mcl_boats_texture_acacia_boat.png": [136, 90, 64], "mcl_boats_texture_dark_oak_boat.png": [89, 76, 64], "mcl_boats_texture_spruce_boat.png": [74, 61, 50], "mcl_boats_acacia_boat.png": [124, 82, 59], "mcl_boats_dark_oak_boat.png": [89, 76, 64], "mobs_nametag.png": [138, 114, 89], "mobs_blood.png": [27, 27, 29], "mcl_minecarts_rail_golden_curved_powered.png": [89, 71, 57], "mcl_minecarts_rail_golden_crossing.png": [83, 70, 55], "mcl_minecarts_rail_detector_curved_powered.png": [81, 68, 64], "mcl_minecarts_rail_golden_t_junction_powered.png": [82, 69, 59], "mcl_minecarts_rail_golden_t_junction.png": [80, 70, 59], "mcl_minecarts_rail_detector.png": [85, 74, 67], "mcl_minecarts_rail_detector_crossing.png": [77, 69, 65], "default_rail_t_junction.png": [79, 68, 61], "mcl_minecarts_rail_activator_crossing_powered.png": [72, 55, 51], "mcl_minecarts_minecart_hopper.png": [45, 45, 45], "mcl_minecarts_minecart_furnace.png": [66, 65, 64], "mcl_minecarts_minecart_command_block.png": [64, 62, 61], "mcl_minecarts_rail_golden.png": [92, 77, 60], "mcl_minecarts_rail_activator_t_junction_powered.png": [76, 61, 55], "default_rail_curved.png": [76, 67, 60], "mcl_minecarts_rail_activator_t_junction.png": [72, 62, 56], "mcl_minecarts_rail_golden_crossing_powered.png": [86, 70, 54], "mcl_minecarts_rail_detector_crossing_powered.png": [78, 68, 64], "mcl_minecarts_rail_detector_curved.png": [77, 70, 66], "default_rail_crossing.png": [79, 68, 59], "mcl_minecarts_rail_detector_t_junction.png": [74, 66, 61], "mcl_minecarts_minecart.png": [72, 60, 51], "mcl_minecarts_rail_golden_curved.png": [85, 73, 58], "mcl_minecarts_rail_activator.png": [78, 64, 56], "mcl_minecarts_rail_activator_powered.png": [86, 62, 54], "mcl_minecarts_rail_detector_t_junction_powered.png": [76, 66, 61], "mcl_minecarts_minecart_normal.png": [47, 45, 43], "mcl_minecarts_minecart_tnt.png": [75, 52, 52], "mcl_minecarts_rail_detector_powered.png": [87, 74, 67], "mcl_minecarts_rail_golden_powered.png": [94, 77, 60], "mcl_minecarts_rail_activator_crossing.png": [65, 56, 52], "default_rail.png": [83, 70, 61], "mcl_minecarts_rail_activator_curved_powered.png": [75, 55, 52], "mcl_minecarts_rail_activator_curved.png": [66, 56, 53], "mcl_minecarts_minecart_chest.png": [51, 48, 46], "mobs_mc_gameconfig_enderman_cactus_background.png": [44, 71, 27], "mcl_paintings_paintings.png": [104, 99, 89], "mcl_paintings_painting.png": [139, 133, 119], "mcl_particles_lava.png": [250, 150, 64], "mcl_particles_instant_effect.png": [160, 160, 160], "mcl_particles_note.png": [41, 40, 39], "mcl_particles_bubble.png": [147, 174, 195], "mcl_particles_sponge1.png": [241, 238, 226], "mcl_particles_smoke_anim.png": [172, 172, 172], "mcl_particles_crit.png": [165, 165, 165], "mcl_particles_mob_death.png": [198, 198, 198], "mcl_particles_droplet_bottle.png": [203, 203, 203], "mcl_particles_sponge4.png": [241, 238, 226], "mcl_particles_effect.png": [184, 184, 184], "mcl_particles_teleport.png": [86, 22, 128], "mcl_particles_sponge5.png": [241, 238, 226], "mcl_particles_flame.png": [244, 149, 63], "mcl_particles_sponge3.png": [241, 238, 226], "mcl_particles_sponge2.png": [241, 238, 226], "mcl_particles_smoke.png": [174, 174, 174], "lightning_lightning_2.png": [255, 255, 255], "lightning_lightning_3.png": [217, 217, 217], "lightning_lightning_1.png": [223, 223, 223], "weather_pack_rain_raindrop_2.png": [33, 79, 142], "weather_pack_rain_raindrop_3.png": [59, 88, 128], "mcl_particles_nether_dust3.png": [143, 105, 102], "weather_pack_rain_raindrop_1.png": [97, 137, 179], "mcl_particles_nether_dust1.png": [143, 105, 102], "weather_pack_snow_snowflake1.png": [255, 255, 255], "mcl_particles_nether_dust2.png": [143, 105, 102], "weather_pack_snow_snowflake2.png": [255, 255, 255], "mcl_moon_moon_phases.png": [80, 106, 141], "hbarmor_bgicon.png": [27, 27, 29], "hbarmor_bar.png": [175, 172, 165], "hbarmor_icon.png": [135, 131, 126], "mcl_base_textures_background9.png": [179, 179, 179], "object_crosshair.png": [255, 255, 255], "bubble.png": [69, 138, 194], "crosshair.png": [255, 255, 255], "heart.png": [137, 47, 40], "mcl_base_textures_background.png": [179, 179, 179], "crack_anylength.png": [93, 93, 93], "mcl_base_textures_button9_pressed.png": [162, 162, 162], "mcl_base_textures_button9.png": [162, 162, 162], "smoke_puff.png": [255, 255, 255], "mineclone2_logo.png": [75, 74, 69], "mineclone2_icon.png": [58, 74, 44], "awards_template.png": [134, 134, 134], "awards_bg_mining.png": [73, 68, 51], "awards_progress_gray.png": [157, 157, 157], "awards_ui_icon.png": [190, 34, 34], "awards_unknown.png": [134, 134, 134], "awards_progress_green.png": [0, 155, 74], "awards_bg_default.png": [38, 38, 38], "hudbars_bar_breath.png": [159, 161, 255], "hudbars_icon_health.png": [137, 47, 40], "hudbars_bar_health.png": [168, 55, 47], "hudbars_bgicon_breath.png": [0, 0, 0], "hudbars_bgicon_health.png": [27, 27, 29], "hudbars_icon_breath.png": [69, 138, 194], "hudbars_bar_background.png": [71, 71, 71], "mcl_achievements_button.png": [158, 152, 67], "mcl_inventory_hotbar.png": [81, 81, 85], "crafting_inventory_creative_survival.png": [195, 195, 195], "crafting_creative_bg_dark.png": [157, 157, 157], "mcl_inventory_empty_armor_slot_shield.png": [25, 32, 34], "crafting_formspec_bg.png": [9, 9, 9], "mcl_inventory_empty_armor_slot_helmet.png": [25, 32, 34], "mcl_inventory_hotbar_selected.png": [113, 85, 40], "crafting_creative_inactive_down.png": [151, 151, 151], "crafting_creative_active_down.png": [196, 196, 196], "crafting_creative_prev.png": [254, 254, 254], "crafting_creative_marker.png": [0, 0, 0], "mcl_inventory_button9_pressed.png": [162, 162, 162], "crafting_creative_active.png": [202, 202, 202], "mcl_inventory_button9.png": [162, 162, 162], "mcl_inventory_empty_armor_slot_chestplate.png": [0, 0, 0], "mcl_inventory_empty_armor_slot_boots.png": [0, 0, 0], "crafting_creative_bg.png": [207, 207, 207], "crafting_creative_inactive.png": [157, 157, 157], "crafting_creative_next.png": [254, 254, 254], "mcl_inventory_empty_armor_slot_leggings.png": [25, 32, 34], "crafting_inventory_creative.png": [206, 206, 206], "crafting_creative_trash.png": [144, 113, 113], "mcl_formspec_itemslot.png": [157, 157, 157], "mcl_experience_bottle.png": [136, 174, 169], "experience_bar_background.png": [49, 46, 45], "experience_orb.png": [93, 174, 0], "experience_bar.png": [74, 102, 70], "mcl_bossbars_empty.png": [255, 255, 255], "mcl_bossbars.png": [76, 68, 75], "mcl_itemframes_item_frame.png": [123, 90, 63], "mcl_itemframes_itemframe_background.png": [136, 104, 75], "mcl_banners_stripe_middle.png": [255, 255, 255], "mcl_banners_skull.png": [255, 255, 255], "mcl_banners_bricks.png": [255, 255, 255], "mcl_banners_square_bottom_left.png": [255, 255, 255], "mcl_banners_gradient.png": [254, 254, 254], "mcl_banners_cross.png": [255, 255, 255], "mcl_banners_gradient_up.png": [254, 254, 254], "mcl_banners_item_overlay.png": [240, 240, 240], "mcl_banners_stripe_downright.png": [255, 255, 255], "mcl_banners_stripe_downleft.png": [255, 255, 255], "mcl_banners_fallback_wood.png": [102, 88, 74], "mcl_banners_base_inverted.png": [255, 255, 255], "mcl_banners_triangles_top.png": [255, 255, 255], "mcl_banners_banner_base.png": [215, 206, 193], "mcl_banners_curly_border.png": [254, 254, 254], "mcl_banners_thing.png": [253, 253, 253], "mcl_banners_small_stripes.png": [255, 255, 255], "mcl_banners_triangle_bottom.png": [254, 254, 254], "mcl_banners_stripe_right.png": [255, 255, 255], "mcl_banners_straight_cross.png": [255, 255, 255], "mcl_banners_triangle_top.png": [255, 255, 255], "mcl_banners_border.png": [255, 255, 255], "mcl_banners_diagonal_left.png": [255, 255, 255], "mcl_banners_diagonal_right.png": [255, 255, 255], "mcl_banners_base.png": [255, 255, 255], "mcl_banners_half_vertical.png": [255, 255, 255], "mcl_banners_circle.png": [254, 254, 254], "mcl_banners_triangles_bottom.png": [255, 255, 255], "mcl_banners_item_base.png": [103, 89, 75], "mcl_banners_stripe_left.png": [255, 255, 255], "mcl_banners_rhombus.png": [255, 255, 255], "mcl_banners_creeper.png": [255, 255, 255], "mcl_banners_flower.png": [254, 254, 254], "mcl_banners_stripe_bottom.png": [255, 255, 255], "mcl_banners_half_horizontal.png": [255, 255, 255], "mcl_banners_half_horizontal_bottom.png": [255, 255, 255], "mcl_banners_square_top_left.png": [255, 255, 255], "mcl_banners_square_top_right.png": [255, 255, 255], "mcl_banners_stripe_center.png": [255, 255, 255], "mcl_banners_diagonal_up_left.png": [255, 255, 255], "mcl_banners_stripe_top.png": [255, 255, 255], "mcl_banners_diagonal_up_right.png": [255, 255, 255], "mcl_banners_square_bottom_right.png": [255, 255, 255], "mcl_banners_half_vertical_right.png": [255, 255, 255], "mcl_doors_trapdoor_dark_oak.png": [81, 68, 56], "mcl_doors_trapdoor_acacia_side.png": [154, 102, 71], "doors_trapdoor_steel_side.png": [149, 140, 140], "mcl_doors_door_jungle_side_upper.png": [109, 75, 57], "mcl_doors_door_dark_oak_side_lower.png": [103, 90, 75], "mcl_doors_door_iron_lower.png": [157, 152, 151], "mcl_doors_door_acacia_upper.png": [152, 100, 69], "mcl_doors_door_jungle_side_lower.png": [107, 72, 55], "mcl_doors_door_wood_lower.png": [89, 70, 55], "doors_trapdoor_steel.png": [149, 140, 140], "mcl_doors_door_iron_side_upper.png": [155, 149, 148], "mcl_doors_door_acacia_side_upper.png": [133, 80, 53], "mcl_doors_door_jungle.png": [116, 83, 62], "mcl_doors_door_iron_side_lower.png": [157, 152, 151], "mcl_doors_door_birch_upper.png": [179, 158, 139], "mcl_doors_trapdoor_spruce_side.png": [73, 59, 47], "mcl_doors_door_iron_upper.png": [155, 149, 148], "mcl_doors_door_spruce_side_lower.png": [92, 79, 68], "mcl_doors_trapdoor_spruce.png": [71, 57, 46], "mcl_doors_trapdoor_birch_side.png": [147, 116, 89], "doors_trapdoor_side.png": [113, 86, 67], "mcl_doors_door_acacia_lower.png": [153, 101, 70], "mcl_doors_door_dark_oak_side_upper.png": [102, 89, 75], "mcl_doors_door_acacia_side_lower.png": [131, 78, 51], "mcl_doors_door_wood_upper.png": [92, 72, 57], "mcl_doors_trapdoor_birch.png": [173, 151, 132], "mcl_doors_door_dark_oak_upper.png": [83, 71, 59], "mcl_doors_door_acacia.png": [148, 98, 67], "mcl_doors_door_spruce.png": [67, 56, 47], "mcl_doors_door_spruce_lower.png": [71, 58, 48], "mcl_doors_door_birch_side_upper.png": [153, 121, 94], "mcl_doors_trapdoor_dark_oak_side.png": [85, 72, 60], "mcl_doors_door_wood_side_upper.png": [84, 65, 51], "mcl_doors_door_birch.png": [172, 147, 124], "mcl_doors_door_birch_lower.png": [165, 140, 119], "mcl_doors_trapdoor_jungle.png": [103, 70, 52], "doors_item_steel.png": [148, 144, 143], "doors_trapdoor.png": [98, 75, 59], "mcl_doors_door_jungle_lower.png": [116, 82, 61], "doors_item_wood.png": [88, 67, 53], "mcl_doors_door_jungle_upper.png": [113, 79, 59], "mcl_doors_door_spruce_upper.png": [71, 58, 47], "mcl_doors_door_dark_oak_lower.png": [84, 71, 59], "mcl_doors_door_dark_oak.png": [82, 69, 57], "mcl_doors_door_wood_side_lower.png": [132, 102, 81], "mcl_doors_trapdoor_jungle_side.png": [121, 87, 62], "mcl_doors_door_spruce_side_upper.png": [92, 79, 68], "mcl_doors_door_birch_side_lower.png": [152, 119, 92], "mcl_doors_trapdoor_acacia.png": [148, 96, 66], "mcl_fishing_clownfish_raw.png": [205, 127, 81], "mcl_fishing_fish_raw.png": [70, 112, 154], "mcl_fishing_salmon_raw.png": [112, 105, 102], "mcl_fishing_fish_cooked.png": [93, 84, 94], "mcl_fishing_bobber.png": [171, 117, 119], "mcl_fishing_pufferfish_raw.png": [219, 165, 77], "mcl_fishing_fishing_rod.png": [134, 116, 103], "mcl_fishing_salmon_cooked.png": [97, 91, 89], "mcl_stairs_diorite_smooth_slab.png": [156, 153, 151], "mcl_stairs_iron_block_slab.png": [166, 159, 159], "mcl_stairs_andesite_smooth_slab.png": [106, 113, 108], "mcl_stairs_gold_block_slab.png": [191, 146, 56], "mcl_stairs_granite_smooth_slab.png": [150, 121, 109], "mcl_stairs_lapis_block_slab.png": [49, 89, 158], "mcl_fireworks_rocket.png": [155, 84, 71], "mcl_bows_arrow_inv.png": [144, 129, 121], "mcl_bows_arrow_overlay.png": [193, 191, 186], "mcl_bows_bow_1.png": [112, 95, 79], "mcl_bows_bow_0.png": [111, 94, 79], "mcl_bows_bow_2.png": [115, 98, 82], "mcl_bows_bow.png": [114, 95, 78], "mcl_bows_arrow.png": [133, 116, 108], "mcl_bows_arrow_front.png": [178, 175, 168], "mcl_bows_arrow_back.png": [218, 216, 213], "mcl_ocean_dead_bubble_coral.png": [118, 108, 126], "mcl_ocean_tube_coral.png": [57, 88, 209], "mcl_ocean_sea_pickle_2_anim.png": [95, 122, 51], "mcl_ocean_dead_horn_coral_fan.png": [150, 143, 123], "mcl_ocean_dead_bubble_coral_block.png": [114, 105, 122], "mcl_ocean_sea_pickle_3_off.png": [68, 99, 36], "mcl_ocean_dead_horn_coral_block.png": [152, 146, 125], "mcl_ocean_bubble_coral_block.png": [143, 76, 195], "mcl_ocean_horn_coral.png": [233, 195, 69], "mcl_ocean_dead_tube_coral_block.png": [99, 104, 127], "mcl_ocean_sea_pickle_item.png": [93, 120, 50], "mcl_ocean_kelp_item.png": [42, 105, 55], "mcl_ocean_dried_kelp_side.png": [71, 80, 67], "mcl_ocean_dead_tube_coral.png": [99, 105, 128], "mcl_ocean_fire_coral_block.png": [198, 74, 62], "mcl_ocean_bubble_coral.png": [149, 77, 200], "mcl_ocean_prismarine_bricks.png": [104, 112, 115], "mcl_ocean_brain_coral.png": [206, 87, 153], "mcl_ocean_dried_kelp_top.png": [56, 71, 57], "mcl_ocean_brain_coral_block.png": [200, 85, 148], "mcl_ocean_prismarine_dark.png": [77, 89, 97], "mcl_ocean_dead_fire_coral_block.png": [127, 102, 100], "mcl_ocean_prismarine_shard.png": [122, 144, 135], "mcl_ocean_sea_pickle_2_off.png": [70, 100, 36], "mcl_ocean_sea_pickle_4_anim.png": [85, 113, 46], "mcl_ocean_dead_brain_coral.png": [134, 117, 127], "mcl_ocean_tube_coral_fan.png": [59, 85, 203], "mcl_ocean_sea_pickle_4_off.png": [68, 98, 36], "mcl_ocean_sea_pickle_1_anim.png": [106, 132, 57], "mcl_ocean_fire_coral.png": [208, 78, 65], "mcl_ocean_sea_pickle_3_anim.png": [89, 116, 48], "mcl_ocean_dead_fire_coral_fan.png": [140, 113, 110], "mcl_ocean_prismarine_crystals.png": [182, 193, 190], "mcl_ocean_prismarine_anim.png": [104, 123, 122], "mcl_ocean_horn_coral_fan.png": [230, 189, 68], "mcl_ocean_dead_tube_coral_fan.png": [98, 103, 125], "mcl_ocean_sea_pickle_1_off.png": [72, 103, 37], "mcl_ocean_dead_horn_coral.png": [154, 148, 127], "mcl_ocean_dead_fire_coral.png": [133, 107, 105], "mcl_ocean_bubble_coral_fan.png": [141, 75, 192], "mcl_ocean_horn_coral_block.png": [232, 193, 69], "mcl_ocean_brain_coral_fan.png": [206, 87, 154], "mcl_ocean_sea_lantern.png": [133, 144, 145], "mcl_ocean_seagrass.png": [48, 125, 60], "mcl_ocean_dead_brain_coral_fan.png": [134, 117, 127], "mcl_ocean_dried_kelp.png": [36, 57, 40], "mcl_ocean_dead_bubble_coral_fan.png": [113, 104, 120], "mcl_ocean_dried_kelp_bottom.png": [56, 71, 57], "mcl_ocean_kelp_plant.png": [42, 105, 55], "mcl_ocean_tube_coral_block.png": [58, 88, 207], "mcl_ocean_dead_brain_coral_block.png": [130, 114, 123], "mcl_ocean_fire_coral_fan.png": [205, 77, 64], "mcl_portals_endframe_bottom.png": [109, 99, 87], "mcl_portals_particle3.png": [146, 0, 201], "mcl_portals_particle2.png": [146, 0, 201], "mcl_portals_endframe_top.png": [95, 85, 74], "mcl_portals_particle4.png": [146, 0, 201], "mcl_portals_endframe_eye.png": [135, 36, 18], "mcl_portals_end_portal.png": [14, 14, 14], "mcl_particles_nether_portal.png": [206, 0, 206], "mcl_portals_particle5.png": [189, 11, 213], "mcl_portals_endframe_side.png": [110, 99, 86], "mcl_portals_particle1.png": [173, 28, 229], "mcl_portals_portal.png": [74, 24, 172], "mcl_particles_nether_portal_t.png": [159, 0, 223], "cake_side.png": [201, 170, 155], "cake_inner.png": [185, 129, 99], "cake_bottom.png": [160, 86, 51], "cake_top.png": [241, 228, 226], "cake.png": [216, 187, 176], "mcl_cocoas_cocoa_top_stage_2.png": [138, 68, 52], "mcl_cocoas_cocoa_stage_1.png": [172, 121, 69], "mcl_cocoas_cocoa_stage_2.png": [132, 65, 50], "mcl_cocoas_cocoa_stage_0.png": [65, 77, 39], "mcl_fences_fence_red_nether_brick.png": [68, 17, 0], "mcl_fences_fence_gate_red_nether_brick.png": [64, 15, 0], "mcl_fences_fence_gate_nether_brick.png": [50, 25, 26], "mcl_mobitems_spider_eye.png": [154, 69, 60], "mcl_mobitems_leather.png": [105, 75, 45], "mcl_mobitems_feather.png": [206, 185, 183], "mcl_mobitems_string.png": [202, 186, 166], "mcl_mobitems_rabbit_foot.png": [124, 107, 97], "mcl_mobitems_saddle.png": [93, 72, 50], "mcl_mobitems_bone.png": [182, 162, 139], "mcl_mobitems_shulker_shell.png": [118, 68, 83], "mcl_mobitems_blaze_rod.png": [143, 64, 28], "mcl_mobitems_beef_raw.png": [147, 63, 54], "mcl_mobitems_rabbit_stew.png": [127, 98, 79], "mcl_mobitems_rotten_flesh.png": [110, 68, 45], "mcl_mobitems_chicken_raw.png": [217, 178, 149], "mcl_mobitems_ghast_tear.png": [148, 160, 166], "mcl_mobitems_porkchop_raw.png": [160, 72, 69], "mcl_mobitems_rabbit_hide.png": [108, 85, 73], "mcl_mobitems_slimeball.png": [75, 134, 82], "mcl_mobitems_magma_cream.png": [102, 54, 34], "default_gunpowder.png": [48, 41, 36], "mcl_mobitems_chicken_cooked.png": [187, 145, 106], "mcl_mobitems_beef_cooked.png": [112, 70, 49], "mcl_mobitems_rabbit_cooked.png": [188, 155, 131], "mcl_mobitems_blaze_powder.png": [86, 50, 34], "mcl_mobitems_rabbit_raw.png": [217, 177, 157], "mcl_mobitems_carrot_on_a_stick.png": [133, 113, 93], "mcl_mobitems_mutton_cooked.png": [144, 104, 77], "mcl_mobitems_nether_star.png": [234, 189, 123], "mcl_mobitems_porkchop_cooked.png": [116, 72, 48], "mcl_mobitems_mutton_raw.png": [175, 77, 77], "mcl_mobitems_bucket_milk.png": [180, 175, 166], "mcl_farming_wheat_stage_0.png": [53, 101, 46], "farming_carrot.png": [147, 106, 63], "farming_potato_poison.png": [121, 93, 55], "farming_cookie.png": [144, 100, 61], "mcl_farming_melon_seeds.png": [100, 72, 61], "mcl_farming_potatoes_stage_1.png": [69, 113, 61], "mcl_farming_melon_stem_disconnected.png": [96, 96, 96], "farming_carrot_4.png": [93, 105, 58], "mcl_farming_wheat_stage_5.png": [101, 142, 66], "farming_tool_woodhoe.png": [120, 101, 86], "mcl_farming_potatoes_stage_0.png": [73, 119, 65], "farming_carrot_1.png": [75, 112, 61], "farming_carrot_3.png": [70, 107, 57], "farming_melon.png": [153, 84, 62], "mcl_farming_pumpkin_seeds.png": [132, 120, 87], "farming_wheat_harvested.png": [178, 134, 80], "farming_pumpkin_side.png": [186, 100, 42], "mcl_farming_pumpkin_face.png": [181, 94, 40], "mcl_farming_wheat_stage_4.png": [86, 129, 65], "mcl_farming_farmland_wet.png": [69, 55, 46], "mcl_farming_beetroot_0.png": [56, 122, 75], "mcl_farming_pumpkin_stem_connected.png": [94, 94, 94], "mcl_farming_farmland_dry.png": [101, 80, 68], "farming_tool_diamondhoe.png": [101, 104, 104], "mcl_farming_beetroot_1.png": [54, 118, 72], "mcl_farming_beetroot_2.png": [54, 119, 73], "mcl_farming_wheat_stage_7.png": [165, 116, 75], "mcl_farming_beetroot.png": [113, 69, 66], "mcl_farming_wheat_stage_6.png": [145, 145, 69], "mcl_farming_wheat_stage_3.png": [64, 113, 52], "mcl_farming_pumpkin_stem_disconnected.png": [96, 96, 96], "mcl_farming_hayblock_top.png": [154, 116, 81], "farming_pumpkin_face_light.png": [189, 100, 45], "farming_potato_baked.png": [118, 84, 45], "farming_melon_side.png": [68, 95, 37], "farming_potato.png": [107, 74, 39], "mcl_farming_wheat_stage_1.png": [49, 97, 45], "farming_pumpkin_top.png": [172, 87, 40], "farming_bread.png": [177, 133, 94], "mcl_farming_beetroot_soup.png": [120, 70, 63], "farming_melon_top.png": [58, 80, 33], "mcl_farming_potatoes_stage_3.png": [82, 106, 57], "farming_tool_stonehoe.png": [133, 122, 111], "mcl_farming_beetroot_seeds.png": [107, 104, 88], "farming_tool_goldhoe.png": [162, 131, 70], "farming_carrot_gold.png": [140, 122, 48], "farming_carrot_2.png": [72, 108, 58], "farming_pumpkin_face.png": [161, 79, 37], "mcl_farming_melon_stem_connected.png": [94, 94, 94], "mcl_farming_pumpkin_pie.png": [172, 98, 45], "mcl_farming_pumpkin_face_preview.png": [166, 81, 38], "mcl_farming_wheat_stage_2.png": [49, 97, 45], "farming_tool_steelhoe.png": [123, 112, 102], "mcl_farming_potatoes_stage_2.png": [72, 116, 62], "mcl_farming_beetroot_3.png": [73, 105, 71], "mcl_farming_wheat_seeds.png": [102, 87, 55], "mcl_farming_hayblock_side.png": [135, 99, 71], "mcl_end_purpur_block.png": [161, 111, 175], "mcl_end_chorus_flower_dead.png": [82, 79, 118], "mcl_end_end_stone.png": [221, 214, 130], "mcl_end_endframe_side.png": [110, 99, 86], "mcl_end_purpur_pillar.png": [157, 108, 171], "mcl_end_chorus_fruit.png": [87, 89, 121], "mcl_end_endframe_eye.png": [135, 36, 18], "mcl_end_chorus_fruit_popped.png": [70, 67, 110], "mcl_end_end_rod_top.png": [123, 75, 97], "mcl_end_endframe_top.png": [95, 85, 74], "mcl_end_purpur_pillar_top.png": [159, 110, 173], "mcl_end_chorus_flower.png": [92, 92, 125], "mcl_end_crystal_item.png": [170, 140, 162], "mcl_end_end_bricks.png": [194, 187, 123], "mcl_end_dragon_egg.png": [55, 34, 32], "mcl_end_ender_eye.png": [130, 33, 17], "mcl_end_chorus_plant.png": [78, 73, 115], "mcl_end_end_rod_bottom.png": [122, 74, 96], "mcl_end_crystal_beam.png": [251, 251, 251], "mcl_end_end_rod_side.png": [242, 202, 177], "mcl_clock_clock_18.png": [152, 123, 81], "mcl_clock_clock_03.png": [160, 129, 88], "mcl_clock_clock_49.png": [155, 122, 79], "mcl_clock_clock_34.png": [140, 115, 76], "mcl_clock_clock_01.png": [161, 129, 88], "mcl_clock_clock_32.png": [141, 116, 77], "mcl_clock_clock_27.png": [142, 117, 78], "mcl_clock_clock_42.png": [147, 119, 79], "mcl_clock_clock_25.png": [145, 119, 78], "mcl_clock_clock_56.png": [160, 126, 81], "mcl_clock_clock_22.png": [146, 119, 79], "mcl_clock_clock_31.png": [141, 116, 76], "mcl_clock_clock_57.png": [161, 127, 83], "mcl_clock_clock_58.png": [157, 127, 86], "mcl_clock_clock_39.png": [146, 119, 79], "mcl_clock_clock_59.png": [160, 128, 86], "mcl_clock_clock_16.png": [157, 125, 80], "mcl_clock_clock_38.png": [141, 117, 78], "mcl_clock_clock_53.png": [158, 124, 80], "mcl_clock_clock_43.png": [149, 121, 80], "mcl_clock_clock_09.png": [161, 127, 81], "mcl_clock_clock_33.png": [141, 116, 76], "mcl_clock_clock_07.png": [162, 128, 83], "mcl_clock_clock_23.png": [148, 121, 80], "mcl_clock_clock_51.png": [156, 123, 80], "mcl_clock_clock_10.png": [158, 127, 85], "mcl_clock_clock_55.png": [160, 126, 81], "mcl_clock_clock_46.png": [152, 122, 81], "mcl_clock_clock_26.png": [142, 117, 79], "mcl_clock_clock_06.png": [157, 127, 86], "mcl_clock_clock_00.png": [162, 129, 87], "mcl_clock_clock_28.png": [141, 116, 77], "mcl_clock_clock_44.png": [150, 120, 79], "mcl_clock_clock_08.png": [160, 127, 81], "mcl_clock_clock_19.png": [152, 122, 80], "mcl_clock_clock_12.png": [159, 127, 83], "mcl_clock_clock_45.png": [153, 123, 81], "mcl_clock_clock_24.png": [147, 120, 80], "mcl_clock_clock_15.png": [157, 125, 81], "mcl_clock_clock_20.png": [150, 121, 79], "mcl_clock_clock_61.png": [160, 129, 88], "mcl_clock_clock_02.png": [159, 129, 89], "mcl_clock_clock_40.png": [147, 120, 79], "mcl_clock_clock_37.png": [143, 118, 79], "mcl_clock_clock_48.png": [155, 123, 79], "mcl_clock_clock_13.png": [159, 126, 82], "mcl_clock_clock_17.png": [156, 125, 81], "mcl_clock_clock_52.png": [156, 123, 80], "mcl_clock_clock_54.png": [156, 125, 84], "mcl_clock_clock_04.png": [159, 128, 87], "mcl_clock_clock_47.png": [154, 122, 80], "mcl_clock_clock_62.png": [159, 129, 89], "mcl_clock_clock_41.png": [147, 120, 79], "mcl_clock_clock_35.png": [140, 115, 76], "mcl_clock_clock_60.png": [159, 128, 87], "mcl_clock_clock_50.png": [155, 123, 80], "mcl_clock_clock_29.png": [142, 117, 78], "mcl_clock_clock_21.png": [150, 122, 81], "mcl_clock_clock_30.png": [140, 115, 76], "mcl_clock_clock_14.png": [157, 125, 81], "mcl_clock_clock_05.png": [160, 128, 85], "mcl_clock_clock_36.png": [141, 116, 77], "mcl_clock_clock_63.png": [161, 129, 88], "mcl_clock_clock_11.png": [160, 127, 82], "mcl_compass_compass_02.png": [116, 107, 104], "mcl_compass_compass_06.png": [117, 107, 104], "mcl_compass_compass_04.png": [117, 106, 104], "mcl_compass_compass_19.png": [116, 106, 103], "mcl_compass_compass_16.png": [114, 106, 104], "mcl_compass_compass_26.png": [117, 107, 104], "mcl_compass_compass_25.png": [117, 107, 105], "mcl_compass_compass_24.png": [117, 107, 105], "mcl_compass_compass_17.png": [115, 106, 104], "mcl_compass_compass_23.png": [117, 107, 105], "mcl_compass_compass_01.png": [115, 107, 104], "mcl_compass_compass_28.png": [116, 107, 104], "mcl_compass_compass_05.png": [117, 106, 104], "mcl_compass_compass_09.png": [117, 107, 104], "mcl_compass_compass_10.png": [117, 107, 105], "mcl_compass_compass_14.png": [116, 107, 105], "mcl_compass_compass_18.png": [117, 107, 104], "mcl_compass_compass_13.png": [117, 106, 104], "mcl_compass_compass_08.png": [117, 107, 104], "mcl_compass_compass_21.png": [117, 107, 104], "mcl_compass_compass_27.png": [117, 106, 104], "mcl_compass_compass_30.png": [116, 107, 104], "mcl_compass_compass_15.png": [115, 106, 104], "mcl_compass_compass_29.png": [115, 106, 104], "mcl_compass_compass_03.png": [116, 106, 104], "mcl_compass_compass_07.png": [117, 107, 104], "mcl_compass_compass_22.png": [117, 107, 105], "mcl_compass_compass_12.png": [117, 106, 104], "mcl_compass_compass_00.png": [114, 107, 104], "mcl_compass_compass_20.png": [116, 106, 104], "mcl_compass_compass_31.png": [115, 107, 104], "mcl_compass_compass_11.png": [117, 106, 104], "mcl_jukebox_record_wait.png": [39, 42, 55], "mcl_jukebox_record_cat.png": [40, 45, 51], "mcl_jukebox_record_mellohi.png": [46, 44, 59], "mcl_jukebox_record_13.png": [51, 47, 51], "mcl_jukebox_record_ward.png": [39, 43, 51], "mcl_jukebox_record_chirp.png": [49, 40, 50], "mcl_jukebox_record_blocks.png": [47, 37, 49], "mcl_jukebox_record_11.png": [41, 40, 52], "mcl_jukebox_record_mall.png": [42, 41, 62], "mcl_jukebox_top.png": [72, 56, 44], "mcl_jukebox_record_strad.png": [45, 45, 57], "mcl_jukebox_record_far.png": [47, 48, 52], "mcl_jukebox_side.png": [94, 74, 57], "mcl_jukebox_record_stal.png": [39, 38, 49], "mcl_fences_fence_acacia.png": [152, 99, 68], "mcl_fences_fence_gate_mask.png": [255, 126, 126], "mcl_fences_fence_gate_spruce.png": [85, 69, 56], "mcl_fences_fence_big_oak.png": [83, 71, 59], "mcl_fences_fence_spruce.png": [84, 67, 54], "mcl_fences_fence_gate_birch.png": [153, 121, 94], "mcl_fences_fence_gate_acacia.png": [155, 102, 70], "mcl_fences_fence_gate_big_oak.png": [85, 73, 61], "mcl_fences_fence_oak.png": [108, 83, 64], "mcl_fences_fence_gate_oak.png": [111, 85, 66], "mcl_fences_fence_jungle.png": [115, 80, 60], "mcl_fences_fence_nether_brick.png": [49, 24, 24], "mcl_fences_fence_birch.png": [151, 119, 93], "mcl_fences_fence_gate_jungle.png": [117, 82, 61], "mcl_fences_fence_mask.png": [255, 126, 126], "mcl_core_leaves_birch.png": [28, 57, 28], "default_mossycobble.png": [100, 105, 94], "default_flint.png": [70, 67, 64], "mcl_core_bowl.png": [78, 61, 47], "mcl_core_bone_block_top.png": [220, 201, 170], "default_acacia_tree.png": [105, 91, 74], "default_steel_block.png": [159, 151, 151], "mcl_core_stonebrick_mossy.png": [81, 101, 76], "default_diamond_block.png": [92, 160, 200], "default_leaves.png": [39, 79, 38], "mcl_core_web.png": [202, 189, 167], "mcl_core_reeds.png": [57, 100, 52], "default_gold_ingot.png": [179, 133, 47], "mcl_core_grass_path_side.png": [113, 89, 62], "mcl_core_red_sand.png": [224, 137, 111], "default_apple.png": [137, 57, 44], "mcl_core_log_birch_top.png": [155, 130, 112], "default_coal_block.png": [51, 49, 51], "mcl_core_andesite_smooth.png": [107, 113, 109], "mcl_core_apple_golden.png": [176, 138, 51], "mcl_core_diorite.png": [153, 149, 146], "mcl_core_granite_smooth.png": [150, 121, 110], "mcl_core_bedrock.png": [91, 77, 66], "mcl_core_planks_spruce.png": [81, 65, 54], "mcl_core_sapling_big_oak.png": [69, 92, 80], "mcl_core_emerald_ore.png": [115, 122, 103], "mcl_core_sandstone_smooth.png": [202, 155, 121], "mcl_core_glass_light_blue.png": [101, 153, 215], "default_brick.png": [139, 87, 75], "mcl_core_redstone_ore.png": [128, 91, 88], "mcl_core_cactus_top.png": [77, 99, 49], "mcl_core_frosted_ice_1.png": [147, 198, 227], "mcl_core_sapling_spruce.png": [55, 72, 53], "mcl_core_stripped_acacia_top.png": [149, 92, 58], "mcl_core_log_spruce_top.png": [97, 71, 57], "mcl_core_glass_lime.png": [126, 203, 24], "mcl_core_lapis_ore.png": [111, 113, 125], "default_junglesapling.png": [64, 88, 39], "default_clay_brick.png": [127, 57, 48], "default_gold_block.png": [192, 147, 59], "default_water_source_animated.png": [37, 98, 129], "mcl_core_glass_yellow.png": [228, 228, 50], "default_acacia_sapling.png": [109, 92, 59], "mcl_core_stripped_acacia_side.png": [155, 96, 61], "mcl_core_sandstone_carved.png": [199, 152, 119], "mcl_core_glass_blue.png": [50, 75, 178], "mcl_core_red_sandstone_normal.png": [198, 120, 104], "mcl_core_glass_gray.png": [75, 75, 75], "mcl_core_leaves_spruce.png": [38, 74, 47], "mcl_core_glass_pink.png": [241, 126, 164], "mcl_core_lapis_block.png": [50, 92, 162], "mcl_core_glass_purple.png": [126, 62, 178], "mcl_core_iron_nugget.png": [156, 151, 145], "default_papyrus.png": [82, 114, 57], "default_dry_grass.png": [100, 94, 54], "mcl_core_stripped_dark_oak_top.png": [91, 78, 68], "mcl_core_glass_silver.png": [153, 153, 153], "mcl_core_andesite.png": [104, 110, 107], "mcl_core_frosted_ice_3.png": [165, 209, 233], "mcl_core_sugar.png": [215, 215, 215], "default_acacia_wood.png": [152, 100, 69], "mcl_core_glass_black.png": [24, 24, 24], "mcl_core_iron_ore.png": [134, 123, 117], "mcl_core_stripped_birch_side.png": [163, 130, 104], "default_clay.png": [124, 124, 124], "mcl_core_stripped_jungle_side.png": [140, 98, 76], "mcl_core_glass_red.png": [153, 50, 50], "mcl_core_grass_block_top.png": [141, 130, 113], "mcl_core_planks_birch.png": [145, 113, 89], "mcl_core_glass_white.png": [254, 254, 254], "mcl_core_stripped_oak_side.png": [119, 94, 71], "mcl_core_glass_cyan.png": [75, 126, 153], "mcl_core_cactus_side.png": [88, 110, 56], "default_ladder.png": [83, 64, 50], "default_dry_grass_side.png": [91, 93, 52], "mcl_core_stripped_jungle_top.png": [143, 101, 78], "mcl_core_ice_packed.png": [165, 211, 231], "mcl_core_frosted_ice_2.png": [153, 202, 229], "default_dry_shrub.png": [118, 88, 69], "mcl_core_red_sandstone_carved.png": [202, 122, 104], "default_tree.png": [95, 75, 57], "default_clay_lump.png": [111, 111, 111], "mcl_core_red_sandstone_top.png": [212, 126, 108], "mcl_core_dirt_podzol_side.png": [101, 79, 63], "mcl_core_red_sandstone_smooth.png": [207, 124, 106], "default_jungletree_top.png": [125, 87, 67], "mcl_core_coal_ore.png": [109, 101, 99], "default_jungleleaves.png": [29, 84, 30], "mcl_core_vine.png": [21, 61, 21], "default_snow.png": [221, 229, 234], "mcl_core_leaves_big_oak.png": [21, 69, 28], "mcl_core_void.png": [59, 59, 59], "default_tree_top.png": [135, 104, 74], "mcl_core_gold_ore.png": [132, 119, 103], "default_steel_ingot.png": [142, 137, 131], "default_sapling.png": [62, 90, 45], "mcl_core_log_birch.png": [194, 184, 174], "mcl_core_stripped_spruce_top.png": [111, 81, 64], "default_water_flowing_animated.png": [38, 101, 129], "mcl_core_emerald_block.png": [44, 138, 39], "default_jungletree.png": [86, 58, 45], "mcl_core_grass_side_snowed.png": [162, 154, 150], "default_stone_brick.png": [97, 89, 86], "default_lava_flowing_animated.png": [177, 42, 16], "mcl_core_stripped_spruce_side.png": [104, 78, 63], "default_coal_lump.png": [41, 39, 41], "default_sand.png": [220, 170, 127], "mcl_core_glass_green.png": [101, 126, 50], "mcl_core_glass_orange.png": [215, 126, 50], "default_acacia_tree_top.png": [130, 84, 55], "mcl_core_stripped_oak_top.png": [139, 108, 78], "mcl_core_grass_block_side_overlay.png": [153, 142, 123], "default_lava_source_animated.png": [180, 45, 17], "mcl_core_cactus_bottom.png": [169, 168, 116], "mcl_core_sandstone_bottom.png": [202, 155, 121], "default_paper.png": [213, 184, 154], "mcl_core_diamond_ore.png": [122, 124, 126], "default_ice.png": [145, 197, 226], "mcl_core_dirt_podzol_top.png": [85, 63, 42], "mcl_core_slime.png": [93, 157, 86], "mcl_core_gold_nugget.png": [213, 169, 74], "default_stick.png": [88, 70, 57], "mcl_core_emerald.png": [59, 160, 52], "default_diamond.png": [109, 179, 217], "mcl_core_mycelium_top.png": [108, 89, 117], "mcl_core_bone_block_side.png": [226, 207, 174], "mcl_core_diorite_smooth.png": [157, 154, 152], "default_obsidian.png": [13, 9, 25], "mcl_core_planks_big_oak.png": [87, 74, 62], "mcl_core_log_spruce.png": [66, 51, 44], "mcl_core_glass_magenta.png": [178, 75, 215], "mcl_core_granite.png": [153, 121, 110], "mcl_core_log_big_oak_top.png": [83, 70, 62], "default_cobble.png": [113, 106, 104], "mcl_core_red_sandstone_bottom.png": [207, 124, 106], "mcl_core_barrier.png": [138, 46, 38], "mcl_core_stripped_dark_oak_side.png": [86, 73, 63], "mcl_core_mycelium_side.png": [107, 84, 87], "mcl_core_stonebrick_cracked.png": [94, 87, 83], "mcl_core_charcoal.png": [40, 35, 32], "mcl_core_glass_brown.png": [101, 75, 50], "mcl_core_stonebrick_carved.png": [97, 90, 85], "default_wood.png": [113, 87, 67], "default_dirt.png": [108, 83, 70], "mcl_core_log_big_oak.png": [74, 62, 55], "default_junglewood.png": [113, 78, 59], "mcl_core_frosted_ice_0.png": [140, 193, 224], "mcl_core_sandstone_normal.png": [195, 149, 117], "default_gravel.png": [112, 105, 99], "mcl_core_sandstone_top.png": [201, 154, 121], "default_glass.png": [213, 223, 235], "default_stone.png": [130, 122, 118], "mcl_core_sapling_birch.png": [78, 110, 74], "mcl_core_coarse_dirt.png": [117, 92, 76], "default_acacia_leaves.png": [110, 89, 45], "mcl_core_stripped_birch_top.png": [157, 126, 102], "mcl_core_grass_path_top.png": [125, 101, 50], "mcl_throwing_ender_pearl.png": [78, 19, 26], "mcl_throwing_egg.png": [199, 157, 106], "mcl_throwing_snowball.png": [191, 200, 203], "mcl_flowers_tulip_red.png": [82, 57, 43], "mcl_flowers_double_plant_rose_top.png": [81, 69, 45], "mcl_flowers_double_plant_sunflower_front.png": [203, 157, 61], "mcl_flowers_tulip_white.png": [106, 122, 95], "mcl_flowers_double_plant_grass_top.png": [156, 145, 125], "mcl_flowers_azure_bluet.png": [97, 114, 98], "mcl_flowers_oxeye_daisy.png": [130, 139, 110], "mcl_flowers_poppy.png": [96, 59, 43], "mcl_flowers_double_plant_paeonia_top.png": [90, 84, 81], "mcl_flowers_double_plant_rose_bottom.png": [78, 63, 41], "mcl_flowers_tallgrass.png": [151, 141, 122], "mcl_flowers_double_plant_sunflower_bottom.png": [45, 76, 40], "mcl_flowers_fern.png": [143, 132, 115], "flowers_tulip.png": [106, 84, 51], "mcl_flowers_double_plant_syringa_bottom.png": [63, 77, 60], "mcl_flowers_double_plant_fern_bottom.png": [140, 130, 113], "flowers_dandelion_yellow.png": [111, 111, 55], "mcl_flowers_double_plant_paeonia_bottom.png": [82, 83, 73], "mcl_flowers_double_plant_sunflower_back.png": [174, 146, 57], "mcl_flowers_allium.png": [120, 116, 144], "flowers_waterlily.png": [28, 81, 29], "mcl_flowers_tulip_pink.png": [100, 99, 90], "mcl_flowers_double_plant_sunflower_top.png": [48, 81, 44], "mcl_flowers_double_plant_syringa_top.png": [95, 90, 98], "mcl_flowers_double_plant_grass_bottom.png": [151, 140, 121], "mcl_flowers_double_plant_grass_inv.png": [48, 95, 43], "mcl_flowers_fern_inv.png": [43, 86, 39], "mcl_flowers_double_plant_fern_top.png": [148, 138, 119], "mcl_flowers_tallgrass_inv.png": [47, 92, 41], "mcl_flowers_double_plant_fern_inv.png": [45, 89, 40], "mcl_flowers_blue_orchid.png": [46, 91, 86], "mcl_armor_leggings_iron.png": [132, 128, 123], "mcl_armor_inv_leggings_iron.png": [130, 125, 120], "mcl_armor_chestplate_chain_preview.png": [124, 98, 90], "mcl_armor_inv_helmet_gold.png": [178, 134, 51], "mcl_armor_leggings_chain.png": [64, 66, 69], "mcl_armor_helmet_chain_preview.png": [154, 150, 143], "mcl_armor_chestplate_diamond_preview.png": [102, 140, 160], "mcl_armor_inv_boots_iron.png": [134, 129, 124], "mcl_armor_boots_gold_preview.png": [178, 133, 42], "mcl_armor_leggings_diamond_preview.png": [80, 118, 138], "mcl_armor_inv_chestplate_chain.png": [128, 105, 96], "mcl_armor_helmet_diamond_preview.png": [101, 134, 152], "mcl_armor_boots_leather_preview.png": [129, 119, 101], "mcl_armor_inv_chestplate_gold.png": [171, 128, 55], "mcl_armor_inv_helmet_diamond.png": [109, 130, 142], "mcl_armor_leggings_leather_preview.png": [141, 134, 114], "mcl_armor_boots_leather.png": [122, 111, 93], "mcl_armor_inv_chestplate_diamond.png": [106, 146, 168], "mcl_armor_helmet_diamond.png": [70, 85, 93], "mcl_armor_chestplate_iron_preview.png": [143, 134, 123], "mcl_armor_inv_chestplate_leather.png": [143, 136, 118], "mcl_armor_boots_diamond.png": [87, 132, 157], "mcl_armor_leggings_diamond.png": [78, 102, 115], "mcl_armor_leggings_gold_preview.png": [185, 156, 108], "mcl_armor_chestplate_gold.png": [157, 117, 55], "mcl_armor_inv_helmet_chain.png": [140, 137, 132], "mcl_armor_boots_chain_preview.png": [78, 78, 79], "mcl_armor_inv_leggings_chain.png": [81, 81, 82], "mcl_armor_inv_helmet_iron.png": [143, 138, 133], "mcl_armor_helmet_leather.png": [130, 121, 102], "mcl_armor_chestplate_diamond.png": [110, 157, 183], "mcl_armor_leggings_leather.png": [119, 108, 91], "mcl_armor_leggings_iron_preview.png": [127, 122, 117], "mcl_armor_inv_boots_gold.png": [187, 142, 46], "mcl_armor_chestplate_leather.png": [139, 132, 112], "mcl_armor_boots_iron.png": [118, 113, 109], "mcl_armor_elytra.png": [75, 121, 147], "mcl_armor_helmet_chain.png": [127, 124, 121], "mcl_armor_helmet_gold_preview.png": [181, 138, 54], "mcl_armor_boots_iron_preview.png": [118, 113, 108], "mcl_armor_helmet_iron.png": [153, 149, 144], "mcl_armor_inv_boots_leather.png": [130, 121, 103], "mcl_armor_leggings_chain_preview.png": [54, 56, 61], "mcl_armor_helmet_iron_preview.png": [143, 138, 132], "mcl_armor_helmet_leather_preview.png": [119, 109, 91], "mcl_armor_chestplate_leather_preview.png": [144, 138, 118], "mcl_armor_leggings_gold.png": [182, 158, 126], "mcl_armor_inv_leggings_gold.png": [175, 145, 97], "mcl_armor_chestplate_iron.png": [130, 120, 112], "mcl_armor_inv_elytra.png": [76, 122, 148], "mcl_armor_boots_chain.png": [88, 88, 88], "mcl_armor_helmet_gold.png": [178, 136, 56], "mcl_armor_inv_boots_diamond.png": [75, 121, 147], "mcl_armor_inv_chestplate_iron.png": [135, 125, 115], "mcl_armor_inv_leggings_diamond.png": [75, 93, 103], "mcl_armor_inv_leggings_leather.png": [126, 116, 98], "mcl_armor_inv_helmet_leather.png": [140, 132, 114], "mcl_armor_inv_boots_chain.png": [69, 69, 72], "mcl_armor_chestplate_gold_preview.png": [169, 127, 56], "mcl_armor_chestplate_chain.png": [119, 98, 93], "mcl_armor_boots_gold.png": [160, 118, 42], "mcl_armor_boots_diamond_preview.png": [89, 141, 169], "mcl_walls_cobble_wall_top.png": [120, 114, 112], "mcl_walls_cobble_mossy_wall_top.png": [53, 97, 61], "mcl_walls_cobble_wall_side.png": [109, 103, 101], "mcl_walls_cobble_mossy_wall_side.png": [86, 98, 83], "mcl_hoppers_item.png": [44, 44, 44], "mcl_hoppers_hopper_top.png": [43, 43, 43], "mcl_hoppers_hopper_outside.png": [44, 43, 43], "mcl_hoppers_hopper_inside.png": [50, 50, 50], "mcl_stairs_stone_slab_top.png": [127, 118, 114], "mcl_stairs_stone_slab_side.png": [127, 117, 113], "mcl_stairs_turntexture.png": [255, 0, 255], "mcl_brewing_bottle_bg.png": [204, 204, 204], "mcl_brewing_bubble_sprite.png": [167, 167, 167], "mcl_brewing_side.png": [175, 156, 160], "mcl_brewing_inventory.png": [168, 168, 168], "mcl_brewing_bubbles_active.png": [186, 186, 186], "mcl_brewing_fuel_bg.png": [200, 200, 200], "mcl_brewing_potion_bg.png": [204, 204, 204], "mcl_brewing_bubbles.png": [154, 154, 154], "mcl_brewing_top.png": [139, 130, 126], "mcl_brewing_base.png": [130, 122, 118], "mcl_brewing_burner.png": [183, 183, 183], "mcl_brewing_burner_active.png": [212, 161, 132], "xpanes_top_glass_cyan.png": [76, 127, 153], "xpanes_top_glass_brown.png": [102, 76, 51], "xpanes_top_glass_magenta.png": [178, 75, 215], "xpanes_top_glass_light_blue.png": [102, 153, 216], "xpanes_top_glass_blue.png": [51, 76, 178], "xpanes_top_glass_gray.png": [76, 76, 76], "xpanes_top_glass_silver.png": [153, 153, 153], "xpanes_top_iron.png": [155, 146, 146], "xpanes_top_glass_black.png": [25, 25, 25], "xpanes_top_glass_white.png": [255, 255, 255], "xpanes_top_glass_lime.png": [127, 204, 25], "xpanes_top_glass_orange.png": [216, 127, 51], "xpanes_top_glass_purple.png": [127, 63, 178], "xpanes_top_glass_red.png": [153, 51, 51], "xpanes_top_glass_natural.png": [222, 222, 239], "xpanes_top_glass_green.png": [102, 127, 51], "xpanes_top_glass_pink.png": [241, 126, 164], "xpanes_pane_iron.png": [160, 152, 152], "xpanes_top_glass_yellow.png": [229, 229, 51], "hardened_clay_stained_pink.png": [164, 79, 76], "mcl_colorblocks_glazed_terracotta_yellow.png": [232, 199, 99], "mcl_colorblocks_glazed_terracotta_orange.png": [170, 146, 81], "mcl_colorblocks_concrete_powder_lime.png": [125, 186, 42], "mcl_colorblocks_concrete_brown.png": [98, 60, 32], "mcl_colorblocks_concrete_magenta.png": [171, 49, 162], "mcl_colorblocks_glazed_terracotta_magenta.png": [210, 108, 215], "mcl_colorblocks_concrete_silver.png": [128, 129, 118], "mcl_colorblocks_glazed_terracotta_grey.png": [90, 90, 90], "mcl_colorblocks_concrete_powder_blue.png": [72, 75, 169], "mcl_colorblocks_concrete_yellow.png": [241, 177, 21], "mcl_colorblocks_concrete_red.png": [146, 34, 34], "mcl_colorblocks_glazed_terracotta_lime.png": [152, 211, 72], "mcl_colorblocks_concrete_black.png": [8, 10, 15], "mcl_colorblocks_glazed_terracotta_silver.png": [134, 151, 151], "hardened_clay_stained_white.png": [213, 197, 184], "mcl_colorblocks_glazed_terracotta_green.png": [111, 135, 50], "mcl_colorblocks_glazed_terracotta_blue.png": [34, 65, 117], "mcl_colorblocks_concrete_powder_red.png": [172, 57, 52], "mcl_colorblocks_concrete_powder_cyan.png": [38, 150, 159], "hardened_clay_stained_purple.png": [81, 71, 123], "hardened_clay_stained_brown.png": [96, 69, 61], "hardened_clay_stained_grey.png": [110, 92, 85], "mcl_colorblocks_concrete_lime.png": [96, 171, 25], "hardened_clay_stained_blue.png": [68, 91, 143], "mcl_colorblocks_concrete_powder_white.png": [224, 225, 225], "hardened_clay_stained_yellow.png": [177, 128, 51], "hardened_clay_stained_light_blue.png": [91, 128, 171], "hardened_clay.png": [143, 104, 87], "mcl_colorblocks_concrete_cyan.png": [21, 123, 140], "mcl_colorblocks_glazed_terracotta_brown.png": [108, 88, 64], "mcl_colorblocks_concrete_grey.png": [56, 59, 64], "mcl_colorblocks_concrete_powder_magenta.png": [196, 94, 189], "mcl_colorblocks_concrete_powder_black.png": [22, 26, 30], "mcl_colorblocks_concrete_pink.png": [213, 103, 144], "mcl_colorblocks_concrete_powder_orange.png": [227, 141, 38], "mcl_colorblocks_glazed_terracotta_cyan.png": [90, 131, 136], "mcl_colorblocks_glazed_terracotta_red.png": [184, 67, 53], "mcl_colorblocks_concrete_green.png": [75, 94, 37], "mcl_colorblocks_concrete_blue.png": [46, 48, 147], "mcl_colorblocks_glazed_terracotta_light_blue.png": [99, 162, 204], "hardened_clay_stained_orange.png": [156, 95, 69], "mcl_colorblocks_concrete_powder_silver.png": [160, 160, 155], "mcl_colorblocks_concrete_powder_pink.png": [224, 148, 176], "hardened_clay_stained_silver.png": [149, 129, 117], "hardened_clay_stained_red.png": [159, 81, 66], "hardened_clay_stained_magenta.png": [150, 80, 85], "mcl_colorblocks_glazed_terracotta_black.png": [38, 22, 22], "mcl_colorblocks_concrete_white.png": [208, 214, 215], "hardened_clay_stained_green.png": [74, 101, 63], "hardened_clay_stained_lime.png": [105, 134, 73], "mcl_colorblocks_concrete_powder_green.png": [104, 127, 45], "mcl_colorblocks_concrete_light_blue.png": [37, 140, 200], "mcl_colorblocks_concrete_powder_brown.png": [128, 86, 54], "mcl_colorblocks_concrete_purple.png": [103, 32, 159], "hardened_clay_stained_cyan.png": [71, 107, 123], "mcl_colorblocks_concrete_powder_purple.png": [138, 58, 180], "mcl_colorblocks_concrete_powder_yellow.png": [230, 198, 54], "mcl_colorblocks_concrete_powder_light_blue.png": [75, 181, 212], "mcl_colorblocks_glazed_terracotta_pink.png": [251, 138, 170], "mcl_colorblocks_glazed_terracotta_purple.png": [112, 49, 152], "mcl_colorblocks_concrete_orange.png": [226, 101, 1], "mcl_colorblocks_concrete_powder_grey.png": [91, 98, 103], "hardened_clay_stained_black.png": [69, 52, 46], "mcl_colorblocks_glazed_terracotta_white.png": [188, 211, 202], "fire_basic_flame_animated.png": [206, 98, 34], "mcl_burning_hud_flame_animated.png": [206, 98, 34], "mcl_fire_fire_charge.png": [95, 58, 41], "mcl_burning_entity_flame_animated.png": [206, 98, 34], "mcl_fire_flint_and_steel.png": [96, 95, 93], "fire_basic_flame.png": [207, 100, 36], "dye_red.png": [113, 74, 47], "dye_yellow.png": [123, 91, 49], "dye_violet.png": [107, 76, 57], "dye_dark_green.png": [99, 81, 47], "mcl_dye_blue.png": [58, 101, 173], "dye_cyan.png": [104, 89, 60], "mcl_dye_lime.png": [107, 91, 53], "dye_pink.png": [120, 81, 61], "mcl_dye_light_blue.png": [103, 88, 70], "dye_dark_grey.png": [108, 81, 52], "mcl_dye_white.png": [205, 193, 166], "dye_grey.png": [113, 86, 58], "dye_magenta.png": [111, 79, 59], "dye_orange.png": [122, 85, 48], "mcl_dye_brown.png": [104, 75, 56], "mcl_dye_black.png": [56, 56, 64], "default_river_water_flowing_animated.png": [38, 123, 130], "default_river_water_source_animated.png": [37, 120, 130], "3d_armor_stand_item.png": [134, 114, 98], "mob_spawner.png": [40, 40, 40], "mcl_nether_quartz_chiseled_side.png": [194, 186, 183], "mcl_nether_quartz_pillar_top.png": [195, 188, 185], "mcl_nether_nether_wart.png": [190, 79, 75], "mcl_nether_nether_wart_stage_1.png": [86, 54, 51], "mcl_nether_quartz_ore.png": [133, 64, 53], "mcl_nether_soul_sand.png": [90, 70, 51], "mcl_nether_nether_wart_block.png": [175, 76, 73], "mcl_nether_nether_wart_stage_0.png": [53, 41, 38], "mcl_nether_quartz_block_bottom.png": [198, 191, 187], "mcl_nether_quartz_block_top.png": [198, 190, 187], "mcl_nether_quartz.png": [152, 149, 147], "mcl_nether_quartz_pillar_side.png": [195, 188, 184], "mcl_nether_netherbrick.png": [58, 24, 20], "mcl_nether_glowstone.png": [202, 154, 96], "mcl_nether_netherrack.png": [130, 50, 39], "mcl_nether_red_nether_brick.png": [69, 17, 5], "mcl_nether_quartz_chiseled_top.png": [197, 189, 186], "mcl_nether_glowstone_dust.png": [209, 137, 67], "mcl_nether_nether_wart_stage_2.png": [106, 57, 53], "mcl_nether_quartz_block_side.png": [198, 190, 187], "mcl_nether_nether_brick.png": [49, 23, 24], "mcl_nether_magma.png": [85, 33, 27], "mcl_cauldrons_cauldron_inner.png": [24, 24, 24], "mcl_cauldrons_cauldron_top.png": [54, 54, 54], "mcl_cauldrons_cauldron_bottom.png": [50, 37, 38], "mcl_cauldrons_cauldron.png": [47, 47, 47], "mcl_cauldrons_cauldron_side.png": [43, 43, 43], "mcl_beds_bed_side_bottom_magenta.png": [127, 48, 89], "mcl_beds_bed_blue.png": [73, 78, 105], "mcl_beds_bed_side_top_r_black.png": [99, 86, 75], "mcl_beds_bed_side_bottom_r_magenta.png": [132, 46, 94], "mcl_beds_bed_side_top_brown.png": [98, 76, 59], "mcl_beds_bed_lime.png": [96, 135, 66], "mcl_beds_bed_side_top_green.png": [98, 76, 59], "mcl_beds_bed_light_blue.png": [100, 107, 142], "mcl_beds_bed_pink.png": [184, 105, 115], "mcl_beds_bed_side_bottom_black.png": [66, 56, 47], "mcl_beds_bed_top_bottom_green.png": [57, 110, 29], "mcl_beds_bed_side_top_blue.png": [98, 76, 59], "mcl_beds_bed_top_top_pink.png": [217, 138, 147], "mcl_beds_bed_side_bottom_light_blue.png": [90, 94, 129], "mcl_beds_bed_side_bottom_blue.png": [63, 65, 90], "mcl_beds_bed_top_top_red.png": [173, 90, 83], "mcl_beds_bed_side_top_grey.png": [98, 76, 59], "mcl_beds_bed_top_top_white.png": [198, 190, 183], "mcl_beds_bed_top_top_black.png": [107, 100, 92], "mcl_beds_bed_top_bottom_brown.png": [101, 69, 38], "mcl_beds_bed_top_bottom_pink.png": [232, 105, 135], "mcl_beds_bed_side_bottom_r_pink.png": [183, 95, 106], "mcl_beds_bed_side_bottom_r_green.png": [73, 97, 42], "mcl_beds_bed_side_bottom_r_grey.png": [86, 77, 69], "mcl_beds_bed_side_top_r_white.png": [158, 145, 134], "mcl_beds_bed_side_bottom_orange.png": [143, 84, 28], "mcl_beds_bed_side_bottom_purple.png": [105, 36, 112], "mcl_beds_bed_side_bottom_r_light_blue.png": [90, 97, 136], "mcl_beds_bed_side_top_r_magenta.png": [140, 81, 103], "mcl_beds_bed_side_bottom_r_yellow.png": [150, 131, 25], "mcl_beds_bed_side_top_r_pink.png": [176, 111, 113], "mcl_beds_bed_top_top_blue.png": [105, 112, 137], "mcl_beds_bed_side_bottom_green.png": [74, 94, 43], "mcl_beds_bed_side_bottom_r_blue.png": [61, 66, 95], "mcl_beds_bed_top_top_grey.png": [129, 121, 113], "mcl_beds_bed_black.png": [76, 68, 61], "mcl_beds_bed_top_top_silver.png": [159, 151, 143], "mcl_beds_bed_white.png": [173, 165, 158], "mcl_beds_bed_top_top_cyan.png": [105, 144, 135], "mcl_beds_bed_top_bottom_orange.png": [184, 91, 0], "mcl_beds_bed_side_top_silver.png": [98, 76, 59], "mcl_beds_bed_top_top_brown.png": [143, 118, 93], "mcl_beds_bed_side_top_r_light_blue.png": [115, 111, 132], "mcl_beds_bed_side_bottom_r_lime.png": [86, 129, 53], "mcl_beds_bed_red.png": [139, 58, 51], "mcl_beds_bed_top_bottom_lime.png": [79, 163, 47], "mcl_beds_bed_side_top_r_brown.png": [121, 97, 75], "mcl_beds_bed_side_bottom_r_silver.png": [119, 109, 102], "mcl_beds_bed_yellow.png": [154, 138, 41], "mcl_beds_bed_side_top_yellow.png": [98, 76, 59], "mcl_beds_bed_top_bottom_black.png": [37, 37, 37], "mcl_beds_bed_brown.png": [110, 85, 61], "mcl_beds_bed_side_top_orange.png": [98, 76, 59], "mcl_beds_bed_side_top_red.png": [98, 76, 59], "mcl_beds_bed_top_top_purple.png": [148, 79, 161], "mcl_beds_bed_side_bottom_pink.png": [177, 93, 102], "mcl_beds_bed_side_top_r_grey.png": [112, 99, 88], "mcl_beds_bed_side_top_r_blue.png": [97, 91, 104], "mcl_beds_bed_side_top_purple.png": [98, 76, 59], "mcl_beds_bed_side_top_cyan.png": [98, 76, 59], "mcl_beds_bed_top_bottom_blue.png": [32, 60, 119], "mcl_beds_bed_side_bottom_yellow.png": [143, 125, 28], "mcl_beds_bed_side_top_black.png": [98, 76, 59], "mcl_beds_bed_top_top_orange.png": [188, 130, 72], "mcl_beds_bed_top_bottom_silver.png": [129, 129, 129], "mcl_beds_bed_top_top_green.png": [117, 140, 88], "mcl_beds_bed_cyan.png": [73, 111, 103], "mcl_beds_bed_top_bottom_red.png": [157, 20, 20], "mcl_beds_bed_top_bottom_purple.png": [111, 0, 163], "mcl_beds_bed_side_top_r_silver.png": [133, 120, 109], "mcl_beds_bed_side_bottom_grey.png": [86, 76, 67], "mcl_beds_bed_grey.png": [96, 88, 81], "mcl_beds_bed_side_top_r_yellow.png": [151, 132, 62], "mcl_beds_bed_side_top_r_green.png": [103, 111, 72], "mcl_beds_bed_side_bottom_brown.png": [100, 73, 48], "mcl_beds_bed_magenta.png": [138, 60, 104], "mcl_beds_bed_side_bottom_r_red.png": [134, 44, 37], "mcl_beds_bed_side_bottom_r_brown.png": [101, 73, 47], "mcl_beds_bed_side_top_lime.png": [98, 76, 59], "mcl_beds_bed_side_top_light_blue.png": [98, 76, 59], "mcl_beds_bed_side_bottom_red.png": [129, 47, 38], "mcl_beds_bed_bottom_top.png": [48, 38, 29], "mcl_beds_bed_top_bottom_grey.png": [76, 76, 76], "mcl_beds_bed_side_bottom_r_orange.png": [150, 86, 25], "mcl_beds_bed_side_bottom_r_black.png": [64, 54, 47], "mcl_beds_bed_top_bottom_cyan.png": [32, 119, 114], "mcl_beds_bed_side_bottom_silver.png": [116, 106, 97], "mcl_beds_bed_side_top_magenta.png": [98, 76, 59], "mcl_beds_bed_top_bottom_white.png": [201, 201, 201], "mcl_beds_bed_side_top_r_orange.png": [151, 105, 62], "mcl_beds_bed_top_bottom_magenta.png": [154, 23, 118], "mcl_beds_bed_side_top_r_lime.png": [110, 131, 80], "mcl_beds_bed_top_top_magenta.png": [172, 92, 137], "mcl_beds_bed_bottom_bottom.png": [48, 38, 29], "mcl_beds_bed_side_top_r_purple.png": [125, 73, 119], "mcl_beds_bed_side_top_r_cyan.png": [97, 113, 103], "mcl_beds_bed_side_top_white.png": [98, 76, 59], "mcl_beds_bed_side_bottom_r_cyan.png": [61, 101, 93], "mcl_beds_bed_side_bottom_cyan.png": [63, 97, 89], "mcl_beds_bed_side_bottom_white.png": [161, 151, 142], "mcl_beds_bed_top_bottom_yellow.png": [184, 169, 0], "mcl_beds_bed_top_bottom_light_blue.png": [82, 113, 182], "mcl_beds_bed_top_top_lime.png": [130, 169, 98], "mcl_beds_bed_silver.png": [109, 100, 93], "mcl_beds_bed_purple.png": [115, 47, 128], "mcl_beds_bed_side_top_r_red.png": [141, 80, 69], "mcl_beds_bed_top_top_light_blue.png": [132, 141, 174], "mcl_beds_bed_side_bottom_r_purple.png": [107, 32, 120], "mcl_beds_bed_side_bottom_r_white.png": [161, 151, 144], "mcl_beds_bed_orange.png": [154, 96, 41], "mcl_beds_bed_top_bottom_gray.png": [57, 57, 57], "mcl_beds_bed_side_bottom_lime.png": [85, 122, 53], "mcl_beds_bed_green.png": [85, 107, 56], "mcl_beds_bed_top_top_yellow.png": [188, 172, 72], "mcl_beds_bed_side_top_pink.png": [98, 76, 59], "mcl_sponges_sponge_wet_river_water.png": [157, 141, 104], "mcl_sponges_sponge.png": [210, 177, 118], "mcl_sponges_sponge_wet.png": [156, 134, 92], "farming_mushroom_red.png": [169, 59, 58], "mcl_mushrooms_mushroom_block_inside.png": [218, 175, 136], "mcl_mushrooms_mushroom_block_skin_brown.png": [131, 86, 68], "mcl_mushrooms_mushroom_block_skin_stem.png": [204, 183, 149], "mcl_mushrooms_mushroom_block_skin_red.png": [137, 39, 25], "farming_mushroom_brown.png": [121, 81, 59], "farming_mushroom_stew.png": [134, 97, 67], "default_tool_goldsword.png": [194, 154, 70], "default_tool_steelsword.png": [134, 130, 125], "default_tool_woodsword.png": [100, 82, 68], "default_tool_goldshovel.png": [167, 133, 64], "default_tool_steelpick.png": [137, 128, 119], "default_tool_woodshovel.png": [108, 90, 76], "default_tool_goldpick.png": [172, 139, 73], "default_tool_woodaxe.png": [110, 92, 77], "default_tool_diamondsword.png": [105, 133, 149], "default_tool_steelshovel.png": [125, 115, 107], "default_tool_stonesword.png": [133, 125, 118], "default_tool_woodpick.png": [110, 91, 76], "default_tool_shears.png": [139, 132, 124], "default_tool_goldaxe.png": [160, 128, 66], "default_tool_stoneshovel.png": [126, 116, 107], "default_tool_diamondaxe.png": [103, 110, 113], "default_tool_diamondshovel.png": [106, 125, 134], "default_tool_steelaxe.png": [129, 119, 110], "default_tool_stoneaxe.png": [126, 115, 104], "default_tool_diamondpick.png": [92, 105, 111], "default_tool_stonepick.png": [126, 114, 104], "mcl_chests_ender_chest_right.png": [73, 67, 64], "mcl_chests_chest_trapped_right.png": [98, 78, 62], "default_chest_front.png": [85, 70, 58], "mcl_chests_blue_shulker_box_top.png": [67, 85, 119], "mcl_chests_chest_left.png": [99, 78, 63], "mcl_chests_dark_green_shulker_box_top.png": [67, 111, 70], "mcl_chests_chest_back.png": [92, 75, 61], "mcl_chests_ender_chest_bottom.png": [61, 55, 55], "mcl_chests_ender.png": [70, 62, 58], "mcl_chests_brown_shulker_box_top.png": [73, 63, 55], "mcl_chests_chest_trapped_back.png": [92, 75, 61], "mcl_chests_chest_trapped_side_big.png": [96, 77, 62], "mcl_chests_magenta_shulker_box_top.png": [128, 81, 124], "mcl_chests_ender_chest_back.png": [72, 66, 64], "mcl_chests_chest_trapped_bottom.png": [118, 91, 70], "mcl_chests_chest_trapped_front.png": [86, 68, 57], "default_chest_side_big.png": [96, 77, 62], "mcl_chests_green_shulker_box_top.png": [88, 122, 75], "mcl_chests_pink_shulker_box_top.png": [163, 116, 158], "mcl_chests_trapped.png": [95, 76, 61], "mcl_chests_blank.png": [255, 255, 255], "mcl_chests_normal_double.png": [98, 78, 62], "mcl_chests_chest_trapped_top.png": [88, 73, 61], "mcl_chests_normal.png": [95, 76, 61], "default_chest_front_big.png": [93, 75, 61], "mcl_chests_ender_chest_front.png": [76, 69, 65], "mcl_chests_white_shulker_box_top.png": [176, 178, 187], "mcl_chests_cyan_shulker_box_top.png": [67, 101, 121], "mcl_chests_chest_trapped_top_big.png": [100, 80, 65], "default_chest_top_big.png": [100, 80, 65], "mcl_chests_grey_shulker_box_top.png": [126, 129, 138], "mcl_chests_red_shulker_box_top.png": [132, 58, 57], "mcl_chests_trapped_double.png": [98, 78, 62], "mcl_chests_violet_shulker_box_top.png": [120, 71, 88], "mcl_chests_chest_trapped_front_big.png": [94, 75, 61], "mcl_chests_lightblue_shulker_box_top.png": [96, 130, 155], "mcl_chests_dark_grey_shulker_box_top.png": [87, 90, 99], "mcl_chests_black_shulker_box_top.png": [56, 57, 62], "mcl_chests_chest_right.png": [98, 78, 62], "mcl_chests_yellow_shulker_box_top.png": [165, 116, 53], "mcl_chests_chest_bottom.png": [118, 91, 70], "default_chest_top.png": [88, 73, 61], "mcl_chests_ender_chest_top.png": [70, 64, 61], "mcl_chests_ender_chest_left.png": [73, 67, 64], "mcl_chests_chest_trapped_left.png": [99, 78, 63], "mcl_chests_orange_shulker_box_top.png": [143, 74, 51], "screwdriver.png": [132, 119, 108], "_un.png": [0, 0, 0], "_at.png": [0, 0, 0], "_s_.png": [0, 0, 0], "_sz.png": [0, 0, 0], "_q.png": [0, 0, 0], "_1.png": [0, 0, 0], "_h_.png": [0, 0, 0], "_o_tilde.png": [0, 0, 0], "_q_.png": [0, 0, 0], "_ae.png": [0, 0, 0], "_e_circumflex_.png": [0, 0, 0], "_ex.png": [0, 0, 0], "_e_.png": [0, 0, 0], "_qo.png": [0, 0, 0], "_z_.png": [0, 0, 0], "_ps.png": [0, 0, 0], "_pound.png": [0, 0, 0], "_div.png": [0, 0, 0], "_l_.png": [0, 0, 0], "_pilcrow.png": [0, 0, 0], "_3_sup.png": [0, 0, 0], "_e_acute.png": [0, 0, 0], "_9.png": [0, 0, 0], "_e_grave_.png": [0, 0, 0], "_u_acute.png": [0, 0, 0], "_a_sup.png": [0, 0, 0], "_sr.png": [0, 0, 0], "_v.png": [0, 0, 0], "_ue_.png": [0, 0, 0], "_t_.png": [0, 0, 0], "_cl.png": [0, 0, 0], "_n_tilde_.png": [0, 0, 0], "_p_.png": [0, 0, 0], "_c.png": [0, 0, 0], "_a.png": [0, 0, 0], "_a_circumflex_.png": [0, 0, 0], "_8.png": [0, 0, 0], "_s.png": [0, 0, 0], "_o_.png": [0, 0, 0], "_1_4.png": [0, 0, 0], "_e_grave.png": [0, 0, 0], "_o_dash.png": [0, 0, 0], "_5.png": [0, 0, 0], "_d_dash_.png": [0, 0, 0], "_i_grave.png": [0, 0, 0], "_vb.png": [0, 0, 0], "_sp.png": [255, 255, 255], "_a_acute_.png": [0, 0, 0], "_as.png": [0, 0, 0], "_y_acute.png": [0, 0, 0], "_3_4.png": [0, 0, 0], "_6.png": [0, 0, 0], "_7.png": [0, 0, 0], "_tl.png": [0, 0, 0], "_t.png": [0, 0, 0], "_y.png": [0, 0, 0], "_ca.png": [0, 0, 0], "_e.png": [0, 0, 0], "_hs.png": [0, 0, 0], "_copyright.png": [0, 0, 0], "_l.png": [0, 0, 0], "_h.png": [0, 0, 0], "_u_circumflex_.png": [0, 0, 0], "_i_acute_.png": [0, 0, 0], "_ha.png": [0, 0, 0], "_y_diaresis.png": [0, 0, 0], "_gt.png": [0, 0, 0], "_b.png": [0, 0, 0], "_degree.png": [0, 0, 0], "_a_tilde_.png": [0, 0, 0], "_u_.png": [0, 0, 0], "_o_sup.png": [0, 0, 0], "_m_.png": [0, 0, 0], "_c_.png": [0, 0, 0], "_cr.png": [0, 0, 0], "_3.png": [0, 0, 0], "_currency.png": [0, 0, 0], "_f.png": [0, 0, 0], "_cedille.png": [0, 0, 0], "_u_grave_.png": [0, 0, 0], "_dt.png": [0, 0, 0], "_am.png": [0, 0, 0], "_c_cedille_.png": [0, 0, 0], "_u_acute_.png": [0, 0, 0], "_bl.png": [0, 0, 0], "_registered.png": [0, 0, 0], "_i_acute.png": [0, 0, 0], "_lt.png": [0, 0, 0], "_e_acute_.png": [0, 0, 0], "_paragraph.png": [0, 0, 0], "_i_grave_.png": [0, 0, 0], "_o.png": [0, 0, 0], "_1_sup.png": [0, 0, 0], "mcl_signs_sign.png": [114, 89, 69], "_yen.png": [0, 0, 0], "_b_.png": [0, 0, 0], "_macron.png": [0, 0, 0], "_qu_inv.png": [0, 0, 0], "_o_dash_.png": [0, 0, 0], "_guill_right.png": [0, 0, 0], "_p.png": [0, 0, 0], "_thorn_.png": [0, 0, 0], "_2_sup.png": [0, 0, 0], "_pr.png": [0, 0, 0], "default_sign.png": [145, 115, 88], "_times_dot.png": [0, 0, 0], "_acute.png": [0, 0, 0], "_g_.png": [0, 0, 0], "_o_acute_.png": [0, 0, 0], "_a_tilde.png": [0, 0, 0], "_j.png": [0, 0, 0], "_k.png": [0, 0, 0], "_co.png": [0, 0, 0], "_dv.png": [0, 0, 0], "_o_circumflex.png": [0, 0, 0], "_a_ring.png": [0, 0, 0], "_br.png": [0, 0, 0], "_d.png": [0, 0, 0], "_ap.png": [0, 0, 0], "_sl.png": [0, 0, 0], "_mn.png": [0, 0, 0], "_m.png": [0, 0, 0], "_ae_lig.png": [0, 0, 0], "_thorn.png": [0, 0, 0], "_2.png": [0, 0, 0], "_gr.png": [0, 0, 0], "_i.png": [0, 0, 0], "_y_acute_.png": [0, 0, 0], "_diaresis.png": [0, 0, 0], "_oe.png": [0, 0, 0], "_mu.png": [0, 0, 0], "_guill_left.png": [0, 0, 0], "_times_cross.png": [0, 0, 0], "_ae_.png": [0, 0, 0], "_w.png": [0, 0, 0], "_u.png": [0, 0, 0], "_broken_bar.png": [0, 0, 0], "_4.png": [0, 0, 0], "_plus_minus.png": [0, 0, 0], "_1_2.png": [0, 0, 0], "_u_circumflex.png": [0, 0, 0], "_w_.png": [0, 0, 0], "_x_.png": [0, 0, 0], "_e_circumflex.png": [0, 0, 0], "_g.png": [0, 0, 0], "_o_tilde_.png": [0, 0, 0], "_ae_lig_.png": [0, 0, 0], "_v_.png": [0, 0, 0], "_dl.png": [0, 0, 0], "_a_grave.png": [0, 0, 0], "_re.png": [0, 0, 0], "_a_acute.png": [0, 0, 0], "_qu.png": [0, 0, 0], "_oe_.png": [0, 0, 0], "_n_tilde.png": [0, 0, 0], "_eq.png": [0, 0, 0], "_d_.png": [0, 0, 0], "_sm.png": [0, 0, 0], "_y_.png": [0, 0, 0], "_not.png": [0, 0, 0], "_n.png": [0, 0, 0], "_j_.png": [0, 0, 0], "_k_.png": [0, 0, 0], "_0.png": [0, 0, 0], "_o_grave_.png": [0, 0, 0], "_r_.png": [0, 0, 0], "_r.png": [0, 0, 0], "_u_grave.png": [0, 0, 0], "_ee_.png": [0, 0, 0], "_c_cedille.png": [0, 0, 0], "_ex_inv.png": [0, 0, 0], "_cm.png": [0, 0, 0], "_o_grave.png": [0, 0, 0], "_x.png": [0, 0, 0], "_i_.png": [0, 0, 0], "_n_.png": [0, 0, 0], "_rc.png": [0, 0, 0], "_a_.png": [0, 0, 0], "_a_grave_.png": [0, 0, 0], "_ee.png": [0, 0, 0], "_o_acute.png": [0, 0, 0], "_a_ring_.png": [0, 0, 0], "_i_circumflex_.png": [0, 0, 0], "_cent.png": [0, 0, 0], "_d_dash.png": [0, 0, 0], "_f_.png": [0, 0, 0], "_o_circumflex_.png": [0, 0, 0], "_ue.png": [0, 0, 0], "_a_circumflex.png": [0, 0, 0], "_i_circumflex.png": [0, 0, 0], "_z.png": [0, 0, 0], "gui_furnace_arrow_fg.png": [239, 239, 239], "default_furnace_front.png": [105, 95, 91], "default_furnace_fire_bg.png": [139, 139, 139], "default_furnace_top.png": [148, 138, 133], "default_furnace_fire_fg.png": [179, 115, 70], "default_furnace_side.png": [117, 107, 102], "gui_furnace_arrow_bg.png": [139, 139, 139], "default_furnace_front_active.png": [119, 95, 85], "default_furnace_bottom.png": [148, 138, 133], "default_torch_on_floor.png": [115, 82, 59], "default_torch_on_floor_animated.png": [116, 84, 61], "default_tnt_bottom.png": [161, 54, 58], "mcl_tnt_blink.png": [255, 255, 255], "default_tnt_top.png": [125, 54, 57], "default_tnt_side.png": [178, 105, 98], "mcl_heads_skeleton.png": [125, 125, 125], "mcl_heads_skeleton_node.png": [124, 124, 124], "mcl_heads_creeper_node.png": [98, 107, 71], "mcl_heads_zombie.png": [66, 104, 69], "mcl_heads_creeper.png": [92, 110, 68], "mcl_heads_steve_node.png": [115, 70, 58], "mcl_heads_skeleton_preview.png": [128, 127, 127], "mcl_heads_steve_preview.png": [117, 83, 66], "mcl_heads_zombie_node.png": [78, 110, 105], "mcl_heads_steve.png": [108, 76, 59], "mcl_heads_wither_skeleton_node.png": [50, 50, 50], "mcl_heads_zombie_preview.png": [66, 103, 68], "mcl_heads_creeper_preview.png": [88, 110, 65], "mcl_heads_wither_skeleton.png": [50, 50, 50], "mcl_heads_wither_skeleton_preview.png": [50, 50, 50], "mcl_flowerpots_cactus.png": [109, 83, 52], "mcl_flowerpots_flowerpot_inventory.png": [121, 54, 45], "mcl_flowerpots_flowerpot.png": [120, 55, 47], "bucket_lava.png": [166, 127, 113], "bucket_river_water.png": [139, 152, 155], "bucket_water.png": [139, 147, 155], "bucket.png": [147, 143, 139], "mcl_anvils_anvil_top_damaged_1.png": [48, 48, 48], "mcl_anvils_anvil_top_damaged_2.png": [46, 46, 46], "mcl_anvils_anvil_top_damaged_0.png": [50, 50, 50], "mcl_anvils_anvil_side.png": [45, 45, 45], "mcl_anvils_inventory.png": [157, 157, 157], "mcl_anvils_anvil_base.png": [40, 40, 40], "mcl_maps_map_filled.png": [213, 176, 148], "mcl_maps_map_empty.png": [217, 187, 157], "mcl_maps_map_filled_markings.png": [183, 183, 183], "mcl_dispensers_dispenser_front_vertical.png": [115, 104, 99], "mcl_dispensers_dispenser_front_horizontal.png": [105, 96, 92], "jeija_wall_lever.png": [95, 80, 69], "mesecons_delayer_front_locked_off.png": [97, 85, 77], "mesecons_delayer_locked_on.png": [114, 100, 95], "mesecons_delayer_sides_locked_off.png": [95, 80, 73], "mesecons_delayer_sides_on.png": [106, 71, 63], "mesecons_delayer_item.png": [100, 87, 82], "mesecons_delayer_end_locked_off.png": [97, 85, 77], "mesecons_delayer_end_locked_on.png": [101, 85, 78], "mesecons_delayer_ends_off.png": [99, 86, 80], "mesecons_delayer_front_locked_on.png": [101, 85, 77], "mesecons_delayer_ends_on.png": [105, 87, 81], "mesecons_delayer_sides_locked_on.png": [104, 81, 74], "mesecons_delayer_locked_off.png": [110, 99, 95], "mesecons_delayer_sides_off.png": [90, 69, 61], "mesecons_delayer_off.png": [112, 100, 96], "mesecons_delayer_on.png": [116, 101, 97], "redstone_redstone_dust_line0.png": [168, 168, 168], "redstone_redstone_dust.png": [81, 0, 0], "redstone_redstone_dust_dot.png": [168, 168, 168], "redstone_redstone_dust_line1.png": [173, 173, 173], "jeija_commandblock_off.png": [110, 99, 96], "jeija_commandblock_on.png": [110, 99, 96], "redstone_redstone_block.png": [128, 8, 9], "jeija_torches_on.png": [102, 68, 56], "jeija_torches_off.png": [90, 66, 54], "mesecons_button_wield_mask.png": [255, 126, 126], "mcl_droppers_dropper_front_vertical.png": [118, 108, 103], "mcl_droppers_dropper_front_horizontal.png": [110, 101, 96], "mesecons_noteblock.png": [104, 81, 63], "jeija_solar_panel_inverted.png": [100, 107, 117], "jeija_solar_panel.png": [124, 113, 101], "jeija_solar_panel_side.png": [60, 47, 36], "mcl_observers_observer_top.png": [139, 128, 123], "mcl_observers_observer_front.png": [95, 80, 84], "mcl_observers_observer_back_lit.png": [75, 67, 65], "mcl_observers_observer_back.png": [72, 67, 64], "mcl_observers_observer_side.png": [111, 103, 99], "mesecons_piston_pusher_front_sticky.png": [97, 81, 63], "mesecons_piston_pusher_top.png": [106, 83, 65], "mesecons_piston_back.png": [110, 101, 98], "mesecons_piston_on_front.png": [111, 101, 98], "mesecons_piston_pusher_back.png": [106, 83, 65], "mesecons_piston_bottom.png": [120, 107, 100], "mesecons_piston_pusher_right.png": [106, 83, 65], "mesecons_piston_pusher_bottom.png": [106, 83, 65], "mesecons_piston_pusher_front.png": [106, 83, 65], "mesecons_piston_pusher_left.png": [106, 83, 65], "jeija_lightstone_gray_on.png": [97, 56, 37], "jeija_lightstone_gray_off.png": [64, 49, 43], "mcl_comparators_sides_on.png": [105, 87, 81], "mcl_comparators_comp.png": [61, 20, 20], "mcl_comparators_on.png": [116, 102, 98], "mcl_comparators_sides_comp.png": [99, 88, 83], "mcl_comparators_off.png": [113, 102, 98], "mcl_comparators_ends_comp.png": [99, 88, 83], "mcl_comparators_ends_sub.png": [105, 88, 83], "mcl_comparators_ends_off.png": [96, 80, 74], "mcl_comparators_ends_on.png": [105, 81, 75], "mcl_comparators_sub.png": [112, 25, 25], "mcl_comparators_item.png": [98, 83, 79], "mcl_comparators_sides_off.png": [99, 86, 80], "mcl_comparators_sides_sub.png": [105, 88, 83], "default_book.png": [103, 67, 44], "default_bookshelf.png": [84, 67, 54], "mcl_books_book_written.png": [110, 74, 44], "mcl_books_book_bg.png": [203, 180, 151], "mcl_books_button9_pressed.png": [145, 112, 86], "mcl_books_button9.png": [145, 112, 86], "mcl_books_book_writable.png": [151, 122, 108], "mcl_books_bookshelf_top.png": [109, 84, 65], "wool_dark_grey.png": [96, 87, 87], "wool_grey.png": [143, 134, 134], "wool_magenta.png": [140, 85, 125], "wool_black.png": [45, 42, 42], "wool_orange.png": [188, 106, 45], "wool_blue.png": [43, 73, 125], "wool_yellow.png": [201, 163, 69], "wool_pink.png": [171, 91, 108], "wool_dark_green.png": [53, 91, 51], "wool_brown.png": [86, 57, 43], "wool_red.png": [132, 42, 45], "mcl_wool_light_blue.png": [91, 130, 180], "wool_cyan.png": [30, 94, 113], "mcl_wool_lime.png": [107, 151, 76], "wool_white.png": [212, 199, 182], "wool_violet.png": [77, 57, 102], "mcl_potions_melon_speckled.png": [170, 97, 62], "mcl_potions_effect_swift.png": [106, 96, 85], "mcl_potions_spider_eye_fermented.png": [143, 97, 62], "mcl_potions_splash_bottle.png": [168, 156, 183], "mcl_potions_effect_water_breathing.png": [59, 69, 100], "mcl_potions_effect_leaping.png": [100, 91, 86], "mcl_potions_effect_weak.png": [127, 126, 126], "mcl_potions_dragon_breath.png": [171, 137, 163], "mcl_potions_effect_food_poisoning.png": [112, 123, 89], "hudbars_icon_regenerate.png": [195, 77, 114], "mcl_potions_effect_fire_proof.png": [112, 68, 68], "mcl_potions_splash_overlay.png": [202, 202, 202], "mcl_potions_effect_invisible.png": [96, 103, 95], "hbhunger_icon_regen_poison.png": [147, 111, 115], "mcl_potions_effect_slow.png": [78, 81, 85], "mcl_potions_lingering_bottle.png": [181, 159, 192], "mcl_potions_potion_overlay.png": [201, 201, 201], "mcl_potions_effect_regenerating.png": [133, 90, 83], "mcl_potions_arrow_inv.png": [171, 165, 160], "mcl_potions_effect_night_vision.png": [86, 99, 74], "mcl_potions_potion_bottle.png": [156, 172, 203], "mcl_potions_effect_poisoned.png": [78, 110, 80], "mcl_potions_effect_strong.png": [100, 82, 97], "crafting_workbench_front.png": [120, 93, 72], "gui_crafting_arrow.png": [139, 139, 139], "crafting_workbench_side.png": [120, 93, 72], "crafting_workbench_top.png": [152, 121, 93], "mcl_enchanting_glyph_11.png": [209, 209, 231], "mcl_enchanting_glyph_14.png": [209, 209, 231], "mcl_enchanting_glyph_6.png": [209, 209, 231], "mcl_enchanting_glyph_8.png": [209, 209, 231], "mcl_enchanting_glyph_9.png": [209, 209, 231], "mcl_enchanting_glyph_3.png": [209, 209, 231], "mcl_enchanting_number_1_off.png": [255, 255, 255], "mcl_enchanting_number_3_off.png": [255, 255, 255], "mcl_enchanting_number_3.png": [151, 47, 40], "mcl_enchanting_book_open.png": [153, 123, 99], "mcl_enchanting_button_off.png": [255, 255, 255], "mcl_enchanting_glyph_2.png": [209, 209, 231], "mcl_enchanting_glyph_1.png": [209, 209, 231], "mcl_enchanting_button.png": [255, 255, 255], "mcl_enchanting_table_side.png": [66, 58, 55], "mcl_enchanting_book_closed.png": [112, 78, 55], "mcl_enchanting_table_bottom.png": [58, 51, 52], "mcl_enchanting_glyph_15.png": [209, 209, 231], "mcl_enchanting_number_2_off.png": [255, 255, 255], "mcl_enchanting_glyph_5.png": [209, 209, 231], "mcl_enchanting_number_1.png": [149, 45, 39], "mcl_enchanting_glyph_7.png": [209, 209, 231], "mcl_enchanting_table_top.png": [88, 86, 84], "mcl_enchanting_number_2.png": [149, 46, 39], "mcl_enchanting_glyph_16.png": [209, 209, 231], "mcl_enchanting_button_hovered.png": [255, 255, 255], "mcl_enchanting_book_enchanted.png": [122, 69, 46], "mcl_enchanting_glyph_4.png": [209, 209, 231], "mcl_enchanting_glyph_10.png": [209, 209, 231], "mcl_enchanting_glyph_13.png": [209, 209, 231], "mcl_enchanting_glyph_17.png": [209, 209, 231], "mcl_enchanting_glyph_18.png": [209, 209, 231], "mcl_enchanting_lapis_background.png": [255, 255, 255], "mcl_enchanting_button_background.png": [229, 202, 171], "mcl_enchanting_glyph_12.png": [209, 209, 231], "doc_basics_gameplay_mtg_2.png": [151, 168, 207], "doc_basics_liquids_renewable_1.png": [139, 146, 159], "doc_basics_players_sam.png": [95, 133, 106], "doc_basics_players_flat.png": [127, 155, 130], "doc_basics_craft_shapeless_2.png": [52, 52, 48], "doc_basics_build.png": [84, 84, 55], "doc_basics_pointing.png": [66, 104, 32], "doc_basics_nodes.png": [108, 104, 94], "doc_basics_craft_groups_2.png": [65, 58, 52], "doc_basics_craft_groups_1.png": [57, 57, 58], "doc_basics_inventory.png": [47, 47, 45], "doc_basics_minimap_radar.png": [73, 164, 128], "doc_basics_sneak.png": [70, 69, 69], "doc_basics_camera_behind.png": [108, 144, 135], "doc_basics_craft_repair.png": [47, 46, 45], "doc_basics_hotbar_relations.png": [85, 84, 69], "doc_basics_gameplay_lott.png": [119, 122, 112], "doc_basics_tools_mining.png": [64, 62, 59], "doc_basics_players_lott.png": [180, 193, 224], "doc_basics_gameplay_outback.png": [146, 114, 109], "doc_basics_gameplay_pixture.png": [94, 120, 57], "doc_basics_craft_grid.png": [46, 46, 46], "doc_basics_craft_groups_3.png": [61, 58, 55], "doc_basics_camera_front.png": [99, 133, 110], "doc_basics_minimap_map.png": [149, 169, 183], "doc_basics_gameplay_mtg_1.png": [136, 117, 86], "doc_basics_gameplay_xtraores_xtension.png": [95, 15, 86], "doc_basics_light_torch.png": [25, 43, 14], "doc_basics_minimap_round.png": [160, 175, 189], "doc_basics_light_test.png": [133, 113, 69], "doc_basics_liquids_nonrenewable.png": [64, 87, 87], "doc_basics_gameplay_hades.png": [81, 70, 62], "doc_basics_gameplay_moontest.png": [75, 74, 79], "doc_basics_liquids_range.png": [146, 166, 179], "doc_basics_inventory_detail.png": [43, 41, 39], "doc_basics_camera_ego.png": [111, 147, 139], "doc_basics_tools.png": [46, 45, 42], "doc_basics_liquids_renewable_2.png": [136, 148, 166], "doc_basics_items_dropped.png": [195, 185, 147], "doc_basics_liquids_types.png": [146, 164, 171], "doc_basics_gameplay_carbone_ng.png": [121, 118, 89], "doc_basics_craft_shaped.png": [55, 52, 50], "doc_basics_hotbar.png": [141, 175, 226], "doc_basics_craft_shapeless_1.png": [52, 52, 48], "doc_button_icon_lores.png": [19, 143, 183], "doc_awards_icon_generic.png": [14, 125, 162], "inventory_plus_doc_inventory_plus.png": [19, 143, 183], "doc_button_icon_hires.png": [30, 149, 188], "doc_identifier_identifier.png": [172, 151, 139], "doc_identifier_identifier_liquid.png": [125, 147, 190], "craftguide_clear_icon.png": [254, 254, 254], "craftguide_book.png": [84, 117, 39], "mcl_craftguide_fuel.png": [187, 121, 75], "craftguide_prev_icon.png": [255, 255, 255], "craftguide_zoomout_icon.png": [255, 255, 255], "craftguide_search_icon.png": [254, 254, 254], "craftguide_arrow.png": [139, 139, 139], "craftguide_zoomin_icon.png": [255, 255, 255], "craftguide_shapeless.png": [130, 130, 130], "craftguide_next_icon.png": [255, 255, 255]} \ No newline at end of file +{"player.png": [123, 74, 62], "player_back.png": [114, 68, 56], "mcl_skins_player_dummy.png": [125, 125, 125], "mcl_skins_player_1.png": [103, 100, 86], "mcl_skins_button.png": [121, 95, 85], "mcl_skins_character_1.png": [93, 90, 77], "mcl_hunger_bar_saturation.png": [255, 255, 0], "hbhunger_bar_health_poison.png": [148, 120, 24], "mcl_hunger_bar_exhaustion.png": [255, 255, 255], "mcl_hunger_icon_exhaustion.png": [213, 213, 213], "mcl_hunger_bgicon_exhaustion.png": [25, 25, 26], "mcl_hunger_icon_foodpoison.png": [109, 106, 40], "mcl_hunger_bgicon_saturation.png": [24, 24, 26], "hbhunger_bar.png": [200, 103, 0], "hbhunger_bgicon.png": [24, 24, 26], "hbhunger_icon_health_poison.png": [69, 98, 45], "mcl_hunger_bar_foodpoison.png": [116, 132, 88], "hbhunger_icon.png": [175, 132, 97], "mcl_hunger_icon_saturation.png": [157, 140, 64], "mcl_playerplus_end_sky.png": [14, 14, 14], "mobs_mc_llama_decor_purple.png": [98, 50, 98], "mobs_mc_spawn_icon_illusioner.png": [98, 111, 155], "mobs_mc_llama_gray.png": [195, 188, 175], "mobs_mc_spawn_icon_zombie.png": [64, 136, 112], "mobs_mc_llama_decor_blue.png": [50, 50, 249], "mobs_mc_spawn_icon_skeleton.png": [146, 146, 146], "mobs_mc_shulker_blue.png": [89, 100, 126], "mobs_mc_shulker_black.png": [78, 75, 76], "mobs_mc_wolf_collar.png": [186, 186, 186], "mobs_mc_spawn_icon_bat.png": [130, 63, 13], "mobs_mc_parrot_green.png": [47, 208, 62], "mobs_mc_llama_decor_magenta.png": [249, 50, 249], "mobs_mc_rabbit_black.png": [73, 64, 61], "mobs_mc_vindicator.png": [56, 56, 57], "mobs_mc_polarbear.png": [233, 220, 208], "mobs_mc_magmacube.png": [83, 40, 27], "mobs_mc_chicken.png": [198, 182, 176], "mobs_mc_ghast_firing.png": [198, 198, 198], "mobs_mc_spawn_icon_zombie_pigman.png": [202, 160, 135], "mobs_mc_husk.png": [98, 95, 76], "mobs_mc_villager_librarian.png": [176, 171, 163], "mobs_mc_villager_priest.png": [100, 64, 74], "mobs_mc_villager_smith.png": [76, 76, 63], "mobs_mc_horse_armor_gold.png": [143, 110, 59], "mobs_mc_spawn_icon_dragon.png": [98, 47, 89], "mobs_mc_spawn_icon_donkey.png": [152, 132, 100], "mobs_mc_squid.png": [37, 52, 68], "mobs_mc_villager_farmer.png": [81, 80, 67], "mobs_mc_spawn_icon_horse_skeleton.png": [245, 204, 202], "mobs_mc_horse_markings_blackdots.png": [24, 22, 22], "mobs_mc_zombie_farmer.png": [119, 99, 85], "mobs_mc_spawn_icon_vex.png": [145, 185, 185], "mobs_mc_parrot_blue.png": [43, 58, 148], "mobs_mc_spider_eyes.png": [174, 48, 48], "mobs_mc_zombie.png": [78, 110, 105], "mobs_mc_llama_decor_light_blue.png": [104, 168, 194], "mobs_mc_zombie_priest.png": [120, 104, 110], "mobs_mc_llama_decor_black.png": [50, 50, 50], "mobs_mc_horse_white.png": [190, 173, 154], "mobs_mc_spawn_icon_vindicator.png": [102, 103, 104], "mobs_mc_silverfish.png": [179, 164, 144], "mobs_mc_llama_decor_gray.png": [98, 98, 98], "mobs_mc_spawn_icon_guardian.png": [119, 156, 148], "mobs_mc_creeper.png": [98, 107, 71], "mobs_mc_shulker_purple.png": [135, 87, 99], "mobs_mc_spawn_icon_rabbit.png": [156, 126, 84], "mobs_mc_horse_armor_iron.png": [134, 123, 118], "mobs_mc_sheep.png": [182, 161, 149], "mobs_mc_parrot_grey.png": [33, 178, 173], "mobs_mc_wolf_icon_sit.png": [8, 88, 116], "mobs_mc_gold_horse_armor.png": [140, 106, 67], "mobs_mc_spawn_icon_witch.png": [98, 85, 68], "mobs_mc_shulker_green.png": [89, 122, 84], "mobs_mc_bat.png": [87, 63, 54], "mobs_mc_horse_chestnut.png": [126, 78, 58], "mobs_mc_shulker_yellow.png": [175, 128, 69], "mobs_mc_spawn_icon_creeper.png": [115, 125, 53], "mobs_mc_slime.png": [63, 133, 78], "mobs_mc_evoker.png": [44, 48, 43], "mobs_mc_horse_skeleton.png": [163, 156, 141], "mobs_mc_spawn_icon_blaze.png": [142, 76, 49], "mobs_mc_shulker_light_blue.png": [114, 140, 158], "mobs_mc_shulker_gray.png": [106, 104, 109], "mobs_mc_horse_darkbrown.png": [69, 47, 34], "mobs_mc_stray_overlay.png": [63, 59, 65], "mobs_mc_arrow_particle.png": [218, 171, 136], "mobs_mc_spawn_icon_cat.png": [120, 66, 10], "mobs_mc_stray.png": [155, 157, 161], "mobs_mc_trading_formspec_bg.png": [157, 157, 157], "mobs_mc_llama_chest.png": [70, 53, 36], "mobs_mc_spawn_icon_villager.png": [134, 124, 81], "mobs_mc_pig.png": [228, 175, 165], "mobs_mc_spawn_icon_mooshroom.png": [160, 56, 55], "mobs_mc_wolf_angry.png": [187, 179, 176], "mobs_mc_cat_black.png": [206, 181, 154], "mobs_mc_vex_charging.png": [142, 153, 153], "mobs_mc_llama.png": [207, 189, 155], "mobs_mc_mushroom_brown.png": [122, 81, 58], "mobs_mc_spawn_icon_shulker.png": [170, 117, 130], "mobs_mc_wither_half_health.png": [7, 58, 91], "mobs_mc_spawn_icon_guardian_elder.png": [174, 140, 113], "mobs_mc_enderman_eyes.png": [184, 211, 242], "mobs_mc_horse_creamy.png": [146, 111, 75], "mobs_mc_spawn_icon_zombie_villager.png": [95, 110, 68], "mobs_mc_vex.png": [128, 162, 162], "mobs_mc_iron_golem.png": [47, 44, 44], "mobs_mc_cat_ocelot.png": [163, 111, 52], "mobs_mc_llama_decor_green.png": [50, 98, 50], "mobs_mc_cow.png": [94, 68, 55], "mobs_mc_llama_decor_brown.png": [101, 75, 60], "mobs_mc_villager_butcher.png": [82, 83, 71], "mobs_mc_parrot_yellow_blue.png": [98, 187, 205], "mobs_mc_zombie_pigman.png": [164, 129, 117], "mobs_mc_spawn_icon_wolf.png": [231, 218, 207], "mobs_mc_zombie_villager.png": [112, 108, 90], "mobs_mc_sheep_fur.png": [203, 186, 174], "mobs_mc_spawn_icon_horse_zombie.png": [129, 143, 66], "mobs_mc_blaze.png": [84, 63, 50], "mcl_totems_totem.png": [185, 139, 52], "mobs_mc_rabbit_salt.png": [122, 99, 87], "mobs_mc_rabbit_white_splotched.png": [146, 139, 135], "mobs_mc_horse_brown.png": [115, 84, 61], "mobs_mc_ghast.png": [199, 199, 199], "mobs_mc_horse_markings_white.png": [165, 149, 132], "mobs_mc_horse_markings_whitefield.png": [193, 178, 162], "mobs_mc_spawn_icon_endermite.png": [138, 67, 74], "mobs_mc_shulker_magenta.png": [143, 97, 130], "mobs_mc_snowman.png": [211, 217, 221], "mobs_mc_zombie_smith.png": [71, 59, 54], "mobs_mc_spawn_icon_squid.png": [55, 58, 103], "mobs_mc_dragon_fireball.png": [89, 66, 79], "mobs_mc_horse_armor_diamond.png": [78, 110, 129], "mobs_mc_diamond_horse_armor.png": [67, 95, 112], "mobs_mc_rabbit_toast.png": [130, 123, 119], "mobs_mc_llama_white.png": [207, 199, 184], "mobs_mc_llama_creamy.png": [208, 190, 155], "mobs_mc_pig_saddle.png": [82, 63, 45], "mobs_mc_spawn_icon_cave_spider.png": [23, 43, 57], "mobs_mc_shulker_silver.png": [140, 138, 143], "mobs_mc_trading_formspec_disabled.png": [193, 26, 26], "mobs_mc_spider.png": [41, 38, 37], "mobs_mc_wither.png": [33, 33, 33], "mobs_mc_llama_decor_white.png": [249, 249, 249], "mobs_mc_witch.png": [80, 74, 67], "mobs_mc_wolf_icon_roam.png": [6, 124, 36], "mobs_mc_illusionist.png": [56, 68, 114], "mobs_mc_endermite.png": [55, 20, 65], "mobs_mc_spawn_icon_witherskeleton.png": [71, 71, 71], "mobs_mc_llama_decor_light_gray.png": [185, 185, 185], "mobs_mc_llama_decor_cyan.png": [18, 249, 249], "mobs_mc_skeleton.png": [124, 124, 124], "mobs_mc_spawn_icon_llama.png": [230, 221, 178], "mobs_mc_spawn_icon_chicken.png": [170, 160, 156], "mobs_mc_shulker_pink.png": [173, 127, 160], "mobs_mc_spawn_icon_spider.png": [53, 43, 43], "mobs_mc_shulker_red.png": [146, 77, 71], "mobs_mc_shulker_white.png": [184, 181, 186], "mobs_mc_spawn_icon_magmacube.png": [52, 33, 23], "mobs_mc_spawn_icon_ghast.png": [212, 212, 212], "mobs_mc_rabbit_brown.png": [112, 86, 73], "mobs_mc_spawn_icon_pig.png": [242, 200, 188], "mobs_mc_spawn_icon_horse.png": [44, 36, 25], "mobs_mc_cat_siamese.png": [161, 144, 133], "mobs_mc_mushroom_red.png": [176, 51, 49], "mobs_mc_shulker_brown.png": [94, 81, 70], "mobs_mc_guardian.png": [78, 116, 130], "mobs_mc_creeper_charge.png": [121, 219, 255], "mobs_mc_villager.png": [88, 91, 55], "mobs_mc_llama_decor_lime.png": [50, 249, 50], "mobs_mc_llama_brown.png": [136, 97, 52], "mobs_mc_parrot_red_blue.png": [171, 70, 37], "mobs_mc_spawn_icon_husk.png": [174, 174, 128], "mobs_mc_rabbit_gold.png": [151, 130, 96], "mobs_mc_spawn_icon_evoker.png": [92, 103, 86], "mobs_mc_iron_horse_armor.png": [133, 119, 114], "mobs_mc_llama_decor_red.png": [249, 50, 50], "mobs_mc_enderman.png": [3, 10, 10], "mobs_mc_mooshroom_brown.png": [93, 50, 28], "mobs_mc_llama_decor_pink.png": [249, 161, 175], "mobs_mc_enderman_block.png": [46, 42, 38], "mobs_mc_mooshroom.png": [90, 42, 41], "mobs_mc_cat_red.png": [221, 163, 120], "mobs_mc_spit.png": [221, 218, 246], "mobs_mc_shulkerbullet.png": [216, 190, 153], "mobs_mc_horse_markings_whitedots.png": [230, 220, 207], "mobs_mc_mule.png": [108, 75, 51], "mobs_mc_spawn_icon_iron_golem.png": [122, 72, 41], "mobs_mc_zombie_butcher.png": [107, 98, 87], "mobs_mc_llama_decor_yellow.png": [249, 249, 50], "mobs_mc_wolf_tame.png": [179, 159, 154], "mobs_mc_horse_gray.png": [78, 68, 62], "mobs_mc_shulker_lime.png": [106, 132, 88], "mobs_mc_rabbit_caerbannog.png": [186, 179, 174], "mobs_mc_zombie_librarian.png": [106, 104, 104], "mobs_mc_spawn_icon_silverfish.png": [199, 168, 128], "mobs_mc_spawn_icon_stray.png": [118, 116, 118], "mobs_mc_spawn_icon_polarbear.png": [237, 235, 212], "mobs_mc_guardian_elder.png": [141, 141, 125], "mobs_mc_spawn_icon_slime.png": [76, 130, 33], "mobs_mc_cave_spider.png": [14, 28, 38], "mobs_mc_spawn_icon_cow.png": [162, 118, 72], "mobs_mc_wolf.png": [182, 165, 159], "mobs_mc_wither_skeleton.png": [50, 50, 50], "mobs_mc_endergolem.png": [135, 87, 99], "mobs_mc_spawn_icon_mule.png": [115, 82, 47], "mobs_mc_llama_decor_orange.png": [249, 131, 50], "mobs_chicken_egg.png": [199, 157, 106], "mobs_mc_rabbit_white.png": [161, 153, 149], "mobs_mc_horse_black.png": [49, 42, 39], "mobs_mc_dragon.png": [79, 54, 67], "mobs_mc_spawn_icon_parrot.png": [202, 100, 54], "mobs_mc_spawn_icon_snowman.png": [216, 173, 147], "mobs_mc_donkey.png": [91, 78, 68], "mobs_mc_shulker_cyan.png": [89, 114, 128], "mobs_mc_spawn_icon_sheep.png": [209, 185, 175], "mobs_mc_TEMP_wither_projectile.png": [69, 69, 69], "mobs_mc_spawn_icon_enderman.png": [63, 82, 87], "mobs_mc_shulker_orange.png": [156, 90, 67], "mobs_mc_empty.png": [255, 255, 255], "mobs_mc_spawn_icon_wither.png": [102, 102, 102], "mcl_boats_spruce_boat.png": [72, 61, 51], "mcl_boats_jungle_boat.png": [102, 73, 58], "mcl_boats_texture_birch_boat.png": [131, 105, 83], "mcl_boats_texture_oak_boat.png": [103, 82, 65], "mcl_boats_birch_boat.png": [120, 95, 78], "mcl_boats_texture_jungle_boat.png": [109, 78, 60], "mcl_boats_oak_boat.png": [93, 76, 62], "mcl_boats_texture_acacia_boat.png": [136, 90, 64], "mcl_boats_texture_dark_oak_boat.png": [89, 76, 64], "mcl_boats_texture_spruce_boat.png": [74, 61, 50], "mcl_boats_acacia_boat.png": [124, 82, 59], "mcl_boats_dark_oak_boat.png": [89, 76, 64], "mobs_nametag.png": [138, 114, 89], "mobs_blood.png": [27, 27, 29], "mcl_minecarts_rail_golden_curved_powered.png": [89, 71, 57], "mcl_minecarts_rail_golden_crossing.png": [83, 70, 55], "mcl_minecarts_rail_detector_curved_powered.png": [81, 68, 64], "mcl_minecarts_rail_golden_t_junction_powered.png": [82, 69, 59], "mcl_minecarts_rail_golden_t_junction.png": [80, 70, 59], "mcl_minecarts_rail_detector.png": [85, 74, 67], "mcl_minecarts_rail_detector_crossing.png": [77, 69, 65], "default_rail_t_junction.png": [79, 68, 61], "mcl_minecarts_rail_activator_crossing_powered.png": [72, 55, 51], "mcl_minecarts_minecart_hopper.png": [45, 45, 45], "mcl_minecarts_minecart_furnace.png": [66, 65, 64], "mcl_minecarts_minecart_command_block.png": [64, 62, 61], "mcl_minecarts_rail_golden.png": [92, 77, 60], "mcl_minecarts_rail_activator_t_junction_powered.png": [76, 61, 55], "default_rail_curved.png": [76, 67, 60], "mcl_minecarts_rail_activator_t_junction.png": [72, 62, 56], "mcl_minecarts_rail_golden_crossing_powered.png": [86, 70, 54], "mcl_minecarts_rail_detector_crossing_powered.png": [78, 68, 64], "mcl_minecarts_rail_detector_curved.png": [77, 70, 66], "default_rail_crossing.png": [79, 68, 59], "mcl_minecarts_rail_detector_t_junction.png": [74, 66, 61], "mcl_minecarts_minecart.png": [72, 60, 51], "mcl_minecarts_rail_golden_curved.png": [85, 73, 58], "mcl_minecarts_rail_activator.png": [78, 64, 56], "mcl_minecarts_rail_activator_powered.png": [86, 62, 54], "mcl_minecarts_rail_detector_t_junction_powered.png": [76, 66, 61], "mcl_minecarts_minecart_normal.png": [47, 45, 43], "mcl_minecarts_minecart_tnt.png": [75, 52, 52], "mcl_minecarts_rail_detector_powered.png": [87, 74, 67], "mcl_minecarts_rail_golden_powered.png": [94, 77, 60], "mcl_minecarts_rail_activator_crossing.png": [65, 56, 52], "default_rail.png": [83, 70, 61], "mcl_minecarts_rail_activator_curved_powered.png": [75, 55, 52], "mcl_minecarts_rail_activator_curved.png": [66, 56, 53], "mcl_minecarts_minecart_chest.png": [51, 48, 46], "mobs_mc_gameconfig_enderman_cactus_background.png": [44, 71, 27], "mcl_paintings_paintings.png": [104, 99, 89], "mcl_paintings_painting.png": [139, 133, 119], "mcl_particles_lava.png": [250, 150, 64], "mcl_particles_instant_effect.png": [160, 160, 160], "mcl_particles_note.png": [41, 40, 39], "mcl_particles_bubble.png": [147, 174, 195], "mcl_particles_sponge1.png": [241, 238, 226], "mcl_particles_smoke_anim.png": [172, 172, 172], "mcl_particles_crit.png": [165, 165, 165], "mcl_particles_mob_death.png": [198, 198, 198], "mcl_particles_droplet_bottle.png": [203, 203, 203], "mcl_particles_sponge4.png": [241, 238, 226], "mcl_particles_effect.png": [184, 184, 184], "mcl_particles_teleport.png": [86, 22, 128], "mcl_particles_sponge5.png": [241, 238, 226], "mcl_particles_flame.png": [244, 149, 63], "mcl_particles_sponge3.png": [241, 238, 226], "mcl_particles_sponge2.png": [241, 238, 226], "mcl_particles_smoke.png": [174, 174, 174], "lightning_lightning_2.png": [255, 255, 255], "lightning_lightning_3.png": [217, 217, 217], "lightning_lightning_1.png": [223, 223, 223], "weather_pack_rain_raindrop_2.png": [33, 79, 142], "weather_pack_rain_raindrop_3.png": [59, 88, 128], "mcl_particles_nether_dust3.png": [143, 105, 102], "weather_pack_rain_raindrop_1.png": [97, 137, 179], "mcl_particles_nether_dust1.png": [143, 105, 102], "weather_pack_snow_snowflake1.png": [255, 255, 255], "mcl_particles_nether_dust2.png": [143, 105, 102], "weather_pack_snow_snowflake2.png": [255, 255, 255], "mcl_moon_moon_phases.png": [80, 106, 141], "hbarmor_bgicon.png": [27, 27, 29], "hbarmor_bar.png": [175, 172, 165], "hbarmor_icon.png": [135, 131, 126], "mcl_base_textures_background9.png": [179, 179, 179], "object_crosshair.png": [255, 255, 255], "bubble.png": [69, 138, 194], "crosshair.png": [255, 255, 255], "heart.png": [137, 47, 40], "mcl_base_textures_background.png": [179, 179, 179], "crack_anylength.png": [93, 93, 93], "mcl_base_textures_button9_pressed.png": [162, 162, 162], "mcl_base_textures_button9.png": [162, 162, 162], "smoke_puff.png": [255, 255, 255], "mineclone2_logo.png": [75, 74, 69], "mineclone2_icon.png": [58, 74, 44], "awards_template.png": [134, 134, 134], "awards_bg_mining.png": [73, 68, 51], "awards_progress_gray.png": [157, 157, 157], "awards_ui_icon.png": [190, 34, 34], "awards_unknown.png": [134, 134, 134], "awards_progress_green.png": [0, 155, 74], "awards_bg_default.png": [38, 38, 38], "hudbars_bar_breath.png": [159, 161, 255], "hudbars_icon_health.png": [137, 47, 40], "hudbars_bar_health.png": [168, 55, 47], "hudbars_bgicon_breath.png": [0, 0, 0], "hudbars_bgicon_health.png": [27, 27, 29], "hudbars_icon_breath.png": [69, 138, 194], "hudbars_bar_background.png": [71, 71, 71], "mcl_achievements_button.png": [158, 152, 67], "mcl_inventory_hotbar.png": [81, 81, 85], "crafting_inventory_creative_survival.png": [195, 195, 195], "crafting_creative_bg_dark.png": [157, 157, 157], "mcl_inventory_empty_armor_slot_shield.png": [25, 32, 34], "crafting_formspec_bg.png": [9, 9, 9], "mcl_inventory_empty_armor_slot_helmet.png": [25, 32, 34], "mcl_inventory_hotbar_selected.png": [113, 85, 40], "crafting_creative_inactive_down.png": [151, 151, 151], "crafting_creative_active_down.png": [196, 196, 196], "crafting_creative_prev.png": [254, 254, 254], "crafting_creative_marker.png": [0, 0, 0], "mcl_inventory_button9_pressed.png": [162, 162, 162], "crafting_creative_active.png": [202, 202, 202], "mcl_inventory_button9.png": [162, 162, 162], "mcl_inventory_empty_armor_slot_chestplate.png": [0, 0, 0], "mcl_inventory_empty_armor_slot_boots.png": [0, 0, 0], "crafting_creative_bg.png": [207, 207, 207], "crafting_creative_inactive.png": [157, 157, 157], "crafting_creative_next.png": [254, 254, 254], "mcl_inventory_empty_armor_slot_leggings.png": [25, 32, 34], "crafting_inventory_creative.png": [206, 206, 206], "crafting_creative_trash.png": [144, 113, 113], "mcl_formspec_itemslot.png": [157, 157, 157], "mcl_experience_bottle.png": [136, 174, 169], "experience_bar_background.png": [49, 46, 45], "experience_orb.png": [93, 174, 0], "experience_bar.png": [74, 102, 70], "mcl_bossbars_empty.png": [255, 255, 255], "mcl_bossbars.png": [76, 68, 75], "mcl_itemframes_item_frame.png": [123, 90, 63], "mcl_itemframes_itemframe_background.png": [136, 104, 75], "mcl_banners_stripe_middle.png": [255, 255, 255], "mcl_banners_skull.png": [255, 255, 255], "mcl_banners_bricks.png": [255, 255, 255], "mcl_banners_square_bottom_left.png": [255, 255, 255], "mcl_banners_gradient.png": [254, 254, 254], "mcl_banners_cross.png": [255, 255, 255], "mcl_banners_gradient_up.png": [254, 254, 254], "mcl_banners_item_overlay.png": [240, 240, 240], "mcl_banners_stripe_downright.png": [255, 255, 255], "mcl_banners_stripe_downleft.png": [255, 255, 255], "mcl_banners_fallback_wood.png": [102, 88, 74], "mcl_banners_base_inverted.png": [255, 255, 255], "mcl_banners_triangles_top.png": [255, 255, 255], "mcl_banners_banner_base.png": [215, 206, 193], "mcl_banners_curly_border.png": [254, 254, 254], "mcl_banners_thing.png": [253, 253, 253], "mcl_banners_small_stripes.png": [255, 255, 255], "mcl_banners_triangle_bottom.png": [254, 254, 254], "mcl_banners_stripe_right.png": [255, 255, 255], "mcl_banners_straight_cross.png": [255, 255, 255], "mcl_banners_triangle_top.png": [255, 255, 255], "mcl_banners_border.png": [255, 255, 255], "mcl_banners_diagonal_left.png": [255, 255, 255], "mcl_banners_diagonal_right.png": [255, 255, 255], "mcl_banners_base.png": [255, 255, 255], "mcl_banners_half_vertical.png": [255, 255, 255], "mcl_banners_circle.png": [254, 254, 254], "mcl_banners_triangles_bottom.png": [255, 255, 255], "mcl_banners_item_base.png": [103, 89, 75], "mcl_banners_stripe_left.png": [255, 255, 255], "mcl_banners_rhombus.png": [255, 255, 255], "mcl_banners_creeper.png": [255, 255, 255], "mcl_banners_flower.png": [254, 254, 254], "mcl_banners_stripe_bottom.png": [255, 255, 255], "mcl_banners_half_horizontal.png": [255, 255, 255], "mcl_banners_half_horizontal_bottom.png": [255, 255, 255], "mcl_banners_square_top_left.png": [255, 255, 255], "mcl_banners_square_top_right.png": [255, 255, 255], "mcl_banners_stripe_center.png": [255, 255, 255], "mcl_banners_diagonal_up_left.png": [255, 255, 255], "mcl_banners_stripe_top.png": [255, 255, 255], "mcl_banners_diagonal_up_right.png": [255, 255, 255], "mcl_banners_square_bottom_right.png": [255, 255, 255], "mcl_banners_half_vertical_right.png": [255, 255, 255], "mcl_doors_trapdoor_dark_oak.png": [81, 68, 56], "mcl_doors_trapdoor_acacia_side.png": [154, 102, 71], "doors_trapdoor_steel_side.png": [149, 140, 140], "mcl_doors_door_jungle_side_upper.png": [109, 75, 57], "mcl_doors_door_dark_oak_side_lower.png": [103, 90, 75], "mcl_doors_door_iron_lower.png": [157, 152, 151], "mcl_doors_door_acacia_upper.png": [152, 100, 69], "mcl_doors_door_jungle_side_lower.png": [107, 72, 55], "mcl_doors_door_wood_lower.png": [89, 70, 55], "doors_trapdoor_steel.png": [149, 140, 140], "mcl_doors_door_iron_side_upper.png": [155, 149, 148], "mcl_doors_door_acacia_side_upper.png": [133, 80, 53], "mcl_doors_door_jungle.png": [116, 83, 62], "mcl_doors_door_iron_side_lower.png": [157, 152, 151], "mcl_doors_door_birch_upper.png": [179, 158, 139], "mcl_doors_trapdoor_spruce_side.png": [73, 59, 47], "mcl_doors_door_iron_upper.png": [155, 149, 148], "mcl_doors_door_spruce_side_lower.png": [92, 79, 68], "mcl_doors_trapdoor_spruce.png": [71, 57, 46], "mcl_doors_trapdoor_birch_side.png": [147, 116, 89], "doors_trapdoor_side.png": [113, 86, 67], "mcl_doors_door_acacia_lower.png": [153, 101, 70], "mcl_doors_door_dark_oak_side_upper.png": [102, 89, 75], "mcl_doors_door_acacia_side_lower.png": [131, 78, 51], "mcl_doors_door_wood_upper.png": [92, 72, 57], "mcl_doors_trapdoor_birch.png": [173, 151, 132], "mcl_doors_door_dark_oak_upper.png": [83, 71, 59], "mcl_doors_door_acacia.png": [148, 98, 67], "mcl_doors_door_spruce.png": [67, 56, 47], "mcl_doors_door_spruce_lower.png": [71, 58, 48], "mcl_doors_door_birch_side_upper.png": [153, 121, 94], "mcl_doors_trapdoor_dark_oak_side.png": [85, 72, 60], "mcl_doors_door_wood_side_upper.png": [84, 65, 51], "mcl_doors_door_birch.png": [172, 147, 124], "mcl_doors_door_birch_lower.png": [165, 140, 119], "mcl_doors_trapdoor_jungle.png": [103, 70, 52], "doors_item_steel.png": [148, 144, 143], "doors_trapdoor.png": [98, 75, 59], "mcl_doors_door_jungle_lower.png": [116, 82, 61], "doors_item_wood.png": [88, 67, 53], "mcl_doors_door_jungle_upper.png": [113, 79, 59], "mcl_doors_door_spruce_upper.png": [71, 58, 47], "mcl_doors_door_dark_oak_lower.png": [84, 71, 59], "mcl_doors_door_dark_oak.png": [82, 69, 57], "mcl_doors_door_wood_side_lower.png": [132, 102, 81], "mcl_doors_trapdoor_jungle_side.png": [121, 87, 62], "mcl_doors_door_spruce_side_upper.png": [92, 79, 68], "mcl_doors_door_birch_side_lower.png": [152, 119, 92], "mcl_doors_trapdoor_acacia.png": [148, 96, 66], "mcl_fishing_clownfish_raw.png": [205, 127, 81], "mcl_fishing_fish_raw.png": [70, 112, 154], "mcl_fishing_salmon_raw.png": [112, 105, 102], "mcl_fishing_fish_cooked.png": [93, 84, 94], "mcl_fishing_bobber.png": [171, 117, 119], "mcl_fishing_pufferfish_raw.png": [219, 165, 77], "mcl_fishing_fishing_rod.png": [134, 116, 103], "mcl_fishing_salmon_cooked.png": [97, 91, 89], "mcl_stairs_diorite_smooth_slab.png": [156, 153, 151], "mcl_stairs_iron_block_slab.png": [166, 159, 159], "mcl_stairs_andesite_smooth_slab.png": [106, 113, 108], "mcl_stairs_gold_block_slab.png": [191, 146, 56], "mcl_stairs_granite_smooth_slab.png": [150, 121, 109], "mcl_stairs_lapis_block_slab.png": [49, 89, 158], "mcl_fireworks_rocket.png": [155, 84, 71], "mcl_bows_arrow_inv.png": [144, 129, 121], "mcl_bows_arrow_overlay.png": [193, 191, 186], "mcl_bows_bow_1.png": [112, 95, 79], "mcl_bows_bow_0.png": [111, 94, 79], "mcl_bows_bow_2.png": [115, 98, 82], "mcl_bows_bow.png": [114, 95, 78], "mcl_bows_arrow.png": [133, 116, 108], "mcl_bows_arrow_front.png": [178, 175, 168], "mcl_bows_arrow_back.png": [218, 216, 213], "mcl_ocean_dead_bubble_coral.png": [118, 108, 126], "mcl_ocean_tube_coral.png": [57, 88, 209], "mcl_ocean_sea_pickle_2_anim.png": [95, 122, 51], "mcl_ocean_dead_horn_coral_fan.png": [150, 143, 123], "mcl_ocean_dead_bubble_coral_block.png": [114, 105, 122], "mcl_ocean_sea_pickle_3_off.png": [68, 99, 36], "mcl_ocean_dead_horn_coral_block.png": [152, 146, 125], "mcl_ocean_bubble_coral_block.png": [143, 76, 195], "mcl_ocean_horn_coral.png": [233, 195, 69], "mcl_ocean_dead_tube_coral_block.png": [99, 104, 127], "mcl_ocean_sea_pickle_item.png": [93, 120, 50], "mcl_ocean_kelp_item.png": [42, 105, 55], "mcl_ocean_dried_kelp_side.png": [71, 80, 67], "mcl_ocean_dead_tube_coral.png": [99, 105, 128], "mcl_ocean_fire_coral_block.png": [198, 74, 62], "mcl_ocean_bubble_coral.png": [149, 77, 200], "mcl_ocean_prismarine_bricks.png": [104, 112, 115], "mcl_ocean_brain_coral.png": [206, 87, 153], "mcl_ocean_dried_kelp_top.png": [56, 71, 57], "mcl_ocean_brain_coral_block.png": [200, 85, 148], "mcl_ocean_prismarine_dark.png": [77, 89, 97], "mcl_ocean_dead_fire_coral_block.png": [127, 102, 100], "mcl_ocean_prismarine_shard.png": [122, 144, 135], "mcl_ocean_sea_pickle_2_off.png": [70, 100, 36], "mcl_ocean_sea_pickle_4_anim.png": [85, 113, 46], "mcl_ocean_dead_brain_coral.png": [134, 117, 127], "mcl_ocean_tube_coral_fan.png": [59, 85, 203], "mcl_ocean_sea_pickle_4_off.png": [68, 98, 36], "mcl_ocean_sea_pickle_1_anim.png": [106, 132, 57], "mcl_ocean_fire_coral.png": [208, 78, 65], "mcl_ocean_sea_pickle_3_anim.png": [89, 116, 48], "mcl_ocean_dead_fire_coral_fan.png": [140, 113, 110], "mcl_ocean_prismarine_crystals.png": [182, 193, 190], "mcl_ocean_prismarine_anim.png": [104, 123, 122], "mcl_ocean_horn_coral_fan.png": [230, 189, 68], "mcl_ocean_dead_tube_coral_fan.png": [98, 103, 125], "mcl_ocean_sea_pickle_1_off.png": [72, 103, 37], "mcl_ocean_dead_horn_coral.png": [154, 148, 127], "mcl_ocean_dead_fire_coral.png": [133, 107, 105], "mcl_ocean_bubble_coral_fan.png": [141, 75, 192], "mcl_ocean_horn_coral_block.png": [232, 193, 69], "mcl_ocean_brain_coral_fan.png": [206, 87, 154], "mcl_ocean_sea_lantern.png": [133, 144, 145], "mcl_ocean_seagrass.png": [48, 125, 60], "mcl_ocean_dead_brain_coral_fan.png": [134, 117, 127], "mcl_ocean_dried_kelp.png": [36, 57, 40], "mcl_ocean_dead_bubble_coral_fan.png": [113, 104, 120], "mcl_ocean_dried_kelp_bottom.png": [56, 71, 57], "mcl_ocean_kelp_plant.png": [42, 105, 55], "mcl_ocean_tube_coral_block.png": [58, 88, 207], "mcl_ocean_dead_brain_coral_block.png": [130, 114, 123], "mcl_ocean_fire_coral_fan.png": [205, 77, 64], "mcl_portals_endframe_bottom.png": [109, 99, 87], "mcl_portals_particle3.png": [146, 0, 201], "mcl_portals_particle2.png": [146, 0, 201], "mcl_portals_endframe_top.png": [95, 85, 74], "mcl_portals_particle4.png": [146, 0, 201], "mcl_portals_endframe_eye.png": [135, 36, 18], "mcl_portals_end_portal.png": [14, 14, 14], "mcl_particles_nether_portal.png": [206, 0, 206], "mcl_portals_particle5.png": [189, 11, 213], "mcl_portals_endframe_side.png": [110, 99, 86], "mcl_portals_particle1.png": [173, 28, 229], "mcl_portals_portal.png": [74, 24, 172], "mcl_particles_nether_portal_t.png": [159, 0, 223], "cake_side.png": [201, 170, 155], "cake_inner.png": [185, 129, 99], "cake_bottom.png": [160, 86, 51], "cake_top.png": [241, 228, 226], "cake.png": [216, 187, 176], "mcl_cocoas_cocoa_top_stage_2.png": [138, 68, 52], "mcl_cocoas_cocoa_stage_1.png": [172, 121, 69], "mcl_cocoas_cocoa_stage_2.png": [132, 65, 50], "mcl_cocoas_cocoa_stage_0.png": [65, 77, 39], "mcl_fences_fence_red_nether_brick.png": [68, 17, 0], "mcl_fences_fence_gate_red_nether_brick.png": [64, 15, 0], "mcl_fences_fence_gate_nether_brick.png": [50, 25, 26], "mcl_mobitems_spider_eye.png": [154, 69, 60], "mcl_mobitems_leather.png": [105, 75, 45], "mcl_mobitems_feather.png": [206, 185, 183], "mcl_mobitems_string.png": [202, 186, 166], "mcl_mobitems_rabbit_foot.png": [124, 107, 97], "mcl_mobitems_saddle.png": [93, 72, 50], "mcl_mobitems_bone.png": [182, 162, 139], "mcl_mobitems_shulker_shell.png": [118, 68, 83], "mcl_mobitems_blaze_rod.png": [143, 64, 28], "mcl_mobitems_beef_raw.png": [147, 63, 54], "mcl_mobitems_rabbit_stew.png": [127, 98, 79], "mcl_mobitems_rotten_flesh.png": [110, 68, 45], "mcl_mobitems_chicken_raw.png": [217, 178, 149], "mcl_mobitems_ghast_tear.png": [148, 160, 166], "mcl_mobitems_porkchop_raw.png": [160, 72, 69], "mcl_mobitems_rabbit_hide.png": [108, 85, 73], "mcl_mobitems_slimeball.png": [75, 134, 82], "mcl_mobitems_magma_cream.png": [102, 54, 34], "default_gunpowder.png": [48, 41, 36], "mcl_mobitems_chicken_cooked.png": [187, 145, 106], "mcl_mobitems_beef_cooked.png": [112, 70, 49], "mcl_mobitems_rabbit_cooked.png": [188, 155, 131], "mcl_mobitems_blaze_powder.png": [86, 50, 34], "mcl_mobitems_rabbit_raw.png": [217, 177, 157], "mcl_mobitems_carrot_on_a_stick.png": [133, 113, 93], "mcl_mobitems_mutton_cooked.png": [144, 104, 77], "mcl_mobitems_nether_star.png": [234, 189, 123], "mcl_mobitems_porkchop_cooked.png": [116, 72, 48], "mcl_mobitems_mutton_raw.png": [175, 77, 77], "mcl_mobitems_bucket_milk.png": [180, 175, 166], "mcl_farming_wheat_stage_0.png": [53, 101, 46], "farming_carrot.png": [147, 106, 63], "farming_potato_poison.png": [121, 93, 55], "farming_cookie.png": [144, 100, 61], "mcl_farming_melon_seeds.png": [100, 72, 61], "mcl_farming_potatoes_stage_1.png": [69, 113, 61], "mcl_farming_melon_stem_disconnected.png": [96, 96, 96], "farming_carrot_4.png": [93, 105, 58], "mcl_farming_wheat_stage_5.png": [101, 142, 66], "farming_tool_woodhoe.png": [120, 101, 86], "mcl_farming_potatoes_stage_0.png": [73, 119, 65], "farming_carrot_1.png": [75, 112, 61], "farming_carrot_3.png": [70, 107, 57], "farming_melon.png": [153, 84, 62], "mcl_farming_pumpkin_seeds.png": [132, 120, 87], "farming_wheat_harvested.png": [178, 134, 80], "farming_pumpkin_side.png": [186, 100, 42], "mcl_farming_pumpkin_face.png": [181, 94, 40], "mcl_farming_wheat_stage_4.png": [86, 129, 65], "mcl_farming_farmland_wet.png": [69, 55, 46], "mcl_farming_beetroot_0.png": [56, 122, 75], "mcl_farming_pumpkin_stem_connected.png": [94, 94, 94], "mcl_farming_farmland_dry.png": [101, 80, 68], "farming_tool_diamondhoe.png": [101, 104, 104], "mcl_farming_beetroot_1.png": [54, 118, 72], "mcl_farming_beetroot_2.png": [54, 119, 73], "mcl_farming_wheat_stage_7.png": [165, 116, 75], "mcl_farming_beetroot.png": [113, 69, 66], "mcl_farming_wheat_stage_6.png": [145, 145, 69], "mcl_farming_wheat_stage_3.png": [64, 113, 52], "mcl_farming_pumpkin_stem_disconnected.png": [96, 96, 96], "mcl_farming_hayblock_top.png": [154, 116, 81], "farming_pumpkin_face_light.png": [189, 100, 45], "farming_potato_baked.png": [118, 84, 45], "farming_melon_side.png": [68, 95, 37], "farming_potato.png": [107, 74, 39], "mcl_farming_wheat_stage_1.png": [49, 97, 45], "farming_pumpkin_top.png": [172, 87, 40], "farming_bread.png": [177, 133, 94], "mcl_farming_beetroot_soup.png": [120, 70, 63], "farming_melon_top.png": [58, 80, 33], "mcl_farming_potatoes_stage_3.png": [82, 106, 57], "farming_tool_stonehoe.png": [133, 122, 111], "mcl_farming_beetroot_seeds.png": [107, 104, 88], "farming_tool_goldhoe.png": [162, 131, 70], "farming_carrot_gold.png": [140, 122, 48], "farming_carrot_2.png": [72, 108, 58], "farming_pumpkin_face.png": [161, 79, 37], "mcl_farming_melon_stem_connected.png": [94, 94, 94], "mcl_farming_pumpkin_pie.png": [172, 98, 45], "mcl_farming_pumpkin_face_preview.png": [166, 81, 38], "mcl_farming_wheat_stage_2.png": [49, 97, 45], "farming_tool_steelhoe.png": [123, 112, 102], "mcl_farming_potatoes_stage_2.png": [72, 116, 62], "mcl_farming_beetroot_3.png": [73, 105, 71], "mcl_farming_wheat_seeds.png": [102, 87, 55], "mcl_farming_hayblock_side.png": [135, 99, 71], "mcl_end_purpur_block.png": [161, 111, 175], "mcl_end_chorus_flower_dead.png": [82, 79, 118], "mcl_end_end_stone.png": [221, 214, 130], "mcl_end_endframe_side.png": [110, 99, 86], "mcl_end_purpur_pillar.png": [157, 108, 171], "mcl_end_chorus_fruit.png": [87, 89, 121], "mcl_end_endframe_eye.png": [135, 36, 18], "mcl_end_chorus_fruit_popped.png": [70, 67, 110], "mcl_end_end_rod_top.png": [123, 75, 97], "mcl_end_endframe_top.png": [95, 85, 74], "mcl_end_purpur_pillar_top.png": [159, 110, 173], "mcl_end_chorus_flower.png": [92, 92, 125], "mcl_end_crystal_item.png": [170, 140, 162], "mcl_end_end_bricks.png": [194, 187, 123], "mcl_end_dragon_egg.png": [55, 34, 32], "mcl_end_ender_eye.png": [130, 33, 17], "mcl_end_chorus_plant.png": [78, 73, 115], "mcl_end_end_rod_bottom.png": [122, 74, 96], "mcl_end_crystal_beam.png": [251, 251, 251], "mcl_end_end_rod_side.png": [242, 202, 177], "mcl_clock_clock_18.png": [152, 123, 81], "mcl_clock_clock_03.png": [160, 129, 88], "mcl_clock_clock_49.png": [155, 122, 79], "mcl_clock_clock_34.png": [140, 115, 76], "mcl_clock_clock_01.png": [161, 129, 88], "mcl_clock_clock_32.png": [141, 116, 77], "mcl_clock_clock_27.png": [142, 117, 78], "mcl_clock_clock_42.png": [147, 119, 79], "mcl_clock_clock_25.png": [145, 119, 78], "mcl_clock_clock_56.png": [160, 126, 81], "mcl_clock_clock_22.png": [146, 119, 79], "mcl_clock_clock_31.png": [141, 116, 76], "mcl_clock_clock_57.png": [161, 127, 83], "mcl_clock_clock_58.png": [157, 127, 86], "mcl_clock_clock_39.png": [146, 119, 79], "mcl_clock_clock_59.png": [160, 128, 86], "mcl_clock_clock_16.png": [157, 125, 80], "mcl_clock_clock_38.png": [141, 117, 78], "mcl_clock_clock_53.png": [158, 124, 80], "mcl_clock_clock_43.png": [149, 121, 80], "mcl_clock_clock_09.png": [161, 127, 81], "mcl_clock_clock_33.png": [141, 116, 76], "mcl_clock_clock_07.png": [162, 128, 83], "mcl_clock_clock_23.png": [148, 121, 80], "mcl_clock_clock_51.png": [156, 123, 80], "mcl_clock_clock_10.png": [158, 127, 85], "mcl_clock_clock_55.png": [160, 126, 81], "mcl_clock_clock_46.png": [152, 122, 81], "mcl_clock_clock_26.png": [142, 117, 79], "mcl_clock_clock_06.png": [157, 127, 86], "mcl_clock_clock_00.png": [162, 129, 87], "mcl_clock_clock_28.png": [141, 116, 77], "mcl_clock_clock_44.png": [150, 120, 79], "mcl_clock_clock_08.png": [160, 127, 81], "mcl_clock_clock_19.png": [152, 122, 80], "mcl_clock_clock_12.png": [159, 127, 83], "mcl_clock_clock_45.png": [153, 123, 81], "mcl_clock_clock_24.png": [147, 120, 80], "mcl_clock_clock_15.png": [157, 125, 81], "mcl_clock_clock_20.png": [150, 121, 79], "mcl_clock_clock_61.png": [160, 129, 88], "mcl_clock_clock_02.png": [159, 129, 89], "mcl_clock_clock_40.png": [147, 120, 79], "mcl_clock_clock_37.png": [143, 118, 79], "mcl_clock_clock_48.png": [155, 123, 79], "mcl_clock_clock_13.png": [159, 126, 82], "mcl_clock_clock_17.png": [156, 125, 81], "mcl_clock_clock_52.png": [156, 123, 80], "mcl_clock_clock_54.png": [156, 125, 84], "mcl_clock_clock_04.png": [159, 128, 87], "mcl_clock_clock_47.png": [154, 122, 80], "mcl_clock_clock_62.png": [159, 129, 89], "mcl_clock_clock_41.png": [147, 120, 79], "mcl_clock_clock_35.png": [140, 115, 76], "mcl_clock_clock_60.png": [159, 128, 87], "mcl_clock_clock_50.png": [155, 123, 80], "mcl_clock_clock_29.png": [142, 117, 78], "mcl_clock_clock_21.png": [150, 122, 81], "mcl_clock_clock_30.png": [140, 115, 76], "mcl_clock_clock_14.png": [157, 125, 81], "mcl_clock_clock_05.png": [160, 128, 85], "mcl_clock_clock_36.png": [141, 116, 77], "mcl_clock_clock_63.png": [161, 129, 88], "mcl_clock_clock_11.png": [160, 127, 82], "mcl_compass_compass_02.png": [116, 107, 104], "mcl_compass_compass_06.png": [117, 107, 104], "mcl_compass_compass_04.png": [117, 106, 104], "mcl_compass_compass_19.png": [116, 106, 103], "mcl_compass_compass_16.png": [114, 106, 104], "mcl_compass_compass_26.png": [117, 107, 104], "mcl_compass_compass_25.png": [117, 107, 105], "mcl_compass_compass_24.png": [117, 107, 105], "mcl_compass_compass_17.png": [115, 106, 104], "mcl_compass_compass_23.png": [117, 107, 105], "mcl_compass_compass_01.png": [115, 107, 104], "mcl_compass_compass_28.png": [116, 107, 104], "mcl_compass_compass_05.png": [117, 106, 104], "mcl_compass_compass_09.png": [117, 107, 104], "mcl_compass_compass_10.png": [117, 107, 105], "mcl_compass_compass_14.png": [116, 107, 105], "mcl_compass_compass_18.png": [117, 107, 104], "mcl_compass_compass_13.png": [117, 106, 104], "mcl_compass_compass_08.png": [117, 107, 104], "mcl_compass_compass_21.png": [117, 107, 104], "mcl_compass_compass_27.png": [117, 106, 104], "mcl_compass_compass_30.png": [116, 107, 104], "mcl_compass_compass_15.png": [115, 106, 104], "mcl_compass_compass_29.png": [115, 106, 104], "mcl_compass_compass_03.png": [116, 106, 104], "mcl_compass_compass_07.png": [117, 107, 104], "mcl_compass_compass_22.png": [117, 107, 105], "mcl_compass_compass_12.png": [117, 106, 104], "mcl_compass_compass_00.png": [114, 107, 104], "mcl_compass_compass_20.png": [116, 106, 104], "mcl_compass_compass_31.png": [115, 107, 104], "mcl_compass_compass_11.png": [117, 106, 104], "mcl_jukebox_record_wait.png": [39, 42, 55], "mcl_jukebox_record_cat.png": [40, 45, 51], "mcl_jukebox_record_mellohi.png": [46, 44, 59], "mcl_jukebox_record_13.png": [51, 47, 51], "mcl_jukebox_record_ward.png": [39, 43, 51], "mcl_jukebox_record_chirp.png": [49, 40, 50], "mcl_jukebox_record_blocks.png": [47, 37, 49], "mcl_jukebox_record_11.png": [41, 40, 52], "mcl_jukebox_record_mall.png": [42, 41, 62], "mcl_jukebox_top.png": [72, 56, 44], "mcl_jukebox_record_strad.png": [45, 45, 57], "mcl_jukebox_record_far.png": [47, 48, 52], "mcl_jukebox_side.png": [94, 74, 57], "mcl_jukebox_record_stal.png": [39, 38, 49], "mcl_fences_fence_acacia.png": [152, 99, 68], "mcl_fences_fence_gate_mask.png": [255, 126, 126], "mcl_fences_fence_gate_spruce.png": [85, 69, 56], "mcl_fences_fence_big_oak.png": [83, 71, 59], "mcl_fences_fence_spruce.png": [84, 67, 54], "mcl_fences_fence_gate_birch.png": [153, 121, 94], "mcl_fences_fence_gate_acacia.png": [155, 102, 70], "mcl_fences_fence_gate_big_oak.png": [85, 73, 61], "mcl_fences_fence_oak.png": [108, 83, 64], "mcl_fences_fence_gate_oak.png": [111, 85, 66], "mcl_fences_fence_jungle.png": [115, 80, 60], "mcl_fences_fence_nether_brick.png": [49, 24, 24], "mcl_fences_fence_birch.png": [151, 119, 93], "mcl_fences_fence_gate_jungle.png": [117, 82, 61], "mcl_fences_fence_mask.png": [255, 126, 126], "mcl_core_leaves_birch.png": [28, 57, 28], "default_mossycobble.png": [100, 105, 94], "default_flint.png": [70, 67, 64], "mcl_core_bowl.png": [78, 61, 47], "mcl_core_bone_block_top.png": [220, 201, 170], "default_acacia_tree.png": [105, 91, 74], "default_steel_block.png": [159, 151, 151], "mcl_core_stonebrick_mossy.png": [81, 101, 76], "default_diamond_block.png": [92, 160, 200], "default_leaves.png": [39, 79, 38], "mcl_core_web.png": [202, 189, 167], "mcl_core_reeds.png": [57, 100, 52], "default_gold_ingot.png": [179, 133, 47], "mcl_core_grass_path_side.png": [113, 89, 62], "mcl_core_red_sand.png": [224, 137, 111], "default_apple.png": [137, 57, 44], "mcl_core_log_birch_top.png": [155, 130, 112], "default_coal_block.png": [51, 49, 51], "mcl_core_andesite_smooth.png": [107, 113, 109], "mcl_core_apple_golden.png": [176, 138, 51], "mcl_core_diorite.png": [153, 149, 146], "mcl_core_granite_smooth.png": [150, 121, 110], "mcl_core_bedrock.png": [91, 77, 66], "mcl_core_planks_spruce.png": [81, 65, 54], "mcl_core_sapling_big_oak.png": [69, 92, 80], "mcl_core_emerald_ore.png": [115, 122, 103], "mcl_core_sandstone_smooth.png": [202, 155, 121], "mcl_core_glass_light_blue.png": [101, 153, 215], "default_brick.png": [139, 87, 75], "mcl_core_redstone_ore.png": [128, 91, 88], "mcl_core_cactus_top.png": [77, 99, 49], "mcl_core_frosted_ice_1.png": [147, 198, 227], "mcl_core_sapling_spruce.png": [55, 72, 53], "mcl_core_stripped_acacia_top.png": [149, 92, 58], "mcl_core_log_spruce_top.png": [97, 71, 57], "mcl_core_glass_lime.png": [126, 203, 24], "mcl_core_lapis_ore.png": [111, 113, 125], "default_junglesapling.png": [64, 88, 39], "default_clay_brick.png": [127, 57, 48], "default_gold_block.png": [192, 147, 59], "default_water_source_animated.png": [37, 98, 129], "mcl_core_glass_yellow.png": [228, 228, 50], "default_acacia_sapling.png": [109, 92, 59], "mcl_core_stripped_acacia_side.png": [155, 96, 61], "mcl_core_sandstone_carved.png": [199, 152, 119], "mcl_core_glass_blue.png": [50, 75, 178], "mcl_core_red_sandstone_normal.png": [198, 120, 104], "mcl_core_glass_gray.png": [75, 75, 75], "mcl_core_leaves_spruce.png": [38, 74, 47], "mcl_core_glass_pink.png": [241, 126, 164], "mcl_core_lapis_block.png": [50, 92, 162], "mcl_core_glass_purple.png": [126, 62, 178], "mcl_core_iron_nugget.png": [156, 151, 145], "mcl_core_papyrus.png": [82, 114, 57], "default_dry_grass.png": [100, 94, 54], "mcl_core_stripped_dark_oak_top.png": [91, 78, 68], "mcl_core_glass_silver.png": [153, 153, 153], "mcl_core_andesite.png": [104, 110, 107], "mcl_core_frosted_ice_3.png": [165, 209, 233], "mcl_core_sugar.png": [215, 215, 215], "default_acacia_wood.png": [152, 100, 69], "mcl_core_glass_black.png": [24, 24, 24], "mcl_core_iron_ore.png": [134, 123, 117], "mcl_core_stripped_birch_side.png": [163, 130, 104], "default_clay.png": [124, 124, 124], "mcl_core_stripped_jungle_side.png": [140, 98, 76], "mcl_core_glass_red.png": [153, 50, 50], "mcl_core_grass_block_top.png": [141, 130, 113], "mcl_core_planks_birch.png": [145, 113, 89], "mcl_core_glass_white.png": [254, 254, 254], "mcl_core_stripped_oak_side.png": [119, 94, 71], "mcl_core_glass_cyan.png": [75, 126, 153], "mcl_core_cactus_side.png": [88, 110, 56], "default_ladder.png": [83, 64, 50], "default_dry_grass_side.png": [91, 93, 52], "mcl_core_stripped_jungle_top.png": [143, 101, 78], "mcl_core_ice_packed.png": [165, 211, 231], "mcl_core_frosted_ice_2.png": [153, 202, 229], "default_dry_shrub.png": [118, 88, 69], "mcl_core_red_sandstone_carved.png": [202, 122, 104], "default_tree.png": [95, 75, 57], "default_clay_lump.png": [111, 111, 111], "mcl_core_red_sandstone_top.png": [212, 126, 108], "mcl_core_dirt_podzol_side.png": [101, 79, 63], "mcl_core_red_sandstone_smooth.png": [207, 124, 106], "default_jungletree_top.png": [125, 87, 67], "mcl_core_coal_ore.png": [109, 101, 99], "default_jungleleaves.png": [29, 84, 30], "mcl_core_vine.png": [21, 61, 21], "default_snow.png": [221, 229, 234], "mcl_core_leaves_big_oak.png": [21, 69, 28], "mcl_core_void.png": [59, 59, 59], "default_tree_top.png": [135, 104, 74], "mcl_core_gold_ore.png": [132, 119, 103], "default_steel_ingot.png": [142, 137, 131], "default_sapling.png": [62, 90, 45], "mcl_core_log_birch.png": [194, 184, 174], "mcl_core_stripped_spruce_top.png": [111, 81, 64], "default_water_flowing_animated.png": [38, 101, 129], "mcl_core_emerald_block.png": [44, 138, 39], "default_jungletree.png": [86, 58, 45], "mcl_core_grass_side_snowed.png": [162, 154, 150], "default_stone_brick.png": [97, 89, 86], "default_lava_flowing_animated.png": [177, 42, 16], "mcl_core_stripped_spruce_side.png": [104, 78, 63], "default_coal_lump.png": [41, 39, 41], "default_sand.png": [220, 170, 127], "mcl_core_glass_green.png": [101, 126, 50], "mcl_core_glass_orange.png": [215, 126, 50], "default_acacia_tree_top.png": [130, 84, 55], "mcl_core_stripped_oak_top.png": [139, 108, 78], "mcl_core_grass_block_side_overlay.png": [153, 142, 123], "default_lava_source_animated.png": [180, 45, 17], "mcl_core_cactus_bottom.png": [169, 168, 116], "mcl_core_sandstone_bottom.png": [202, 155, 121], "default_paper.png": [213, 184, 154], "mcl_core_diamond_ore.png": [122, 124, 126], "default_ice.png": [145, 197, 226], "mcl_core_dirt_podzol_top.png": [85, 63, 42], "mcl_core_slime.png": [93, 157, 86], "mcl_core_gold_nugget.png": [213, 169, 74], "default_stick.png": [88, 70, 57], "mcl_core_emerald.png": [59, 160, 52], "default_diamond.png": [109, 179, 217], "mcl_core_mycelium_top.png": [108, 89, 117], "mcl_core_bone_block_side.png": [226, 207, 174], "mcl_core_diorite_smooth.png": [157, 154, 152], "default_obsidian.png": [13, 9, 25], "mcl_core_planks_big_oak.png": [87, 74, 62], "mcl_core_log_spruce.png": [66, 51, 44], "mcl_core_glass_magenta.png": [178, 75, 215], "mcl_core_granite.png": [153, 121, 110], "mcl_core_log_big_oak_top.png": [83, 70, 62], "default_cobble.png": [113, 106, 104], "mcl_core_red_sandstone_bottom.png": [207, 124, 106], "mcl_core_barrier.png": [138, 46, 38], "mcl_core_stripped_dark_oak_side.png": [86, 73, 63], "mcl_core_mycelium_side.png": [107, 84, 87], "mcl_core_stonebrick_cracked.png": [94, 87, 83], "mcl_core_charcoal.png": [40, 35, 32], "mcl_core_glass_brown.png": [101, 75, 50], "mcl_core_stonebrick_carved.png": [97, 90, 85], "default_wood.png": [113, 87, 67], "default_dirt.png": [108, 83, 70], "mcl_core_log_big_oak.png": [74, 62, 55], "default_junglewood.png": [113, 78, 59], "mcl_core_frosted_ice_0.png": [140, 193, 224], "mcl_core_sandstone_normal.png": [195, 149, 117], "default_gravel.png": [112, 105, 99], "mcl_core_sandstone_top.png": [201, 154, 121], "default_glass.png": [213, 223, 235], "default_stone.png": [130, 122, 118], "mcl_core_sapling_birch.png": [78, 110, 74], "mcl_core_coarse_dirt.png": [117, 92, 76], "default_acacia_leaves.png": [110, 89, 45], "mcl_core_stripped_birch_top.png": [157, 126, 102], "mcl_core_grass_path_top.png": [125, 101, 50], "mcl_throwing_ender_pearl.png": [78, 19, 26], "mcl_throwing_egg.png": [199, 157, 106], "mcl_throwing_snowball.png": [191, 200, 203], "mcl_flowers_tulip_red.png": [82, 57, 43], "mcl_flowers_double_plant_rose_top.png": [81, 69, 45], "mcl_flowers_double_plant_sunflower_front.png": [203, 157, 61], "mcl_flowers_tulip_white.png": [106, 122, 95], "mcl_flowers_double_plant_grass_top.png": [156, 145, 125], "mcl_flowers_azure_bluet.png": [97, 114, 98], "mcl_flowers_oxeye_daisy.png": [130, 139, 110], "mcl_flowers_poppy.png": [96, 59, 43], "mcl_flowers_double_plant_paeonia_top.png": [90, 84, 81], "mcl_flowers_double_plant_rose_bottom.png": [78, 63, 41], "mcl_flowers_tallgrass.png": [151, 141, 122], "mcl_flowers_double_plant_sunflower_bottom.png": [45, 76, 40], "mcl_flowers_fern.png": [143, 132, 115], "flowers_tulip.png": [106, 84, 51], "mcl_flowers_double_plant_syringa_bottom.png": [63, 77, 60], "mcl_flowers_double_plant_fern_bottom.png": [140, 130, 113], "flowers_dandelion_yellow.png": [111, 111, 55], "mcl_flowers_double_plant_paeonia_bottom.png": [82, 83, 73], "mcl_flowers_double_plant_sunflower_back.png": [174, 146, 57], "mcl_flowers_allium.png": [120, 116, 144], "flowers_waterlily.png": [28, 81, 29], "mcl_flowers_tulip_pink.png": [100, 99, 90], "mcl_flowers_double_plant_sunflower_top.png": [48, 81, 44], "mcl_flowers_double_plant_syringa_top.png": [95, 90, 98], "mcl_flowers_double_plant_grass_bottom.png": [151, 140, 121], "mcl_flowers_double_plant_grass_inv.png": [48, 95, 43], "mcl_flowers_fern_inv.png": [43, 86, 39], "mcl_flowers_double_plant_fern_top.png": [148, 138, 119], "mcl_flowers_tallgrass_inv.png": [47, 92, 41], "mcl_flowers_double_plant_fern_inv.png": [45, 89, 40], "mcl_flowers_blue_orchid.png": [46, 91, 86], "mcl_armor_leggings_iron.png": [132, 128, 123], "mcl_armor_inv_leggings_iron.png": [130, 125, 120], "mcl_armor_chestplate_chain_preview.png": [124, 98, 90], "mcl_armor_inv_helmet_gold.png": [178, 134, 51], "mcl_armor_leggings_chain.png": [64, 66, 69], "mcl_armor_helmet_chain_preview.png": [154, 150, 143], "mcl_armor_chestplate_diamond_preview.png": [102, 140, 160], "mcl_armor_inv_boots_iron.png": [134, 129, 124], "mcl_armor_boots_gold_preview.png": [178, 133, 42], "mcl_armor_leggings_diamond_preview.png": [80, 118, 138], "mcl_armor_inv_chestplate_chain.png": [128, 105, 96], "mcl_armor_helmet_diamond_preview.png": [101, 134, 152], "mcl_armor_boots_leather_preview.png": [129, 119, 101], "mcl_armor_inv_chestplate_gold.png": [171, 128, 55], "mcl_armor_inv_helmet_diamond.png": [109, 130, 142], "mcl_armor_leggings_leather_preview.png": [141, 134, 114], "mcl_armor_boots_leather.png": [122, 111, 93], "mcl_armor_inv_chestplate_diamond.png": [106, 146, 168], "mcl_armor_helmet_diamond.png": [70, 85, 93], "mcl_armor_chestplate_iron_preview.png": [143, 134, 123], "mcl_armor_inv_chestplate_leather.png": [143, 136, 118], "mcl_armor_boots_diamond.png": [87, 132, 157], "mcl_armor_leggings_diamond.png": [78, 102, 115], "mcl_armor_leggings_gold_preview.png": [185, 156, 108], "mcl_armor_chestplate_gold.png": [157, 117, 55], "mcl_armor_inv_helmet_chain.png": [140, 137, 132], "mcl_armor_boots_chain_preview.png": [78, 78, 79], "mcl_armor_inv_leggings_chain.png": [81, 81, 82], "mcl_armor_inv_helmet_iron.png": [143, 138, 133], "mcl_armor_helmet_leather.png": [130, 121, 102], "mcl_armor_chestplate_diamond.png": [110, 157, 183], "mcl_armor_leggings_leather.png": [119, 108, 91], "mcl_armor_leggings_iron_preview.png": [127, 122, 117], "mcl_armor_inv_boots_gold.png": [187, 142, 46], "mcl_armor_chestplate_leather.png": [139, 132, 112], "mcl_armor_boots_iron.png": [118, 113, 109], "mcl_armor_elytra.png": [75, 121, 147], "mcl_armor_helmet_chain.png": [127, 124, 121], "mcl_armor_helmet_gold_preview.png": [181, 138, 54], "mcl_armor_boots_iron_preview.png": [118, 113, 108], "mcl_armor_helmet_iron.png": [153, 149, 144], "mcl_armor_inv_boots_leather.png": [130, 121, 103], "mcl_armor_leggings_chain_preview.png": [54, 56, 61], "mcl_armor_helmet_iron_preview.png": [143, 138, 132], "mcl_armor_helmet_leather_preview.png": [119, 109, 91], "mcl_armor_chestplate_leather_preview.png": [144, 138, 118], "mcl_armor_leggings_gold.png": [182, 158, 126], "mcl_armor_inv_leggings_gold.png": [175, 145, 97], "mcl_armor_chestplate_iron.png": [130, 120, 112], "mcl_armor_inv_elytra.png": [76, 122, 148], "mcl_armor_boots_chain.png": [88, 88, 88], "mcl_armor_helmet_gold.png": [178, 136, 56], "mcl_armor_inv_boots_diamond.png": [75, 121, 147], "mcl_armor_inv_chestplate_iron.png": [135, 125, 115], "mcl_armor_inv_leggings_diamond.png": [75, 93, 103], "mcl_armor_inv_leggings_leather.png": [126, 116, 98], "mcl_armor_inv_helmet_leather.png": [140, 132, 114], "mcl_armor_inv_boots_chain.png": [69, 69, 72], "mcl_armor_chestplate_gold_preview.png": [169, 127, 56], "mcl_armor_chestplate_chain.png": [119, 98, 93], "mcl_armor_boots_gold.png": [160, 118, 42], "mcl_armor_boots_diamond_preview.png": [89, 141, 169], "mcl_walls_cobble_wall_top.png": [120, 114, 112], "mcl_walls_cobble_mossy_wall_top.png": [53, 97, 61], "mcl_walls_cobble_wall_side.png": [109, 103, 101], "mcl_walls_cobble_mossy_wall_side.png": [86, 98, 83], "mcl_hoppers_item.png": [44, 44, 44], "mcl_hoppers_hopper_top.png": [43, 43, 43], "mcl_hoppers_hopper_outside.png": [44, 43, 43], "mcl_hoppers_hopper_inside.png": [50, 50, 50], "mcl_stairs_stone_slab_top.png": [127, 118, 114], "mcl_stairs_stone_slab_side.png": [127, 117, 113], "mcl_stairs_turntexture.png": [255, 0, 255], "mcl_brewing_bottle_bg.png": [204, 204, 204], "mcl_brewing_bubble_sprite.png": [167, 167, 167], "mcl_brewing_side.png": [175, 156, 160], "mcl_brewing_inventory.png": [168, 168, 168], "mcl_brewing_bubbles_active.png": [186, 186, 186], "mcl_brewing_fuel_bg.png": [200, 200, 200], "mcl_brewing_potion_bg.png": [204, 204, 204], "mcl_brewing_bubbles.png": [154, 154, 154], "mcl_brewing_top.png": [139, 130, 126], "mcl_brewing_base.png": [130, 122, 118], "mcl_brewing_burner.png": [183, 183, 183], "mcl_brewing_burner_active.png": [212, 161, 132], "xpanes_top_glass_cyan.png": [76, 127, 153], "xpanes_top_glass_brown.png": [102, 76, 51], "xpanes_top_glass_magenta.png": [178, 75, 215], "xpanes_top_glass_light_blue.png": [102, 153, 216], "xpanes_top_glass_blue.png": [51, 76, 178], "xpanes_top_glass_gray.png": [76, 76, 76], "xpanes_top_glass_silver.png": [153, 153, 153], "xpanes_top_iron.png": [155, 146, 146], "xpanes_top_glass_black.png": [25, 25, 25], "xpanes_top_glass_white.png": [255, 255, 255], "xpanes_top_glass_lime.png": [127, 204, 25], "xpanes_top_glass_orange.png": [216, 127, 51], "xpanes_top_glass_purple.png": [127, 63, 178], "xpanes_top_glass_red.png": [153, 51, 51], "xpanes_top_glass_natural.png": [222, 222, 239], "xpanes_top_glass_green.png": [102, 127, 51], "xpanes_top_glass_pink.png": [241, 126, 164], "xpanes_pane_iron.png": [160, 152, 152], "xpanes_top_glass_yellow.png": [229, 229, 51], "hardened_clay_stained_pink.png": [164, 79, 76], "mcl_colorblocks_glazed_terracotta_yellow.png": [232, 199, 99], "mcl_colorblocks_glazed_terracotta_orange.png": [170, 146, 81], "mcl_colorblocks_concrete_powder_lime.png": [125, 186, 42], "mcl_colorblocks_concrete_brown.png": [98, 60, 32], "mcl_colorblocks_concrete_magenta.png": [171, 49, 162], "mcl_colorblocks_glazed_terracotta_magenta.png": [210, 108, 215], "mcl_colorblocks_concrete_silver.png": [128, 129, 118], "mcl_colorblocks_glazed_terracotta_grey.png": [90, 90, 90], "mcl_colorblocks_concrete_powder_blue.png": [72, 75, 169], "mcl_colorblocks_concrete_yellow.png": [241, 177, 21], "mcl_colorblocks_concrete_red.png": [146, 34, 34], "mcl_colorblocks_glazed_terracotta_lime.png": [152, 211, 72], "mcl_colorblocks_concrete_black.png": [8, 10, 15], "mcl_colorblocks_glazed_terracotta_silver.png": [134, 151, 151], "hardened_clay_stained_white.png": [213, 197, 184], "mcl_colorblocks_glazed_terracotta_green.png": [111, 135, 50], "mcl_colorblocks_glazed_terracotta_blue.png": [34, 65, 117], "mcl_colorblocks_concrete_powder_red.png": [172, 57, 52], "mcl_colorblocks_concrete_powder_cyan.png": [38, 150, 159], "hardened_clay_stained_purple.png": [81, 71, 123], "hardened_clay_stained_brown.png": [96, 69, 61], "hardened_clay_stained_grey.png": [110, 92, 85], "mcl_colorblocks_concrete_lime.png": [96, 171, 25], "hardened_clay_stained_blue.png": [68, 91, 143], "mcl_colorblocks_concrete_powder_white.png": [224, 225, 225], "hardened_clay_stained_yellow.png": [177, 128, 51], "hardened_clay_stained_light_blue.png": [91, 128, 171], "hardened_clay.png": [143, 104, 87], "mcl_colorblocks_concrete_cyan.png": [21, 123, 140], "mcl_colorblocks_glazed_terracotta_brown.png": [108, 88, 64], "mcl_colorblocks_concrete_grey.png": [56, 59, 64], "mcl_colorblocks_concrete_powder_magenta.png": [196, 94, 189], "mcl_colorblocks_concrete_powder_black.png": [22, 26, 30], "mcl_colorblocks_concrete_pink.png": [213, 103, 144], "mcl_colorblocks_concrete_powder_orange.png": [227, 141, 38], "mcl_colorblocks_glazed_terracotta_cyan.png": [90, 131, 136], "mcl_colorblocks_glazed_terracotta_red.png": [184, 67, 53], "mcl_colorblocks_concrete_green.png": [75, 94, 37], "mcl_colorblocks_concrete_blue.png": [46, 48, 147], "mcl_colorblocks_glazed_terracotta_light_blue.png": [99, 162, 204], "hardened_clay_stained_orange.png": [156, 95, 69], "mcl_colorblocks_concrete_powder_silver.png": [160, 160, 155], "mcl_colorblocks_concrete_powder_pink.png": [224, 148, 176], "hardened_clay_stained_silver.png": [149, 129, 117], "hardened_clay_stained_red.png": [159, 81, 66], "hardened_clay_stained_magenta.png": [150, 80, 85], "mcl_colorblocks_glazed_terracotta_black.png": [38, 22, 22], "mcl_colorblocks_concrete_white.png": [208, 214, 215], "hardened_clay_stained_green.png": [74, 101, 63], "hardened_clay_stained_lime.png": [105, 134, 73], "mcl_colorblocks_concrete_powder_green.png": [104, 127, 45], "mcl_colorblocks_concrete_light_blue.png": [37, 140, 200], "mcl_colorblocks_concrete_powder_brown.png": [128, 86, 54], "mcl_colorblocks_concrete_purple.png": [103, 32, 159], "hardened_clay_stained_cyan.png": [71, 107, 123], "mcl_colorblocks_concrete_powder_purple.png": [138, 58, 180], "mcl_colorblocks_concrete_powder_yellow.png": [230, 198, 54], "mcl_colorblocks_concrete_powder_light_blue.png": [75, 181, 212], "mcl_colorblocks_glazed_terracotta_pink.png": [251, 138, 170], "mcl_colorblocks_glazed_terracotta_purple.png": [112, 49, 152], "mcl_colorblocks_concrete_orange.png": [226, 101, 1], "mcl_colorblocks_concrete_powder_grey.png": [91, 98, 103], "hardened_clay_stained_black.png": [69, 52, 46], "mcl_colorblocks_glazed_terracotta_white.png": [188, 211, 202], "fire_basic_flame_animated.png": [206, 98, 34], "mcl_burning_hud_flame_animated.png": [206, 98, 34], "mcl_fire_fire_charge.png": [95, 58, 41], "mcl_burning_entity_flame_animated.png": [206, 98, 34], "mcl_fire_flint_and_steel.png": [96, 95, 93], "fire_basic_flame.png": [207, 100, 36], "dye_red.png": [113, 74, 47], "dye_yellow.png": [123, 91, 49], "dye_violet.png": [107, 76, 57], "dye_dark_green.png": [99, 81, 47], "mcl_dye_blue.png": [58, 101, 173], "dye_cyan.png": [104, 89, 60], "mcl_dye_lime.png": [107, 91, 53], "dye_pink.png": [120, 81, 61], "mcl_dye_light_blue.png": [103, 88, 70], "dye_dark_grey.png": [108, 81, 52], "mcl_dye_white.png": [205, 193, 166], "dye_grey.png": [113, 86, 58], "dye_magenta.png": [111, 79, 59], "dye_orange.png": [122, 85, 48], "mcl_dye_brown.png": [104, 75, 56], "mcl_dye_black.png": [56, 56, 64], "default_river_water_flowing_animated.png": [38, 123, 130], "default_river_water_source_animated.png": [37, 120, 130], "3d_armor_stand_item.png": [134, 114, 98], "mob_spawner.png": [40, 40, 40], "mcl_nether_quartz_chiseled_side.png": [194, 186, 183], "mcl_nether_quartz_pillar_top.png": [195, 188, 185], "mcl_nether_nether_wart.png": [190, 79, 75], "mcl_nether_nether_wart_stage_1.png": [86, 54, 51], "mcl_nether_quartz_ore.png": [133, 64, 53], "mcl_nether_soul_sand.png": [90, 70, 51], "mcl_nether_nether_wart_block.png": [175, 76, 73], "mcl_nether_nether_wart_stage_0.png": [53, 41, 38], "mcl_nether_quartz_block_bottom.png": [198, 191, 187], "mcl_nether_quartz_block_top.png": [198, 190, 187], "mcl_nether_quartz.png": [152, 149, 147], "mcl_nether_quartz_pillar_side.png": [195, 188, 184], "mcl_nether_netherbrick.png": [58, 24, 20], "mcl_nether_glowstone.png": [202, 154, 96], "mcl_nether_netherrack.png": [130, 50, 39], "mcl_nether_red_nether_brick.png": [69, 17, 5], "mcl_nether_quartz_chiseled_top.png": [197, 189, 186], "mcl_nether_glowstone_dust.png": [209, 137, 67], "mcl_nether_nether_wart_stage_2.png": [106, 57, 53], "mcl_nether_quartz_block_side.png": [198, 190, 187], "mcl_nether_nether_brick.png": [49, 23, 24], "mcl_nether_magma.png": [85, 33, 27], "mcl_cauldrons_cauldron_inner.png": [24, 24, 24], "mcl_cauldrons_cauldron_top.png": [54, 54, 54], "mcl_cauldrons_cauldron_bottom.png": [50, 37, 38], "mcl_cauldrons_cauldron.png": [47, 47, 47], "mcl_cauldrons_cauldron_side.png": [43, 43, 43], "mcl_beds_bed_side_bottom_magenta.png": [127, 48, 89], "mcl_beds_bed_blue.png": [73, 78, 105], "mcl_beds_bed_side_top_r_black.png": [99, 86, 75], "mcl_beds_bed_side_bottom_r_magenta.png": [132, 46, 94], "mcl_beds_bed_side_top_brown.png": [98, 76, 59], "mcl_beds_bed_lime.png": [96, 135, 66], "mcl_beds_bed_side_top_green.png": [98, 76, 59], "mcl_beds_bed_light_blue.png": [100, 107, 142], "mcl_beds_bed_pink.png": [184, 105, 115], "mcl_beds_bed_side_bottom_black.png": [66, 56, 47], "mcl_beds_bed_top_bottom_green.png": [57, 110, 29], "mcl_beds_bed_side_top_blue.png": [98, 76, 59], "mcl_beds_bed_top_top_pink.png": [217, 138, 147], "mcl_beds_bed_side_bottom_light_blue.png": [90, 94, 129], "mcl_beds_bed_side_bottom_blue.png": [63, 65, 90], "mcl_beds_bed_top_top_red.png": [173, 90, 83], "mcl_beds_bed_side_top_grey.png": [98, 76, 59], "mcl_beds_bed_top_top_white.png": [198, 190, 183], "mcl_beds_bed_top_top_black.png": [107, 100, 92], "mcl_beds_bed_top_bottom_brown.png": [101, 69, 38], "mcl_beds_bed_top_bottom_pink.png": [232, 105, 135], "mcl_beds_bed_side_bottom_r_pink.png": [183, 95, 106], "mcl_beds_bed_side_bottom_r_green.png": [73, 97, 42], "mcl_beds_bed_side_bottom_r_grey.png": [86, 77, 69], "mcl_beds_bed_side_top_r_white.png": [158, 145, 134], "mcl_beds_bed_side_bottom_orange.png": [143, 84, 28], "mcl_beds_bed_side_bottom_purple.png": [105, 36, 112], "mcl_beds_bed_side_bottom_r_light_blue.png": [90, 97, 136], "mcl_beds_bed_side_top_r_magenta.png": [140, 81, 103], "mcl_beds_bed_side_bottom_r_yellow.png": [150, 131, 25], "mcl_beds_bed_side_top_r_pink.png": [176, 111, 113], "mcl_beds_bed_top_top_blue.png": [105, 112, 137], "mcl_beds_bed_side_bottom_green.png": [74, 94, 43], "mcl_beds_bed_side_bottom_r_blue.png": [61, 66, 95], "mcl_beds_bed_top_top_grey.png": [129, 121, 113], "mcl_beds_bed_black.png": [76, 68, 61], "mcl_beds_bed_top_top_silver.png": [159, 151, 143], "mcl_beds_bed_white.png": [173, 165, 158], "mcl_beds_bed_top_top_cyan.png": [105, 144, 135], "mcl_beds_bed_top_bottom_orange.png": [184, 91, 0], "mcl_beds_bed_side_top_silver.png": [98, 76, 59], "mcl_beds_bed_top_top_brown.png": [143, 118, 93], "mcl_beds_bed_side_top_r_light_blue.png": [115, 111, 132], "mcl_beds_bed_side_bottom_r_lime.png": [86, 129, 53], "mcl_beds_bed_red.png": [139, 58, 51], "mcl_beds_bed_top_bottom_lime.png": [79, 163, 47], "mcl_beds_bed_side_top_r_brown.png": [121, 97, 75], "mcl_beds_bed_side_bottom_r_silver.png": [119, 109, 102], "mcl_beds_bed_yellow.png": [154, 138, 41], "mcl_beds_bed_side_top_yellow.png": [98, 76, 59], "mcl_beds_bed_top_bottom_black.png": [37, 37, 37], "mcl_beds_bed_brown.png": [110, 85, 61], "mcl_beds_bed_side_top_orange.png": [98, 76, 59], "mcl_beds_bed_side_top_red.png": [98, 76, 59], "mcl_beds_bed_top_top_purple.png": [148, 79, 161], "mcl_beds_bed_side_bottom_pink.png": [177, 93, 102], "mcl_beds_bed_side_top_r_grey.png": [112, 99, 88], "mcl_beds_bed_side_top_r_blue.png": [97, 91, 104], "mcl_beds_bed_side_top_purple.png": [98, 76, 59], "mcl_beds_bed_side_top_cyan.png": [98, 76, 59], "mcl_beds_bed_top_bottom_blue.png": [32, 60, 119], "mcl_beds_bed_side_bottom_yellow.png": [143, 125, 28], "mcl_beds_bed_side_top_black.png": [98, 76, 59], "mcl_beds_bed_top_top_orange.png": [188, 130, 72], "mcl_beds_bed_top_bottom_silver.png": [129, 129, 129], "mcl_beds_bed_top_top_green.png": [117, 140, 88], "mcl_beds_bed_cyan.png": [73, 111, 103], "mcl_beds_bed_top_bottom_red.png": [157, 20, 20], "mcl_beds_bed_top_bottom_purple.png": [111, 0, 163], "mcl_beds_bed_side_top_r_silver.png": [133, 120, 109], "mcl_beds_bed_side_bottom_grey.png": [86, 76, 67], "mcl_beds_bed_grey.png": [96, 88, 81], "mcl_beds_bed_side_top_r_yellow.png": [151, 132, 62], "mcl_beds_bed_side_top_r_green.png": [103, 111, 72], "mcl_beds_bed_side_bottom_brown.png": [100, 73, 48], "mcl_beds_bed_magenta.png": [138, 60, 104], "mcl_beds_bed_side_bottom_r_red.png": [134, 44, 37], "mcl_beds_bed_side_bottom_r_brown.png": [101, 73, 47], "mcl_beds_bed_side_top_lime.png": [98, 76, 59], "mcl_beds_bed_side_top_light_blue.png": [98, 76, 59], "mcl_beds_bed_side_bottom_red.png": [129, 47, 38], "mcl_beds_bed_bottom_top.png": [48, 38, 29], "mcl_beds_bed_top_bottom_grey.png": [76, 76, 76], "mcl_beds_bed_side_bottom_r_orange.png": [150, 86, 25], "mcl_beds_bed_side_bottom_r_black.png": [64, 54, 47], "mcl_beds_bed_top_bottom_cyan.png": [32, 119, 114], "mcl_beds_bed_side_bottom_silver.png": [116, 106, 97], "mcl_beds_bed_side_top_magenta.png": [98, 76, 59], "mcl_beds_bed_top_bottom_white.png": [201, 201, 201], "mcl_beds_bed_side_top_r_orange.png": [151, 105, 62], "mcl_beds_bed_top_bottom_magenta.png": [154, 23, 118], "mcl_beds_bed_side_top_r_lime.png": [110, 131, 80], "mcl_beds_bed_top_top_magenta.png": [172, 92, 137], "mcl_beds_bed_bottom_bottom.png": [48, 38, 29], "mcl_beds_bed_side_top_r_purple.png": [125, 73, 119], "mcl_beds_bed_side_top_r_cyan.png": [97, 113, 103], "mcl_beds_bed_side_top_white.png": [98, 76, 59], "mcl_beds_bed_side_bottom_r_cyan.png": [61, 101, 93], "mcl_beds_bed_side_bottom_cyan.png": [63, 97, 89], "mcl_beds_bed_side_bottom_white.png": [161, 151, 142], "mcl_beds_bed_top_bottom_yellow.png": [184, 169, 0], "mcl_beds_bed_top_bottom_light_blue.png": [82, 113, 182], "mcl_beds_bed_top_top_lime.png": [130, 169, 98], "mcl_beds_bed_silver.png": [109, 100, 93], "mcl_beds_bed_purple.png": [115, 47, 128], "mcl_beds_bed_side_top_r_red.png": [141, 80, 69], "mcl_beds_bed_top_top_light_blue.png": [132, 141, 174], "mcl_beds_bed_side_bottom_r_purple.png": [107, 32, 120], "mcl_beds_bed_side_bottom_r_white.png": [161, 151, 144], "mcl_beds_bed_orange.png": [154, 96, 41], "mcl_beds_bed_top_bottom_gray.png": [57, 57, 57], "mcl_beds_bed_side_bottom_lime.png": [85, 122, 53], "mcl_beds_bed_green.png": [85, 107, 56], "mcl_beds_bed_top_top_yellow.png": [188, 172, 72], "mcl_beds_bed_side_top_pink.png": [98, 76, 59], "mcl_sponges_sponge_wet_river_water.png": [157, 141, 104], "mcl_sponges_sponge.png": [210, 177, 118], "mcl_sponges_sponge_wet.png": [156, 134, 92], "farming_mushroom_red.png": [169, 59, 58], "mcl_mushrooms_mushroom_block_inside.png": [218, 175, 136], "mcl_mushrooms_mushroom_block_skin_brown.png": [131, 86, 68], "mcl_mushrooms_mushroom_block_skin_stem.png": [204, 183, 149], "mcl_mushrooms_mushroom_block_skin_red.png": [137, 39, 25], "farming_mushroom_brown.png": [121, 81, 59], "farming_mushroom_stew.png": [134, 97, 67], "default_tool_goldsword.png": [194, 154, 70], "default_tool_steelsword.png": [134, 130, 125], "default_tool_woodsword.png": [100, 82, 68], "default_tool_goldshovel.png": [167, 133, 64], "default_tool_steelpick.png": [137, 128, 119], "default_tool_woodshovel.png": [108, 90, 76], "default_tool_goldpick.png": [172, 139, 73], "default_tool_woodaxe.png": [110, 92, 77], "default_tool_diamondsword.png": [105, 133, 149], "default_tool_steelshovel.png": [125, 115, 107], "default_tool_stonesword.png": [133, 125, 118], "default_tool_woodpick.png": [110, 91, 76], "default_tool_shears.png": [139, 132, 124], "default_tool_goldaxe.png": [160, 128, 66], "default_tool_stoneshovel.png": [126, 116, 107], "default_tool_diamondaxe.png": [103, 110, 113], "default_tool_diamondshovel.png": [106, 125, 134], "default_tool_steelaxe.png": [129, 119, 110], "default_tool_stoneaxe.png": [126, 115, 104], "default_tool_diamondpick.png": [92, 105, 111], "default_tool_stonepick.png": [126, 114, 104], "mcl_chests_ender_chest_right.png": [73, 67, 64], "mcl_chests_chest_trapped_right.png": [98, 78, 62], "default_chest_front.png": [85, 70, 58], "mcl_chests_blue_shulker_box_top.png": [67, 85, 119], "mcl_chests_chest_left.png": [99, 78, 63], "mcl_chests_dark_green_shulker_box_top.png": [67, 111, 70], "mcl_chests_chest_back.png": [92, 75, 61], "mcl_chests_ender_chest_bottom.png": [61, 55, 55], "mcl_chests_ender.png": [70, 62, 58], "mcl_chests_brown_shulker_box_top.png": [73, 63, 55], "mcl_chests_chest_trapped_back.png": [92, 75, 61], "mcl_chests_chest_trapped_side_big.png": [96, 77, 62], "mcl_chests_magenta_shulker_box_top.png": [128, 81, 124], "mcl_chests_ender_chest_back.png": [72, 66, 64], "mcl_chests_chest_trapped_bottom.png": [118, 91, 70], "mcl_chests_chest_trapped_front.png": [86, 68, 57], "default_chest_side_big.png": [96, 77, 62], "mcl_chests_green_shulker_box_top.png": [88, 122, 75], "mcl_chests_pink_shulker_box_top.png": [163, 116, 158], "mcl_chests_trapped.png": [95, 76, 61], "mcl_chests_blank.png": [255, 255, 255], "mcl_chests_normal_double.png": [98, 78, 62], "mcl_chests_chest_trapped_top.png": [88, 73, 61], "mcl_chests_normal.png": [95, 76, 61], "default_chest_front_big.png": [93, 75, 61], "mcl_chests_ender_chest_front.png": [76, 69, 65], "mcl_chests_white_shulker_box_top.png": [176, 178, 187], "mcl_chests_cyan_shulker_box_top.png": [67, 101, 121], "mcl_chests_chest_trapped_top_big.png": [100, 80, 65], "default_chest_top_big.png": [100, 80, 65], "mcl_chests_grey_shulker_box_top.png": [126, 129, 138], "mcl_chests_red_shulker_box_top.png": [132, 58, 57], "mcl_chests_trapped_double.png": [98, 78, 62], "mcl_chests_violet_shulker_box_top.png": [120, 71, 88], "mcl_chests_chest_trapped_front_big.png": [94, 75, 61], "mcl_chests_lightblue_shulker_box_top.png": [96, 130, 155], "mcl_chests_dark_grey_shulker_box_top.png": [87, 90, 99], "mcl_chests_black_shulker_box_top.png": [56, 57, 62], "mcl_chests_chest_right.png": [98, 78, 62], "mcl_chests_yellow_shulker_box_top.png": [165, 116, 53], "mcl_chests_chest_bottom.png": [118, 91, 70], "default_chest_top.png": [88, 73, 61], "mcl_chests_ender_chest_top.png": [70, 64, 61], "mcl_chests_ender_chest_left.png": [73, 67, 64], "mcl_chests_chest_trapped_left.png": [99, 78, 63], "mcl_chests_orange_shulker_box_top.png": [143, 74, 51], "screwdriver.png": [132, 119, 108], "_un.png": [0, 0, 0], "_at.png": [0, 0, 0], "_s_.png": [0, 0, 0], "_sz.png": [0, 0, 0], "_q.png": [0, 0, 0], "_1.png": [0, 0, 0], "_h_.png": [0, 0, 0], "_o_tilde.png": [0, 0, 0], "_q_.png": [0, 0, 0], "_ae.png": [0, 0, 0], "_e_circumflex_.png": [0, 0, 0], "_ex.png": [0, 0, 0], "_e_.png": [0, 0, 0], "_qo.png": [0, 0, 0], "_z_.png": [0, 0, 0], "_ps.png": [0, 0, 0], "_pound.png": [0, 0, 0], "_div.png": [0, 0, 0], "_l_.png": [0, 0, 0], "_pilcrow.png": [0, 0, 0], "_3_sup.png": [0, 0, 0], "_e_acute.png": [0, 0, 0], "_9.png": [0, 0, 0], "_e_grave_.png": [0, 0, 0], "_u_acute.png": [0, 0, 0], "_a_sup.png": [0, 0, 0], "_sr.png": [0, 0, 0], "_v.png": [0, 0, 0], "_ue_.png": [0, 0, 0], "_t_.png": [0, 0, 0], "_cl.png": [0, 0, 0], "_n_tilde_.png": [0, 0, 0], "_p_.png": [0, 0, 0], "_c.png": [0, 0, 0], "_a.png": [0, 0, 0], "_a_circumflex_.png": [0, 0, 0], "_8.png": [0, 0, 0], "_s.png": [0, 0, 0], "_o_.png": [0, 0, 0], "_1_4.png": [0, 0, 0], "_e_grave.png": [0, 0, 0], "_o_dash.png": [0, 0, 0], "_5.png": [0, 0, 0], "_d_dash_.png": [0, 0, 0], "_i_grave.png": [0, 0, 0], "_vb.png": [0, 0, 0], "_sp.png": [255, 255, 255], "_a_acute_.png": [0, 0, 0], "_as.png": [0, 0, 0], "_y_acute.png": [0, 0, 0], "_3_4.png": [0, 0, 0], "_6.png": [0, 0, 0], "_7.png": [0, 0, 0], "_tl.png": [0, 0, 0], "_t.png": [0, 0, 0], "_y.png": [0, 0, 0], "_ca.png": [0, 0, 0], "_e.png": [0, 0, 0], "_hs.png": [0, 0, 0], "_copyright.png": [0, 0, 0], "_l.png": [0, 0, 0], "_h.png": [0, 0, 0], "_u_circumflex_.png": [0, 0, 0], "_i_acute_.png": [0, 0, 0], "_ha.png": [0, 0, 0], "_y_diaresis.png": [0, 0, 0], "_gt.png": [0, 0, 0], "_b.png": [0, 0, 0], "_degree.png": [0, 0, 0], "_a_tilde_.png": [0, 0, 0], "_u_.png": [0, 0, 0], "_o_sup.png": [0, 0, 0], "_m_.png": [0, 0, 0], "_c_.png": [0, 0, 0], "_cr.png": [0, 0, 0], "_3.png": [0, 0, 0], "_currency.png": [0, 0, 0], "_f.png": [0, 0, 0], "_cedille.png": [0, 0, 0], "_u_grave_.png": [0, 0, 0], "_dt.png": [0, 0, 0], "_am.png": [0, 0, 0], "_c_cedille_.png": [0, 0, 0], "_u_acute_.png": [0, 0, 0], "_bl.png": [0, 0, 0], "_registered.png": [0, 0, 0], "_i_acute.png": [0, 0, 0], "_lt.png": [0, 0, 0], "_e_acute_.png": [0, 0, 0], "_paragraph.png": [0, 0, 0], "_i_grave_.png": [0, 0, 0], "_o.png": [0, 0, 0], "_1_sup.png": [0, 0, 0], "mcl_signs_sign.png": [114, 89, 69], "_yen.png": [0, 0, 0], "_b_.png": [0, 0, 0], "_macron.png": [0, 0, 0], "_qu_inv.png": [0, 0, 0], "_o_dash_.png": [0, 0, 0], "_guill_right.png": [0, 0, 0], "_p.png": [0, 0, 0], "_thorn_.png": [0, 0, 0], "_2_sup.png": [0, 0, 0], "_pr.png": [0, 0, 0], "default_sign.png": [145, 115, 88], "_times_dot.png": [0, 0, 0], "_acute.png": [0, 0, 0], "_g_.png": [0, 0, 0], "_o_acute_.png": [0, 0, 0], "_a_tilde.png": [0, 0, 0], "_j.png": [0, 0, 0], "_k.png": [0, 0, 0], "_co.png": [0, 0, 0], "_dv.png": [0, 0, 0], "_o_circumflex.png": [0, 0, 0], "_a_ring.png": [0, 0, 0], "_br.png": [0, 0, 0], "_d.png": [0, 0, 0], "_ap.png": [0, 0, 0], "_sl.png": [0, 0, 0], "_mn.png": [0, 0, 0], "_m.png": [0, 0, 0], "_ae_lig.png": [0, 0, 0], "_thorn.png": [0, 0, 0], "_2.png": [0, 0, 0], "_gr.png": [0, 0, 0], "_i.png": [0, 0, 0], "_y_acute_.png": [0, 0, 0], "_diaresis.png": [0, 0, 0], "_oe.png": [0, 0, 0], "_mu.png": [0, 0, 0], "_guill_left.png": [0, 0, 0], "_times_cross.png": [0, 0, 0], "_ae_.png": [0, 0, 0], "_w.png": [0, 0, 0], "_u.png": [0, 0, 0], "_broken_bar.png": [0, 0, 0], "_4.png": [0, 0, 0], "_plus_minus.png": [0, 0, 0], "_1_2.png": [0, 0, 0], "_u_circumflex.png": [0, 0, 0], "_w_.png": [0, 0, 0], "_x_.png": [0, 0, 0], "_e_circumflex.png": [0, 0, 0], "_g.png": [0, 0, 0], "_o_tilde_.png": [0, 0, 0], "_ae_lig_.png": [0, 0, 0], "_v_.png": [0, 0, 0], "_dl.png": [0, 0, 0], "_a_grave.png": [0, 0, 0], "_re.png": [0, 0, 0], "_a_acute.png": [0, 0, 0], "_qu.png": [0, 0, 0], "_oe_.png": [0, 0, 0], "_n_tilde.png": [0, 0, 0], "_eq.png": [0, 0, 0], "_d_.png": [0, 0, 0], "_sm.png": [0, 0, 0], "_y_.png": [0, 0, 0], "_not.png": [0, 0, 0], "_n.png": [0, 0, 0], "_j_.png": [0, 0, 0], "_k_.png": [0, 0, 0], "_0.png": [0, 0, 0], "_o_grave_.png": [0, 0, 0], "_r_.png": [0, 0, 0], "_r.png": [0, 0, 0], "_u_grave.png": [0, 0, 0], "_ee_.png": [0, 0, 0], "_c_cedille.png": [0, 0, 0], "_ex_inv.png": [0, 0, 0], "_cm.png": [0, 0, 0], "_o_grave.png": [0, 0, 0], "_x.png": [0, 0, 0], "_i_.png": [0, 0, 0], "_n_.png": [0, 0, 0], "_rc.png": [0, 0, 0], "_a_.png": [0, 0, 0], "_a_grave_.png": [0, 0, 0], "_ee.png": [0, 0, 0], "_o_acute.png": [0, 0, 0], "_a_ring_.png": [0, 0, 0], "_i_circumflex_.png": [0, 0, 0], "_cent.png": [0, 0, 0], "_d_dash.png": [0, 0, 0], "_f_.png": [0, 0, 0], "_o_circumflex_.png": [0, 0, 0], "_ue.png": [0, 0, 0], "_a_circumflex.png": [0, 0, 0], "_i_circumflex.png": [0, 0, 0], "_z.png": [0, 0, 0], "gui_furnace_arrow_fg.png": [239, 239, 239], "default_furnace_front.png": [105, 95, 91], "default_furnace_fire_bg.png": [139, 139, 139], "default_furnace_top.png": [148, 138, 133], "default_furnace_fire_fg.png": [179, 115, 70], "default_furnace_side.png": [117, 107, 102], "gui_furnace_arrow_bg.png": [139, 139, 139], "default_furnace_front_active.png": [119, 95, 85], "default_furnace_bottom.png": [148, 138, 133], "default_torch_on_floor.png": [115, 82, 59], "default_torch_on_floor_animated.png": [116, 84, 61], "default_tnt_bottom.png": [161, 54, 58], "mcl_tnt_blink.png": [255, 255, 255], "default_tnt_top.png": [125, 54, 57], "default_tnt_side.png": [178, 105, 98], "mcl_heads_skeleton.png": [125, 125, 125], "mcl_heads_skeleton_node.png": [124, 124, 124], "mcl_heads_creeper_node.png": [98, 107, 71], "mcl_heads_zombie.png": [66, 104, 69], "mcl_heads_creeper.png": [92, 110, 68], "mcl_heads_steve_node.png": [115, 70, 58], "mcl_heads_skeleton_preview.png": [128, 127, 127], "mcl_heads_steve_preview.png": [117, 83, 66], "mcl_heads_zombie_node.png": [78, 110, 105], "mcl_heads_steve.png": [108, 76, 59], "mcl_heads_wither_skeleton_node.png": [50, 50, 50], "mcl_heads_zombie_preview.png": [66, 103, 68], "mcl_heads_creeper_preview.png": [88, 110, 65], "mcl_heads_wither_skeleton.png": [50, 50, 50], "mcl_heads_wither_skeleton_preview.png": [50, 50, 50], "mcl_flowerpots_cactus.png": [109, 83, 52], "mcl_flowerpots_flowerpot_inventory.png": [121, 54, 45], "mcl_flowerpots_flowerpot.png": [120, 55, 47], "bucket_lava.png": [166, 127, 113], "bucket_river_water.png": [139, 152, 155], "bucket_water.png": [139, 147, 155], "bucket.png": [147, 143, 139], "mcl_anvils_anvil_top_damaged_1.png": [48, 48, 48], "mcl_anvils_anvil_top_damaged_2.png": [46, 46, 46], "mcl_anvils_anvil_top_damaged_0.png": [50, 50, 50], "mcl_anvils_anvil_side.png": [45, 45, 45], "mcl_anvils_inventory.png": [157, 157, 157], "mcl_anvils_anvil_base.png": [40, 40, 40], "mcl_maps_map_filled.png": [213, 176, 148], "mcl_maps_map_empty.png": [217, 187, 157], "mcl_maps_map_filled_markings.png": [183, 183, 183], "mcl_dispensers_dispenser_front_vertical.png": [115, 104, 99], "mcl_dispensers_dispenser_front_horizontal.png": [105, 96, 92], "jeija_wall_lever.png": [95, 80, 69], "mesecons_delayer_front_locked_off.png": [97, 85, 77], "mesecons_delayer_locked_on.png": [114, 100, 95], "mesecons_delayer_sides_locked_off.png": [95, 80, 73], "mesecons_delayer_sides_on.png": [106, 71, 63], "mesecons_delayer_item.png": [100, 87, 82], "mesecons_delayer_end_locked_off.png": [97, 85, 77], "mesecons_delayer_end_locked_on.png": [101, 85, 78], "mesecons_delayer_ends_off.png": [99, 86, 80], "mesecons_delayer_front_locked_on.png": [101, 85, 77], "mesecons_delayer_ends_on.png": [105, 87, 81], "mesecons_delayer_sides_locked_on.png": [104, 81, 74], "mesecons_delayer_locked_off.png": [110, 99, 95], "mesecons_delayer_sides_off.png": [90, 69, 61], "mesecons_delayer_off.png": [112, 100, 96], "mesecons_delayer_on.png": [116, 101, 97], "redstone_redstone_dust_line0.png": [168, 168, 168], "redstone_redstone_dust.png": [81, 0, 0], "redstone_redstone_dust_dot.png": [168, 168, 168], "redstone_redstone_dust_line1.png": [173, 173, 173], "jeija_commandblock_off.png": [110, 99, 96], "jeija_commandblock_on.png": [110, 99, 96], "redstone_redstone_block.png": [128, 8, 9], "jeija_torches_on.png": [102, 68, 56], "jeija_torches_off.png": [90, 66, 54], "mesecons_button_wield_mask.png": [255, 126, 126], "mcl_droppers_dropper_front_vertical.png": [118, 108, 103], "mcl_droppers_dropper_front_horizontal.png": [110, 101, 96], "mesecons_noteblock.png": [104, 81, 63], "jeija_solar_panel_inverted.png": [100, 107, 117], "jeija_solar_panel.png": [124, 113, 101], "jeija_solar_panel_side.png": [60, 47, 36], "mcl_observers_observer_top.png": [139, 128, 123], "mcl_observers_observer_front.png": [95, 80, 84], "mcl_observers_observer_back_lit.png": [75, 67, 65], "mcl_observers_observer_back.png": [72, 67, 64], "mcl_observers_observer_side.png": [111, 103, 99], "mesecons_piston_pusher_front_sticky.png": [97, 81, 63], "mesecons_piston_pusher_top.png": [106, 83, 65], "mesecons_piston_back.png": [110, 101, 98], "mesecons_piston_on_front.png": [111, 101, 98], "mesecons_piston_pusher_back.png": [106, 83, 65], "mesecons_piston_bottom.png": [120, 107, 100], "mesecons_piston_pusher_right.png": [106, 83, 65], "mesecons_piston_pusher_bottom.png": [106, 83, 65], "mesecons_piston_pusher_front.png": [106, 83, 65], "mesecons_piston_pusher_left.png": [106, 83, 65], "jeija_lightstone_gray_on.png": [97, 56, 37], "jeija_lightstone_gray_off.png": [64, 49, 43], "mcl_comparators_sides_on.png": [105, 87, 81], "mcl_comparators_comp.png": [61, 20, 20], "mcl_comparators_on.png": [116, 102, 98], "mcl_comparators_sides_comp.png": [99, 88, 83], "mcl_comparators_off.png": [113, 102, 98], "mcl_comparators_ends_comp.png": [99, 88, 83], "mcl_comparators_ends_sub.png": [105, 88, 83], "mcl_comparators_ends_off.png": [96, 80, 74], "mcl_comparators_ends_on.png": [105, 81, 75], "mcl_comparators_sub.png": [112, 25, 25], "mcl_comparators_item.png": [98, 83, 79], "mcl_comparators_sides_off.png": [99, 86, 80], "mcl_comparators_sides_sub.png": [105, 88, 83], "default_book.png": [103, 67, 44], "default_bookshelf.png": [84, 67, 54], "mcl_books_book_written.png": [110, 74, 44], "mcl_books_book_bg.png": [203, 180, 151], "mcl_books_button9_pressed.png": [145, 112, 86], "mcl_books_button9.png": [145, 112, 86], "mcl_books_book_writable.png": [151, 122, 108], "mcl_books_bookshelf_top.png": [109, 84, 65], "wool_dark_grey.png": [96, 87, 87], "wool_grey.png": [143, 134, 134], "wool_magenta.png": [140, 85, 125], "wool_black.png": [45, 42, 42], "wool_orange.png": [188, 106, 45], "wool_blue.png": [43, 73, 125], "wool_yellow.png": [201, 163, 69], "wool_pink.png": [171, 91, 108], "wool_dark_green.png": [53, 91, 51], "wool_brown.png": [86, 57, 43], "wool_red.png": [132, 42, 45], "mcl_wool_light_blue.png": [91, 130, 180], "wool_cyan.png": [30, 94, 113], "mcl_wool_lime.png": [107, 151, 76], "wool_white.png": [212, 199, 182], "wool_violet.png": [77, 57, 102], "mcl_potions_melon_speckled.png": [170, 97, 62], "mcl_potions_effect_swift.png": [106, 96, 85], "mcl_potions_spider_eye_fermented.png": [143, 97, 62], "mcl_potions_splash_bottle.png": [168, 156, 183], "mcl_potions_effect_water_breathing.png": [59, 69, 100], "mcl_potions_effect_leaping.png": [100, 91, 86], "mcl_potions_effect_weak.png": [127, 126, 126], "mcl_potions_dragon_breath.png": [171, 137, 163], "mcl_potions_effect_food_poisoning.png": [112, 123, 89], "hudbars_icon_regenerate.png": [195, 77, 114], "mcl_potions_effect_fire_proof.png": [112, 68, 68], "mcl_potions_splash_overlay.png": [202, 202, 202], "mcl_potions_effect_invisible.png": [96, 103, 95], "hbhunger_icon_regen_poison.png": [147, 111, 115], "mcl_potions_effect_slow.png": [78, 81, 85], "mcl_potions_lingering_bottle.png": [181, 159, 192], "mcl_potions_potion_overlay.png": [201, 201, 201], "mcl_potions_effect_regenerating.png": [133, 90, 83], "mcl_potions_arrow_inv.png": [171, 165, 160], "mcl_potions_effect_night_vision.png": [86, 99, 74], "mcl_potions_potion_bottle.png": [156, 172, 203], "mcl_potions_effect_poisoned.png": [78, 110, 80], "mcl_potions_effect_strong.png": [100, 82, 97], "crafting_workbench_front.png": [120, 93, 72], "gui_crafting_arrow.png": [139, 139, 139], "crafting_workbench_side.png": [120, 93, 72], "crafting_workbench_top.png": [152, 121, 93], "mcl_enchanting_glyph_11.png": [209, 209, 231], "mcl_enchanting_glyph_14.png": [209, 209, 231], "mcl_enchanting_glyph_6.png": [209, 209, 231], "mcl_enchanting_glyph_8.png": [209, 209, 231], "mcl_enchanting_glyph_9.png": [209, 209, 231], "mcl_enchanting_glyph_3.png": [209, 209, 231], "mcl_enchanting_number_1_off.png": [255, 255, 255], "mcl_enchanting_number_3_off.png": [255, 255, 255], "mcl_enchanting_number_3.png": [151, 47, 40], "mcl_enchanting_book_open.png": [153, 123, 99], "mcl_enchanting_button_off.png": [255, 255, 255], "mcl_enchanting_glyph_2.png": [209, 209, 231], "mcl_enchanting_glyph_1.png": [209, 209, 231], "mcl_enchanting_button.png": [255, 255, 255], "mcl_enchanting_table_side.png": [66, 58, 55], "mcl_enchanting_book_closed.png": [112, 78, 55], "mcl_enchanting_table_bottom.png": [58, 51, 52], "mcl_enchanting_glyph_15.png": [209, 209, 231], "mcl_enchanting_number_2_off.png": [255, 255, 255], "mcl_enchanting_glyph_5.png": [209, 209, 231], "mcl_enchanting_number_1.png": [149, 45, 39], "mcl_enchanting_glyph_7.png": [209, 209, 231], "mcl_enchanting_table_top.png": [88, 86, 84], "mcl_enchanting_number_2.png": [149, 46, 39], "mcl_enchanting_glyph_16.png": [209, 209, 231], "mcl_enchanting_button_hovered.png": [255, 255, 255], "mcl_enchanting_book_enchanted.png": [122, 69, 46], "mcl_enchanting_glyph_4.png": [209, 209, 231], "mcl_enchanting_glyph_10.png": [209, 209, 231], "mcl_enchanting_glyph_13.png": [209, 209, 231], "mcl_enchanting_glyph_17.png": [209, 209, 231], "mcl_enchanting_glyph_18.png": [209, 209, 231], "mcl_enchanting_lapis_background.png": [255, 255, 255], "mcl_enchanting_button_background.png": [229, 202, 171], "mcl_enchanting_glyph_12.png": [209, 209, 231], "doc_basics_gameplay_mtg_2.png": [151, 168, 207], "doc_basics_liquids_renewable_1.png": [139, 146, 159], "doc_basics_players_sam.png": [95, 133, 106], "doc_basics_players_flat.png": [127, 155, 130], "doc_basics_craft_shapeless_2.png": [52, 52, 48], "doc_basics_build.png": [84, 84, 55], "doc_basics_pointing.png": [66, 104, 32], "doc_basics_nodes.png": [108, 104, 94], "doc_basics_craft_groups_2.png": [65, 58, 52], "doc_basics_craft_groups_1.png": [57, 57, 58], "doc_basics_inventory.png": [47, 47, 45], "doc_basics_minimap_radar.png": [73, 164, 128], "doc_basics_sneak.png": [70, 69, 69], "doc_basics_camera_behind.png": [108, 144, 135], "doc_basics_craft_repair.png": [47, 46, 45], "doc_basics_hotbar_relations.png": [85, 84, 69], "doc_basics_gameplay_lott.png": [119, 122, 112], "doc_basics_tools_mining.png": [64, 62, 59], "doc_basics_players_lott.png": [180, 193, 224], "doc_basics_gameplay_outback.png": [146, 114, 109], "doc_basics_gameplay_pixture.png": [94, 120, 57], "doc_basics_craft_grid.png": [46, 46, 46], "doc_basics_craft_groups_3.png": [61, 58, 55], "doc_basics_camera_front.png": [99, 133, 110], "doc_basics_minimap_map.png": [149, 169, 183], "doc_basics_gameplay_mtg_1.png": [136, 117, 86], "doc_basics_gameplay_xtraores_xtension.png": [95, 15, 86], "doc_basics_light_torch.png": [25, 43, 14], "doc_basics_minimap_round.png": [160, 175, 189], "doc_basics_light_test.png": [133, 113, 69], "doc_basics_liquids_nonrenewable.png": [64, 87, 87], "doc_basics_gameplay_hades.png": [81, 70, 62], "doc_basics_gameplay_moontest.png": [75, 74, 79], "doc_basics_liquids_range.png": [146, 166, 179], "doc_basics_inventory_detail.png": [43, 41, 39], "doc_basics_camera_ego.png": [111, 147, 139], "doc_basics_tools.png": [46, 45, 42], "doc_basics_liquids_renewable_2.png": [136, 148, 166], "doc_basics_items_dropped.png": [195, 185, 147], "doc_basics_liquids_types.png": [146, 164, 171], "doc_basics_gameplay_carbone_ng.png": [121, 118, 89], "doc_basics_craft_shaped.png": [55, 52, 50], "doc_basics_hotbar.png": [141, 175, 226], "doc_basics_craft_shapeless_1.png": [52, 52, 48], "doc_button_icon_lores.png": [19, 143, 183], "doc_awards_icon_generic.png": [14, 125, 162], "inventory_plus_doc_inventory_plus.png": [19, 143, 183], "doc_button_icon_hires.png": [30, 149, 188], "doc_identifier_identifier.png": [172, 151, 139], "doc_identifier_identifier_liquid.png": [125, 147, 190], "craftguide_clear_icon.png": [254, 254, 254], "craftguide_book.png": [84, 117, 39], "mcl_craftguide_fuel.png": [187, 121, 75], "craftguide_prev_icon.png": [255, 255, 255], "craftguide_zoomout_icon.png": [255, 255, 255], "craftguide_search_icon.png": [254, 254, 254], "craftguide_arrow.png": [139, 139, 139], "craftguide_zoomin_icon.png": [255, 255, 255], "craftguide_shapeless.png": [130, 130, 130], "craftguide_next_icon.png": [255, 255, 255]} diff --git a/mods/ITEMS/mcl_maps/init.lua b/mods/ITEMS/mcl_maps/init.lua index d2ff951ad4..450d8fbadf 100644 --- a/mods/ITEMS/mcl_maps/init.lua +++ b/mods/ITEMS/mcl_maps/init.lua @@ -147,11 +147,23 @@ function mcl_maps.load_map(id) local texture = "mcl_maps_map_texture_" .. id .. ".tga" if not loaded_maps[id] then - loaded_maps[id] = true - dynamic_add_media(map_textures_path .. texture, function() end) + if not minetest.features.dynamic_add_media_table then + -- minetest.dynamic_add_media() blocks in + -- Minetest 5.3 and 5.4 until media loads + loaded_maps[id] = true + dynamic_add_media(map_textures_path .. texture, function() end) + else + -- minetest.dynamic_add_media() never blocks + -- in Minetest 5.5, callback runs after load + dynamic_add_media(map_textures_path .. texture, function() + loaded_maps[id] = true + end) + end end - return texture + if loaded_maps[id] then + return texture + end end function mcl_maps.load_map_item(itemstack) diff --git a/mods/ITEMS/mcl_maps/locale/mcl_maps.zh_TW.tr b/mods/ITEMS/mcl_maps/locale/mcl_maps.zh_TW.tr new file mode 100644 index 0000000000..62206306ce --- /dev/null +++ b/mods/ITEMS/mcl_maps/locale/mcl_maps.zh_TW.tr @@ -0,0 +1,10 @@ +# textdomain: mcl_maps +Empty Map=空地圖 +Empty maps are not useful as maps, but they can be stacked and turned to maps which can be used.=空的地圖作為地圖是沒有用的,但它們可以被疊加,並變成可以使用的地圖。 +Rightclick to start using the map (which can't be stacked anymore).=右鍵單擊以開始使用地圖(該地圖無法再堆疊)。 +Map=地圖 +Maps show your surroundings as you explore the world.=當您探索世界時,地圖會顯示您的周圍環境。 +Hold the map in any of the hotbar slots. This allows you to access the minimap by pressing the minimap key (see controls settings).=在任何一個熱鍵槽中放置地圖。這允許你通過按小地圖鍵來訪問小地圖(見控制設置)。 +In Creative Mode, you don't need this item; the minimap is always available.=在創造模式下,您不需要此項目; 小地圖始終可用。 +Enables minimap=啓用小地圖 +Use the minimap key to show the map.=使用小地圖鍵來顯示小地圖。 diff --git a/mods/ITEMS/mcl_mobspawners/locale/mcl_mobspawners.zh_TW.tr b/mods/ITEMS/mcl_mobspawners/locale/mcl_mobspawners.zh_TW.tr new file mode 100644 index 0000000000..09cdf6458a --- /dev/null +++ b/mods/ITEMS/mcl_mobspawners/locale/mcl_mobspawners.zh_TW.tr @@ -0,0 +1,5 @@ +# textdomain: mcl_mobspawners +Mob Spawner=生怪磚 +A mob spawner regularily causes mobs to appear around it while a player is nearby. Some mob spawners are disabled while in light.= +If you have a spawn egg, you can use it to change the mob to spawn. Just place the item on the mob spawner. Player-set mob spawners always spawn mobs regardless of the light level.=當玩家在附近時,生怪磚會定期導致生物出現在其周圍。有些生怪磚在光照下會被禁用。 +Makes mobs appear=生成生物 diff --git a/mods/ITEMS/mcl_monster_eggs/locale/mcl_monster_eggs.zh_TW.tr b/mods/ITEMS/mcl_monster_eggs/locale/mcl_monster_eggs.zh_TW.tr new file mode 100644 index 0000000000..542c0f1b97 --- /dev/null +++ b/mods/ITEMS/mcl_monster_eggs/locale/mcl_monster_eggs.zh_TW.tr @@ -0,0 +1,9 @@ +# textdomain: mcl_monster_eggs +An infested block is a block from which a silverfish will pop out when it is broken. It looks identical to its normal counterpart.=蛀蝕的方塊是一個方塊,當它被打破時,蠹魚會從裡面跳出來。它看起來與正常的方塊完全一樣。 +Infested Stone=蛀蝕的石頭 +Infested Cobblestone=蛀蝕的鵝卵石 +Infested Stone Bricks=蛀蝕的石磚 +Infested Cracked Stone Bricks=蛀蝕的裂紋石磚 +Infested Mossy Stone Bricks=蛀蝕的青苔石磚 +Infested Chiseled Stone Bricks=蛀蝕的浮雕石磚 +Hides a silverfish=包含一個蠹魚 diff --git a/mods/ITEMS/mcl_mushrooms/huge.lua b/mods/ITEMS/mcl_mushrooms/huge.lua index 617f128107..0e99ae0be2 100644 --- a/mods/ITEMS/mcl_mushrooms/huge.lua +++ b/mods/ITEMS/mcl_mushrooms/huge.lua @@ -3,7 +3,10 @@ local S = minetest.get_translator(minetest.get_current_modname()) local vector = vector local template = { - groups = {handy=1,axey=1, building_block = 1, material_wood = 1, flammable = -1 }, + groups = { + handy = 1, axey = 1, building_block = 1, material_wood = 1, + flammable = -1, compostability = 85 + }, sounds = mcl_sounds.node_sound_wood_defaults(), is_ground_content = true, _mcl_blast_resistance = 0.2, @@ -51,6 +54,7 @@ local function register_mushroom(color, species_id, template, d_cap, d_stem, d_s stem_full.tiles = { "mcl_mushrooms_mushroom_block_skin_stem.png" } stem_full.groups.huge_mushroom = species_id stem_full.groups.huge_mushroom_stem = 2 + stem_full.groups.compostability = 65 minetest.register_node("mcl_mushrooms:"..color.."_mushroom_block_stem_full", stem_full) -- Stem @@ -60,6 +64,7 @@ local function register_mushroom(color, species_id, template, d_cap, d_stem, d_s stem.tiles = { "mcl_mushrooms_mushroom_block_inside.png", "mcl_mushrooms_mushroom_block_inside.png", "mcl_mushrooms_mushroom_block_skin_stem.png" } stem.groups.huge_mushroom = species_id stem.groups.huge_mushroom_stem = 1 + stem.groups.compostability = 65 minetest.register_node("mcl_mushrooms:"..color.."_mushroom_block_stem", stem) -- Mushroom block (cap) diff --git a/mods/ITEMS/mcl_mushrooms/locale/mcl_mushrooms.zh_TW.tr b/mods/ITEMS/mcl_mushrooms/locale/mcl_mushrooms.zh_TW.tr new file mode 100644 index 0000000000..f4c6ba1928 --- /dev/null +++ b/mods/ITEMS/mcl_mushrooms/locale/mcl_mushrooms.zh_TW.tr @@ -0,0 +1,24 @@ +# textdomain: mcl_mushrooms +This decorative block is like a huge mushroom stem, but with the stem texture on all sides.=這個裝飾塊就像一個巨大的蘑菇莖,但四面都有莖的紋理。 +Huge red mushroom blocks are the cap parts of huge red mushrooms. It consists of a red skin and can have pores on each of its sides.=紅色蘑菇方塊是巨大的紅蘑菇的菌蓋部分。它由紅色的皮膚組成,每一面都可以有毛孔。 +The stem part of a huge red mushroom.= +Huge Red Mushroom Block=紅色蘑菇方塊 +Huge Red Mushroom Stem=紅色蘑菇柄 +Huge Red Mushroom All-Faces Stem=紅色蘑菇(全紋理)柄 +Huge brown mushroom blocks are the cap parts of huge brown mushrooms. It consists of a brown skin and can have pores on each of its sides.= +The stem part of a huge brown mushroom.= +Huge Brown Mushroom Block=棕色蘑菇方塊 +Huge Brown Mushroom Stem=棕色蘑菇柄 +Huge Brown Mushroom All-Faces Stem=棕色蘑菇(全紋理)柄 +Brown mushrooms are fungi which grow and spread in darkness, but are sensitive to light. They are inedible as such, but they can be used to craft food items.=棕色蘑菇是在黑暗中生長和傳播的真菌,但對光線敏感。它們本身不能食用,但可以用來製作食品。 +Red mushrooms are fungi which grow and spread in darkness, but are sensitive to light. They are inedible as such, but they can be used to craft food items.=紅色蘑菇是在黑暗中生長和傳播的真菌,但對光線敏感。它們本身不能食用,但可以用來製作食品。 +A single mushroom of this species will slowly spread over time towards a random solid opaque block with a light level of 12 or lower in a 3×3×3 cube around the mushroom. It stops spreading when there are 5 or more mushrooms of the same species within an area of 9×3×9 blocks around the mushroom.=這個品種的單個蘑菇會隨著時間的推移,慢慢地向蘑菇周圍3×3×3立方體中光照度為12或更低的隨機固體不透明方塊擴散。當蘑菇周圍9×3×9塊的區域內有5個或更多相同種類的蘑菇時,它就會停止擴散。 +Mushrooms will eventually uproot at a light level of 12 or higher. On mycelium or podzol, they survive and spread at any light level.=蘑菇最終會在12或更高的光照水平下連根拔起。在菌絲體或灰壤上,它們在任何光照水平下都能生存和傳播。 +This mushroom can be placed on mycelium and podzol at any light level. It can also be placed on blocks which are both solid and opaque, as long as the light level at daytime is not higher than 12.=這種蘑菇可以放置在任何光照水平的菌絲和莢膜上。只要白天的光照度不高於12,它也可以放在既堅固又不透明的木塊上。 +Brown Mushroom=棕色蘑菇 +Red Mushroom=紅色蘑菇 +Mushroom Stew=蘑菇湯 +Mushroom stew is a healthy soup which can be consumed to restore some hunger points.=蘑菇湯是一種健康的湯,食用後可以恢復一些飢餓值。 +By placing huge mushroom blocks of the same species next to each other, the sides that touch each other will turn into pores permanently.=通過將同一物種的巨大蘑菇塊放在一起,相互接觸的側面將永久地變成毛孔。 +Grows on podzol, mycelium and other blocks=在灰壤,菌絲體和其他方塊上生長 +Spreads in darkness=在黑暗中擴散 diff --git a/mods/ITEMS/mcl_mushrooms/small.lua b/mods/ITEMS/mcl_mushrooms/small.lua index c6d7edcdca..f6fbd29091 100644 --- a/mods/ITEMS/mcl_mushrooms/small.lua +++ b/mods/ITEMS/mcl_mushrooms/small.lua @@ -38,7 +38,11 @@ minetest.register_node("mcl_mushrooms:mushroom_brown", { sunlight_propagates = true, paramtype = "light", walkable = false, - groups = {dig_immediate=3,mushroom=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1,enderman_takable=1,deco_block=1}, + groups = { + attached_node = 1, deco_block = 1, destroy_by_lava_flow = 1, + dig_immediate = 3, dig_by_water = 1, dig_by_piston = 1, + mushroom = 1, enderman_takable = 1, compostability = 65 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), light_source = 1, selection_box = { @@ -62,7 +66,11 @@ minetest.register_node("mcl_mushrooms:mushroom_red", { sunlight_propagates = true, paramtype = "light", walkable = false, - groups = {dig_immediate=3,mushroom=1,attached_node=1,dig_by_water=1,destroy_by_lava_flow=1,dig_by_piston=1,enderman_takable=1,deco_block=1}, + groups = { + attached_node = 1, deco_block = 1, destroy_by_lava_flow = 1, + dig_immediate = 3, dig_by_water = 1, dig_by_piston = 1, + mushroom = 1, enderman_takable = 1, compostability = 65 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), selection_box = { type = "fixed", diff --git a/mods/ITEMS/mcl_nether/init.lua b/mods/ITEMS/mcl_nether/init.lua index c5afe66aee..b474065a5a 100644 --- a/mods/ITEMS/mcl_nether/init.lua +++ b/mods/ITEMS/mcl_nether/init.lua @@ -106,7 +106,8 @@ minetest.register_node("mcl_nether:magma", { sounds = mcl_sounds.node_sound_stone_defaults(), -- From walkover mod on_walk_over = function(loc, nodeiamon, player) - if player and player:get_player_control().sneak or minetest.global_exists("mcl_potions") and mcl_potions.player_has_effect(player, "fire_proof") then + local armor_feet = player:get_inventory():get_stack("armor", 5) + if player and player:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.player_has_effect(player, "fire_proof")) then return end -- Hurt players standing on top of this block @@ -173,7 +174,7 @@ minetest.register_node("mcl_nether:nether_wart_block", { stack_max = 64, tiles = {"mcl_nether_nether_wart_block.png"}, is_ground_content = false, - groups = {handy=1, hoey=1, building_block=1}, + groups = {handy=1, hoey=1, building_block=1, compostability = 85}, sounds = mcl_sounds.node_sound_leaves_defaults( { footstep={name="default_dirt_footstep", gain=0.7}, diff --git a/mods/ITEMS/mcl_nether/nether_wart.lua b/mods/ITEMS/mcl_nether/nether_wart.lua index 41b23f662b..f6eb0c03cc 100644 --- a/mods/ITEMS/mcl_nether/nether_wart.lua +++ b/mods/ITEMS/mcl_nether/nether_wart.lua @@ -110,6 +110,7 @@ minetest.register_craftitem("mcl_nether:nether_wart_item", { _doc_items_usagehelp = S("Place this item on soul sand to plant it and watch it grow."), inventory_image = "mcl_nether_nether_wart.png", wield_image = "mcl_nether_nether_wart.png", + groups = {craftitem = 1, brewitem = 1, compostability = 30}, on_place = function(itemstack, placer, pointed_thing) if pointed_thing.type ~= "node" then return itemstack @@ -143,7 +144,6 @@ minetest.register_craftitem("mcl_nether:nether_wart_item", { end end end, - groups = { craftitem = 1, brewitem=1 }, }) local names = {"mcl_nether:nether_wart_0", "mcl_nether:nether_wart_1", "mcl_nether:nether_wart_2"} diff --git a/mods/ITEMS/mcl_ocean/kelp.lua b/mods/ITEMS/mcl_ocean/kelp.lua index 422f475ac8..ae273abe9a 100644 --- a/mods/ITEMS/mcl_ocean/kelp.lua +++ b/mods/ITEMS/mcl_ocean/kelp.lua @@ -741,7 +741,7 @@ minetest.register_craftitem("mcl_ocean:kelp", { inventory_image = "mcl_ocean_kelp_item.png", wield_image = "mcl_ocean_kelp_item.png", on_place = kelp.kelp_on_place, - groups = { deco_block = 1 }, + groups = {deco_block = 1, compostability = 30}, }) if mod_doc then @@ -756,7 +756,7 @@ minetest.register_craftitem("mcl_ocean:dried_kelp", { _doc_items_longdesc = S("Dried kelp is a food item."), inventory_image = "mcl_ocean_dried_kelp.png", wield_image = "mcl_ocean_dried_kelp.png", - groups = { food = 2, eatable = 1 }, + groups = {food = 2, eatable = 1, compostability = 30}, on_place = minetest.item_eat(1), on_secondary_use = minetest.item_eat(1), _mcl_saturation = 0.6, @@ -773,7 +773,10 @@ minetest.register_node("mcl_ocean:dried_kelp_block", { description = S("Dried Kelp Block"), _doc_items_longdesc = S("A decorative block that serves as a great furnace fuel."), tiles = { "mcl_ocean_dried_kelp_top.png", "mcl_ocean_dried_kelp_bottom.png", "mcl_ocean_dried_kelp_side.png" }, - groups = { handy = 1, hoey = 1, building_block = 1, flammable = 2, fire_encouragement = 30, fire_flammability = 60 }, + groups = { + handy = 1, hoey = 1, building_block = 1, compostability = 50, + flammable = 2, fire_encouragement = 30, fire_flammability = 60 + }, sounds = mcl_sounds.node_sound_leaves_defaults(), paramtype2 = "facedir", on_place = mcl_util.rotate_axis, diff --git a/mods/ITEMS/mcl_ocean/sea_pickle.lua b/mods/ITEMS/mcl_ocean/sea_pickle.lua index d215fd3b30..6a4e4a751d 100644 --- a/mods/ITEMS/mcl_ocean/sea_pickle.lua +++ b/mods/ITEMS/mcl_ocean/sea_pickle.lua @@ -106,7 +106,10 @@ for s=1,4 do }, inventory_image = img, wield_image = img, - groups = { dig_immediate = 3, deco_block = 1, sea_pickle=1, not_in_creative_inventory=nici }, + groups = { + dig_immediate = 3, deco_block = 1, sea_pickle = 1, + not_in_creative_inventory=nici, compostability = 65 + }, -- Light level: 6 at size 1, +3 for each additional stage light_source = math.min(6 + (s-1)*3, minetest.LIGHT_MAX), selection_box = { diff --git a/mods/ITEMS/mcl_ocean/seagrass.lua b/mods/ITEMS/mcl_ocean/seagrass.lua index 5fd3827756..2f58a28124 100644 --- a/mods/ITEMS/mcl_ocean/seagrass.lua +++ b/mods/ITEMS/mcl_ocean/seagrass.lua @@ -85,7 +85,7 @@ minetest.register_craftitem("mcl_ocean:seagrass", { inventory_image = "mcl_ocean_seagrass.png^[verticalframe:12:0", wield_image = "mcl_ocean_seagrass.png^[verticalframe:12:0", on_place = seagrass_on_place, - groups = { deco_block = 1 }, + groups = {deco_block = 1, compostability = 30}, }) -- Seagrass nodes: seagrass on a surface node diff --git a/mods/ITEMS/mcl_portals/locale/mcl_portals.zh_TW.tr b/mods/ITEMS/mcl_portals/locale/mcl_portals.zh_TW.tr new file mode 100644 index 0000000000..a6b389036a --- /dev/null +++ b/mods/ITEMS/mcl_portals/locale/mcl_portals.zh_TW.tr @@ -0,0 +1,15 @@ +# textdomain: mcl_portals +End Portal=終界傳送門 +An End portal teleports creatures and objects to the mysterious End dimension (and back!).=終界傳送門用於將生物和實體到達終末之界(或回來!)。 +Hop into the portal to teleport. Entering an End portal in the Overworld teleports you to a fixed position in the End dimension and creates a 5×5 obsidian platform at your destination. End portals in the End will lead back to your spawn point in the Overworld.=跳入傳送門進行傳送。進入終界傳送門會將你傳送到終界的一個固定位置,並在你的目的地創建一個5×5的黑曜石平台。終界的傳送門會將你帶回你在主界的出生點。 +End Portal Frame=終界傳送門框架 +End portal frames are used in the construction of End portals. Each block has a socket for an eye of ender.=終界傳送門框架用於建造終界傳送門。每個框架都有一個插座,用於放置終界之眼。 +NOTE: The End dimension is currently incomplete and might change in future versions.=注意:終界目前還不完整,在未來的版本中可能會有變化。 +End Portal Frame with Eye of Ender=含終界之眼的終界傳送門框架 +Nether Portal=地獄傳送門 +A Nether portal teleports creatures and objects to the hot and dangerous Nether dimension (and back!). Enter at your own risk!=地獄傳送門將生物和實體傳送到炎熱和危險的地獄(或回來!)。進入後風險自負! +Stand in the portal for a moment to activate the teleportation. Entering a Nether portal for the first time will also create a new portal in the other dimension. If a Nether portal has been built in the Nether, it will lead to the Overworld. A Nether portal is destroyed if the any of the obsidian which surrounds it is destroyed, or if it was caught in an explosion.=在傳送門中站立片刻以激活傳送。第一次進入地獄傳送門也會在另一維度創建一個新的傳送門。如果在地獄建立了地獄傳送門,它將會通​​向主世界。如果圍繞著它的任何黑曜石被毀壞,或者它被捲入一場爆炸,地獄傳送門就會被破壞。 +Obsidian is also used as the frame of Nether portals.=黑曜石也被用來作為地獄傳送門的框架。 +To open a Nether portal, place an upright frame of obsidian with a width of at least 4 blocks and a height of 5 blocks, leaving only air in the center. After placing this frame, light a fire in the obsidian frame. Nether portals only work in the Overworld and the Nether.=要打開地獄傳送門,需要放置一個直立的黑曜石框架,寬度至少為4塊,高度為5塊,中間只留有空氣。放置這個框架後,在黑曜石框架中點火。地獄傳送門只在主世界上和地獄起作用。 +Once placed, an eye of ender can not be taken back.=在擺放後,終界之眼無法再取回。 +Used to construct end portals=用於建造終界傳送門 diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index 46025619cb..0d93e11d1a 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -204,37 +204,52 @@ local function get_target(p) end end --- Destroy portal if pos (portal frame or portal node) got destroyed +-- Destroy a nether portal. Connected portal nodes are searched and removed +-- using 'bulk_set_node'. This function is called from 'after_destruct' of +-- nether portal nodes. The flag 'destroying_portal' is used to avoid this +-- function being called recursively through callbacks in 'bulk_set_node'. +local destroying_portal = false local function destroy_nether_portal(pos, node) - if not node then return end - local nn, orientation = node.name, node.param2 - local obsidian = nn == OBSIDIAN - - local function check_remove(pos, orientation) - local node = get_node(pos) - if node and (node.name == PORTAL and (orientation == nil or (node.param2 == orientation))) then - minetest.remove_node(pos) - remove_exit(pos) - end - end - if obsidian then -- check each of 6 sides of it and destroy every portal: - check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0) - check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0) - check_remove({x = pos.x, y = pos.y, z = pos.z - 1}, 1) - check_remove({x = pos.x, y = pos.y, z = pos.z + 1}, 1) - check_remove({x = pos.x, y = pos.y - 1, z = pos.z}) - check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) + if destroying_portal then return end - if orientation == 0 then - check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0) - check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0) - else - check_remove({x = pos.x, y = pos.y, z = pos.z - 1}, 1) - check_remove({x = pos.x, y = pos.y, z = pos.z + 1}, 1) + destroying_portal = true + + local orientation = node.param2 + local checked_tab = { [minetest.hash_node_position(pos)] = true } + local nodes = { pos } + + local function check_remove(pos) + local h = minetest.hash_node_position(pos) + if checked_tab[h] then + return + end + + local node = minetest.get_node(pos) + if node and node.name == PORTAL and (orientation == nil or node.param2 == orientation) then + table.insert(nodes, pos) + checked_tab[h] = true + end end - check_remove({x = pos.x, y = pos.y - 1, z = pos.z}) - check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) + + local i = 1 + while i <= #nodes do + pos = nodes[i] + if orientation == 0 then + check_remove({x = pos.x - 1, y = pos.y, z = pos.z}) + check_remove({x = pos.x + 1, y = pos.y, z = pos.z}) + else + check_remove({x = pos.x, y = pos.y, z = pos.z - 1}) + check_remove({x = pos.x, y = pos.y, z = pos.z + 1}) + end + check_remove({x = pos.x, y = pos.y - 1, z = pos.z}) + check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) + remove_exit(pos) + i = i + 1 + end + + minetest.bulk_set_node(nodes, { name = "air" }) + destroying_portal = false end local on_rotate @@ -817,7 +832,23 @@ local usagehelp = S("To open a Nether portal, place an upright frame of obsidian minetest.override_item(OBSIDIAN, { _doc_items_longdesc = longdesc, _doc_items_usagehelp = usagehelp, - after_destruct = destroy_nether_portal, + after_destruct = function(pos, node) + local function check_remove(pos, orientation) + local node = get_node(pos) + if node and node.name == PORTAL then + minetest.remove_node(pos) + end + end + + -- check each of 6 sides of it and destroy every portal + check_remove({x = pos.x - 1, y = pos.y, z = pos.z}) + check_remove({x = pos.x + 1, y = pos.y, z = pos.z}) + check_remove({x = pos.x, y = pos.y, z = pos.z - 1}) + check_remove({x = pos.x, y = pos.y, z = pos.z + 1}) + check_remove({x = pos.x, y = pos.y - 1, z = pos.z}) + check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) + end, + _on_ignite = function(user, pointed_thing) local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z -- Check empty spaces around obsidian and light all frames found: diff --git a/mods/ITEMS/mcl_potions/lingering.lua b/mods/ITEMS/mcl_potions/lingering.lua index d22dd41817..64f846cb61 100644 --- a/mods/ITEMS/mcl_potions/lingering.lua +++ b/mods/ITEMS/mcl_potions/lingering.lua @@ -1,5 +1,7 @@ local S = minetest.get_translator(minetest.get_current_modname()) +local mod_target = minetest.get_modpath("mcl_target") + local function lingering_image(colorstring, opacity) if not opacity then opacity = 127 @@ -95,71 +97,74 @@ function mcl_potions.register_lingering(name, descr, color, def) end end minetest.register_craftitem(id, { - description = descr, - _tt_help = def.tt, - _doc_items_longdesc = longdesc, - _doc_items_usagehelp = S("Use the “Punch” key to throw it."), - inventory_image = lingering_image(color), - groups = {brewitem=1, not_in_creative_inventory=0}, - on_use = function(item, placer, pointed_thing) - local velocity = 10 - local dir = placer:get_look_dir(); - local pos = placer:getpos(); - minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true) - local obj = minetest.add_entity({x=pos.x+dir.x,y=pos.y+2+dir.y,z=pos.z+dir.z}, id.."_flying") - obj:setvelocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) - obj:setacceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) - obj:get_luaentity()._thrower = placer:get_player_name() - if not minetest.is_creative_enabled(placer:get_player_name()) then - item:take_item() + description = descr, + _tt_help = def.tt, + _doc_items_longdesc = longdesc, + _doc_items_usagehelp = S("Use the “Punch” key to throw it."), + inventory_image = lingering_image(color), + groups = {brewitem=1, not_in_creative_inventory=0}, + on_use = function(item, placer, pointed_thing) + local velocity = 10 + local dir = placer:get_look_dir(); + local pos = placer:getpos(); + minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true) + local obj = minetest.add_entity({x=pos.x+dir.x,y=pos.y+2+dir.y,z=pos.z+dir.z}, id.."_flying") + obj:setvelocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) + obj:setacceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) + obj:get_luaentity()._thrower = placer:get_player_name() + if not minetest.is_creative_enabled(placer:get_player_name()) then + item:take_item() + end + return item + end, + stack_max = 1, + _on_dispense = function(stack, dispenserpos, droppos, dropnode, dropdir) + local s_pos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51)) + local pos = {x=s_pos.x+dropdir.x,y=s_pos.y+dropdir.y,z=s_pos.z+dropdir.z} + minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true) + local obj = minetest.add_entity(pos, id.."_flying") + local velocity = 22 + obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity}) + obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3}) end - return item - end, - stack_max = 1, - _on_dispense = function(stack, dispenserpos, droppos, dropnode, dropdir) - local s_pos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51)) - local pos = {x=s_pos.x+dropdir.x,y=s_pos.y+dropdir.y,z=s_pos.z+dropdir.z} - minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true) - local obj = minetest.add_entity(pos, id.."_flying") - local velocity = 22 - obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity}) - obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3}) - end -}) + }) -local w = 0.7 + local w = 0.7 -minetest.register_entity(id.."_flying",{ - textures = {lingering_image(color)}, - hp_max = 1, - visual_size = {x=w/2,y=w/2}, - collisionbox = {-0.1,-0.1,-0.1,0.1,0.1,0.1}, - pointable = false, - on_step = function(self, dtime) - local pos = self.object:get_pos() - local node = minetest.get_node(pos) - local n = node.name - local g = minetest.get_item_group(n, "liquid") - local d = 4 - if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then - minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1}) - add_lingering_effect(pos, color, def, name == "water") - local texture - if name == "water" then - texture = "mcl_particles_droplet_bottle.png" - else - if def.instant then - texture = "mcl_particles_instant_effect.png" + minetest.register_entity(id.."_flying",{ + textures = {lingering_image(color)}, + hp_max = 1, + visual_size = {x=w/2,y=w/2}, + collisionbox = {-0.1,-0.1,-0.1,0.1,0.1,0.1}, + pointable = false, + on_step = function(self, dtime) + local pos = self.object:get_pos() + local node = minetest.get_node(pos) + local n = node.name + local g = minetest.get_item_group(n, "liquid") + local d = 4 + if mod_target and n == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end + if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then + minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1}) + add_lingering_effect(pos, color, def, name == "water") + local texture + if name == "water" then + texture = "mcl_particles_droplet_bottle.png" else - texture = "mcl_particles_effect.png" + if def.instant then + texture = "mcl_particles_instant_effect.png" + else + texture = "mcl_particles_effect.png" + end end + linger_particles(pos, d, texture, color) + if name == "water" then + mcl_potions._extinguish_nearby_fire(pos, d) + end + self.object:remove() end - linger_particles(pos, d, texture, color) - if name == "water" then - mcl_potions._extinguish_nearby_fire(pos, d) - end - self.object:remove() - end - end, -}) + end, + }) end diff --git a/mods/ITEMS/mcl_potions/splash.lua b/mods/ITEMS/mcl_potions/splash.lua index 112b587543..4a820e4672 100644 --- a/mods/ITEMS/mcl_potions/splash.lua +++ b/mods/ITEMS/mcl_potions/splash.lua @@ -1,6 +1,8 @@ local S = minetest.get_translator(minetest.get_current_modname()) local GRAVITY = tonumber(minetest.settings:get("movement_gravity")) +local mod_target = minetest.get_modpath("mcl_target") + local function splash_image(colorstring, opacity) if not opacity then opacity = 127 @@ -66,6 +68,9 @@ function mcl_potions.register_splash(name, descr, color, def) local g = minetest.get_item_group(n, "liquid") local d = 0.1 local redux_map = {7/8,0.5,0.25} + if mod_target and n == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1}) local texture, acc diff --git a/mods/ITEMS/mcl_potions/tipped_arrow.lua b/mods/ITEMS/mcl_potions/tipped_arrow.lua index 1717533a8f..880dff9562 100644 --- a/mods/ITEMS/mcl_potions/tipped_arrow.lua +++ b/mods/ITEMS/mcl_potions/tipped_arrow.lua @@ -1,5 +1,7 @@ local S = minetest.get_translator(minetest.get_current_modname()) +local mod_target = minetest.get_modpath("mcl_target") + local math = math -- Time in seconds after which a stuck arrow is deleted @@ -342,6 +344,11 @@ function mcl_potions.register_arrow(name, desc, color, def) self.object:set_velocity({x=0, y=0, z=0}) self.object:set_acceleration({x=0, y=0, z=0}) + -- Activate target + if mod_target and snode.name == "mcl_target:target_off" then + mcl_target.hit(self._stuckin, 1) --10 redstone ticks + end + -- Push the button! Push, push, push the button! if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then local bdir = minetest.wallmounted_to_dir(node.param2) diff --git a/mods/ITEMS/mcl_shields/init.lua b/mods/ITEMS/mcl_shields/init.lua new file mode 100644 index 0000000000..a1be310e77 --- /dev/null +++ b/mods/ITEMS/mcl_shields/init.lua @@ -0,0 +1,515 @@ +local minetest, math, vector = minetest, math, vector +local modname = minetest.get_current_modname() +local S = minetest.get_translator(modname) + +mcl_shields = { + types = { + mob = true, + player = true, + arrow = true, + generic = true, + explosion = true, + dragon_breath = true, + }, + enchantments = {"mending", "unbreaking"}, + players = {}, +} + +local interact_priv = minetest.registered_privileges.interact +interact_priv.give_to_singleplayer = false +interact_priv.give_to_admin = false + +local overlay = mcl_enchanting.overlay +local hud = "mcl_shield_hud.png" + +minetest.register_tool("mcl_shields:shield", { + description = S("Shield"), + _doc_items_longdesc = S("A shield is a tool used for protecting the player against attacks."), + inventory_image = "mcl_shield.png", + stack_max = 1, + groups = { + shield = 1, + weapon = 1, + enchantability = -1, + no_wieldview = 1, + offhand_item = 1, + }, + sound = {breaks = "default_tool_breaks"}, + _repair_material = "group:wood", + wield_scale = vector.new(2, 2, 2), +}) + +local function wielded_item(obj, i) + local itemstack = obj:get_wielded_item() + if i == 1 then + itemstack = obj:get_inventory():get_stack("offhand", 1) + end + return itemstack:get_name() +end + +function mcl_shields.wielding_shield(obj, i) + return wielded_item(obj, i):find("mcl_shields:shield") +end + +local function shield_is_enchanted(obj, i) + return mcl_enchanting.is_enchanted(wielded_item(obj, i)) +end + +minetest.register_entity("mcl_shields:shield_entity", { + initial_properties = { + visual = "mesh", + mesh = "mcl_shield.obj", + physical = false, + pointable = false, + collide_with_objects = false, + textures = {"mcl_shield_base_nopattern.png"}, + visual_size = vector.new(1, 1, 1), + }, + _blocking = false, + _shield_number = 2, + _texture_copy = "", + on_step = function(self, dtime, moveresult) + local player = self.object:get_attach() + if not player then + self.object:remove() + return + end + local shield_texture = "mcl_shield_base_nopattern.png" + local i = self._shield_number + local item = wielded_item(player, i) + + if item ~= "mcl_shields:shield" and item ~= "mcl_shields:shield_enchanted" then + local itemstack = player:get_wielded_item() + if i == 1 then + itemstack = player:get_inventory():get_stack("offhand", 1) + end + local meta_texture = itemstack:get_meta():get_string("mcl_shields:shield_custom_pattern_texture") + if meta_texture ~= "" then + shield_texture = meta_texture + else + local color = minetest.registered_items[item]._shield_color + if color then + shield_texture = "mcl_shield_base_nopattern.png^(mcl_shield_pattern_base.png^[colorize:" .. color .. ")" + end + end + end + + if shield_is_enchanted(player, i) then + shield_texture = shield_texture .. overlay + end + + if self._texture_copy ~= shield_texture then + self.object:set_properties({textures = {shield_texture}}) + end + + self._texture_copy = shield_texture + end, +}) + +for _, e in pairs(mcl_shields.enchantments) do + mcl_enchanting.enchantments[e].secondary.shield = true +end + +function mcl_shields.is_blocking(obj) + if not obj:is_player() then return end + local blocking = mcl_shields.players[obj].blocking + if blocking <= 0 then + return + end + + local shieldstack = obj:get_wielded_item() + if blocking == 1 then + shieldstack = obj:get_inventory():get_stack("offhand", 1) + end + return blocking, shieldstack +end + +mcl_damage.register_modifier(function(obj, damage, reason) + local type = reason.type + local damager = reason.direct + local blocking, shieldstack = mcl_shields.is_blocking(obj) + + if not (obj:is_player() and blocking and mcl_shields.types[type] and damager) then + return + end + + local entity = damager:get_luaentity() + if entity and entity._shooter then + damager = entity._shooter + end + + local dpos = damager:get_pos() + + -- Used for removed / killed entities before the projectile hits the player + if entity and not entity._shooter and entity._saved_shooter_pos then + dpos = entity._saved_shooter_pos + end + + if not dpos or vector.dot(obj:get_look_dir(), vector.subtract(dpos, obj:get_pos())) < 0 then + return + end + + local durability = 336 + local unbreaking = mcl_enchanting.get_enchantment(shieldstack, mcl_shields.enchantments[2]) + if unbreaking > 0 then + durability = durability * (unbreaking + 1) + end + + if not minetest.is_creative_enabled(obj:get_player_name()) and damage >= 3 then + shieldstack:add_wear(65535 / durability) + if blocking == 2 then + obj:set_wielded_item(shieldstack) + else + obj:get_inventory():set_stack("offhand", 1, shieldstack) + mcl_inventory.update_inventory_formspec(obj) + end + end + minetest.sound_play({name = "mcl_block"}) + return 0 +end) + +local function modify_shield(player, vpos, vrot, i) + local arm = "Right" + if i == 1 then + arm = "Left" + end + local shield = mcl_shields.players[player].shields[i] + if shield then + shield:set_attach(player, "Arm_" .. arm, vpos, vrot, false) + end +end + +local function set_shield(player, block, i) + if block then + if i == 1 then + modify_shield(player, vector.new(-9, 4, 0.5), vector.new(80, 100, 0), i) -- TODO + else + modify_shield(player, vector.new(-8, 4, -2.5), vector.new(80, 80, 0), i) + end + else + if i == 1 then + modify_shield(player, vector.new(-3, -5, 0), vector.new(0, 180, 0), i) + else + modify_shield(player, vector.new(3, -5, 0), vector.new(0, 0, 0), i) + end + end + local shield = mcl_shields.players[player].shields[i] + if not shield then return end + + local luaentity = shield:get_luaentity() + if not luaentity then return end + + luaentity._blocking = block +end + +local function set_interact(player, interact) + local player_name = player:get_player_name() + local privs = minetest.get_player_privs(player_name) + if privs.interact == interact then + return + end + local meta = player:get_meta() + if meta:get_int("mcl_privs:interact_revoked") ~= 1 then + privs.interact = interact + minetest.set_player_privs(player_name, privs) + meta:set_int("mcl_privs:interact_revoked",0) + end +end + +local shield_hud = {} + +local function remove_shield_hud(player) + if shield_hud[player] then + player:hud_remove(shield_hud[player]) + shield_hud[player] = nil + set_shield(player, false, 1) + set_shield(player, false, 2) + end + + local hf = player:hud_get_flags() + if not hf.wielditem then + player:hud_set_flags({wielditem = true}) + end + + playerphysics.remove_physics_factor(player, "speed", "shield_speed") + set_interact(player, true) +end + +local function add_shield_entity(player, i) + local shield = minetest.add_entity(player:get_pos(), "mcl_shields:shield_entity") + shield:get_luaentity()._shield_number = i + mcl_shields.players[player].shields[i] = shield + set_shield(player, false, i) +end + +local function remove_shield_entity(player, i) + local shields = mcl_shields.players[player].shields + if shields[i] then + shields[i]:remove() + shields[i] = nil + end +end + +local function handle_blocking(player) + local player_shield = mcl_shields.players[player] + local rmb = player:get_player_control().RMB + if not rmb then + player_shield.blocking = 0 + return + end + + local shield_in_offhand = mcl_shields.wielding_shield(player, 1) + local shield_in_hand = mcl_shields.wielding_shield(player) + local not_blocking = player_shield.blocking == 0 + + local pos = player:get_pos() + if shield_in_hand then + if not_blocking then + minetest.after(0.25, function() + if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then + player_shield.blocking = 2 + set_shield(player, true, 2) + end + end) + elseif not shield_in_offhand then + player_shield.blocking = 2 + end + elseif shield_in_offhand then + local offhand_can_block = (wielded_item(player) == "" or not mcl_util.get_pointed_thing(player, true)) + and (minetest.get_item_group(wielded_item(player), "bow") ~= 1 and minetest.get_item_group(wielded_item(player), "crossbow") ~= 1) + + if not offhand_can_block then + return + end + if not_blocking then + minetest.after(0.25, function() + if (not_blocking or not shield_in_hand) and shield_in_offhand and rmb and offhand_can_block then + player_shield.blocking = 1 + set_shield(player, true, 1) + end + end) + elseif not shield_in_hand then + player_shield.blocking = 1 + end + else + player_shield.blocking = 0 + end +end + +local function update_shield_entity(player, blocking, i) + local shield = mcl_shields.players[player].shields[i] + if mcl_shields.wielding_shield(player, i) then + if not shield then + add_shield_entity(player, i) + else + if blocking == i then + if shield:get_luaentity() and not shield:get_luaentity()._blocking then + set_shield(player, true, i) + end + else + set_shield(player, false, i) + end + end + elseif shield then + remove_shield_entity(player, i) + end +end + +local function add_shield_hud(shieldstack, player, blocking) + local texture = hud + if mcl_enchanting.is_enchanted(shieldstack:get_name()) then + texture = texture .. overlay + end + local offset = 100 + if blocking == 1 then + texture = texture .. "^[transform4" + offset = -100 + else + player:hud_set_flags({wielditem = false}) + end + shield_hud[player] = player:hud_add({ + hud_elem_type = "image", + position = {x = 0.5, y = 0.5}, + scale = {x = -101, y = -101}, + offset = {x = offset, y = 0}, + text = texture, + z_index = -200, + }) + playerphysics.add_physics_factor(player, "speed", "shield_speed", 0.5) + set_interact(player, nil) +end + +local function update_shield_hud(player, blocking, shieldstack) + local shieldhud = shield_hud[player] + if not shieldhud then + add_shield_hud(shieldstack, player, blocking) + return + end + + local wielditem = player:hud_get_flags().wielditem + if blocking == 1 then + if not wielditem then + player:hud_change(shieldhud, "text", hud .. "^[transform4") + player:hud_change(shieldhud, "offset", {x = -100, y = 0}) + player:hud_set_flags({wielditem = true}) + end + elseif wielditem then + player:hud_change(shieldhud, "text", hud) + player:hud_change(shieldhud, "offset", {x = 100, y = 0}) + player:hud_set_flags({wielditem = false}) + end + + local image = player:hud_get(shieldhud).text + local enchanted = hud .. overlay + local enchanted1 = image == enchanted + local enchanted2 = image == enchanted .. "^[transform4" + if mcl_enchanting.is_enchanted(shieldstack:get_name()) then + if not enchanted1 and not enchanted2 then + if blocking == 1 then + player:hud_change(shieldhud, "text", hud .. overlay .. "^[transform4") + else + player:hud_change(shieldhud, "text", hud .. overlay) + end + end + elseif enchanted1 or enchanted2 then + if blocking == 1 then + player:hud_change(shieldhud, "text", hud .. "^[transform4") + else + player:hud_change(shieldhud, "text", hud) + end + end +end + +minetest.register_globalstep(function(dtime) + for _, player in pairs(minetest.get_connected_players()) do + + handle_blocking(player) + + local blocking, shieldstack = mcl_shields.is_blocking(player) + + if blocking then + update_shield_hud(player, blocking, shieldstack) + else + remove_shield_hud(player) + end + + for i = 1, 2 do + update_shield_entity(player, blocking, i) + end + end +end) + +minetest.register_on_dieplayer(function(player) + remove_shield_hud(player) + if not minetest.settings:get_bool("mcl_keepInventory") then + remove_shield_entity(player, 1) + remove_shield_entity(player, 2) + end +end) + +minetest.register_on_leaveplayer(function(player) + shield_hud[player] = nil + mcl_shields.players[player] = nil +end) + +minetest.register_craft({ + output = "mcl_shields:shield", + recipe = { + {"group:wood", "mcl_core:iron_ingot", "group:wood"}, + {"group:wood", "group:wood", "group:wood"}, + {"", "group:wood", ""}, + } +}) + +for _, colortab in pairs(mcl_banners.colors) do + local color = colortab[1] + minetest.register_tool("mcl_shields:shield_" .. color, { + description = S(colortab[6] .. " Shield"), + _doc_items_longdesc = S("A shield is a tool used for protecting the player against attacks."), + inventory_image = "mcl_shield.png^(mcl_shield_item_overlay.png^[colorize:" .. colortab[4] ..")", + stack_max = 1, + groups = { + shield = 1, + weapon = 1, + enchantability = -1, + no_wieldview = 1, + not_in_creative_inventory = 1, + offhand_item = 1, + }, + sound = {breaks = "default_tool_breaks"}, + _repair_material = "group:wood", + wield_scale = vector.new(2, 2, 2), + _shield_color = colortab[4], + }) + + local banner = "mcl_banners:banner_item_" .. color + minetest.register_craft({ + type = "shapeless", + output = "mcl_shields:shield_" .. color, + recipe = {"mcl_shields:shield", banner}, + }) + minetest.register_craft({ + type = "shapeless", + output = "mcl_shields:shield_" .. color .. "_enchanted", + recipe = {"mcl_shields:shield_enchanted", banner}, + }) +end + +local function to_shield_texture(banner_texture) + return banner_texture + :gsub("mcl_banners_base_inverted.png", "mcl_shield_base_nopattern.png^mcl_shield_pattern_base.png") + :gsub("mcl_banners_banner_base.png", "mcl_shield_base_nopattern.png^mcl_shield_pattern_base.png") + :gsub("mcl_banners_base", "mcl_shield_pattern_base") + :gsub("mcl_banners", "mcl_shield_pattern") +end + +local function craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv) + if not string.find(itemstack:get_name(), "mcl_shields:shield_") then + return itemstack + end + + local shield_stack + for i = 1, player:get_inventory():get_size("craft") do + local stack = old_craft_grid[i] + local name = stack:get_name() + if minetest.get_item_group(name, "shield") then + shield_stack = stack + break + end + end + + for i = 1, player:get_inventory():get_size("craft") do + local banner_stack = old_craft_grid[i] + local banner_name = banner_stack:get_name() + if string.find(banner_name, "mcl_banners:banner") and shield_stack then + local banner_meta = banner_stack:get_meta() + local layers_meta = banner_meta:get_string("layers") + local new_shield_meta = itemstack:get_meta() + if layers_meta ~= "" then + local color = mcl_banners.color_reverse(banner_name) + local layers = minetest.deserialize(layers_meta) + local texture = mcl_banners.make_banner_texture(color, layers) + new_shield_meta:set_string("description", mcl_banners.make_advanced_banner_description(itemstack:get_description(), layers)) + new_shield_meta:set_string("mcl_shields:shield_custom_pattern_texture", to_shield_texture(texture)) + end + itemstack:set_wear(shield_stack:get_wear()) + break + end + end +end + +minetest.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv) + return craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv) +end) + +minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv) + return craft_banner_on_shield(itemstack, player, old_craft_grid, craft_inv) +end) + +minetest.register_on_joinplayer(function(player) + mcl_shields.players[player] = { + shields = {}, + blocking = 0, + } + remove_shield_hud(player) +end) diff --git a/mods/ITEMS/mcl_shields/locale/mcl_shields.de.tr b/mods/ITEMS/mcl_shields/locale/mcl_shields.de.tr new file mode 100644 index 0000000000..2a4deccc01 --- /dev/null +++ b/mods/ITEMS/mcl_shields/locale/mcl_shields.de.tr @@ -0,0 +1,19 @@ +# textdomain: mcl_shields +Shield=Schild +A shield is a tool used for protecting the player against attacks.=Der Schild ist eine Schutzwaffe, die den Spieler vor Angriffen schützt. +White Shield=Weißer Schild +Grey Shield=Grauer Schild +Light Grey Shield=Hellgrauer Schild +Black Shield=Schwarzer Schild +Red Shield=Roter Schild +Yellow Shield=Gelber Schild +Green Shield=Grüner Schild +Cyan Shield=Türkiser Schild +Blue Shield=Blauer Schild +Magenta Shield=Magenta Schild +Orange Shield=Oranger Schild +Purple Shield=Violetter Schild +Brown Shield=Brauner Schild +Pink Shield=Rosa Schild +Lime Shield=Hellgrüner Schild +Light Blue Shield=Hellblauer Schild diff --git a/mods/ITEMS/mcl_shields/locale/template.txt b/mods/ITEMS/mcl_shields/locale/template.txt new file mode 100644 index 0000000000..bcf7b1b543 --- /dev/null +++ b/mods/ITEMS/mcl_shields/locale/template.txt @@ -0,0 +1,19 @@ +# textdomain: mcl_shields +Shield= +A shield is a tool used for protecting the player against attacks.= +White Shield= +Grey Shield= +Light Grey Shield= +Black Shield= +Red Shield= +Yellow Shield= +Green Shield= +Cyan Shield= +Blue Shield= +Magenta Shield= +Orange Shield= +Purple Shield= +Brown Shield= +Pink Shield= +Lime Shield= +Light Blue Shield= diff --git a/mods/ITEMS/mcl_shields/mod.conf b/mods/ITEMS/mcl_shields/mod.conf new file mode 100644 index 0000000000..8aded6a621 --- /dev/null +++ b/mods/ITEMS/mcl_shields/mod.conf @@ -0,0 +1,3 @@ +name = mcl_shields +author = NO11 +depends = mcl_damage, mcl_enchanting, mcl_banners, mcl_util, playerphysics diff --git a/mods/ITEMS/mcl_shields/models/mcl_shield.obj b/mods/ITEMS/mcl_shields/models/mcl_shield.obj new file mode 100644 index 0000000000..b1cf77c280 --- /dev/null +++ b/mods/ITEMS/mcl_shields/models/mcl_shield.obj @@ -0,0 +1,88 @@ +# Blender v3.0.0 OBJ File: '' +# www.blender.org +mtllib mcl_shield.mtl +o Cube.002_Cube.003 +v 4.663009 11.096291 6.387994 +v 4.663009 4.596560 5.241916 +v 5.213008 4.596560 5.241916 +v 5.213008 11.096291 6.387994 +v 5.213007 13.197435 -5.528180 +v 5.213007 6.697705 -6.674258 +v 4.663008 6.697705 -6.674258 +v 4.663008 13.197435 -5.528180 +v 4.663008 8.641873 -1.863572 +v 4.663008 8.068833 1.386293 +v 1.363008 8.068833 1.386294 +v 1.363008 8.641873 -1.863572 +v 1.363008 9.152122 1.577307 +v 1.363008 9.725162 -1.672559 +v 4.663008 9.152122 1.577306 +v 4.663008 9.725162 -1.672559 +vt 0.015625 0.984375 +vt 0.203125 0.984375 +vt 0.203125 1.000000 +vt 0.015625 1.000000 +vt 0.203125 0.640625 +vt 0.203125 0.984375 +vt 0.015625 0.984375 +vt 0.015625 0.640625 +vt 0.015625 0.984375 +vt 0.015625 0.640625 +vt -0.000000 0.640625 +vt -0.000000 0.984375 +vt 0.203125 0.984375 +vt 0.390625 0.984375 +vt 0.390625 1.000000 +vt 0.203125 1.000000 +vt 0.203125 0.984375 +vt 0.203125 0.640625 +vt 0.218750 0.640625 +vt 0.218750 0.984375 +vt 0.406250 0.640625 +vt 0.406250 0.984375 +vt 0.218750 0.984375 +vt 0.218750 0.640625 +vt 0.531250 0.812500 +vt 0.625000 0.812500 +vt 0.625000 0.906250 +vt 0.531250 0.906250 +vt 0.500000 0.906250 +vt 0.500000 0.812500 +vt 0.531250 0.812500 +vt 0.531250 0.906250 +vt 0.406250 0.812500 +vt 0.500000 0.812500 +vt 0.500000 0.906250 +vt 0.406250 0.906250 +vt 0.625000 0.812500 +vt 0.656250 0.812500 +vt 0.656250 0.906250 +vt 0.625000 0.906250 +vt 0.562500 1.000000 +vt 0.531250 1.000000 +vt 0.531250 0.906250 +vt 0.562500 0.906250 +vt 0.531250 1.000000 +vt 0.500000 1.000000 +vt 0.500000 0.906250 +vt 0.531250 0.906250 +vn 0.0000 -0.1736 0.9848 +vn 1.0000 0.0000 -0.0000 +vn 0.0000 -0.9848 -0.1736 +vn 0.0000 0.1736 -0.9848 +vn 0.0000 0.9848 0.1736 +vn -1.0000 -0.0000 0.0000 +usemtl Material.002 +s 1 +f 1/1/1 2/2/1 3/3/1 4/4/1 +f 5/5/2 4/6/2 3/7/2 6/8/2 +f 6/9/3 3/10/3 2/11/3 7/12/3 +f 7/13/4 8/14/4 5/15/4 6/16/4 +f 8/17/5 1/18/5 4/19/5 5/20/5 +f 7/21/6 2/22/6 1/23/6 8/24/6 +f 9/25/3 10/26/3 11/27/3 12/28/3 +f 12/29/6 11/30/6 13/31/6 14/32/6 +f 14/33/5 13/34/5 15/35/5 16/36/5 +f 16/37/2 15/38/2 10/39/2 9/40/2 +f 12/41/4 14/42/4 16/43/4 9/44/4 +f 13/45/1 11/46/1 10/47/1 15/48/1 diff --git a/mods/ITEMS/mcl_shields/sounds/mcl_block.ogg b/mods/ITEMS/mcl_shields/sounds/mcl_block.ogg new file mode 100644 index 0000000000..3af7f04b4d Binary files /dev/null and b/mods/ITEMS/mcl_shields/sounds/mcl_block.ogg differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield.png b/mods/ITEMS/mcl_shields/textures/mcl_shield.png new file mode 100644 index 0000000000..7391636e94 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_base_nopattern.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_base_nopattern.png new file mode 100644 index 0000000000..8146632bbc Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_base_nopattern.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_hud.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_hud.png new file mode 100644 index 0000000000..4286d3e83c Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_hud.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_item_overlay.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_item_overlay.png new file mode 100644 index 0000000000..3e79536090 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_item_overlay.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_base.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_base.png new file mode 100644 index 0000000000..268445b36c Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_base.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_border.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_border.png new file mode 100644 index 0000000000..e128218e60 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_border.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_bricks.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_bricks.png new file mode 100644 index 0000000000..f1ddd716bd Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_bricks.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_circle.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_circle.png new file mode 100644 index 0000000000..8ff66b8c87 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_circle.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_creeper.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_creeper.png new file mode 100644 index 0000000000..5b30dc76be Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_creeper.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_cross.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_cross.png new file mode 100644 index 0000000000..40a6624aef Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_cross.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_curly_border.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_curly_border.png new file mode 100644 index 0000000000..9f8c21773d Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_curly_border.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_left.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_left.png new file mode 100644 index 0000000000..a04a6fdc08 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_left.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_right.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_right.png new file mode 100644 index 0000000000..309f711bf9 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_right.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_up_left.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_up_left.png new file mode 100644 index 0000000000..c5f4399a07 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_up_left.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_up_right.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_up_right.png new file mode 100644 index 0000000000..59dd957dd9 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_diagonal_up_right.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_flower.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_flower.png new file mode 100644 index 0000000000..fe7ca826f6 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_flower.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_gradient.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_gradient.png new file mode 100644 index 0000000000..29a98c7045 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_gradient.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_gradient_up.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_gradient_up.png new file mode 100644 index 0000000000..09effb26ac Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_gradient_up.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_horizontal.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_horizontal.png new file mode 100644 index 0000000000..5187803b39 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_horizontal.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_horizontal_bottom.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_horizontal_bottom.png new file mode 100644 index 0000000000..515e6ddfec Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_horizontal_bottom.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_vertical.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_vertical.png new file mode 100644 index 0000000000..9a56804da0 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_vertical.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_vertical_right.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_vertical_right.png new file mode 100644 index 0000000000..4a5af61fba Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_half_vertical_right.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_rhombus.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_rhombus.png new file mode 100644 index 0000000000..13b502289a Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_rhombus.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_skull.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_skull.png new file mode 100644 index 0000000000..4e0c7c1f5b Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_skull.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_small_stripes.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_small_stripes.png new file mode 100644 index 0000000000..f125ba2fbf Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_small_stripes.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_bottom_left.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_bottom_left.png new file mode 100644 index 0000000000..a5c4e00c06 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_bottom_left.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_bottom_right.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_bottom_right.png new file mode 100644 index 0000000000..ca2c53692b Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_bottom_right.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_top_left.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_top_left.png new file mode 100644 index 0000000000..2123cba15c Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_top_left.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_top_right.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_top_right.png new file mode 100644 index 0000000000..3f7a759a82 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_square_top_right.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_straight_cross.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_straight_cross.png new file mode 100644 index 0000000000..dc861f0484 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_straight_cross.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_bottom.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_bottom.png new file mode 100644 index 0000000000..859ad11d1a Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_bottom.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_center.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_center.png new file mode 100644 index 0000000000..8d1e2404c1 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_center.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_downleft.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_downleft.png new file mode 100644 index 0000000000..c0a93cd4f7 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_downleft.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_downright.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_downright.png new file mode 100644 index 0000000000..09580857cb Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_downright.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_left.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_left.png new file mode 100644 index 0000000000..6e5bcb02e7 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_left.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_middle.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_middle.png new file mode 100644 index 0000000000..af5ebc12a9 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_middle.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_right.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_right.png new file mode 100644 index 0000000000..dcb911b680 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_right.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_top.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_top.png new file mode 100644 index 0000000000..a1e10be463 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_stripe_top.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_thing.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_thing.png new file mode 100644 index 0000000000..43b2a1d499 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_thing.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangle_bottom.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangle_bottom.png new file mode 100644 index 0000000000..87d1aa95b3 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangle_bottom.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangle_top.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangle_top.png new file mode 100644 index 0000000000..94d6528783 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangle_top.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangles_bottom.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangles_bottom.png new file mode 100644 index 0000000000..3e4851abb9 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangles_bottom.png differ diff --git a/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangles_top.png b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangles_top.png new file mode 100644 index 0000000000..0ae85d6d18 Binary files /dev/null and b/mods/ITEMS/mcl_shields/textures/mcl_shield_pattern_triangles_top.png differ diff --git a/mods/ITEMS/mcl_signs/locale/mcl_signs.zh_TW.tr b/mods/ITEMS/mcl_signs/locale/mcl_signs.zh_TW.tr new file mode 100644 index 0000000000..62994bc3de --- /dev/null +++ b/mods/ITEMS/mcl_signs/locale/mcl_signs.zh_TW.tr @@ -0,0 +1,9 @@ +# textdomain: mcl_signs +Sign=告示牌 +Signs can be written and come in two variants: Wall sign and sign on a sign post. Signs can be placed on the top and the sides of other blocks, but not below them.=告示牌可以寫字,有兩種變體:牆上的告示牌和柱上的告示牌。告示牌可以放在其他方塊的頂部和側面,但不能放在下面。 +After placing the sign, you can write something on it. You have 4 lines of text with up to 15 characters for each line; anything beyond these limits is lost. Not all characters are supported. The text can not be changed once it has been written; you have to break and place the sign again.=放置告示牌後,你可以在上面寫東西。你最多可以寫4行文字,每行最多可以寫15個字符;超過這些限制的文字就會丟失。不是所有的字符都被支持。文字一旦寫完就不能更改;你必須打破並重新放置標誌。 +Enter sign text:=輸入告示牌文字: +Maximum line length: 15=每行最多可以寫15個字符 +Maximum lines: 4=最多可以寫4行文字 +Done=確認 +Can be written=可以寫字 diff --git a/mods/ITEMS/mcl_sponges/locale/mcl_sponges.zh_TW.tr b/mods/ITEMS/mcl_sponges/locale/mcl_sponges.zh_TW.tr new file mode 100644 index 0000000000..3b466dff40 --- /dev/null +++ b/mods/ITEMS/mcl_sponges/locale/mcl_sponges.zh_TW.tr @@ -0,0 +1,10 @@ +# textdomain: mcl_sponges +Sponge=海綿 +Sponges are blocks which remove water around them when they are placed or come in contact with water, turning it into a wet sponge.=海綿是一種方塊,當它們被放置或與水接觸時,會去除它們周圍的水,使其變成濕海綿。 +Waterlogged Sponge=濕海綿 +A waterlogged sponge can be dried in the furnace to turn it into (dry) sponge. When there's an empty bucket in the fuel slot of a furnace, the water will pour into the bucket.=濕海綿可以在熔爐裡烘乾,變成(乾)海綿。當爐子的燃料槽裡有一個空桶時,水會倒進桶裡。 +Riverwaterlogged Sponge=濕河水海綿 +This is a sponge soaking wet with river water. It can be dried in the furnace to turn it into (dry) sponge. When there's an empty bucket in the fuel slot of the furnace, the river water will pour into the bucket.=濕河水海綿是含有濕河水的海綿。可以在爐子裡曬乾,變成(乾)海綿。當爐子的燃料槽裡有一個空桶時,水會倒進桶裡。 +A sponge becomes riverwaterlogged (instead of waterlogged) if it sucks up more river water than (normal) water.= +Removes water on contact=如果海綿吸的河水比(正常的)水多,它就會變成濕河水海綿(而不是濕海綿)。 +Can be dried in furnace=可以在熔爐裏烘乾 diff --git a/mods/ITEMS/mcl_throwing/locale/mcl_throwing.zh_TW.tr b/mods/ITEMS/mcl_throwing/locale/mcl_throwing.zh_TW.tr new file mode 100644 index 0000000000..3ee2209258 --- /dev/null +++ b/mods/ITEMS/mcl_throwing/locale/mcl_throwing.zh_TW.tr @@ -0,0 +1,12 @@ +# textdomain: mcl_throwing +@1 used the ender pearl too often.=@1 扔得太多終界珍珠了。 +Use the punch key to throw.=按下擊打鍵扔出 +Snowball=雪球 +Snowballs can be thrown or launched from a dispenser for fun. Hitting something with a snowball does nothing.=雪球可以被扔出或從發射器中發射出去取樂。用雪球打東西沒有任何作用。 +Egg=蛋 +Eggs can be thrown or launched from a dispenser and breaks on impact. There is a small chance that 1 or even 4 chicks will pop out of the egg.=雞蛋可以被拋出或從發射器中發射出去,並在撞擊中破碎。有機會,1至4個小雞會從蛋裡跳出來。 +Ender Pearl=終界珍珠 +An ender pearl is an item which can be used for teleportation at the cost of health. It can be thrown and teleport the thrower to its impact location when it hits a solid block or a plant. Each teleportation hurts the user by 5 hit points.=末影珍珠是一種可以在損失生命值的情況下用於傳送的物品。可以將其扔出並將撞到實心塊或植物時將其傳送到其撞擊位置。每次傳送都會傷害使用者5點生命值。 +Throwable=可扔出 +Chance to hatch chicks when broken=破碎時有可能孵化小雞 +Teleports you on impact for cost of 5 HP=損失5點生命值以傳送 diff --git a/mods/ITEMS/mcl_throwing/mod.conf b/mods/ITEMS/mcl_throwing/mod.conf index 60d3e31a79..18248e76f7 100644 --- a/mods/ITEMS/mcl_throwing/mod.conf +++ b/mods/ITEMS/mcl_throwing/mod.conf @@ -1,3 +1,3 @@ name = mcl_throwing depends = mcl_colors -optional_depends = mcl_core, mcl_mobitems, doc +optional_depends = mcl_core, mcl_mobitems, doc, mcl_target diff --git a/mods/ITEMS/mcl_throwing/register.lua b/mods/ITEMS/mcl_throwing/register.lua index ec11f86c72..8683eea0a7 100644 --- a/mods/ITEMS/mcl_throwing/register.lua +++ b/mods/ITEMS/mcl_throwing/register.lua @@ -3,6 +3,8 @@ local S = minetest.get_translator(minetest.get_current_modname()) local math = math local vector = vector +local mod_target = minetest.get_modpath("mcl_target") + -- The snowball entity local snowball_ENTITY={ physical = false, @@ -111,6 +113,9 @@ local function snowball_on_step(self, dtime) minetest.sound_play("mcl_throwing_snowball_impact_hard", { pos = pos, max_hear_distance=16, gain=0.7 }, true) snowball_particles(self._lastpos, vel) self.object:remove() + if mod_target and node.name == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end return end end @@ -172,6 +177,9 @@ local function egg_on_step(self, dtime) end minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) self.object:remove() + if mod_target and node.name == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end return end end @@ -276,6 +284,9 @@ local function pearl_on_step(self, dtime) end self.object:remove() + if mod_target and node.name == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end return end end diff --git a/mods/ITEMS/mcl_tnt/locale/mcl_tnt.zh_TW.tr b/mods/ITEMS/mcl_tnt/locale/mcl_tnt.zh_TW.tr new file mode 100644 index 0000000000..aaa4c1e524 --- /dev/null +++ b/mods/ITEMS/mcl_tnt/locale/mcl_tnt.zh_TW.tr @@ -0,0 +1,8 @@ +# textdomain: mcl_tnt +@1 was caught in an explosion.=@1被炸飛了。 +TNT= +An explosive device. When it explodes, it will hurt living beings and destroy blocks around it. TNT has an explosion radius of @1. With a small chance, blocks may drop as an item (as if being mined) rather than being destroyed. TNT can be ignited by tools, explosions, fire, lava and redstone signals.=一個爆炸性裝置。當它爆炸時,會傷害生物,並摧毀周圍的方塊。TNT的爆炸半徑為@1。有很小的機率,方塊可能會作為物品掉落(就像被開採一樣)而不是被摧毀。TNT可以被工具、爆炸、火、熔岩和紅石信號點燃。 +An explosive device. When it explodes, it will hurt living beings. TNT has an explosion radius of @1. TNT can be ignited by tools, explosions, fire, lava and redstone signals.=一個爆炸性裝置。當它爆炸時,會傷害生物,並摧毀周圍的方塊。TNT的爆炸半徑為@1。TNT可以被工具、爆炸、火、熔岩和紅石信號點燃。 +Place the TNT and ignite it with one of the methods above. Quickly get in safe distance. The TNT will start to be affected by gravity and explodes in 4 seconds.=放置TNT,並用上述方法之一點燃它。迅速和TNT保持安全距離。TNT將開始受到重力的影響,並在4秒內爆炸。 +Ignited by tools, explosions, fire, lava, redstone power=被工具、爆炸、火、熔岩和紅石信號點燃。 +Explosion radius: @1=爆炸半徑:@1 diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index 1d68a09731..e1fdf7aba3 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -238,7 +238,7 @@ if minetest.get_modpath("mcl_farming") then minetest.sound_play({name="default_grass_footstep", gain=1}, {pos = pointed_thing.above}, true) local dir = vector.subtract(pointed_thing.under, pointed_thing.above) local param2 = minetest.dir_to_facedir(dir) - minetest.swap_node(pointed_thing.under, {name="mcl_farming:pumpkin_face", param2 = param2}) + minetest.set_node(pointed_thing.under, {name="mcl_farming:pumpkin_face", param2 = param2}) minetest.add_item(pointed_thing.above, "mcl_farming:pumpkin_seeds 4") end return itemstack diff --git a/mods/ITEMS/mcl_tools/locale/mcl_tools.zh_TW.tr b/mods/ITEMS/mcl_tools/locale/mcl_tools.zh_TW.tr new file mode 100644 index 0000000000..ed40c64bac --- /dev/null +++ b/mods/ITEMS/mcl_tools/locale/mcl_tools.zh_TW.tr @@ -0,0 +1,32 @@ +# textdomain: mcl_tools +You use your bare hand whenever you are not wielding any item. With your hand you can mine most blocks, but this is the slowest method and only the weakest blocks will yield their useful drop. The hand also deals minor damage by punching. Using the hand is often a last resort, as proper mining tools and weapons are much better.=只要你不揮舞任何物品,你就用你的手。用你的手可以開採大多數塊狀物,但這是最慢的方法,只有最弱的方塊才會產生有用的掉落物。手還可以通過打拳造成輕微的傷害。使用手往往是最後的手段,因為適當的採礦工具和武器要好得多。 +When you are wielding an item which is not a mining tool or a weapon, it will behave as if it were the hand when you start mining or punching.=當你揮舞一個不是採礦工具或武器的物品時開始採礦或打拳時,它的行為就像手一樣。 +In Creative Mode, the hand is able to break all blocks instantly.=在創造模式式下,手能夠立即打破所有方塊。 +Pickaxes are mining tools to mine hard blocks, such as stone. A pickaxe can also be used as weapon, but it is rather inefficient.=鎬是開採硬方塊的工具,如石頭。鎬也可以作為武器使用,但它的效率很低。 +An axe is your tool of choice to cut down trees, wood-based blocks and other blocks. Axes deal a lot of damage as well, but they are rather slow.=斧頭是您砍伐樹木,木質方塊等的首選工具。斧頭也造成很多傷害,但是速度很慢。 +Swords are great in melee combat, as they are fast, deal high damage and can endure countless battles. Swords can also be used to cut down a few particular blocks, such as cobwebs.=劍在近戰中非常好,因為它們速度快,傷害高,可以經受無數次的戰鬥。劍也可以用來開採一些特殊的方塊,如蜘蛛網。 +Shovels are tools for digging coarse blocks, such as dirt, sand and gravel. They can also be used to turn grass blocks to grass paths. Shovels can be used as weapons, but they are very weak.=鏟子是挖掘粗方塊的工具,如泥土、沙子和礫石。它們也可以用來把草塊變成草路。鏟子可以作為武器使用,但它們非常弱。 +To turn a grass block into a grass path, hold the shovel in your hand, then use (rightclick) the top or side of a grass block. This only works when there's air above the grass block.=要把草塊變成草路,請用手握住鏟子,然後右擊草塊的頂部或側面。這只有在草塊上方的方塊是空氣時才有效。 +Shears are tools to shear sheep and to mine a few block types. Shears are a special mining tool and can be used to obtain the original item from grass, leaves and similar blocks that require cutting.=剪刀是剪羊毛的工具,也是開採一些方塊的工具。剪子是一種特殊的開採工具,可以用來從草、樹葉等方塊中獲得原始物品。 +To shear sheep or carve faceless pumpkins, use the “place” key on them. Faces can only be carved at the side of faceless pumpkins. Mining works as usual, but the drops are different for a few blocks.=要剪羊毛或雕刻南瓜,請在其上使用「放置」鍵。只能在南瓜側面雕刻臉部。開採照常進行,但是掉落物在部分方塊上是不同的。 +Wooden Pickaxe=木鎬 +Stone Pickaxe=石鎬 +Iron Pickaxe=鐵鎬 +Golden Pickaxe=金鎬 +Diamond Pickaxe=鑽石鎬 +Wooden Shovel=木鏟 +Stone Shovel=石鏟 +Iron Shovel=鐵鏟 +Golden Shovel=金鏟 +Diamond Shovel=鑽石鏟 +Wooden Axe=木斧 +Stone Axe=石斧 +Iron Axe=鐵斧 +Golden Axe=金斧 +Diamond Axe=鑽石斧 +Wooden Sword=木劍 +Stone Sword=石劍 +Iron Sword=鐵劍 +Golden Sword=金劍 +Diamond Sword=鑽石劍 +Shears=剪刀 diff --git a/mods/ITEMS/mcl_torches/locale/mcl_torches.zh_TW.tr b/mods/ITEMS/mcl_torches/locale/mcl_torches.zh_TW.tr new file mode 100644 index 0000000000..01088cd96c --- /dev/null +++ b/mods/ITEMS/mcl_torches/locale/mcl_torches.zh_TW.tr @@ -0,0 +1,3 @@ +# textdomain: mcl_torches +Torch=火把 +Torches are light sources which can be placed at the side or on the top of most blocks.=火把是光源,可以放在大多數方塊的側面或頂部。 diff --git a/mods/ITEMS/mcl_totems/init.lua b/mods/ITEMS/mcl_totems/init.lua index b11e68df77..7a45ea58f0 100644 --- a/mods/ITEMS/mcl_totems/init.lua +++ b/mods/ITEMS/mcl_totems/init.lua @@ -12,6 +12,14 @@ mcl_damage.register_modifier(function(obj, damage, reason) local hp = obj:get_hp() if hp - damage <= 0 then local wield = obj:get_wielded_item() + local in_offhand = false + if not (wield:get_name() == "mobs_mc:totem") then + local inv = obj:get_inventory() + if inv then + wield = obj:get_inventory():get_stack("offhand", 1) + in_offhand = true + end + end if wield:get_name() == "mobs_mc:totem" then local ppos = obj:get_pos() local pnname = minetest.get_node(ppos).name @@ -28,7 +36,12 @@ mcl_damage.register_modifier(function(obj, damage, reason) if not minetest.is_creative_enabled(obj:get_player_name()) then wield:take_item() - obj:set_wielded_item(wield) + if in_offhand then + obj:get_inventory():set_stack("offhand", 1, wield) + mcl_inventory.update_inventory_formspec(obj) + else + obj:set_wielded_item(wield) + end end -- Effects diff --git a/mods/ITEMS/mcl_walls/locale/mcl_walls.zh_TW.tr b/mods/ITEMS/mcl_walls/locale/mcl_walls.zh_TW.tr new file mode 100644 index 0000000000..111241e04a --- /dev/null +++ b/mods/ITEMS/mcl_walls/locale/mcl_walls.zh_TW.tr @@ -0,0 +1,16 @@ +# textdomain: mcl_walls +A piece of wall. It cannot be jumped over with a simple jump. When multiple of these are placed to next to each other, they will automatically build a nice wall structure.=一塊牆。它不能用簡單的跳躍方式跳過去。當多個這樣的東西被放在一起時,它們會自動建立一個漂亮的牆體結構。 +Cobblestone Wall=鵝卵石牆 +Mossy Cobblestone Wall=青苔鵝卵石牆 +Andesite Wall=安山岩牆 +Granite Wall=花崗岩牆 +Diorite Wall=閃長岩牆 +Brick Wall=紅磚牆 +Sandstone Wall=砂岩牆 +Red Sandstone Wall=紅砂岩牆 +Stone Brick Wall=石磚牆 +Mossy Stone Brick Wall=青苔石磚牆 +Prismarine Wall=海磷石牆 +End Stone Brick Wall=終界石磚牆 +Nether Brick Wall=地獄磚牆 +Red Nether Brick Wall=紅地獄磚牆 diff --git a/mods/ITEMS/mcl_wool/init.lua b/mods/ITEMS/mcl_wool/init.lua index 8fb4f51ec8..65cbb87088 100644 --- a/mods/ITEMS/mcl_wool/init.lua +++ b/mods/ITEMS/mcl_wool/init.lua @@ -71,12 +71,11 @@ for _, row in ipairs(wool.dyes) do _doc_items_entry_name = name_carpet, _doc_items_longdesc = longdesc_carpet, - walkable = false, -- See is_ground_content = false, tiles = {texture..".png"}, wield_image = texture..".png", wield_scale = { x=1, y=1, z=0.5 }, - groups = {handy=1, carpet=1,attached_node=1,flammable=1,fire_encouragement=60, fire_flammability=20, dig_by_water=1,deco_block=1,[color_group]=1}, + groups = {handy=1, carpet=1,supported_node=1,flammable=1,fire_encouragement=60, fire_flammability=20, dig_by_water=1,deco_block=1,[color_group]=1}, sounds = mcl_sounds.node_sound_wool_defaults(), paramtype = "light", sunlight_propagates = true, diff --git a/mods/ITEMS/mclx_core/locale/mclx_core.zh_TW.tr b/mods/ITEMS/mclx_core/locale/mclx_core.zh_TW.tr new file mode 100644 index 0000000000..649fc353df --- /dev/null +++ b/mods/ITEMS/mclx_core/locale/mclx_core.zh_TW.tr @@ -0,0 +1,5 @@ +# textdomain: mclx_core +River Water Source=河水源頭 +River water has the same properties as water, but has a reduced flowing distance and is not renewable.=河水具有與水相同的特性,但流動距離較短,且不可再生。 +River Water=河水 +Flowing River Water=流動的河水 diff --git a/mods/ITEMS/mclx_fences/locale/mclx_fences.zh_TW.tr b/mods/ITEMS/mclx_fences/locale/mclx_fences.zh_TW.tr new file mode 100644 index 0000000000..bf06d72406 --- /dev/null +++ b/mods/ITEMS/mclx_fences/locale/mclx_fences.zh_TW.tr @@ -0,0 +1,4 @@ +# textdomain: mclx_fences +Red Nether Brick Fence=紅地獄磚柵欄 +Red Nether Brick Fence Gate=紅地獄磚柵欄門 +Nether Brick Fence Gate=地獄磚柵欄門 diff --git a/mods/ITEMS/screwdriver/locale/screwdriver.zh_TW.tr b/mods/ITEMS/screwdriver/locale/screwdriver.zh_TW.tr new file mode 100644 index 0000000000..f29a4bf330 --- /dev/null +++ b/mods/ITEMS/screwdriver/locale/screwdriver.zh_TW.tr @@ -0,0 +1,2 @@ +#textdomain: screwdriver +Screwdriver=螺絲刀 diff --git a/mods/ITEMS/xpanes/locale/xpanes.zh_TW.tr b/mods/ITEMS/xpanes/locale/xpanes.zh_TW.tr new file mode 100644 index 0000000000..bcf33c2055 --- /dev/null +++ b/mods/ITEMS/xpanes/locale/xpanes.zh_TW.tr @@ -0,0 +1,23 @@ +# textdomain: xpanes +Glass panes are thin layers of glass which neatly connect to their neighbors as you build them.=玻璃板是薄薄的玻璃層,在你建造它們時,它們會整齊地連接到鄰近的方塊。 +Stained glass panes are thin layers of stained glass which neatly connect to their neighbors as you build them. They come in many different colors.=染色玻璃片是薄薄的一層染色玻璃,在你建造它們時,它們會整齊地連接到它們的鄰居。它們有許多不同的顏色。 +Iron Bars=鐵柵欄 +Iron bars neatly connect to their neighbors as you build them.=在你建造鐵柵欄時,它們會整齊地連接到鄰近的方塊。 +Glass Pane=玻璃片 +Stained Glass Pane=染色玻璃片 +Red Stained Glass Pane=紅色玻璃片 +Green Stained Glass Pane=綠色玻璃片 +Blue Stained Glass Pane=藍色玻璃片 +Light Blue Stained Glass Pane=淺藍色玻璃片 +Black Stained Glass Pane=黑色玻璃片 +White Stained Glass Pane=白色玻璃片 +Yellow Stained Glass Pane=黃色玻璃片 +Brown Stained Glass Pane=棕色玻璃片 +Orange Stained Glass Pane=橙色玻璃片 +Pink Stained Glass Pane=粉紅色玻璃片 +Grey Stained Glass Pane=灰色玻璃片 +Lime Stained Glass Pane=淺綠色玻璃片 +Light Grey Stained Glass Pane=淺灰色玻璃片 +Magenta Stained Glass Pane=洋紅色玻璃片 +Purple Stained Glass Pane=紫色玻璃片 +Cyan Stained Glass Pane=青色玻璃片 diff --git a/mods/MAPGEN/mcl_biomes/init.lua b/mods/MAPGEN/mcl_biomes/init.lua index a048224399..f198e09fa2 100644 --- a/mods/MAPGEN/mcl_biomes/init.lua +++ b/mods/MAPGEN/mcl_biomes/init.lua @@ -3538,7 +3538,7 @@ local function register_decorations() -- Pumpkin minetest.register_decoration({ deco_type = "simple", - decoration = "mcl_farming:pumpkin_face", + decoration = "mcl_farming:pumpkin", param2 = 0, param2_max = 3, place_on = {"group:grass_block_no_snow"}, diff --git a/mods/MAPGEN/mcl_dungeons/init.lua b/mods/MAPGEN/mcl_dungeons/init.lua index 905e26396b..f809b18e4e 100644 --- a/mods/MAPGEN/mcl_dungeons/init.lua +++ b/mods/MAPGEN/mcl_dungeons/init.lua @@ -134,10 +134,15 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) -- Check floor and ceiling: Must be *completely* solid local y_floor = y local y_ceiling = y + dim.y + 1 - if check then for tx = x+1, x+dim.x do for tz = z+1, z+dim.z do - if not registered_nodes[get_node({x = tx, y = y_floor , z = tz}).name].walkable - or not registered_nodes[get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end - end end end + if check then + for tx = x+1, x+dim.x do + for tz = z+1, z+dim.z do + local fdef = registered_nodes[get_node({x = tx, y = y_floor , z = tz}).name] + local cdef = registered_nodes[get_node({x = tx, y = y_ceiling, z = tz}).name] + if not fdef or not fdef.walkable or not cdef or not cdef.walkable then return false end + end + end + end -- Check for air openings (2 stacked air at ground level) in wall positions local openings_counter = 0 @@ -287,7 +292,8 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) -- Do not overwrite nodes with is_ground_content == false (e.g. bedrock) -- Exceptions: cobblestone and mossy cobblestone so neighborings dungeons nicely connect to each other local name = get_node(p).name - if registered_nodes[name].is_ground_content or name == "mcl_core:cobble" or name == "mcl_core:mossycobble" then + local rn = registered_nodes[name] + if rn and rn.is_ground_content or name == "mcl_core:cobble" or name == "mcl_core:mossycobble" then -- Floor if ty == y then if pr:next(1,4) == 1 then diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 41bee508b5..69132927c6 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -64,6 +64,7 @@ local c_stone = minetest.get_content_id("mcl_core:stone") local c_dirt = minetest.get_content_id("mcl_core:dirt") local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass") local c_dirt_with_grass_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow") +local c_reeds = minetest.get_content_id("mcl_core:reeds") local c_sand = minetest.get_content_id("mcl_core:sand") --local c_sandstone = minetest.get_content_id("mcl_core:sandstone") local c_void = minetest.get_content_id("mcl_core:void") @@ -827,7 +828,7 @@ local function register_mgv6_decorations() -- Pumpkin minetest.register_decoration({ deco_type = "simple", - decoration = "mcl_farming:pumpkin_face", + decoration = "mcl_farming:pumpkin", param2 = 0, param2_max = 3, place_on = {"group:grass_block_no_snow"}, @@ -2095,7 +2096,22 @@ local function basic(vm, data, data2, emin, emax, area, minp, maxp, blockseed) lvm_used = true end end - + + -- Set param2 (=color) of sugar cane + nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:reeds"}) + for n=1, #nodes do + local n = nodes[n] + local p_pos = area:index(n.x, n.y, n.z) + local b_pos = aream:index(n.x, 0, n.z) + local bn = minetest.get_biome_name(biomemap[b_pos]) + if bn then + local biome = minetest.registered_biomes[bn] + if biome and biome._mcl_biome_type then + data2[p_pos] = biome._mcl_palette_index + lvm_used = true + end + end + end end -- Nether block fixes: @@ -2179,15 +2195,16 @@ local function basic(vm, data, data2, emin, emax, area, minp, maxp, blockseed) lvm_used = true end + return lvm_used, shadow +end + +local function basic_node(minp, maxp, blockseed) if mg_name ~= "singlenode" then -- Generate special decorations generate_underground_mushrooms(minp, maxp, blockseed) generate_nether_decorations(minp, maxp, blockseed) - generate_structures(minp, maxp, blockseed, biomemap) + generate_structures(minp, maxp, blockseed, minetest.get_mapgen_object("biomemap")) end - - return lvm_used, shadow end -mcl_mapgen_core.register_generator("main", basic, nil, 1, true) - +mcl_mapgen_core.register_generator("main", basic, basic_node, 1, true) diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index be1be0f67c..f596147f0a 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -179,7 +179,7 @@ function mcl_structures.generate_igloo(pos, rotation, pr) real_depth = real_depth + 1 local node = minetest.get_node({x=tpos.x,y=tpos.y-y,z=tpos.z}) local def = minetest.registered_nodes[node.name] - if (not def) or (not def.walkable) or (def.liquidtype ~= "none") or (not def.is_ground_content) then + if not (def and def.walkable and def.liquidtype == "none" and def.is_ground_content) then bpos.y = tpos.y-y+1 break end diff --git a/mods/MAPGEN/mcl_structures/locale/mcl_structures.zh_TW.tr b/mods/MAPGEN/mcl_structures/locale/mcl_structures.zh_TW.tr new file mode 100644 index 0000000000..49796e5209 --- /dev/null +++ b/mods/MAPGEN/mcl_structures/locale/mcl_structures.zh_TW.tr @@ -0,0 +1,7 @@ +# textdomain: mcl_structures +Generate a pre-defined structure near your position.=在你的位置附近生成一個預定義的結構。 +Structure placed.=結構已生成。 +Village built. WARNING: Villages are experimental and might have bugs.=村莊已生成。警告:村莊是實驗性的,可能會有錯誤。 +Error: No structure type given. Please use “/spawnstruct ”.=錯誤:未提供結構類型。請使用「/spawnstruct <種類>」。 +Error: Unknown structure type. Please use “/spawnstruct ”.=錯誤:未知結構類型。請使用「/spawnstruct <種類>」。 +Use /help spawnstruct to see a list of avaiable types.=使用「/help spawnstruct」以查看可用結構列表。 diff --git a/mods/MAPGEN/mcl_villages/buildings.lua b/mods/MAPGEN/mcl_villages/buildings.lua index a690290633..c014bb07af 100644 --- a/mods/MAPGEN/mcl_villages/buildings.lua +++ b/mods/MAPGEN/mcl_villages/buildings.lua @@ -93,10 +93,6 @@ function settlements.create_site_plan(maxp, minp, pr) -- go build settlement around center if not center_surface then return false end - -- add settlement to list - table.insert(settlements_in_world, center_surface) - -- save list to file - settlements.save() -- initialize all settlement_info table local count_buildings, number_of_buildings, number_built = settlements.initialize_settlement_info(pr) -- first building is townhall in the center diff --git a/mods/MAPGEN/mcl_villages/const.lua b/mods/MAPGEN/mcl_villages/const.lua index eb7806209d..65f43f3445 100644 --- a/mods/MAPGEN/mcl_villages/const.lua +++ b/mods/MAPGEN/mcl_villages/const.lua @@ -65,11 +65,6 @@ settlements.schematic_table = { {name = "well", mts = schem_path.."well.mts", hwidth = 6, hdepth = 8, hheight = 6, hsize = 10, max_num = 0.045, rplc = basic_pseudobiome_villages }, } --- --- list of settlements, load on server start up --- -settlements_in_world = {} --- -- -- maximum allowed difference in height for building a sttlement -- diff --git a/mods/MAPGEN/mcl_villages/init.lua b/mods/MAPGEN/mcl_villages/init.lua index 7e460990e0..a899b3234c 100644 --- a/mods/MAPGEN/mcl_villages/init.lua +++ b/mods/MAPGEN/mcl_villages/init.lua @@ -10,7 +10,6 @@ dofile(settlements.modpath.."/paths.lua") -- -- load settlements on server -- -settlements_in_world = settlements.load() settlements.grundstellungen() diff --git a/mods/MAPGEN/mcl_villages/utils.lua b/mods/MAPGEN/mcl_villages/utils.lua index 993de11c42..22453a8ab5 100644 --- a/mods/MAPGEN/mcl_villages/utils.lua +++ b/mods/MAPGEN/mcl_villages/utils.lua @@ -88,29 +88,6 @@ function settlements.check_distance(settlement_info, building_pos, building_size return true end ------------------------------------------------------------------------------- --- save list of generated settlements -------------------------------------------------------------------------------- -function settlements.save() - local file = io.open(minetest.get_worldpath().."/settlements.txt", "w") - if file then - file:write(minetest.serialize(settlements_in_world)) - file:close() - end -end -------------------------------------------------------------------------------- --- load list of generated settlements -------------------------------------------------------------------------------- -function settlements.load() - local file = io.open(minetest.get_worldpath().."/settlements.txt", "r") - if file then - local table = minetest.deserialize(file:read("*all")) - if type(table) == "table" then - return table - end - end - return {} -end -------------------------------------------------------------------------------- -- fill chests ------------------------------------------------------------------------------- function settlements.fill_chest(pos, pr) diff --git a/mods/MAPGEN/tsm_railcorridors/init.lua b/mods/MAPGEN/tsm_railcorridors/init.lua index 65a7d6a699..4514061679 100644 --- a/mods/MAPGEN/tsm_railcorridors/init.lua +++ b/mods/MAPGEN/tsm_railcorridors/init.lua @@ -154,16 +154,16 @@ local function SetNodeIfCanBuild(pos, node, check_above, can_replace_rail) local abovename = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}).name local abovedef = minetest.registered_nodes[abovename] if abovename == "unknown" or abovename == "ignore" or - (abovedef.groups and abovedef.groups.attached_node) or + (abovedef and abovedef.groups and abovedef.groups.attached_node) or -- This is done because cobwebs are often fake liquids - (abovedef.liquidtype ~= "none" and abovename ~= tsm_railcorridors.nodes.cobweb) then + (abovedef and abovedef.liquidtype ~= "none" and abovename ~= tsm_railcorridors.nodes.cobweb) then return false end end local name = minetest.get_node(pos).name local def = minetest.registered_nodes[name] if name ~= "unknown" and name ~= "ignore" and - ((def.is_ground_content and def.liquidtype == "none") or + ((def and def.is_ground_content and def.liquidtype == "none") or name == tsm_railcorridors.nodes.cobweb or name == tsm_railcorridors.nodes.torch_wall or name == tsm_railcorridors.nodes.torch_floor or @@ -192,7 +192,7 @@ end local function IsGround(pos) local nodename = minetest.get_node(pos).name local nodedef = minetest.registered_nodes[nodename] - return nodename ~= "unknown" and nodename ~= "ignore" and nodedef.is_ground_content and nodedef.walkable and nodedef.liquidtype == "none" + return nodename ~= "unknown" and nodename ~= "ignore" and nodedef and nodedef.is_ground_content and nodedef.walkable and nodedef.liquidtype == "none" end -- Returns true if rails are allowed to be placed on top of this node @@ -200,7 +200,7 @@ local function IsRailSurface(pos) local nodename = minetest.get_node(pos).name local nodename_above = minetest.get_node({x=pos.x,y=pos.y+2,z=pos.z}).name local nodedef = minetest.registered_nodes[nodename] - return nodename ~= "unknown" and nodename ~= "ignore" and nodedef.walkable and (nodedef.node_box == nil or nodedef.node_box.type == "regular") and nodename_above ~= tsm_railcorridors.nodes.rail + return nodename ~= "unknown" and nodename ~= "ignore" and nodedef and nodedef.walkable and (nodedef.node_box == nil or nodedef.node_box.type == "regular") and nodename_above ~= tsm_railcorridors.nodes.rail end -- Checks if the node is empty space which requires to be filled by a platform @@ -211,7 +211,7 @@ local function NeedsPlatform(pos) local falling = minetest.get_item_group(node.name, "falling_node") == 1 return -- Node can be replaced if ground content or rail - (node.name ~= "ignore" and node.name ~= "unknown" and nodedef.is_ground_content) and + (node.name ~= "ignore" and node.name ~= "unknown" and nodedef and nodedef.is_ground_content) and -- Node needs platform if node below is not walkable. -- Unless 2 nodes below there is dirt: This is a special case for the starter cube. ((nodedef.walkable == false and node2.name ~= tsm_railcorridors.nodes.dirt) or @@ -253,7 +253,7 @@ local function Cube(p, radius, node, replace_air_only, wood, post) if yi == y_top then local topnode = minetest.get_node({x=xi,y=yi+1,z=zi}) local topdef = minetest.registered_nodes[topnode.name] - if minetest.get_item_group(topnode.name, "attached_node") ~= 1 and topdef.liquidtype == "none" then + if minetest.get_item_group(topnode.name, "attached_node") ~= 1 and topdef and topdef.liquidtype == "none" then ok = true end elseif column_last_attached and yi == column_last_attached - 1 then @@ -277,7 +277,7 @@ local function Cube(p, radius, node, replace_air_only, wood, post) elseif wood and (xi == p.x or zi == p.z) and thisnode.name == wood then local topnode = minetest.get_node({x=xi,y=yi+1,z=zi}) local topdef = minetest.registered_nodes[topnode.name] - if topdef.walkable and topnode.name ~= wood then + if topdef and topdef.walkable and topnode.name ~= wood then minetest.set_node({x=xi,y=yi,z=zi}, node) -- Check for torches around the wood and schedule them -- for removal @@ -429,7 +429,7 @@ local function TryPlaceCobweb(pos, needs_check, side_vector) local cpos = vector.add(pos, check_vectors[c]) local cname = minetest.get_node(cpos).name local cdef = minetest.registered_nodes[cname] - if cname ~= "ignore" and cdef.walkable then + if cname ~= "ignore" and cdef and cdef.walkable then check_passed = true break end @@ -523,12 +523,12 @@ local function WoodSupport(p, wood, post, torches, dir, torchdir) local nodedef1 = minetest.registered_nodes[minetest.get_node(pos1).name] local nodedef2 = minetest.registered_nodes[minetest.get_node(pos2).name] - if nodedef1.walkable then + if nodedef1 and nodedef1.walkable then pos1.y = pos1.y + 1 end SetNodeIfCanBuild(pos1, node, true) - if nodedef2.walkable then + if nodedef2 and nodedef2.walkable then pos2.y = pos2.y + 1 end SetNodeIfCanBuild(pos2, node, true) diff --git a/mods/MISC/findbiome/locale/findbiome.zh_TW.tr b/mods/MISC/findbiome/locale/findbiome.zh_TW.tr new file mode 100644 index 0000000000..d84abda867 --- /dev/null +++ b/mods/MISC/findbiome/locale/findbiome.zh_TW.tr @@ -0,0 +1,10 @@ +# textdomain: findbiome +Find and teleport to biome=找尋和傳送至生態域 +=<生態域> +No player.=沒有玩家。 +Biome does not exist!=生態域不存在! +Biome found at @1.=生態域在 @1 找到。 +No biome found!=生態域找不到! +List all biomes=列出所有生態域 +No biomes.=沒有生態域。 +Not supported. The “biomeinfo” mod is required for v6 mapgen support!=不支援。「biomeinfo」MOD要求v6世界生成器! diff --git a/mods/MISC/mcl_commands/locale/mcl_commands.zh_TW.tr b/mods/MISC/mcl_commands/locale/mcl_commands.zh_TW.tr new file mode 100644 index 0000000000..0f3885cfe7 --- /dev/null +++ b/mods/MISC/mcl_commands/locale/mcl_commands.zh_TW.tr @@ -0,0 +1,23 @@ +# textdomain: mcl_commands +Players can't be killed right now, damage has been disabled.=玩家現在不能被殺死,傷害已被禁用。 +Player @1 does not exist.=玩家 @1 不存在。 +You are already dead=你已經死了 +@1 is already dead=@1 已經死了。 +@1 committed suicide.=@1 自殺了。 +@1 was killed by @2.=@1 被 @2 殺死了。 +[]=[<名字>] +Kill player or yourself=殺死玩家或自己 +Can use /say=可以使用 /say +=<信息> +Send a message to every player=廣播信息給每個玩家 +Invalid usage, see /help say.=無效用法,見 /help say +,, =,, <方塊名稱> +Set node at given position=在指定位置放置指定方塊 +Invalid node=無效方塊 +@1 spawned.=@1 已生成。 +Invalid parameters (see /help setblock)=無效參數(見 /help setblock) +List bans=查看封鎖列表 +Ban list: @1=封鎖列表:@1 +Show who is logged on=列出在線玩家 +Displays the world seed=顯示種子碼 +Only peaceful mobs allowed!=只允許和平生物! diff --git a/mods/MISC/mcl_privs/init.lua b/mods/MISC/mcl_privs/init.lua index f06ff35820..dc3aa0f69a 100644 --- a/mods/MISC/mcl_privs/init.lua +++ b/mods/MISC/mcl_privs/init.lua @@ -7,7 +7,7 @@ minetest.register_privilege("maphack", { minetest.register_on_joinplayer(function(player) local name = player:get_player_name() local meta = player:get_meta() - if meta:get_int("fly_changed") == 1 then return end + if meta:get_int("mcl_privs:fly_changed") == 1 then return end local fly = nil if minetest.is_creative_enabled(name) then @@ -20,10 +20,27 @@ end) for _, action in pairs({"grant", "revoke"}) do minetest["register_on_priv_" .. action](function(name, _, priv) + local player = minetest.get_player_by_name(name) + if not player then + return + end + + local meta = player:get_meta() + if priv == "fly" then - local player = minetest.get_player_by_name(name) - local meta = player:get_meta() - meta:set_int("fly_changed", 1) + meta:set_int("mcl_privs:fly_changed", 1) + end + + --[[ + so e.g. hackers who have been revoked of the interact privilege + will not automatically get the interact privilege through the mcl shields code back + ]] + if priv == "interact" then + if action == "revoke" then + meta:set_int("mcl_privs:interact_revoked", 1) + else + meta:set_int("mcl_privs:interact_revoked", 0) + end end end) end \ No newline at end of file diff --git a/mods/MISC/mcl_privs/locale/mcl_privs.zh_TW.tr b/mods/MISC/mcl_privs/locale/mcl_privs.zh_TW.tr new file mode 100644 index 0000000000..d4e3f96f65 --- /dev/null +++ b/mods/MISC/mcl_privs/locale/mcl_privs.zh_TW.tr @@ -0,0 +1,2 @@ +# textdomain: mcl_privs +Can place and use advanced blocks like mob spawners, command blocks and barriers.=可以放置和使用高級方塊,如生怪磚、命令方塊和屏障 diff --git a/mods/MISC/mcl_wip/locale/mcl_wip.zh_TW.tr b/mods/MISC/mcl_wip/locale/mcl_wip.zh_TW.tr new file mode 100644 index 0000000000..e4b36ff07d --- /dev/null +++ b/mods/MISC/mcl_wip/locale/mcl_wip.zh_TW.tr @@ -0,0 +1,4 @@ +# textdomain: mcl_wip +# WIP means “Work in Progress” +(WIP)=(WIP) +(Temporary)=(暫時) diff --git a/mods/PLAYER/mcl_death_drop/init.lua b/mods/PLAYER/mcl_death_drop/init.lua index bfeee0c3e4..665393ca52 100644 --- a/mods/PLAYER/mcl_death_drop/init.lua +++ b/mods/PLAYER/mcl_death_drop/init.lua @@ -13,6 +13,7 @@ end mcl_death_drop.register_dropped_list("PLAYER", "main", true) mcl_death_drop.register_dropped_list("PLAYER", "craft", true) mcl_death_drop.register_dropped_list("PLAYER", "armor", true) +mcl_death_drop.register_dropped_list("PLAYER", "offhand", true) minetest.register_on_dieplayer(function(player) local keep = minetest.settings:get_bool("mcl_keepInventory", false) diff --git a/mods/PLAYER/mcl_hunger/locale/mcl_hunger.zh_TW.tr b/mods/PLAYER/mcl_hunger/locale/mcl_hunger.zh_TW.tr new file mode 100644 index 0000000000..18d265ef42 --- /dev/null +++ b/mods/PLAYER/mcl_hunger/locale/mcl_hunger.zh_TW.tr @@ -0,0 +1,8 @@ +# textdomain: mcl_hunger +@1 succumbed to the poison.= +Food=食物 +Saturation=飽食度 +%s: %.1f/%d= +Exhaust.=飢餓值 +%s: %d/%d= +@1 starved to death.=@1 餓死了。 diff --git a/mods/PLAYER/mcl_player/init.lua b/mods/PLAYER/mcl_player/init.lua index 2a4c25c349..0dfe539765 100644 --- a/mods/PLAYER/mcl_player/init.lua +++ b/mods/PLAYER/mcl_player/init.lua @@ -9,7 +9,8 @@ local animation_blend = 0 local function get_mouse_button(player) local controls = player:get_player_control() local get_wielded_item_name = player:get_wielded_item():get_name() - if controls.RMB and not string.find(get_wielded_item_name, "mcl_bows:bow") and not string.find(get_wielded_item_name, "mcl_bows:crossbow") or controls.LMB then + if controls.RMB and not string.find(get_wielded_item_name, "mcl_bows:bow") and not string.find(get_wielded_item_name, "mcl_bows:crossbow") and + not mcl_shields.wielding_shield(player, 1) and not mcl_shields.wielding_shield(player, 2) or controls.LMB then return true else return false @@ -188,7 +189,9 @@ minetest.register_globalstep(function(dtime) animation_speed_mod = animation_speed_mod / 2 end - + if mcl_shields.is_blocking(player) then + animation_speed_mod = animation_speed_mod / 2 + end -- ask if player is swiming local head_in_water = minetest.get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 @@ -204,6 +207,8 @@ minetest.register_globalstep(function(dtime) or walking and velocity.x < -0.35 or walking and velocity.z > 0.35 or walking and velocity.z < -0.35 then + local wielded_itemname = player:get_wielded_item():get_name() + local no_arm_moving = string.find(wielded_itemname, "mcl_bows:bow") or mcl_shields.wielding_shield(player, 1) or mcl_shields.wielding_shield(player, 2) if player_sneak[name] ~= controls.sneak then player_anim[name] = nil player_sneak[name] = controls.sneak @@ -212,9 +217,9 @@ minetest.register_globalstep(function(dtime) player_set_animation(player, "swim_walk_mine", animation_speed_mod) elseif not controls.sneak and head_in_water and is_sprinting == true then player_set_animation(player, "swim_walk", animation_speed_mod) - elseif string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") and controls.RMB and controls.sneak or string.find(player:get_wielded_item():get_name(), "mcl_bows:crossbow_") and controls.sneak then + elseif no_arm_moving and controls.RMB and controls.sneak or string.find(wielded_itemname, "mcl_bows:crossbow_") and controls.sneak then player_set_animation(player, "bow_sneak", animation_speed_mod) - elseif string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") and controls.RMB or string.find(player:get_wielded_item():get_name(), "mcl_bows:crossbow_") then + elseif no_arm_moving and controls.RMB or string.find(wielded_itemname, "mcl_bows:crossbow_") then player_set_animation(player, "bow_walk", animation_speed_mod) elseif is_sprinting == true and get_mouse_button(player) == true and not controls.sneak and not head_in_water then player_set_animation(player, "run_walk_mine", animation_speed_mod) diff --git a/mods/PLAYER/mcl_player/mod.conf b/mods/PLAYER/mcl_player/mod.conf index 97ccce8e6b..7cc5d14faa 100644 --- a/mods/PLAYER/mcl_player/mod.conf +++ b/mods/PLAYER/mcl_player/mod.conf @@ -1,3 +1,4 @@ name = mcl_player author = celeron55 description = Adds the 3D player model, taken from Minetest Game 0.4.16. +depends = mcl_shields \ No newline at end of file diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index f86d5e26a8..1784b2e113 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -35,8 +35,8 @@ local function player_collision(player) for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do - if object and (object:is_player() - or (object:get_luaentity()._cmi_is_mob == true and object ~= player)) then + local ent = object:get_luaentity() + if (object:is_player() or (ent and ent._cmi_is_mob and object ~= player)) then local pos2 = object:get_pos() local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z} @@ -120,6 +120,101 @@ end local node_stand, node_stand_below, node_head, node_feet +-- This following part is 2 wrapper functions for player:set_bones +-- and player:set_properties preventing them from being resent on +-- every globalstep when they have not changed. + +local function roundN(n, d) + if type(n) ~= "number" then return n end + local m = 10^d + return math.floor(n * m + 0.5) / m +end + +local function close_enough(a,b) + local rt=true + if type(a) == "table" and type(b) == "table" then + for k,v in pairs(a) do + if roundN(v,2) ~= roundN(b[k],2) then + rt=false + break + end + end + else + rt = roundN(a,2) == roundN(b,2) + end + return rt +end + + + +local function props_changed(props,oldprops) + local changed=false + local p={} + for k,v in pairs(props) do + if not close_enough(v,oldprops[k]) then + p[k]=v + changed=true + end + end + return changed,p +end + +--tests for roundN +local test_round1=15 +local test_round2=15.00199999999 +local test_round3=15.00111111 +local test_round4=15.00999999 + +assert(roundN(test_round1,2)==roundN(test_round1,2)) +assert(roundN(test_round1,2)==roundN(test_round2,2)) +assert(roundN(test_round1,2)==roundN(test_round3,2)) +assert(roundN(test_round1,2)~=roundN(test_round4,2)) + +-- tests for close_enough +local test_cb = {-0.35,0,-0.35,0.35,0.8,0.35} --collisionboxes +local test_cb_close = {-0.351213,0,-0.35,0.35,0.8,0.351212} +local test_cb_diff = {-0.35,0,-1.35,0.35,0.8,0.35} + +local test_eh = 1.65 --eye height +local test_eh_close = 1.65123123 +local test_eh_diff = 1.35 + +local test_nt = { r = 225, b = 225, a = 225, g = 225 } --nametag +local test_nt_diff = { r = 225, b = 225, a = 0, g = 225 } + +assert(close_enough(test_cb,test_cb_close)) +assert(not close_enough(test_cb,test_cb_diff)) +assert(close_enough(test_eh,test_eh_close)) +assert(not close_enough(test_eh,test_eh_diff)) +assert(not close_enough(test_nt,test_nt_diff)) --no floats involved here + +--tests for properties_changed +local test_properties_set1={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }} +local test_properties_set2={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 225, g = 225 }} + +local test_p1,_=props_changed(test_properties_set1,test_properties_set1) +local test_p2,_=props_changed(test_properties_set1,test_properties_set2) + +assert(not test_p1) +assert(test_p2) + +local function set_properties_conditional(player,props) + local changed,p=props_changed(props,player:get_properties()) + if changed then + player:set_properties(p) + end +end + +local function set_bone_position_conditional(player,b,p,r) --bone,position,rotation + local oldp,oldr=player:get_bone_position(b) + if vector.equals(vector.round(oldp),vector.round(p)) and vector.equals(vector.round(oldr),vector.round(r)) then + return + end + player:set_bone_position(b,p,r) +end + + + minetest.register_globalstep(function(dtime) time = time + dtime @@ -173,12 +268,6 @@ minetest.register_globalstep(function(dtime) and (fly_node == "air" or fly_node == "ignore") if elytra.active then - if player_velocity.x < (player_velocity_old.x - 10) or player_velocity.x > (player_velocity_old.x + 10) and fly_node ~= "ignore" then - mcl_util.deal_damage(player, math.abs(player_velocity_old.x) * 0.2, {type = "fly_into_wall"}) - end - if player_velocity.z < (player_velocity_old.z - 10) or player_velocity.z > (player_velocity_old.z + 10) and fly_node ~= "ignore" then - mcl_util.deal_damage(player, math.abs(player_velocity_old.z) * 0.2, {type = "fly_into_wall"}) - end mcl_player.player_set_animation(player, "fly") if player_velocity.y < -1.5 then player:add_velocity({x=0, y=0.17, z=0}) @@ -218,78 +307,82 @@ minetest.register_globalstep(function(dtime) end if wielded_def and wielded_def._mcl_toollike_wield then - player:set_bone_position("Wield_Item", vector.new(0,3.9,1.3), vector.new(90,0,0)) + set_bone_position_conditional(player,"Wield_Item", vector.new(0,3.9,1.3), vector.new(90,0,0)) elseif string.find(wielded:get_name(), "mcl_bows:bow") then - player:set_bone_position("Wield_Item", vector.new(.5,4.5,-1.6), vector.new(90,0,20)) + set_bone_position_conditional(player,"Wield_Item", vector.new(.5,4.5,-1.6), vector.new(90,0,20)) elseif string.find(wielded:get_name(), "mcl_bows:crossbow_loaded") then - player:set_bone_position("Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(64,90,0)) + set_bone_position_conditional(player,"Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(64,90,0)) elseif string.find(wielded:get_name(), "mcl_bows:crossbow") then - player:set_bone_position("Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(90,90,0)) + set_bone_position_conditional(player,"Wield_Item", vector.new(-1.5,5.7,1.8), vector.new(90,90,0)) else - player:set_bone_position("Wield_Item", vector.new(-1.5,4.9,1.8), vector.new(135,0,90)) + set_bone_position_conditional(player,"Wield_Item", vector.new(-1.5,4.9,1.8), vector.new(135,0,90)) end player_velocity_old = player:get_velocity() or player:get_player_velocity() - -- controls right and left arms pitch when shooting a bow - if string.find(wielded:get_name(), "mcl_bows:bow") and control.RMB then - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) + -- controls right and left arms pitch when shooting a bow or blocking + if mcl_shields.is_blocking(player) == 2 then + set_bone_position_conditional(player, "Arm_Right_Pitch_Control", vector.new(-3, 5.785, 0), vector.new(20, -20, 0)) + elseif mcl_shields.is_blocking(player) == 1 then + set_bone_position_conditional(player, "Arm_Left_Pitch_Control", vector.new(3, 5.785, 0), vector.new(20, 20, 0)) + elseif string.find(wielded:get_name(), "mcl_bows:bow") and control.RMB then + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) -- controls right and left arms pitch when holing a loaded crossbow elseif string.find(wielded:get_name(), "mcl_bows:crossbow_loaded") then - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) -- controls right and left arms pitch when loading a crossbow - elseif string.find(wielded:get_name(), "mcl_bows:crossbow_") then - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(45,-20,25)) - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(55,20,-45)) + elseif string.find(wielded:get_name(), "mcl_bows:crossbow_") then + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(45,-20,25)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(55,20,-45)) -- when punching elseif control.LMB and not parent then - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) -- when holding an item. elseif wielded:get_name() ~= "" then - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(20,0,0)) - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(20,0,0)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) -- resets arms pitch else - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0)) end if elytra.active then -- set head pitch and yaw when flying - player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0)) + set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0)) -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + set_properties_conditional(player,{collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) -- control body bone when flying - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0)) elseif parent then local parent_yaw = degrees(parent:get_yaw()) - player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) - player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch, -limit_vel_yaw(yaw, parent_yaw) + parent_yaw, 0)) - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) + set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch, -limit_vel_yaw(yaw, parent_yaw) + parent_yaw, 0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) elseif control.sneak then -- controls head pitch when sneaking - player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, player_vel_yaw - yaw)) + set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, player_vel_yaw - yaw)) -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }}) + set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }}) -- sneaking body conrols - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0)) elseif get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 and is_sprinting(name) == true then -- set head pitch and yaw when swimming - player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0)) + set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch-degrees(dir_to_pitch(player_velocity)),player_vel_yaw - yaw,0)) -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,0.8,0.312}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,0.8,0.312}, eye_height = 0.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) -- control body bone when swimming - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,-player_vel_yaw + yaw + 180,0)) else -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + set_properties_conditional(player,{collisionbox = {-0.312,0,-0.312,0.312,1.8,0.312}, eye_height = 1.5, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) - player:set_bone_position("Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, 0)) - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0)) + set_bone_position_conditional(player,"Head_Control", vector.new(0,6.3,0), vector.new(pitch, player_vel_yaw - yaw, 0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0, -player_vel_yaw + yaw, 0)) end -- Update jump status immediately since we need this info in real time. @@ -550,7 +643,8 @@ mcl_damage.register_modifier(function(obj, damage, reason) node = minetest.get_node(pos) end if node then - if minetest.registered_nodes[node.name].walkable then + local def = minetest.registered_nodes[node.name] + if not def or def.walkable then return end if minetest.get_item_group(node.name, "water") ~= 0 then diff --git a/mods/PLAYER/mcl_playerplus/locale/mcl_playerplus.zh_TW.tr b/mods/PLAYER/mcl_playerplus/locale/mcl_playerplus.zh_TW.tr new file mode 100644 index 0000000000..eb9e6b1dba --- /dev/null +++ b/mods/PLAYER/mcl_playerplus/locale/mcl_playerplus.zh_TW.tr @@ -0,0 +1,3 @@ +# textdomain: mcl_playerplus +@1 suffocated to death.=@1 在牆壁裡窒息。 +@1 was prickled to death by a cactus.=@1 被仙人掌刺死了。 diff --git a/mods/PLAYER/mcl_playerplus/mod.conf b/mods/PLAYER/mcl_playerplus/mod.conf index b77c9e2e5e..953ea9403a 100644 --- a/mods/PLAYER/mcl_playerplus/mod.conf +++ b/mods/PLAYER/mcl_playerplus/mod.conf @@ -1,5 +1,5 @@ name = mcl_playerplus author = TenPlus1 description = Adds some simple player-related gameplay effects: Hurt by touching a cactus, suffocation and more. -depends = mcl_init, mcl_core, mcl_particles, mcl_hunger, playerphysics, mcl_playerinfo, mcl_weather, mcl_spawn, mcl_enchanting, mcl_damage, mcl_sprint +depends = mcl_init, mcl_core, mcl_particles, mcl_hunger, playerphysics, mcl_playerinfo, mcl_weather, mcl_spawn, mcl_enchanting, mcl_damage, mcl_sprint, mcl_util, mcl_shields diff --git a/mods/PLAYER/mcl_skins/locale/mcl_skins.zh_TW.tr b/mods/PLAYER/mcl_skins/locale/mcl_skins.zh_TW.tr new file mode 100644 index 0000000000..1347800ee6 --- /dev/null +++ b/mods/PLAYER/mcl_skins/locale/mcl_skins.zh_TW.tr @@ -0,0 +1,13 @@ +# textdomain: mcl_skins +[] []=[<玩家名字>] [<皮膚篇號>] +Select player skin of yourself or another player=替自己或其他玩家選擇皮膚 +Insufficient or wrong parameters=無效或錯誤參數 +Player @1 not online!=玩家 @1 不在線! +You need the “server” privilege to change the skin of other players!=你需要「server」權限來替換其他玩家的皮膚! +Invalid skin number! Valid numbers: 0 to @1=無效皮膚篇號!有效篇號:0至@1 +Your skin has been set to: @1=你的皮膚已換成:@1 +Your skin has been set to: @1 (@2)=你的皮膚已換成:@1(@2) +Skin of @1 set to: @2 (@3)=@1的皮膚已換成:@1 +Select player skin:=選擇玩家皮膚: +@1 (@2)=@1(@2) +Name: @1=名稱:@1 diff --git a/mods/PLAYER/mcl_spawn/locale/mcl_spawn.zh_TW.tr b/mods/PLAYER/mcl_spawn/locale/mcl_spawn.zh_TW.tr new file mode 100644 index 0000000000..f47d22c2d4 --- /dev/null +++ b/mods/PLAYER/mcl_spawn/locale/mcl_spawn.zh_TW.tr @@ -0,0 +1,4 @@ +# textdomain: mcl_spawn +New respawn position set!=新重生點已設定! +Respawn position cleared!=重生點已清除! +Your spawn bed was missing or blocked.=你的床被破壞或被堵住了。 diff --git a/mods/PLAYER/mcl_wieldview/init.lua b/mods/PLAYER/mcl_wieldview/init.lua index 7200f61869..ff70445e3f 100644 --- a/mods/PLAYER/mcl_wieldview/init.lua +++ b/mods/PLAYER/mcl_wieldview/init.lua @@ -6,7 +6,7 @@ mcl_wieldview = { } function mcl_wieldview.get_item_texture(itemname) - if itemname == "" then + if itemname == "" or minetest.get_item_group(itemname, "no_wieldview") ~= 0 then return end @@ -113,6 +113,10 @@ minetest.register_entity("mcl_wieldview:wieldnode", { self.object:set_properties({textures = {""}}) end + if minetest.get_item_group(itemstring, "no_wieldview") ~= 0 then + self.object:set_properties({textures = {""}}) + end + self.itemstring = itemstring end else diff --git a/tools/Conversion_Table.csv b/tools/Conversion_Table.csv index 426712f5b4..07343479d0 100644 --- a/tools/Conversion_Table.csv +++ b/tools/Conversion_Table.csv @@ -176,7 +176,7 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/blocks,cobblestone_mossy.png,/mods/ITEMS/mcl_core/textures,default_mossycobble.png,,,,,,, /assets/minecraft/textures/blocks,obsidian.png,/mods/ITEMS/mcl_core/textures,default_obsidian.png,,,,,,, /assets/minecraft/textures/items,paper.png,/mods/ITEMS/mcl_core/textures,default_paper.png,,,,,,, -/assets/minecraft/textures/blocks,reeds.png,/mods/ITEMS/mcl_core/textures,default_papyrus.png,,,,,,, +/assets/minecraft/textures/blocks,reeds.png,/mods/ITEMS/mcl_core/textures,mcl_core_papyrus.png,,,,,,, /assets/minecraft/textures/blocks,sand.png,/mods/ITEMS/mcl_core/textures,default_sand.png,,,,,,, /assets/minecraft/textures/blocks,snow.png,/mods/ITEMS/mcl_core/textures,default_snow.png,,,,,,, /assets/minecraft/textures/blocks,iron_block.png,/mods/ITEMS/mcl_core/textures,default_steel_block.png,,,,,,,