village mod
@ -2044,5 +2044,4 @@ minetest.register_on_generated(function(minp, maxp)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
4
mods/mobs_npc/depends.txt
Normal file
@ -0,0 +1,4 @@
|
||||
default
|
||||
mobs
|
||||
intllib?
|
||||
lucky_block?
|
1
mods/mobs_npc/description.txt
Normal file
@ -0,0 +1 @@
|
||||
Adds simple NPC and Trader.
|
117
mods/mobs_npc/igor.lua
Normal file
@ -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")
|
33
mods/mobs_npc/init.lua
Normal file
@ -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"))
|
21
mods/mobs_npc/license.txt
Normal file
@ -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.
|
23
mods/mobs_npc/locale/de.txt
Normal file
@ -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] <Trader @1 > Hello, @2, have a look at my wares. = [NSC] <Händler @1 > 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
|
21
mods/mobs_npc/locale/template.txt
Normal file
@ -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] <Trader @1 > Hello, @2, have a look at my wares. =
|
||||
Trader @1's stock: =
|
||||
Selection =
|
||||
Price =
|
||||
Payment =
|
||||
Bought items =
|
||||
Trader =
|
10
mods/mobs_npc/lucky_block.lua
Normal file
@ -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
|
1
mods/mobs_npc/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
name = mobs_npc
|
130
mods/mobs_npc/npc.lua
Normal file
@ -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")
|
13
mods/mobs_npc/readme.md
Normal file
@ -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
|
BIN
mods/mobs_npc/textures/mobs_igor.png
Normal file
After Width: | Height: | Size: 222 B |
BIN
mods/mobs_npc/textures/mobs_igor2.png
Normal file
After Width: | Height: | Size: 924 B |
BIN
mods/mobs_npc/textures/mobs_igor3.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
mods/mobs_npc/textures/mobs_igor4.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
mods/mobs_npc/textures/mobs_igor5.png
Normal file
After Width: | Height: | Size: 848 B |
BIN
mods/mobs_npc/textures/mobs_igor6.png
Normal file
After Width: | Height: | Size: 816 B |
BIN
mods/mobs_npc/textures/mobs_igor7.png
Normal file
After Width: | Height: | Size: 799 B |
BIN
mods/mobs_npc/textures/mobs_igor8.png
Normal file
After Width: | Height: | Size: 792 B |
BIN
mods/mobs_npc/textures/mobs_npc.png
Normal file
After Width: | Height: | Size: 901 B |
BIN
mods/mobs_npc/textures/mobs_npc2.png
Normal file
After Width: | Height: | Size: 1018 B |
BIN
mods/mobs_npc/textures/mobs_npc_baby.png
Normal file
After Width: | Height: | Size: 684 B |
BIN
mods/mobs_npc/textures/mobs_trader.png
Normal file
After Width: | Height: | Size: 783 B |
BIN
mods/mobs_npc/textures/mobs_trader2.png
Normal file
After Width: | Height: | Size: 783 B |
BIN
mods/mobs_npc/textures/mobs_trader3.png
Normal file
After Width: | Height: | Size: 779 B |
355
mods/mobs_npc/trader.lua
Normal file
@ -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] <Trader @1 > 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")
|
@ -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
|
||||
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,14 +330,9 @@ 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
|
||||
and flight_check(self, pos_w) then
|
||||
return true
|
||||
end
|
||||
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,10 +1334,10 @@ 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})
|
||||
@ -1233,6 +1345,9 @@ local follow_flop = function(self)
|
||||
set_animation(self, "stand")
|
||||
|
||||
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,8 +1530,16 @@ local do_states = function(self, dtime)
|
||||
set_animation(self, "stand")
|
||||
else
|
||||
set_velocity(self, self.walk_velocity)
|
||||
|
||||
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
|
||||
elseif self.state == "runaway" then
|
||||
@ -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,6 +1906,8 @@ local do_states = function(self, dtime)
|
||||
|
||||
local obj = minetest.add_entity(p, self.arrow)
|
||||
local ent = obj:get_luaentity()
|
||||
|
||||
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
|
||||
@ -1771,6 +1924,7 @@ local do_states = function(self, dtime)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- falling and fall damage
|
||||
@ -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
|
||||
|
@ -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.
|
||||
|
||||
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
||||
|
Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 267 B |
1
mods/villages/depends.txt
Normal file
@ -0,0 +1 @@
|
||||
default
|
57
mods/villages/init.lua
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
minetest.register_node("villages:colony_deed", {
|
||||
description = "Villager Colony Deed",
|
||||
tiles = {"villages_deed.png"},
|
||||
inventory_image = "villages_deed.png",
|
||||
drawtype = "signlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
selection_box = {type="wallmounted",},
|
||||
groups = {crumbly=1, dig_immediate=3, oddly_breakable_by_hand=1},
|
||||
on_construct = function(pos, node, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("villages:hobo_deed", {
|
||||
description = "Hobo Colony Deed",
|
||||
tiles = {"villages_deed.png^[colorize:brown:50"},
|
||||
inventory_image = "villages_deed.png^[colorize:brown:50",
|
||||
drawtype = "signlike",
|
||||
paramtype = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
selection_box = {type="wallmounted",},
|
||||
groups = {crumbly=1, dig_immediate=3, oddly_breakable_by_hand=1,},
|
||||
on_construct = function(pos, node, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("position", "not in building")
|
||||
meta:set_string("population", "0")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"villages:colony_deed"},
|
||||
interval = 5,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
local meta = minetest:get_meta(pos)
|
||||
minetest.chat_send_all("a deed just checked for a house")
|
||||
if meta:get_string("position") == "inside building" then
|
||||
if meta:get_string("population") == "0" and math.random(1,2) == 1 then
|
||||
minetest.add_entity(pos, "mobs_npc:npc")
|
||||
meta:set_string("population", "1")
|
||||
minetest.chat_send_all("npc spawned")
|
||||
end
|
||||
end
|
||||
local beds = minetest.find_node_near(pos, 5, {"beds:bed_bottom", "beds:bed"})
|
||||
local light_sources = minetest.find_node_near(pos, 5, {"default:torch", "default:torch_wall", "default:torch_floor", "default:torch_ceiling", "mese_lamp"})
|
||||
local doors = minetest.find_node_near(pos, 5, {"doors:door_wood_a", "doors:door_glass_a", "doors:door_obsidian_glass_a"})
|
||||
if beds ~= nil and light_sources ~= nil and doors ~= nil then
|
||||
meta:set_string("position", "inside building")
|
||||
minetest.chat_send_all("a building was found")
|
||||
else
|
||||
meta:set_string("position", "not in building")
|
||||
minetest.chat_send_all("no building was found")
|
||||
end
|
||||
end
|
||||
})
|
BIN
mods/villages/textures/villages_deed.png
Normal file
After Width: | Height: | Size: 388 B |