village mod

This commit is contained in:
D00Med 2017-02-02 08:21:34 +10:00
parent df1f2c34b4
commit 81ffc8af59
35 changed files with 1143 additions and 115 deletions

View File

@ -2044,5 +2044,4 @@ minetest.register_on_generated(function(minp, maxp)
end
end
end
end
end)

View File

@ -0,0 +1,4 @@
default
mobs
intllib?
lucky_block?

View File

@ -0,0 +1 @@
Adds simple NPC and Trader.

117
mods/mobs_npc/igor.lua Normal file
View 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
View 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
View 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.

View 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

View 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 =

View 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
View File

@ -0,0 +1 @@
name = mobs_npc

130
mods/mobs_npc/npc.lua Normal file
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

355
mods/mobs_npc/trader.lua Normal file
View 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")

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 267 B

View File

@ -0,0 +1 @@
default

57
mods/villages/init.lua Normal file
View 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
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B