First commit. Using mobs_npc code as start.

This commit is contained in:
zorman2000 2016-11-12 07:06:09 -05:00
commit eb158f6f15
20 changed files with 1077 additions and 0 deletions

4
.buildpath Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
<buildpathentry kind="src" path=""/>
</buildpath>

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>advanced_npc</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.dltk.core.scriptbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.ldt.nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
Grammar__default_id=lua-5.1
eclipse.preferences.version=1

3
depends.txt Executable file
View File

@ -0,0 +1,3 @@
default
mobs
intllib?

1
description.txt Executable file
View File

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

30
init.lua Executable file
View File

@ -0,0 +1,30 @@
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")
print (S("[MOD] Mobs Redo 'NPCs' loaded"))

21
license.txt Executable 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.

23
locale/de.txt Executable file
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

21
locale/template.txt Executable file
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 =

1
mod.conf Executable file
View File

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

324
npc.lua Executable file
View File

@ -0,0 +1,324 @@
local S = mobs.intllib
-- Npc by TenPlus1
-- NPC Chat code by Zorman2000
-- Chat system consists of chatline and options objects that are re-used to create a conversation.
-- The objects are the following:
--
-- chatline = { text = "", options = {}, name = "", flag = "" }
-- 1. text: What the NPC says on this chat line
-- 2. options: What the player can answer to the chat line. Options are of another type of chat lines.
-- If you want the player to have no options to answer, set to nil
-- 3. name: The name of the NPC that will use this line. Use this when you want a specific NPC
-- to speak this line.
-- 4. flag: When the NPC speaks this line, this flag will be set into the entity's metadata.
--
-- options = { opt = "", answer = { chatline }
-- 1. opt: The text that the player can say to the NPC
-- 2. answer: A chatline object (as described above)
--
-- Example of conversation hierarchy
-- chat_options = {
-- chatline1 = { text = "Q1", options = {
-- option1 = { opt = "O1", answer = {
-- chatline = { text = "A1", options = nil }
-- }
-- },
-- chatline2 = { text = "Q2", options = nil }
-- }
local chat_options = {
{ text = "Don't talk with me know, please", options = nil, name = "Angry Guy" },
{ text = "Hello, how are you doing?", options = {
{ opt = "Good", answer =
{ text = "That's good. Take care of yourself.", options = nil }
},
{ opt = "Great! And you?", answer =
{ text = "I'm doing well, thank you. See ya around!", options = nil }
},
{ opt = "Not so well...", answer =
{ text = "Hey, why not feeling good? What's wrong?", options = {
{ opt = "Not your business!", answer =
{ text = "So rude! Don't speak to me anymore!", options = nil, flag = "not_speak" }
},
{ opt = "It's nothing! But thank you for asking!", answer =
{ text = "Ok my friend. See ya around!", options = nil }
},
}
}
}
}
},
{ text = "I'm thinking of buying something but not sure...", options = nil },
{ text = "I have traveled around the world and only like this place...", options = nil }
}
local options = {"Question 1","Question 2","Question 3","Question 4"}
---------------------------------------------------------------------
-- Creates a formspec for dialog
--------------------------------------------------------------------
local function create_formspec(options, close_option)
local options_length = table.getn(options) + 1
local formspec_height = (options_length * 0.7) + 1
local formspec = "size[7,"..tostring(formspec_height).."]"
for i, opt in ipairs(options) do
local y = 0.7;
if i > 1 then
y = (y * i)
end
formspec = formspec.."button[0.5,"..y..";6,0.5;opt"..tostring(i)..";"..options[i].opt.."]"
end
formspec = formspec.."button_exit[0.5,"..(formspec_height - 1)..";6,0.5;exit;"..close_option.."]"
return formspec
end
---------------------------------------------------------------------
-- Returns a random chatline for unimportant NPCs
---------------------------------------------------------------------
local function get_random_chatline(chat_options)
local chat_options_length = table.getn(chat_options)
local random_option = math.random(1, chat_options_length - 1)
local found = false
while found == false do
for i,chatline in ipairs(chat_options) do
if i == random_option and chatline.name == nil then
found = true
return chatline
end
end
end
end
---------------------------------------------------------------------
-- Returns all chatlines for a specific NPC
---------------------------------------------------------------------
local function get_chatline_for_npc(chat_options, npc_name)
local result = {}
for i,chatline in ipairs(chat_options) do
if chatline.name == npc_name then
table.insert(result, chatline)
end
end
return result
end
-----------------------------------------------------------------------------
-- Functions for rotating NPC to look at player (taken from the API itself)
-----------------------------------------------------------------------------
local atan = function(x)
if x ~= x then
return 0
else
return math.atan(x)
end
end
local function rotate_npc_to_player(self)
local s = self.object:getpos()
local objs = minetest.get_objects_inside_radius(s, 4)
local lp = nil
local yaw = 0
for n = 1, #objs do
if objs[n]:is_player() then
lp = objs[n]:getpos()
break
end
end
if lp then
local vec = {
x = lp.x - s.x,
y = lp.y - s.y,
z = lp.z - s.z
}
yaw = (atan(vec.z / vec.x) + math.pi / 2) - self.rotate
if lp.x > s.x then
yaw = yaw + math.pi
end
end
self.object:setyaw(yaw)
end
---------------------------------------------------------------------
-- Drives conversation
---------------------------------------------------------------------
local function show_chat_option(npc_name, self, player_name, chat_options, close_option)
rotate_npc_to_player(self)
self.order = "stand"
local chatline = get_random_chatline(chat_options)
minetest.chat_send_player(player_name, chatline.text)
if chatline.options ~= nil then
minetest.log("Current options: "..dump(chatline.options))
local formspec = create_formspec(chatline.options, close_option)
minetest.show_formspec(player_name, "rndform", formspec)
end
self.order = "follow"
end
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,
-- Added group attack
group_attack = true,
--pathfinding = true,
pathfinding = 1,
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 = {},
-- Added walk chance
walk_chance = 30,
-- Added stepheight
stepheight = 1,
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",
--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)
-- 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
-- See chat
--show_chat_option(self.nametag, self, name, chat_options, "Nevermind")
-- capture npc with net or lasso
mobs:capture_mob(self, clicker, 0, 5, 80, false, nil)
-- 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:register_spawn("mobs:npc", {"default:dirt_with_grass"}, 20, 0, 7000, 1, 31000)
--mobs:spawn_specific("mobs:npc", {"default:brick"}, {"air"}, 0, 15, 1, 1, 1, 0, 200, true)
--mobs:register_spawn("mobs:npc", {"mg_villages:plotmarker"}, 20, 0, 1, 7000, 31000)
--mobs:spawn_specific("mobs:npc", {"mg_villages:plotmarker"}, {"air"}, 0, 15, 30, 1, 100, 0, 200, true)
minetest.register_abm({
label = "NPC spawning",
nodenames = {"mg_villages:plotmarker"},
neighbors = {"air"},
interval = 30,
chance = 25,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
if active_object_count_wider > 20 then
return
end
minetest.log("Spawning NPC on: "..dump(pos.x)..", "..dump(pos.y + 1)..", "..dump(pos.z))
minetest.log("Active Object count: "..dump(active_object_count))
minetest.log("Wider object count: "..dump(active_object_count_wider))
pos.y = pos.y + 1
local mob = minetest.add_entity(pos, "mobs_npc:npc")
local ent = mob:get_luaentity()
if not ent then
mob:remove()
return
end
end
})
mobs:register_egg("mobs_npc:npc", S("Npc"), "default_brick.png", 1)
-- compatibility
mobs:alias_mob("mobs:npc", "mobs_npc:npc")

11
readme.md Executable file
View File

@ -0,0 +1,11 @@
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.

BIN
textures/mobs_npc.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

BIN
textures/mobs_npc2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

BIN
textures/mobs_npc_baby.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

BIN
textures/mobs_trader.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

BIN
textures/mobs_trader2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

BIN
textures/mobs_trader3.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

355
trader.lua Executable 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")

264
trader_test.lua Executable file
View File

@ -0,0 +1,264 @@
if not minetest.get_modpath("shop") then
minetest.register_alias("shop:coin", "default:gold_ingot")
end
local S = mobs.intllib
mobs.human = {
items = {
-- item, price, chance
{"default:apple 10", "shop:coin 2", 40},
{"farming:bread 10", "shop:coin 4", 50},
{"default:clay 10", "shop:coin 2", 14},
{"default:brick 10", "shop:coin 4", 17},
{"default:glass 10", "shop:coin 4", 17},
{"default:obsidian 10", "shop:coin 15", 50},
{"default:diamond 1", "default:goldblock 1", 7},
{"default:goldblock 1", "default:diamond 1", 7},
{"farming:wheat 10", "shop:coin 2", 17},
{"default:tree 5", "shop:coin 4", 20},
{"default:stone 10", "shop:coin 8", 17},
{"default:desert_stone 10", "shop:coin 8", 27},
{"default:sapling 1", "shop:coin 1", 7},
{"default:pick_steel 1", "shop:coin 2", 7},
{"default:sword_steel 1", "shop:coin 2", 17},
{"default:shovel_steel 1", "shop:coin 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
{"mobs_trader2.png"}, -- re-coloured by amhadinger
{"mobs_trader3.png"}, -- re-coloured by amhadinger
},
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, 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
-------------------------------------------------------------------------------
-- Modifications Copyright 2016 by James Stevenson
local trader_inventory = {}
local function add_goods(race)
local goods_to_add = nil
for i = 1, 16 do
if math.random(0, 100) > race.items[i][3] then
trader_inventory.set_stack(trader_inventory,
"goods", i, race.items[i][1])
end
end
end
function mobs_trader(self, clicker, 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 = function(inv, from_list, from_index, to_list, to_index, count, player)
if (from_list == "goods" and
to_list == "selection") or
(from_list == "selection" and
to_list == "goods") then
return count
else
return 0
end
end,
allow_put = function(inv, listname, index, stack, player)
return 0
end,
allow_take = function(inv, listname, index, stack, player)
return 0
end,
on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
if from_list == "goods" and
to_list == "selection" then
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
inv.set_stack(inv, "price", 1, good[2])
else
inv.set_stack(inv, "price", 1, nil)
end
elseif from_list == "selection" and
to_list == "goods" then
inv.set_stack(inv, "price", 1, nil)
end
end,
on_put = function(inv, listname, index, stack, player)
end,
on_take = function(inv, listname, index, stack, player)
end,
}
if is_inventory == nil then
trader_inventory = minetest.create_detached_inventory(unique_entity_id, move_put_take)
trader_inventory.set_size(trader_inventory, "goods", 16)
trader_inventory.set_size(trader_inventory, "selection", 1)
trader_inventory.set_size(trader_inventory, "price", 1)
add_goods(race)
--print("added stuff")
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, "mobs_npc:trader", "size[8,9]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"list[detached:" .. unique_entity_id .. ";goods;0,0;8,2]" ..
"label[0,3;Selection]" ..
"list[detached:" .. unique_entity_id .. ";selection;2,3;1,1]" ..
"label[4,3;Price]" ..
"list[detached:" .. unique_entity_id .. ";price;6,3;1,1]" ..
"button[4,4;2,1;purchase;Purchase]" ..
"list[current_player;main;0,5;8,1;]" ..
"list[current_player;main;0,6.25;8,3;8]" ..
default.get_hotbar_bg(0, 5))
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "mobs_npc:trader" then
return
end
--print(dump(trader_inventory:get_lists()))
local selection_name = trader_inventory:get_stack("selection", 1):get_name()
local selection_count = trader_inventory:get_stack("selection", 1):get_count()
local selection_string = selection_name .. " " .. tostring(selection_count)
local price_name = trader_inventory:get_stack("price", 1):get_name()
local price_count = trader_inventory:get_stack("price", 1):get_count()
local price_string = price_name .. " " .. tostring(price_count)
--print(selection_string .. "\nfor:\n" .. price_string)
if player:get_inventory():contains_item("main", price_string) then
--print("you got it!")
trader_inventory:set_stack("selection", 1, nil)
trader_inventory:set_stack("price", 1, nil)
player:get_inventory():remove_item("main", price_string)
local adder = player:get_inventory():add_item("main", selection_string)
if adder then
minetest.add_item(player:getpos(), adder)
end
else
minetest.chat_send_player(player:get_player_name(),
"Not enough credits!")
end
end)
mobs:register_egg("mobs_npc:trader", S("Trader"), "default_sandstone.png", 1)
-- compatibility
mobs:alias_mob("mobs:trader", "mobs_npc:trader")