First commit. Using mobs_npc code as start.
This commit is contained in:
commit
eb158f6f15
4
.buildpath
Normal file
4
.buildpath
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<buildpath>
|
||||
<buildpathentry kind="src" path=""/>
|
||||
</buildpath>
|
17
.project
Normal file
17
.project
Normal 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>
|
2
.settings/org.eclipse.ldt.prefs
Normal file
2
.settings/org.eclipse.ldt.prefs
Normal file
@ -0,0 +1,2 @@
|
||||
Grammar__default_id=lua-5.1
|
||||
eclipse.preferences.version=1
|
3
depends.txt
Executable file
3
depends.txt
Executable file
@ -0,0 +1,3 @@
|
||||
default
|
||||
mobs
|
||||
intllib?
|
1
description.txt
Executable file
1
description.txt
Executable file
@ -0,0 +1 @@
|
||||
Adds simple NPC and Trader.
|
30
init.lua
Executable file
30
init.lua
Executable 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
21
license.txt
Executable 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
23
locale/de.txt
Executable 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
21
locale/template.txt
Executable 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 =
|
324
npc.lua
Executable file
324
npc.lua
Executable 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
11
readme.md
Executable 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
BIN
textures/mobs_npc.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 901 B |
BIN
textures/mobs_npc2.png
Executable file
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
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
BIN
textures/mobs_trader.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 783 B |
BIN
textures/mobs_trader2.png
Executable file
BIN
textures/mobs_trader2.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 783 B |
BIN
textures/mobs_trader3.png
Executable file
BIN
textures/mobs_trader3.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 779 B |
355
trader.lua
Executable file
355
trader.lua
Executable 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
264
trader_test.lua
Executable 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")
|
Loading…
Reference in New Issue
Block a user