From 81ffc8af59b0df4bddb9f7d6b37194713b13973c Mon Sep 17 00:00:00 2001 From: D00Med Date: Thu, 2 Feb 2017 08:21:34 +1000 Subject: [PATCH] village mod --- mods/mapgen/mapgen.lua | 1 - mods/mobs_npc/depends.txt | 4 + mods/mobs_npc/description.txt | 1 + mods/mobs_npc/igor.lua | 117 +++++++ mods/mobs_npc/init.lua | 33 ++ mods/mobs_npc/license.txt | 21 ++ mods/mobs_npc/locale/de.txt | 23 ++ mods/mobs_npc/locale/template.txt | 21 ++ mods/mobs_npc/lucky_block.lua | 10 + mods/mobs_npc/mod.conf | 1 + mods/mobs_npc/npc.lua | 130 +++++++ mods/mobs_npc/readme.md | 13 + mods/mobs_npc/textures/mobs_igor.png | Bin 0 -> 222 bytes mods/mobs_npc/textures/mobs_igor2.png | Bin 0 -> 924 bytes mods/mobs_npc/textures/mobs_igor3.png | Bin 0 -> 1109 bytes mods/mobs_npc/textures/mobs_igor4.png | Bin 0 -> 544 bytes mods/mobs_npc/textures/mobs_igor5.png | Bin 0 -> 848 bytes mods/mobs_npc/textures/mobs_igor6.png | Bin 0 -> 816 bytes mods/mobs_npc/textures/mobs_igor7.png | Bin 0 -> 799 bytes mods/mobs_npc/textures/mobs_igor8.png | Bin 0 -> 792 bytes mods/mobs_npc/textures/mobs_npc.png | Bin 0 -> 901 bytes mods/mobs_npc/textures/mobs_npc2.png | Bin 0 -> 1018 bytes mods/mobs_npc/textures/mobs_npc_baby.png | Bin 0 -> 684 bytes mods/mobs_npc/textures/mobs_trader.png | Bin 0 -> 783 bytes mods/mobs_npc/textures/mobs_trader2.png | Bin 0 -> 783 bytes mods/mobs_npc/textures/mobs_trader3.png | Bin 0 -> 779 bytes mods/mobs_npc/trader.lua | 355 +++++++++++++++++++ mods/mobs_redo/api.lua | 425 +++++++++++++++++------ mods/mobs_redo/api.txt | 14 +- mods/mobs_redo/crafts.lua | 2 +- mods/mobs_redo/mount.lua | 29 +- mods/mobs_redo/textures/mobs_blood.png | Bin 183 -> 267 bytes mods/villages/depends.txt | 1 + mods/villages/init.lua | 57 +++ mods/villages/textures/villages_deed.png | Bin 0 -> 388 bytes 35 files changed, 1143 insertions(+), 115 deletions(-) create mode 100644 mods/mobs_npc/depends.txt create mode 100644 mods/mobs_npc/description.txt create mode 100644 mods/mobs_npc/igor.lua create mode 100644 mods/mobs_npc/init.lua create mode 100644 mods/mobs_npc/license.txt create mode 100644 mods/mobs_npc/locale/de.txt create mode 100644 mods/mobs_npc/locale/template.txt create mode 100644 mods/mobs_npc/lucky_block.lua create mode 100644 mods/mobs_npc/mod.conf create mode 100644 mods/mobs_npc/npc.lua create mode 100644 mods/mobs_npc/readme.md create mode 100644 mods/mobs_npc/textures/mobs_igor.png create mode 100644 mods/mobs_npc/textures/mobs_igor2.png create mode 100644 mods/mobs_npc/textures/mobs_igor3.png create mode 100644 mods/mobs_npc/textures/mobs_igor4.png create mode 100644 mods/mobs_npc/textures/mobs_igor5.png create mode 100644 mods/mobs_npc/textures/mobs_igor6.png create mode 100644 mods/mobs_npc/textures/mobs_igor7.png create mode 100644 mods/mobs_npc/textures/mobs_igor8.png create mode 100644 mods/mobs_npc/textures/mobs_npc.png create mode 100644 mods/mobs_npc/textures/mobs_npc2.png create mode 100644 mods/mobs_npc/textures/mobs_npc_baby.png create mode 100644 mods/mobs_npc/textures/mobs_trader.png create mode 100644 mods/mobs_npc/textures/mobs_trader2.png create mode 100644 mods/mobs_npc/textures/mobs_trader3.png create mode 100644 mods/mobs_npc/trader.lua create mode 100644 mods/villages/depends.txt create mode 100644 mods/villages/init.lua create mode 100644 mods/villages/textures/villages_deed.png diff --git a/mods/mapgen/mapgen.lua b/mods/mapgen/mapgen.lua index fadafe9..f15196b 100644 --- a/mods/mapgen/mapgen.lua +++ b/mods/mapgen/mapgen.lua @@ -2042,7 +2042,6 @@ minetest.register_on_generated(function(minp, maxp) else minetest.place_schematic(pos, minetest.get_modpath("hyrule_mapgen").."/schematics/dungeon"..number..".mts", random, {}, true) end - end end end end) \ No newline at end of file diff --git a/mods/mobs_npc/depends.txt b/mods/mobs_npc/depends.txt new file mode 100644 index 0000000..58b4e62 --- /dev/null +++ b/mods/mobs_npc/depends.txt @@ -0,0 +1,4 @@ +default +mobs +intllib? +lucky_block? diff --git a/mods/mobs_npc/description.txt b/mods/mobs_npc/description.txt new file mode 100644 index 0000000..3936b7f --- /dev/null +++ b/mods/mobs_npc/description.txt @@ -0,0 +1 @@ +Adds simple NPC and Trader. diff --git a/mods/mobs_npc/igor.lua b/mods/mobs_npc/igor.lua new file mode 100644 index 0000000..a1b6bce --- /dev/null +++ b/mods/mobs_npc/igor.lua @@ -0,0 +1,117 @@ + +local S = mobs.intllib + +-- Igor by TenPlus1 + +mobs.igor_drops = { + "vessels:glass_bottle", "mobs:meat_raw", "default:sword_steel", + "farming:bread", "bucket:bucket_water" +} + +mobs:register_mob("mobs_npc:igor", { + type = "npc", + passive = false, + damage = 5, + attack_type = "dogfight", + pathfinding = true, + reach = 2, + attacks_monsters = true, + hp_min = 20, + hp_max = 30, + armor = 100, + collisionbox = {-0.35,-1.0,-0.35, 0.35,0.8,0.35}, + visual = "mesh", + mesh = "character.b3d", + textures = { + {"mobs_igor.png"}, -- skin by ruby32199 + {"mobs_igor2.png"}, + {"mobs_igor3.png"}, + {"mobs_igor4.png"}, + {"mobs_igor5.png"}, + {"mobs_igor6.png"}, + {"mobs_igor7.png"}, + {"mobs_igor8.png"}, + }, + makes_footstep_sound = true, + sounds = {}, + walk_velocity = 1, + run_velocity = 2, + stepheight = 1.1, + fear_height = 2, + jump = true, + drops = { + {name = "mobs:meat_raw", chance = 1, min = 1, max = 2}, + {name = "default:gold_lump", chance = 3, min = 1, max = 1}, + }, + water_damage = 1, + lava_damage = 3, + light_damage = 0, + follow = {"mobs:meat_raw", "default:diamond"}, + view_range = 15, + owner = "", + order = "follow", + -- model animation + animation = { + speed_normal = 30, + speed_run = 30, + stand_start = 0, + stand_end = 79, + walk_start = 168, + walk_end = 187, + run_start = 168, + run_end = 187, + punch_start = 200, + punch_end = 219, + }, + -- right clicking with raw meat will give Igor more health + on_rightclick = function(self, clicker) + + -- feed to heal npc + if mobs:feed_tame(self, clicker, 8, false, true) then + return + end + + local item = clicker:get_wielded_item() + local name = clicker:get_player_name() + + -- right clicking with gold lump drops random item from mobs.npc_drops + if item:get_name() == "default:gold_lump" then + + if not minetest.setting_getbool("creative_mode") then + item:take_item() + clicker:set_wielded_item(item) + end + + local pos = self.object:getpos() + pos.y = pos.y + 0.5 + + minetest.add_item(pos, { + name = mobs.igor_drops[math.random(1, #mobs.igor_drops)] + }) + + minetest.chat_send_player(name, S("NPC dropped you an item for gold!")) + + return + end + + -- if owner switch between follow and stand + if self.owner and self.owner == name then + + if self.order == "follow" then + self.order = "stand" + minetest.chat_send_player(name, S("NPC stands still.")) + else + self.order = "follow" + minetest.chat_send_player(name, S("NPC will follow you.")) + end + end + + mobs:protect(self, clicker) + mobs:capture_mob(self, clicker, 0, 5, 80, false, nil) + end, +}) +-- register spawn egg +mobs:register_egg("mobs_npc:igor", S("Igor"), "mobs_meat_raw.png", 1) + +-- compatibility +mobs:alias_mob("mobs:igor", "mobs_npc:igor") diff --git a/mods/mobs_npc/init.lua b/mods/mobs_npc/init.lua new file mode 100644 index 0000000..09e7b3d --- /dev/null +++ b/mods/mobs_npc/init.lua @@ -0,0 +1,33 @@ + +local path = minetest.get_modpath("mobs_npc") + +-- Intllib +local S +if minetest.get_modpath("intllib") then + S = intllib.Getter() +else + S = function(s, a, ...) + if a == nil then + return s + end + a = {a, ...} + return s:gsub("(@?)@(%(?)(%d+)(%)?)", + function(e, o, n, c) + if e == ""then + return a[tonumber(n)] .. (o == "" and c or "") + else + return "@" .. o .. n .. c + end + end) + end +end +mobs.intllib = S + +-- NPC +dofile(path .. "/npc.lua") -- TenPlus1 +dofile(path .. "/trader.lua") +dofile(path .. "/igor.lua") + +dofile(path .. "/lucky_block.lua") + +print (S("[MOD] Mobs Redo 'NPCs' loaded")) diff --git a/mods/mobs_npc/license.txt b/mods/mobs_npc/license.txt new file mode 100644 index 0000000..fec6f6a --- /dev/null +++ b/mods/mobs_npc/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 TenPlus1 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/mods/mobs_npc/locale/de.txt b/mods/mobs_npc/locale/de.txt new file mode 100644 index 0000000..cffa840 --- /dev/null +++ b/mods/mobs_npc/locale/de.txt @@ -0,0 +1,23 @@ +# German Translation for mobs_npc mod +# Deutsche Übersetzung der mobs_npc Mod +# last update: 2016/June/10 +# Author: Xanthin + +#init.lua +[MOD] Mobs Redo 'NPCs' loaded = [MOD] Mobs Redo 'NPCs' geladen + +#npc.lua +NPC dropped you an item for gold! = NSC ließ dir für Gold einen Gegenstand fallen! +NPC stands still. = NSC bleibt stehen. +NPC will follow you. = NSC wird dir folgen. +Npc = Nsc + +#trader.lua +Trader @1 = Händler @1 +[NPC] Hello, @2, have a look at my wares. = [NSC] Hallo, @2, wirf einen Blick auf meine Waren. +Trader @1's stock: = Händler @1s Warenlager +Selection = Auswahl +Price = Preis +Payment = Bezahlung +Bought items = Ware +Trader = Händler \ No newline at end of file diff --git a/mods/mobs_npc/locale/template.txt b/mods/mobs_npc/locale/template.txt new file mode 100644 index 0000000..906ddd2 --- /dev/null +++ b/mods/mobs_npc/locale/template.txt @@ -0,0 +1,21 @@ +# Template for translations of mobs_npc mod +# last update: 2016/June/10 + +#init.lua +[MOD] Mobs Redo 'NPCs' loaded = + +#npc.lua +NPC dropped you an item for gold! = +NPC stands still. = +NPC will follow you. = +Npc = + +#trader.lua +Trader @1 = +[NPC] Hello, @2, have a look at my wares. = +Trader @1's stock: = +Selection = +Price = +Payment = +Bought items = +Trader = \ No newline at end of file diff --git a/mods/mobs_npc/lucky_block.lua b/mods/mobs_npc/lucky_block.lua new file mode 100644 index 0000000..0e38e92 --- /dev/null +++ b/mods/mobs_npc/lucky_block.lua @@ -0,0 +1,10 @@ + +if minetest.get_modpath("lucky_block") then + + lucky_block:add_blocks({ + {"spw", "mobs:npc", 1, true, true}, + {"spw", "mobs:trader", 1, false, false}, + {"lig"}, + }) + +end diff --git a/mods/mobs_npc/mod.conf b/mods/mobs_npc/mod.conf new file mode 100644 index 0000000..9646cf7 --- /dev/null +++ b/mods/mobs_npc/mod.conf @@ -0,0 +1 @@ +name = mobs_npc diff --git a/mods/mobs_npc/npc.lua b/mods/mobs_npc/npc.lua new file mode 100644 index 0000000..9d1556a --- /dev/null +++ b/mods/mobs_npc/npc.lua @@ -0,0 +1,130 @@ + +local S = mobs.intllib + +-- Npc by TenPlus1 + +mobs.npc_drops = { + "default:pick_steel", "mobs:meat", "default:sword_steel", + "default:shovel_steel", "farming:bread", "bucket:bucket_water" +} + +mobs:register_mob("mobs_npc:npc", { + type = "npc", + passive = false, + damage = 3, + attack_type = "dogfight", + attacks_monsters = true, + pathfinding = true, + hp_min = 10, + hp_max = 20, + armor = 100, + collisionbox = {-0.35,-1.0,-0.35, 0.35,0.8,0.35}, + visual = "mesh", + mesh = "character.b3d", + drawtype = "front", + textures = { + {"mobs_npc.png"}, + {"mobs_npc2.png"}, -- female by nuttmeg20 + }, + child_texture = { + {"mobs_npc_baby.png"}, -- derpy baby by AmirDerAssassine + }, + makes_footstep_sound = true, + sounds = {}, + walk_velocity = 2, + run_velocity = 3, + jump = true, + drops = { + {name = "default:wood", chance = 1, min = 1, max = 3}, + {name = "default:apple", chance = 2, min = 1, max = 2}, + {name = "default:axe_stone", chance = 5, min = 1, max = 1}, + }, + water_damage = 0, + lava_damage = 2, + light_damage = 0, + follow = {"farming:bread", "mobs:meat", "default:diamond"}, + view_range = 15, + owner = "", + order = "follow", + fear_height = 3, + animation = { + speed_normal = 30, + speed_run = 30, + stand_start = 0, + stand_end = 79, + walk_start = 168, + walk_end = 187, + run_start = 168, + run_end = 187, + punch_start = 200, + punch_end = 219, + }, + on_rightclick = function(self, clicker) + + -- feed to heal npc + if mobs:feed_tame(self, clicker, 8, true, true) then + return + end + + local item = clicker:get_wielded_item() + local name = clicker:get_player_name() + + -- right clicking with gold lump drops random item from mobs.npc_drops + if item:get_name() == "default:gold_lump" then + + if not minetest.setting_getbool("creative_mode") then + item:take_item() + clicker:set_wielded_item(item) + end + + local pos = self.object:getpos() + + pos.y = pos.y + 0.5 + + minetest.add_item(pos, { + name = mobs.npc_drops[math.random(1, #mobs.npc_drops)] + }) + + minetest.chat_send_player(name, S("NPC dropped you an item for gold!")) + + return + end + + -- capture npc with net or lasso + mobs:capture_mob(self, clicker, 0, 5, 80, false, nil) + + -- protect npc with mobs:protector + mobs:protect(self, clicker) + + -- by right-clicking owner can switch npc between follow and stand + if self.owner and self.owner == name then + + if self.order == "follow" then + self.order = "stand" + + minetest.chat_send_player(name, S("NPC stands still.")) + else + self.order = "follow" + + minetest.chat_send_player(name, S("NPC will follow you.")) + end + end + + end, +}) + +mobs:spawn({ + name = "mobs_npc:npc", + nodes = {"default:brick"}, + neighbors = {"default:grass_3"}, + min_light = 10, + chance = 10000, + active_object_count = 1, + min_height = 0, + day_toggle = true, +}) + +mobs:register_egg("mobs_npc:npc", S("Npc"), "default_brick.png", 1) + +-- compatibility +mobs:alias_mob("mobs:npc", "mobs_npc:npc") diff --git a/mods/mobs_npc/readme.md b/mods/mobs_npc/readme.md new file mode 100644 index 0000000..447fb35 --- /dev/null +++ b/mods/mobs_npc/readme.md @@ -0,0 +1,13 @@ + +NPC MOBS + + +NPC + +- While NPC's don't actually spawn in the world just yet, they do have a spawn egg available to drop him/her into the world and wander around defending himself if attacked. It will also he will help you attack any monsters in the area and will follow you if you hold a diamond. Right-clicking the NPC with a gold lump will make him drop steel tools or food, right-clicking with an empty hand orders the NPC to stay or follow if owned. + +Trader + +- Traders are new and still being tested but can be placed into the world using a spawn egg. Right-clicking on a trader opens his shop and allows you to buy his wares inside. If provoked a trader will attack a player or monster. + +Lucky Blocks: 3 diff --git a/mods/mobs_npc/textures/mobs_igor.png b/mods/mobs_npc/textures/mobs_igor.png new file mode 100644 index 0000000000000000000000000000000000000000..0d9f9c0114a4b9d69b0028b6454d2d96b012b34a GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!VDw>HYaZfQgQ)4A+A6g2t)-~q@<*-vh%!O zSMz>H&!-bh|6gAB|Nnn2rN6U)(u^fRe!&b5&u*jvIeDHgjv*GOlM^IZ7c;POaA|2a zW;i=KDhP?Vh&cx<=yZfLhRAJaN_-Q>p~RdhGEZR^Q({SF3G1=8V{H|pE#2KqAB8GJ z#?5OBcdT;#>GFq*h4tg?31Kgq?(-&Qu3T6ln!vPyNmavPT0^JcQU(S-Ce>(P#S;Y} OXL`E&xvX}cAAM9kRb*a&Z70EA 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 u>{pD5`O` z9AZ*zX3SD+Tyk$tBYY@`2GCq_5T2XMk#&AXPTm#(gt9#EC7I(mUnokrKN3K2S9#rZ?Cfe09#Ed(5UJv zbPs_4dA)A)hfe^2Rp9$6O-*mx z><8dkJNJk0063sy0ifB%vb(zrAneb_2>=Jo%mBcCfD8a2srz+40N{X`82}hyW@gL) zsP^Fj0OseJn%SM9vs2>)hZRF=|0Si>9unUG#|-9ypC&tu!K*I@Br7wwFFPYb+O!l)Q-C85CHWe>3f8Va} zDuSk!it64(-w_;@0OCB(Nc{EVxB2taLCJZvM@F>*h6Wi&op@Bl*y3 z>mvZ!wgt4d+csZzzNGE8tt@R?ZMSU|;LrdxTV2)r7x&g~bxUh=O|G@Kx>A5+wSdxP z>HgBIYpp8XjdXIk#T5&1&;@K4&~3Lsx3)-=-XsWsW6c8W+RqioU{4jtV9!VH5BCST dKji)Z_y-x5q>D}$FggGL002ovPDHLkV1l1-RXhLy literal 0 HcmV?d00001 diff --git a/mods/mobs_npc/textures/mobs_igor8.png b/mods/mobs_npc/textures/mobs_igor8.png new file mode 100644 index 0000000000000000000000000000000000000000..b30259f63fb3b256daf06e27ad8f0e49bfecdae3 GIT binary patch literal 792 zcmV+z1LypSP)4FEMaG`bf6!xacdNJUIeOYU<3xsPGYk8b{u z0G*$l|DZ3;sea?ChP1Y`@4J-g%%t(mrqtHc^Vz-V>gW0H&Hei7{{Q?X7)s~>0004W zQchC_#U_%sgclqdI)gjlK~T#Q)_G2#agXJE$>Y3>_3aDQvt805F7zC0{Ug{5undr z;P@y7cR4^ZR5>93ei-_mCFBqsr+8f?gaQDxDj}pQAYk}Djz0!lE1(xKHIf5Y-vo+c8)fI0+TmJp!L01V-0Z!eVs2ILS51$6XMBjExlN#d{G{{EwL4kjrh zJ{L+NA@9 W8X_;vXP$uo0000`~YN literal 0 HcmV?d00001 diff --git a/mods/mobs_npc/textures/mobs_npc.png b/mods/mobs_npc/textures/mobs_npc.png new file mode 100644 index 0000000000000000000000000000000000000000..93563989580324581cac10eaa5a91c427eaac724 GIT binary patch literal 901 zcmV;01A6?4P)067o8=&K2l_nO4V-n|G)B{ptiksc002fl!)YT zauTX)vt?PX*QHpQtAo{27_Eh=elm_*5!U(mUnpU$)#7J>>-Fo4Be(e#Kx-v*{UZS4 zZnrN!eVvd0rIA(%q5ce@l(y3Rroo#OoDxn5BmOL6EuA(($zK3|FCzprQV97r@HlH{ zm2^;0NbQW`OsrJ87FH>1p~;c@aW={tYmmRPsHJmCYKeYwwKZ^^coFY78zHgLn5_Y% z6lh6w75dUBA?ru^zCUiakMHZToP2Q2ue+M6=C)FxuZ46k^*_!UmA9fcdTU7Z5?r*U zF-`&DZ3-66XRHDOk|_hdP@5Y3Q5dj!Ct{&5(1d2Y5f;59Yb~?@s?cxC$Y+8wD`%8( zj&FlTLs;vK+pl+w!DG;_Q-Jw+4!rL1-q&;a4*sQ?!Z3^tZ2yiShVvQkVVtIMxC6{U zIL8!T06aFP_&^Sk^AFJjcpQd%K*pwcer)$c=(GkTimIdcl3tfpK& zXw3khAQqpO6XPc$EUbPE1OzG!Fk(EHee)e4Gjtl6LBe`win(Ke)$gM(oPeEn2L3+= zc}8vni@h?yhLrohFo55qa)GEnu~FMJZQJ;kP7e)I#{+yPo5U=plpo0i&Dq={Jj)i3ekvLUQ?c>wU)9kyd?HXbb9NVJ!%#CueOw`|tk zd!{O}eeXG#_`^eTABK@hu@5RJ2caCG0)&nq>K_0l&=VHHggs&gr&G5=l?rYQFuIL# zcuJv*MaTxoDRqT-Ov8|9GZY$^s6#NuvK$$NZWpWJB82jl;y9wA%V`~VM~Y0Hy#3R!0{9|`}$00000NkvXXu0mjfYEy{n literal 0 HcmV?d00001 diff --git a/mods/mobs_npc/textures/mobs_npc2.png b/mods/mobs_npc/textures/mobs_npc2.png new file mode 100644 index 0000000000000000000000000000000000000000..a9d1a2c216d55d943556282f27e5ddb2ab381523 GIT binary patch literal 1018 zcmV3 zK#@>8fmK9ZUtE+^K5Jk(mQ+BWS45y#Kc-wnh-pWvUq_i~QiyL$P0n{DQ$O7iM;P?!Sh$-0Mo&h*6K#c>X^|Gk_H9=))R7*7$S0MuMH2Vzw7v0~l z@8vtV=w=Q=Fb>?0wNey;?{|sdQ%}V!1jLyV@x7)LY!@LnucZ;5O-NkOjbR8Cn+$C5 zT;H`!ZC2MyeI4pmJXQvP4ksu(oswQOGn2dnjA1ZWVP*{}1BaPJ@EuzBAiX|R*{0G=d81nB2UR32#$nBpZY@(MhWla$sQN)`#` zBNiY@qP!I#M|k4X8-^I07*qoM6N<$f=z4BN&o-= literal 0 HcmV?d00001 diff --git a/mods/mobs_npc/textures/mobs_npc_baby.png b/mods/mobs_npc/textures/mobs_npc_baby.png new file mode 100644 index 0000000000000000000000000000000000000000..e26e450112be808a83cd019069f2f94bef5db144 GIT binary patch literal 684 zcmV;d0#p5oP)X<)d}xq;TP>eC)Q1^|poezLfvNng7I*is0b>$eR7gq5jdR{{Q^x;Au_( z0004WQchCNq+tro zfL~wBw9!;+<+s+acMaYV3xK~L0K^zTfPV(^K7bEc03cKO1OO4Zx6c8ZyZ3Ijewu=| z-g`3eSrK*dNDAxa4FKhv8>w470wmX1cHI9B0Qw?SPi>%z?ZiO35+TBm0N}OBf5Ztk zc$4ck9~=Q7|IR>8-`^JiaM^Y49|15bs9EFr3jjPKHfu{*_9sAiY#vQ?0+@B*wrDez z5psZk)ZRoaW4{RQphs?XTuqL!02)oIrBR4IyRrzDa!e2Pd_M1Iz!a6*b=l83T6rO| z{{WJ~&}V?u_z{39foLxQ>X8T(t%)37q)^H;!1c*wnPt9$^P*OzE-U$P55hLmyFXlD z>}b0I_9}z5@3QJxf&CP7%nv4gmA;9{_CM0el|AHvQSC`xKY~13(U=lcU+n4G|!P zdjxn)0Hm-7U~-&_SsSzw-db`vfQ52v(&+T*ZTPI=0|01HQ!QqNRDtQz=7dHOCI9JI z;x;%V$fSYN(H?|UwM@hD0`ZJxQ%LOU)DFK=r928L9YxB`uD{soqf}zqb>u(qr!3KW SyUJSt00002 zB?3V!7E3GuP%;`ILmFB&09rd9DNrDLKmsUTB#%e~FKa5IR0FYE10#YOiDg2+Uji(Y z9?EC|+iwAnk&dOAX`P>(x2tp2t_7*9sKu#*)wYTD$q3=XlZYyq+40U<}uV0Zz*IZGCf3~J$?2(&0ZBLR*%f>1tLc9xtc>mOI&O7e(V#Ci0D zhJXK7S{>Q$&;`K$3(sly$*#u=bZw&t-&PpO+XyQ9bu)o!U zOM38*?lDWu`SWwhaWUCSOTk${4)$>k#6O#5Sx`TZn?XxSJe~?%{1AX@!?ckuh#7-3 z(h61{NEXQBV`O;>jCGXBXL8oCoSs9x9LP^k<)ro9H#_JLbUoTC-E^~V`mxRL0lQeV zI|EMFb^8ARp0Y5B@JkQj_af_zA!Dt~l zV~y6gfRIuMX`1@6@24pR31U*lE8;RYN^52K0+1|j0kU(S5&&aArPNE1N76nEtM`7$Oyo2bJ_sY6|mWixRAwIhK(!>2sT<5J0S=l zgl1KjO2X<5Kr}XO3V^lVI;G35R4wo1Ko`Iqf&fCA zuYki5f6(zL*WpmT2D}aGtYP$XnsUqeGTH&xC} z2Kzg8!%zV0)OB@U0n42(fcKA&_wp~oy`GlTy!B;k;quPLRfPLF{tKzeNI=)W4Lbk; N002ovPDHLkV1jXhRdfIV literal 0 HcmV?d00001 diff --git a/mods/mobs_npc/textures/mobs_trader2.png b/mods/mobs_npc/textures/mobs_trader2.png new file mode 100644 index 0000000000000000000000000000000000000000..cbd9b9367aa0d107c1573ce16a5e9be08afd5425 GIT binary patch literal 783 zcmV+q1MvKbP)2 zB?3V!7E3GuP%;`?H2_*W9ve|nA!KBQToh_#BPMZiiDg18gM%xMWQ~O{mya@!k&d93 zHMNu~Ij*jynQ5J$oVTlU)vg7ptEjuNKE$!gVP$vY;twDZu8R?mtM?L5?}D?)<3SkmE;k#i1X+P z4FMxU2mxh%eEv>$r-&#?fFucNDC>gfVC^rVp34ZoJ})tzRF3Ktt*H-navcsv!j_#pt*hG`>R5Hkj6 zq!p|@kSvhL$H?*&80#pL&*ZFOIX#DXIgp>8%2DgPZw}BO=z6qOy6I-!_+y*j0}iq1 za0Z;N>-7HtJY``N;g=r5??u)bL&jQ}%V{bMhpJJ4vi>^&hyrLI$RgfYlDQ#Pipey9 z#u}|}0U@Oj(m3|(z8}XFB#22FuZYXsD6N&@3qZ2C1<1~QN&u|;F{NIDJd!p_`H}%^ z?1>DJB~q8{#q#x)wibcVx3O4I*iz|Yfs6nQH>V9SUIE+f8W*xymtiZ*0)ma!#ZCwU z2%%ZkrIN6E0}!p7wgtdi@0`+QSE?3x62WRIL`u_l3uglE5`>dVL5@r26`%`X3PAuN zO;^Bt#2<7#$~Di`Yrxx}&KgF)iG(1Urnd`VKi9x{-WPSlrt5|@_%w8NzJZ2rYO0)@ z4EA^GhM@p9sq5;z0+u^n0Pi0k@8w^Fdp#|wdF#v8!sVTfs|fdV{1?6#OGkIi(DeWS N002ovPDHLkV1oMWWF7zj literal 0 HcmV?d00001 diff --git a/mods/mobs_npc/textures/mobs_trader3.png b/mods/mobs_npc/textures/mobs_trader3.png new file mode 100644 index 0000000000000000000000000000000000000000..e6b239adf78ea1b535531e83872250ce9202671c GIT binary patch literal 779 zcmV+m1N8ifP)D z85uk!0zoSlWg#F-EC5h48e22~U@{<_0L7?+)wYTE$pGQPlVdE6Y1l*Hqyz(o%Ms5X*zatdO` zpq(5AD-R?Ih?j0`;-6}`zfVff;>z+rF?Nf z27AH*T*A7zmz1xsv{3{?-^P-H!j{UE6xa#CQOmRerYm5#8*#zKScaV}3kY_`lypK6 zKnN{WQ!0s6ZvdjPX;%Pb%t0$tcIBD^%_5{)3X#(MHH9+)cL_qLQjm7ZyaG%C%pnLM zr1=V1KJbA)KIB@Knrpz@pw1e`yorP$n&-C*;JDPlWjPjg!?x>&H25@hb-sm$Zf>fa z8wbZbb;D2q+thV+UIFW!E`Z;6s@;;Bw{zK!aCv9rD#HC7{|DWkLwB8)lq~=N002ov JPDHLkV1mH2W8?q; literal 0 HcmV?d00001 diff --git a/mods/mobs_npc/trader.lua b/mods/mobs_npc/trader.lua new file mode 100644 index 0000000..169f445 --- /dev/null +++ b/mods/mobs_npc/trader.lua @@ -0,0 +1,355 @@ + +local S = mobs.intllib + +mobs.human = { + items = { + --{item for sale, price, chance of appearing in trader's inventory} + {"default:apple 10", "default:gold_ingot 2", 10}, + {"farming:bread 10", "default:gold_ingot 4", 5}, + {"default:clay 10", "default:gold_ingot 2", 12}, + {"default:brick 10", "default:gold_ingot 4", 17}, + {"default:glass 10", "default:gold_ingot 4", 17}, + {"default:obsidian 10", "default:gold_ingot 15", 50}, + {"default:diamond 1", "default:gold_ingot 5", 40}, + {"farming:wheat 10", "default:gold_ingot 2", 17}, + {"default:tree 5", "default:gold_ingot 4", 20}, + {"default:stone 10", "default:gold_ingot 8", 17}, + {"default:desert_stone 10", "default:gold_ingot 8", 27}, + {"default:sapling 1", "default:gold_ingot 1", 7}, + {"default:pick_steel 1", "default:gold_ingot 2", 7}, + {"default:sword_steel 1", "default:gold_ingot 2", 17}, + {"default:shovel_steel 1", "default:gold_ingot 1", 17}, + }, + names = { + "Bob", "Duncan", "Bill", "Tom", "James", "Ian", "Lenny" + } +} + +-- Trader ( same as NPC but with right-click shop ) + +mobs:register_mob("mobs_npc:trader", { + type = "npc", + passive = false, + damage = 3, + attack_type = "dogfight", + attacks_monsters = true, + pathfinding = false, + hp_min = 10, + hp_max = 20, + armor = 100, + collisionbox = {-0.35,-1.0,-0.35, 0.35,0.8,0.35}, + visual = "mesh", + mesh = "character.b3d", + textures = { + {"mobs_trader.png"}, -- by Frerin + }, + makes_footstep_sound = true, + sounds = {}, + walk_velocity = 2, + run_velocity = 3, + jump = false, + drops = {}, + water_damage = 0, + lava_damage = 4, + light_damage = 0, + follow = {"default:diamond"}, + view_range = 15, + owner = "", + order = "stand", + fear_height = 3, + animation = { + speed_normal = 30, + speed_run = 30, + stand_start = 0, + stand_end = 79, + walk_start = 168, + walk_end = 187, + run_start = 168, + run_end = 187, + punch_start = 200, + punch_end = 219, + }, + on_rightclick = function(self, clicker) + mobs_trader(self, clicker, entity, mobs.human) + end, +}) + +--This code comes almost exclusively from the trader and inventory of mobf, by Sapier. +--The copyright notice below is from mobf: +------------------------------------------------------------------------------- +-- Mob Framework Mod by Sapier +-- +-- You may copy, use, modify or do nearly anything except removing this +-- copyright notice. +-- And of course you are NOT allow to pretend you have written it. +-- +--! @file inventory.lua +--! @brief component containing mob inventory related functions +--! @copyright Sapier +--! @author Sapier +--! @date 2013-01-02 +-- +--! @defgroup Inventory Inventory subcomponent +--! @brief Component handling mob inventory +--! @ingroup framework_int +--! @{ +-- +-- Contact sapier a t gmx net +------------------------------------------------------------------------------- + +function mobs.allow_move(inv, from_list, from_index, to_list, to_index, count, player) + + if to_list ~= "selection" + or from_list == "price" + or from_list == "payment" + or from_list == "takeaway" + or from_list == "identifier" then + + return 0 + end + + -- forbid moving split stacks + local old_stack = inv.get_stack(inv, from_list, from_index) + + if count ~= old_stack.get_count(old_stack) then + return 0 + end + + return count +end + +function mobs.allow_put(inv, listname, index, stack, player) + + if listname == "payment" then + return 99 + end + + return 0 +end + +function mobs.allow_take(inv, listname, index, stack, player) + + if listname == "takeaway" + or listname == "payment" then + + return 99 + else + return 0 + end +end + +function mobs.on_put(inv, listname, index, stack) + + if listname == "payment" then + mobs.update_takeaway(inv) + end +end + +function mobs.on_take(inv, listname, count, index, stack, player) + + if listname == "takeaway" then + + local amount = inv:get_stack("payment", 1):get_count() + local price = inv:get_stack("price", 1):get_count() + local thing = inv:get_stack("payment", 1):get_name() + + inv.set_stack(inv,"selection", 1, nil) + inv.set_stack(inv,"price", 1, nil) + inv.set_stack(inv,"takeaway", 1, nil) + inv.set_stack(inv,"payment", 1, thing .. " " .. amount - price) + end + + if listname == "payment" then + + if mobs.check_pay(inv, false) then + + local selection = inv.get_stack(inv, "selection", 1) + + if selection ~= nil then + inv.set_stack(inv,"takeaway", 1, selection) + end + else + inv.set_stack(inv, "takeaway", 1, nil) + end + end +end + +function mobs.update_takeaway(inv) + + if mobs.check_pay(inv,false) then + + local selection = inv.get_stack(inv,"selection", 1) + + if selection ~= nil then + inv.set_stack(inv,"takeaway", 1, selection) + end + else + inv.set_stack(inv,"takeaway", 1, nil) + end +end + +function mobs.check_pay(inv, paynow) + + local now_at_pay = inv.get_stack(inv,"payment", 1) + local count = now_at_pay.get_count(now_at_pay) + local name = now_at_pay.get_name(now_at_pay) + local price = inv.get_stack(inv, "price", 1) + + if price:get_name() == name then + + local price = price:get_count() + + if price > 0 + and price <= count then + + if paynow then + + now_at_pay.take_item(now_at_pay, price) + + inv.set_stack(inv,"payment", 1, now_at_pay) + + return true + else + return true + end + else + if paynow then + inv.set_stack(inv, "payment", 1, nil) + end + end + end + + return false +end + +mobs.trader_inventories = {} + +function mobs.add_goods(entity, race) + + local goods_to_add = nil + + for i = 1, 15 do + + if math.random(0, 100) > race.items[i][3] then + mobs.trader_inventory.set_stack(mobs.trader_inventory, + "goods", i, race.items[i][1]) + end + end +end + +function mobs_trader(self, clicker, entity, race) + + local player = clicker:get_player_name() + + if not self.id then + self.id = (math.random(1, 1000) * math.random(1, 10000)) + .. self.name .. (math.random(1, 1000) ^ 2) + end + + if not self.game_name then + + self.game_name = tostring(race.names[math.random(1, #race.names)]) + self.nametag = S("Trader @1", self.game_name) + + self.object:set_properties({ + nametag = self.nametag, + nametag_color = "#00FF00" + }) + + end + + local unique_entity_id = self.id + local is_inventory = minetest.get_inventory({ + type = "detached", name = unique_entity_id}) + + local move_put_take = { + + allow_move = mobs.allow_move, + allow_put = mobs.allow_put, + allow_take = mobs.allow_take, + + on_move = function(inventory, from_list, from_index, to_list, to_index, count, player) + + if from_list == "goods" + and to_list == "selection" then + + local inv = inventory + local moved = inv.get_stack(inv,to_list, to_index) + local goodname = moved.get_name(moved) + local elements = moved.get_count(moved) + + if elements > count then + + -- remove the surplus parts + inv.set_stack(inv,"selection", 1, + goodname .. " " .. tostring(count)) + + -- the slot we took from is now free + inv.set_stack(inv,"goods",from_index, + goodname .. " " .. tostring(elements - count)) + + -- update the real amount of items in the slot now + elements = count + end + + local good = nil + + for i = 1, #race.items, 1 do + + local stackstring = goodname .." " .. count + + if race.items[i][1] == stackstring then + good = race.items[i] + end + end + + if good ~= nil then + inventory.set_stack(inventory,"price", 1, good[2]) + else + inventory.set_stack(inventory,"price", 1, nil) + end + + mobs.update_takeaway(inv) + + end + end, + + on_put = mobs.on_put, + on_take = mobs.on_take + } + + if is_inventory == nil then + + mobs.trader_inventory = minetest.create_detached_inventory(unique_entity_id, move_put_take) + mobs.trader_inventory.set_size(mobs.trader_inventory,"goods", 15) + mobs.trader_inventory.set_size(mobs.trader_inventory,"takeaway", 1) + mobs.trader_inventory.set_size(mobs.trader_inventory,"selection", 1) + mobs.trader_inventory.set_size(mobs.trader_inventory,"price", 1) + mobs.trader_inventory.set_size(mobs.trader_inventory,"payment", 1) + mobs.add_goods(entity, race) + end + + minetest.chat_send_player(player, S("[NPC] Hello, @2, have a look at my wares.", + self.game_name, player)) + + minetest.show_formspec(player, "trade", "size[8,10;]" + .. default.gui_bg_img + .. default.gui_slots + .. "label[0,0;" .. S("Trader @1's stock:", self.game_name) .. "]" + .. "list[detached:" .. unique_entity_id .. ";goods;.5,.5;3,5;]" + .. "label[4.5,0.5;" .. S("Selection") .. "]" + .. "list[detached:" .. unique_entity_id .. ";selection;4.5,1;5.5,2;]" + .. "label[6,0.5;" .. S("Price") .. "]" + .. "list[detached:" .. unique_entity_id .. ";price;6,1;7,2;]" + .. "label[4.5,3.5;" .. S("Payment") .. "]" + .. "list[detached:" .. unique_entity_id .. ";payment;4.5,4;5.5,5;]" + .. "label[6,3.5;" .. S("Bought items") .. "]" + .. "list[detached:" .. unique_entity_id .. ";takeaway;6,4;7.5,5.5;]" + .. "list[current_player;main;0,6;8,4;]" + ) +end + +mobs:register_egg("mobs_npc:trader", S("Trader"), "default_sandstone.png", 1) + +-- compatibility +mobs:alias_mob("mobs:trader", "mobs_npc:trader") diff --git a/mods/mobs_redo/api.lua b/mods/mobs_redo/api.lua index 2336cfa..193a00a 100644 --- a/mods/mobs_redo/api.lua +++ b/mods/mobs_redo/api.lua @@ -1,5 +1,5 @@ --- Mobs Api (7th January 2017) +-- Mobs Api (31st January 2017) mobs = {} mobs.mod = "redo" @@ -7,24 +7,18 @@ mobs.mod = "redo" -- Intllib local S + if minetest.get_modpath("intllib") then S = intllib.Getter() else - S = function(s, a, ...) - if a == nil then - return s - end - a = {a, ...} - return s:gsub("(@?)@(%(?)(%d+)(%)?)", - function(e, o, n, c) - if e == "" then - return a[tonumber(n)] .. (o == "" and c or "") - else - return "@" .. o .. n .. c - end - end) + S = function(s, a, ...) a = {a, ...} + return s:gsub("@(%d+)", function(n) + return a[tonumber(n)] + end) end + end + mobs.intllib = S @@ -64,14 +58,12 @@ local abs = math.abs local min = math.min local max = math.max local atann = math.atan -local atan2 = math.atan2 local random = math.random local floor = math.floor local atan = function(x) if x ~= x then --error("atan bassed NaN") - --print ("atan based NaN") return 0 else return atann(x) @@ -109,20 +101,25 @@ end set_yaw = function(self, yaw) if yaw ~= yaw then +-- print ("--- yaw nan") return end - self.yaw = yaw - self.object:setyaw(yaw) + self.yaw = yaw -- + self.rotate + self.object:setyaw(self.yaw) end set_velocity = function(self, v) + local yaw = self.object:getyaw() + self.rotate + self.object:setvelocity({ - x = sin(self.yaw) * -v, +-- x = sin(self.yaw) * -v, + x = sin(yaw) * -v, y = self.object:getvelocity().y, - z = cos(self.yaw) * v +-- z = cos(self.yaw) * v + z = cos(yaw) * v }) end @@ -142,8 +139,7 @@ set_anim = function(self, anim_start, anim_end, anim_speed, anim_name) end self.object:set_animation( - {x = anim_start, y = anim_end}, - anim_speed or 15, 0) + {x = anim_start, y = anim_end}, anim_speed or 15, 0) self.animation.current = anim_name end @@ -205,11 +201,110 @@ set_animation = function(self, type) self.animation.die_start, self.animation.die_end, self.animation.speed_die, "die") + + elseif type == "fly" and self.animation.current ~= "fly" then + + set_anim(self, + self.animation.fly_start, + self.animation.fly_end, + self.animation.speed_fly, "fly") + end +end + +-- get distance +local get_distance = function(a, b) + + local x, y, z = a.x - b.x, a.y - b.y, a.z - b.z + + return square(x * x + y * y + z * z) +end + + +-- check line of sight (BrunoMine) +function line_of_sight(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 = get_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. + 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 = get_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 + + ad = ad + stepsize + + -- scan again + r, pos = minetest.line_of_sight(npos1, pos2, stepsize) + + if r == true then return true end + + -- New Nodename found + nn = minetest.get_node(pos).name + + end + + return false +end + + +-- are we flying in what we are suppose to? (taikedz) +local function flight_check(self, pos_w) + +-- local nod = minetest.get_node(pos_w).name + local nod = self.standing_in + + if type(self.fly_in) == "string" + and ( nod == self.fly_in or nod == self.fly_in:gsub("_source", "_flowing") ) then + + return true + + elseif type(self.fly_in) == "table" then + + for _,fly_in in pairs(self.fly_in) do + + if nod == fly_in or nod == fly_in:gsub("_source", "_flowing") then + + return true + end + end end end --- check line of sight for walkers and swimmers alike +-- check line of sight for walkers and swimmers alike (deprecated) function line_of_sight_water(self, pos1, pos2, stepsize) local s, pos_w = minetest.line_of_sight(pos1, pos2, stepsize) @@ -235,13 +330,8 @@ function line_of_sight_water(self, pos1, pos2, stepsize) -- just incase we have a special node for flying/swimming mobs elseif s == false and self.fly - and self.fly_in then - - local nod = minetest.get_node(pos_w).name - - if nod == self.fly_in then - return true - end + and flight_check(self, pos_w) then + return true end return false @@ -341,6 +431,7 @@ function check_for_death(self) -- drop items when dead local obj local pos = self.object:getpos() + self.drops = self.drops or {} -- error check for n = 1, #self.drops do @@ -422,8 +513,11 @@ local function is_at_cliff(self) return false end - local dir_x = -sin(self.yaw) * (self.collisionbox[4] + 0.5) - local dir_z = cos(self.yaw) * (self.collisionbox[4] + 0.5) + local yaw = self.object:getyaw() +-- local dir_x = -sin(self.yaw) * (self.collisionbox[4] + 0.5) +-- local dir_z = cos(self.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:getpos() local ypos = pos.y + self.collisionbox[2] -- just above floor @@ -522,10 +616,10 @@ do_env_damage = function(self) self.health = self.health - self.water_damage effect(pos, 5, "bubble.png", nil, nil, 1, nil) - end +-- end -- lava or fire - if self.lava_damage ~= 0 + elseif self.lava_damage ~= 0 and (nodef.groups.lava or self.standing_in == "fire:basic_flame" or self.standing_in == "fire:permanent_flame") then @@ -533,6 +627,15 @@ do_env_damage = function(self) self.health = self.health - self.lava_damage effect(pos, 5, "fire_basic_flame.png", nil, nil, 1, nil) + + -- damage_per_second node check + elseif minetest.registered_nodes[self.standing_in].damage_per_second ~= 0 then + + local dps = minetest.registered_nodes[self.standing_in].damage_per_second + + self.health = self.health - dps + + effect(pos, 5, "tnt_smoke.png") end end @@ -549,6 +652,7 @@ do_jump = function(self) end local pos = self.object:getpos() + local yaw = self.object:getyaw() -- what is mob standing on? pos.y = pos.y + self.collisionbox[2] - 0.2 @@ -562,8 +666,10 @@ do_jump = function(self) end -- where is front - local dir_x = -sin(self.yaw) * (self.collisionbox[4] + 0.5) - local dir_z = cos(self.yaw) * (self.collisionbox[4] + 0.5) +-- local dir_x = -sin(self.yaw) * (self.collisionbox[4] + 0.5) +-- local dir_z = cos(self.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? local nod = node_ok({ @@ -936,7 +1042,8 @@ function smart_mobs(self, s, p, dist, dtime) else -- dig 2 blocks to make door toward player direction - local yaw1 = self.yaw + pi / 2 +-- local yaw1 = self.yaw + pi / 2 + local yaw1 = self.object:getyaw() + pi / 2 local p1 = { x = s.x + cos(yaw1), @@ -1063,7 +1170,8 @@ local monster_attack = function(self) -- field of view check goes here -- choose closest player to attack - if line_of_sight_water(self, sp, p, 2) == true +-- if line_of_sight_water(self, sp, p, 2) == true + if line_of_sight(self, sp, p, 2) == true and dist < min_dist then min_dist = dist min_player = player @@ -1190,9 +1298,13 @@ local follow_flop = function(self) z = p.z - s.z } - local yaw = (atan2(vec.z, vec.x) - pi / 2) - self.rotate +-- local yaw = atan2(vec.z, vec.x) - pi / 2 + local yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - set_yaw(self, yaw) + if p.x > s.x then yaw = yaw + pi end + + self.object:setyaw(yaw) +-- set_yaw(self, yaw) -- anyone but standing npc's can move along if dist > self.reach @@ -1222,17 +1334,20 @@ local follow_flop = function(self) end end - -- water swimmers flop when on land - if self.fly - and self.fly_in == "default:water_source" - and self.standing_in ~= self.fly_in then + -- swimmers flop when out of their element, and swim again when back in + if self.fly then + local s = self.object:getpos() + if not flight_check(self, s) then - self.state = "flop" - self.object:setvelocity({x = 0, y = -5, z = 0}) + self.state = "flop" + self.object:setvelocity({x = 0, y = -5, z = 0}) - set_animation(self, "stand") + set_animation(self, "stand") - return + return + elseif self.state == "flop" then + self.state = "stand" + end end end @@ -1266,7 +1381,7 @@ end -- execute current state (stand, walk, run, attacks) local do_states = function(self, dtime) - local yaw = self.yaw -- 0 + local yaw = 0 -- self.yaw if self.state == "stand" then @@ -1292,12 +1407,17 @@ local do_states = function(self, dtime) z = lp.z - s.z } - yaw = (atan2(vec.z, vec.x) - pi / 2) - self.rotate +-- yaw = atan2(vec.z, vec.x) - pi / 2 + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + + if lp.x > s.x then yaw = yaw + pi end else - yaw = random() * 2 * pi +-- yaw = random() * 2 * pi + yaw = (random(0, 360) - 180) / 180 * pi end - set_yaw(self, yaw) + self.object:setyaw(yaw) +-- set_yaw(self, yaw) end set_velocity(self, 0) @@ -1356,9 +1476,13 @@ local do_states = function(self, dtime) z = lp.z - s.z } - yaw = atan2(vec.z, vec.x) + pi / 2 - self.rotate +-- yaw = atan2(vec.z, vec.x) + pi / 2 + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + + if lp.x > s.x then yaw = yaw + pi end else - yaw = random() * 2 * pi +-- yaw = random() * 2 * pi + yaw = (random(0, 360) - 180) / 180 * pi end else @@ -1368,17 +1492,22 @@ local do_states = function(self, dtime) z = lp.z - s.z } - yaw = atan2(vec.z, vec.x) + pi / 2 - self.rotate +-- yaw = atan2(vec.z, vec.x) + pi / 2 + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate + + if lp.x > s.x then yaw = yaw + pi end end - set_yaw(self, yaw) + self.object:setyaw(yaw) +-- set_yaw(self, yaw) -- otherwise randomly turn elseif random(1, 100) <= 30 then yaw = random() * 2 * pi - set_yaw(self, yaw) + self.object:setyaw(yaw) +-- set_yaw(self, yaw) end -- stand for great fall in front @@ -1401,7 +1530,15 @@ local do_states = function(self, dtime) set_animation(self, "stand") else set_velocity(self, self.walk_velocity) - set_animation(self, "walk") + + if flight_check(self) + and self.animation + and self.animation.fly_start + and self.animation.fly_end then + set_animation(self, "fly") + else + set_animation(self, "walk") + end end -- runaway when punched @@ -1463,9 +1600,13 @@ local do_states = function(self, dtime) z = p.z - s.z } - yaw = atan2(vec.z, vec.x) - pi / 2 - self.rotate +-- yaw = atan2(vec.z, vec.x) - pi / 2 + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - set_yaw(self, yaw) + if p.x > s.x then yaw = yaw + pi end + + self.object:setyaw(yaw) +-- set_yaw(self, yaw) if dist > self.reach then @@ -1554,7 +1695,8 @@ local do_states = function(self, dtime) local p_y = floor(p2.y + 1) local v = self.object:getvelocity() - if nod.name == self.fly_in then +-- if nod.name == self.fly_in then + if flight_check(self, s) then if me_y < p_y then @@ -1626,9 +1768,13 @@ local do_states = function(self, dtime) z = p.z - s.z } - yaw = (atan2(vec.z, vec.x) - pi / 2) - self.rotate +-- yaw = atan2(vec.z, vec.x) - pi / 2 + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - set_yaw(self, yaw) + if p.x > s.x then yaw = yaw + pi end + + self.object:setyaw(yaw) +-- set_yaw(self, yaw) -- move towards enemy if beyond mob reach if dist > self.reach then @@ -1692,7 +1838,8 @@ local do_states = function(self, dtime) p2.y = p2.y + .5--1.5 s2.y = s2.y + .5--1.5 - if line_of_sight_water(self, p2, s2) == true then +-- if line_of_sight_water(self, p2, s2) == true then + if line_of_sight(self, p2, s2) == true then -- play attack sound mob_sound(self, self.sounds.attack) @@ -1733,9 +1880,13 @@ local do_states = function(self, dtime) z = p.z - s.z } - yaw = (atan2(vec.z, vec.x) - pi / 2) - self.rotate +-- yaw = atan2(vec.z, vec.x) - pi / 2 + yaw = (atan(vec.z / vec.x) + pi / 2) - self.rotate - set_yaw(self, yaw) + if p.x > s.x then yaw = yaw + pi end + + self.object:setyaw(yaw) +-- set_yaw(self, yaw) set_velocity(self, 0) @@ -1755,18 +1906,21 @@ local do_states = function(self, dtime) local obj = minetest.add_entity(p, self.arrow) local ent = obj:get_luaentity() - local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5 - local v = ent.velocity or 1 -- or set to default - ent.switch = 1 - ent.owner_id = tostring(self.object) -- add unique owner id to arrow - -- offset makes shoot aim accurate - vec.y = vec.y + self.shoot_offset - vec.x = vec.x * (v / amount) - vec.y = vec.y * (v / amount) - vec.z = vec.z * (v / amount) + if ent then + local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5 + local v = ent.velocity or 1 -- or set to default + ent.switch = 1 + ent.owner_id = tostring(self.object) -- add unique owner id to arrow - obj:setvelocity(vec) + -- offset makes shoot aim accurate + vec.y = vec.y + self.shoot_offset + vec.x = vec.x * (v / amount) + vec.y = vec.y * (v / amount) + vec.z = vec.z * (v / amount) + + obj:setvelocity(vec) + end end end end @@ -1996,7 +2150,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) z = lp.z - s.z } - local yaw = atan(vec.z / vec.x) + 3 * pi / 2 - self.rotate + local yaw = atan(vec.z / vec.x) + 3 * pi / 2 if lp.x > s.x then yaw = yaw + pi @@ -2134,7 +2288,8 @@ local mob_activate = function(self, staticdata, dtime_s, def) -- set anything changed above self.object:set_properties(self) - set_yaw(self, ((random(0, 360) - 180) / 180 * pi)) +-- set_yaw(self, random() * 2 * pi) + self.object:setyaw((random(0, 360) - 180) / 180 * pi) update_tag(self) end @@ -2142,7 +2297,8 @@ end local mob_step = function(self, dtime) local pos = self.object:getpos() - local yaw = self.yaw +-- local yaw = self.yaw + local yaw = 0 -- when lifetimer expires remove mob (except npc and tamed) if self.type ~= "npc" @@ -2274,6 +2430,9 @@ function mobs:register_mob(name, def) minetest.register_entity(name, { +--automatic_face_movement_dir = def.rotate and math.rad(def.rotate) or false, +--automatic_face_movement_max_rotation_per_sec = -1, + stepheight = def.stepheight or 0.6, name = name, type = def.type, @@ -2721,6 +2880,9 @@ function mobs:register_arrow(name, def) timer = 0, switch = 0, owner_id = def.owner_id, + rotate = def.rotate, + automatic_face_movement_dir = def.rotate + and (def.rotate - (pi / 180)) or false, on_step = def.on_step or function(self, dtime) @@ -2742,25 +2904,15 @@ function mobs:register_arrow(name, def) and def.tail == 1 and def.tail_texture then --- effect(pos, 1, def.tail_texture, --- def.tail_size or 5, --- def.tail_size or 10, --- 0, 0) -- 0 radius and 0 gravity to just hover - - minetest.add_particlespawner({ - amount = 1, - time = 0.25, - minpos = pos, - maxpos = pos, - minvel = {x = 0, y = 0, z = 0}, - maxvel = {x = 0, y = 0, z = 0}, - minacc = {x = 0, y = 0, z = 0}, - maxacc = {x = 0, y = 0, z = 0}, - minexptime = 0.1, - maxexptime = 1, - minsize = def.tail_size or 5, - maxsize = def.tail_size or 10, + 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 @@ -2854,6 +3006,13 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) 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 @@ -2883,6 +3042,56 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) return itemstack end, }) + + -- spawn egg containing mob information + minetest.register_craftitem(mob .. "_set", { + + description = desc .. " (set)", + inventory_image = invimg, + groups = {not_in_creative_inventory = 1}, + stack_max = 1, + + 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 + + pos.y = pos.y + 1 + + local data = itemstack:get_metadata() + local mob = minetest.add_entity(pos, mob, data) + local ent = mob:get_luaentity() + + if not ent then + mob:remove() + return + end + + if ent.type ~= "monster" then + -- set owner and tame if not monster + ent.owner = placer:get_player_name() + ent.tamed = true + end + + -- if not in creative then take item + if not creative then + itemstack:take_item() + end + end + + return itemstack + end, + }) end @@ -2953,7 +3162,27 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, -- calculate chance.. add to inventory if successful? if random(1, 100) <= chance then - clicker:get_inventory():add_item("main", mobname) +-- add special mob egg containing all mob information +local new_stack = ItemStack(mobname .. "_set") +local tmp = {} +for _,stat in pairs(self) do + local t = type(stat) + if t ~= 'function' + and t ~= 'nil' + and t ~= 'userdata' then + tmp[_] = self[_] + end +end +local data_str = minetest.serialize(tmp) +local inv = clicker:get_inventory() +new_stack:set_metadata(data_str) +if inv:room_for_item("main", new_stack) then + inv:add_item("main", new_stack) +else + minetest.add_item(clicker:getpos(), new_stack) +end + +-- clicker:get_inventory():add_item("main", mobname) self.object:remove() else diff --git a/mods/mobs_redo/api.txt b/mods/mobs_redo/api.txt index 139aa9e..21a778e 100644 --- a/mods/mobs_redo/api.txt +++ b/mods/mobs_redo/api.txt @@ -1,5 +1,5 @@ -MOB API (29th December 2016) +MOB API (31st January 2017) The mob api is a function that can be called on by other mods to add new animals or monsters into minetest. @@ -82,8 +82,8 @@ This functions registers a new mob as a Minetest entity. 'shoot' shoots defined arrows when player is within range 'explode' follows player in range and will flash and explode when in reach 'dogshoot' shoots arrows when in range and one on one attack when in reach - 'dogshoot_switch' allows switching between shoot and dogfight modes inside dogshoot using timer (1 = shoot, 2 = dogfight) - 'dogshoot_count_max' number of seconds before switching above modes. + 'dogshoot_switch' allows switching between shoot and dogfight modes inside dogshoot using timer (1 = shoot, 2 = dogfight) + 'dogshoot_count_max' number of seconds before switching above modes. 'custom_attack' is a function that is called when mob is in range to attack player, parameters are (self, to_attack) 'double_melee_attack' if false then api will choose randomly between 'punch' and 'punch2' attack animations 'on_blast' is called when TNT explodes near mob, function uses (object, damage) and returns (do_damage, do_knockback, drops) @@ -118,11 +118,14 @@ This functions registers a new mob as a Minetest entity. 'die_start' start frame of die animation 'die_end' end frame of die animation 'speed_normal' normal animation speed + 'fly_start' start frame of fly animation + 'fly_end' end frame of fly animation 'speed_run' running animation speed 'speed_punch' punching animation speed 'speed_punch2' alternative punching animation speed 'speed_shoot' shooting animation speed 'speed_die' die animation speed + 'speed_fly' fly animation speed 'replace_what' group if items to replace e.g. {"farming:wheat_8", "farming:carrot_8"} 'replace_with' replace with what e.g. "air" or in chickens case "mobs:egg" 'replace_rate' how random should the replace rate be (typically 10) @@ -194,6 +197,9 @@ This function registers a arrow for mobs with the attack type shoot. 'tail' when set to 1 adds a trail or tail to mob arrows 'tail_texture' texture string used for above effect 'tail_size' has size for above texture (defaults to between 5 and 10) + 'expire' contains float value for how long tail appears for (defaults to 0.25) + 'glow' has value for how brightly tail glows 1 to 10 (default is 0, no glow) + 'rotate' integer value in degrees to rotate arrow 'on_step' is a custom function when arrow is active, nil for default. @@ -301,6 +307,7 @@ Certain variables need to be set before using the above functions: 'self.terrain_type' integer containing terrain mob can walk on (1 = water, 2 or 3 = land) 'self.driver_attach_at' position offset for attaching player to mob 'self.driver_eye_offset' position offset for attached player view + 'self.driver_scale' sets driver scale for mobs larger than {x=1, y=1} Here is an example mob to show how the above functions work: @@ -357,6 +364,7 @@ mobs:register_mob("mob_horse:horse", { self.terrain_type = 3 self.driver_attach_at = {x = 0, y = 20, z = -2} self.driver_eye_offset = {x = 0, y = 3, z = 0} + self.driver_scale = {x = 1, y = 1} end -- if driver present allow control of horse diff --git a/mods/mobs_redo/crafts.lua b/mods/mobs_redo/crafts.lua index b0ac728..eb5dcda 100644 --- a/mods/mobs_redo/crafts.lua +++ b/mods/mobs_redo/crafts.lua @@ -40,7 +40,7 @@ minetest.register_craft({ cooktime = 5, }) --- golden lasso +-- magic lasso minetest.register_tool("mobs:magic_lasso", { description = S("Magic Lasso (right-click animal to put in inventory)"), inventory_image = "mobs_magic_lasso.png", diff --git a/mods/mobs_redo/mount.lua b/mods/mobs_redo/mount.lua index b7aaed7..ca86b8e 100644 --- a/mods/mobs_redo/mount.lua +++ b/mods/mobs_redo/mount.lua @@ -80,6 +80,7 @@ local function force_detach(player) default.player_attached[player:get_player_name()] = false player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0}) default.player_set_animation(player, "stand" , 30) + player:set_properties({visual_size = {x = 1, y = 1} }) end @@ -108,9 +109,10 @@ function mobs.attach(entity, player) local attach_at, eye_offset = {}, {} - if not entity.player_rotation then - entity.player_rotation = {x = 0, y = 0, z = 0} - end + entity.player_rotation = entity.player_rotation or {x = 0, y = 0, z = 0} + entity.driver_attach_at = entity.driver_attach_at or {x = 0, y = 0, z = 0} + entity.driver_eye_offset = entity.driver_eye_offset or {x = 0, y = 0, z = 0} + entity.driver_scale = entity.driver_scale or {x = 1, y = 1} local rot_view = 0 @@ -118,14 +120,6 @@ function mobs.attach(entity, player) rot_view = math.pi/2 end - if not entity.driver_attach_at then - entity.driver_attach_at = {x = 0, y = 0, z = 0} - end - - if not entity.driver_eye_offset then - entity.driver_eye_offset = {x = 0, y = 0, z = 0} - end - attach_at = entity.driver_attach_at eye_offset = entity.driver_eye_offset entity.driver = player @@ -136,6 +130,13 @@ function mobs.attach(entity, player) default.player_attached[player:get_player_name()] = true player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0}) + player:set_properties({ + visual_size = { + x = entity.driver_scale.x, + y = entity.driver_scale.y + } + }) + minetest.after(0.2, function() default.player_set_animation(player, "sit" , 30) end) @@ -147,6 +148,7 @@ end function mobs.detach(player, offset) force_detach(player) + default.player_set_animation(player, "stand" , 30) local pos = player:getpos() @@ -195,7 +197,10 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) end --entity.object:setyaw(entity.driver:get_look_yaw() - rot_steer) - entity.object:setyaw(entity.driver:get_look_horizontal())-- - rot_steer) +-- entity.object:setyaw(entity.driver:get_look_horizontal())-- - rot_steer) + + -- fix mob rotation + entity.object:setyaw(entity.driver:get_look_horizontal() - entity.rotate) if can_fly then diff --git a/mods/mobs_redo/textures/mobs_blood.png b/mods/mobs_redo/textures/mobs_blood.png index 0e2951363c153f224fd528f5cdddd47323c4a5f8..77cfbdaa665922472018ffd016e7a47c974e6bf5 100644 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4&HECyrsn$JLrv%n*= zn1O*?7=#%aX3dcR3bL1Y`ns~;V-*l#XF68-IUFb?S>hT|;+&tGo0?a`;9QiNSdyBe zP@Y+mq2TW68xY>eCk|9p?CIhdVsU!wWN*F(0}fVpzOeIp;)i?nt~kXd=NwvPBT@I^ z`)$SD_5YRF3_|ya?$bSJv37BxYPI+g?T<4qoM6#^erD3SrIE87pG`RweterrYcywC zi% literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nRwj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&pI+QHD?6$gKz&SWzAvGef= zFvcJvXsy}r_b8=E(-aY*Uavo05I!18DGrANMN!afHc66%;c!TjBt%j4dxXVear>Uj zvc!9j)*53B&N;^8@%sqgdjQt!HQswfg!z1qwf1F+Pk_ti!fZC9-EISrrYZe?pDfF& z0kqb{aSXs}wPG+BAR=_T-D&{uJz@COZ4^bE&u5m)C1Due{kH(66uaFH?>(E%25T*i zMuX{eiZP~I2c1rb?RHDA*W-9R0x%klsztb7uZRe(Rtw->=Bx8xK2i__oK7bIthLl? iHJo!e=O~JT|EEvzb%Ra>7N@lU0000