Initial commit

master
Elkien3 2017-09-24 21:12:03 -05:00
commit ef5923e85c
22 changed files with 18056 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

59
README.txt Normal file
View File

@ -0,0 +1,59 @@
Prestibags Minetest Mod
=======================
Prestibags are simple bags that act like chests you can pick up. They do not
modify the player's normal inventory formspec, so they will not interfere with
any mods that do. Here are some of their features:
* Retain their inventory when picked up or unloaded/reloaded by the server.
* Can be stored in other bags, nested as deeply as you like.
* Are NOT owned, so any player can open them and pick them up.
* Are flammable, so don't put them near lava or fire!
* Fit in spaces with non-solid nodes (e.g. water, torches), but don't build
solid stuff on top of them!
Note that bags are "active entities", although they are non-physical and act in
many ways like nodes. This means that the "/clearobjects" command will destroy
them, and they can potentially take damage from sources other than fire. They
will show wear like a tool when taken into inventory if they have taken any
damage.
Required Minetest Version: >=0.4.5
Dependencies: (none)
Soft Dependencies: default, wool (for crafting), fire
Craft Recipies (W = "group:wool"):
— W —
W — W
W W W
Git Repo: https://github.com/prestidigitator/minetest-mod-prestibags
Change History
--------------
Version 1.0
* Released 2013-03-07.
* First working version.
Future Direction
----------------
In the future I may enhance bags so they can be opened directly from inventory
by wielding and "using" them, but I'm struggling with this because I kind of
like the drawback that you have to risk placing them to interact with their
inventories.
Copyright and Licensing
-----------------------
All content, including source code, textures, models, and sounds, are 100%
original content by the mod author (prestidigitator).
Author: prestidigitator (as registered on forum.minetest.net)
License: WTFPL (all content)

2
depends.txt Normal file
View File

@ -0,0 +1,2 @@
inventory_plus
wool

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

467
init.lua Normal file
View File

@ -0,0 +1,467 @@
--- backpack Minetest mod
--
-- @author prestidigitator
-- @copyright 2013, licensed under WTFPL
---- Configuration
--- Width and height of bag inventory (>0)
local BAG_WIDTH = 4
local BAG_HEIGHT = 3
player_backpack = {}
--- Sound played when placing/dropping a bag on the ground
local DROP_BAG_SOUND = "prestibags_drop_bag"
local DROP_BAG_SOUND_GAIN = 1.0
local DROP_BAG_SOUND_DIST = 5.0
--- Sound played when opening a bag's inventory
local OPEN_BAG_SOUND = "prestibags_rustle_bag"
local OPEN_BAG_SOUND_GAIN = 1.0
local OPEN_BAG_SOUND_DIST = 5.0
--- HP of undamaged bag (integer >0).
local BAG_MAX_HP = 4
--- How often the inventories of destroyed bags are checked and cleaned up
-- (>0.0).
local CLEANUP_PERIOD__S = 10.0
--- How often environmental effects like burning are checked (>0.0).
local ENV_CHECK_PERIOD__S = 0.5
--- Max distance an igniter node can be and still ignite/burn the bag (>=1).
local MAX_IGNITE_DIST = 4.0
--- Probability (0.0 <= p <= 1.0) bag will be damaged for each igniter touching
-- it (increases if igniter's max range is greater than current distance).
-- Always damaged if in lava.
local BURN_DAMAGE_PROB = 0.25
--- Probability (0.0 <= p <= 1.0) bag will ignite and spawn some flames on or
-- touching it for each igniter within igniter range (increases if
-- igniter's max range is greater than current distance). Alawys ignites
-- if in lava. Ignition is ignored if "fire:basic_flame" is not available.
local IGNITE_PROB = 0.25
--- Amount of damage bag takes each time it is burned. Note that a bag can be
-- burned at most once each update cycle, so this is the MAXIMUM damage
-- taken by burning each ENV_CHECK_PERIOD__S period.
local BURN_DAMAGE__HP = 1
---- end of configuration
local EPSILON = 0.001 -- "close enough"
local function serializeContents(contents)
if not contents then return "" end
local tabs = {}
for i, stack in ipairs(contents) do
tabs[i] = stack and stack:to_table() or ""
end
return minetest.serialize(tabs)
end
local function deserializeContents(data)
if not data or data == "" then return nil end
local tabs = minetest.deserialize(data)
if not tabs or type(tabs) ~= "table" then return nil end
local contents = {}
for i, tab in ipairs(tabs) do
contents[i] = ItemStack(tab)
end
return contents
end
-- weak references to keep track of what detached inventory lists to remove
local idSet = {}
local idToWeakEntityMap = {}
setmetatable(idToWeakEntityMap, { __mode = "v" })
local entityInv
local function cleanInventory()
for id, dummy in pairs(idSet) do
if not idToWeakEntityMap[id] then
entityInv:set_size(id, 0)
idSet[id] = nil
end
end
minetest.after(CLEANUP_PERIOD__S, cleanInventory)
end
minetest.after(CLEANUP_PERIOD__S, cleanInventory)
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
if player_backpack[name] then
local pos = player:getpos()
pos.y = pos.y + 0.4
player_backpack[name]:set_detach()
player_backpack[name]:setpos(pos)
player_backpack[name] = nil
end
end)
minetest.register_on_joinplayer(function(player)
inventory_plus.register_button(player,"backpack", "Backpack")
end)
minetest.register_on_dieplayer(function(player)
local name = player:get_player_name()
if player_backpack[name] then
local pos = player:getpos()
pos.y = pos.y + 0.5
player_backpack[name]:set_detach()
player_backpack[name]:setpos(pos)
player_backpack[name] = nil
end
end)
minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.backpack then
local name = player:get_player_name()
if player_backpack[name] then
local pos = player:getpos()
pos.y = pos.y + 0.4
player_backpack[name]:set_detach()
player_backpack[name]:setpos(pos)
player_backpack[name] = nil
end
end
end)
entityInv = minetest.create_detached_inventory(
"backpack:bags",
{
allow_move = function(inv,
fromList, fromIndex,
toList, toIndex,
count,
player)
return idToWeakEntityMap[fromList] and idToWeakEntityMap[toList]
and count
or 0
end,
allow_put = function(inv, toList, toIndex, stack, player)
return idToWeakEntityMap[toList] and stack:get_count() or 0
end,
allow_take = function(inv, fromList, fromIndex, stack, player)
return idToWeakEntityMap[fromList] and stack:get_count() or 0
end,
on_move = function(inv,
fromList, fromIndex,
toList, toIndex,
count,
player)
local fromEntity = idToWeakEntityMap[fromList]
local toEntity = idToWeakEntityMap[toList]
local fromStack = fromEntity.contents[fromIndex]
local toStack = toEntity.contents[toIndex]
local moved = fromStack:take_item(count)
toStack:add_item(moved)
end,
on_put = function(inv, toList, toIndex, stack, player)
local toEntity = idToWeakEntityMap[toList]
local toStack = toEntity.contents[toIndex]
toStack:add_item(stack)
end,
on_take = function(inv, fromList, fromIndex, stack, player)
local fromEntity = idToWeakEntityMap[fromList]
local fromStack = fromEntity.contents[fromIndex]
fromStack:take_item(stack:get_count())
end
})
local function bag_envUpdate(self, dt)
end
minetest.register_entity(
"backpack:bag_entity",
{
initial_properties =
{
hp_max = BAG_MAX_HP,
physical = false,
collisionbox = { -0.2, -0.3, -0.2, 0.2, 0.3, 0.2 },--collisionbox = { -0.44, -0.5, -0.425, 0.44, 0.35, 0.425 },
visual = "mesh",
visual_size = { x = 1, y = 1 },
mesh = "backpack.obj",
textures = { "backpack.png" }
},
on_activate = function(self, staticData, dt)
local id
repeat
id = "bag"..(math.random(0, 2^15-1)*2^15 + math.random(0, 2^15-1))
until not idSet[id]
idSet[id] = id
idToWeakEntityMap[id] = self
self.id = id
self.object:set_armor_groups({ punch_operable = 1, immortal = 1 })
local contents = deserializeContents(staticData)
if not contents then
contents = {}
for i = 1, BAG_WIDTH*BAG_HEIGHT do
contents[#contents+1] = ItemStack(nil)
end
end
self.contents = contents
self.timer = ENV_CHECK_PERIOD__S
end,
get_staticdata = function(self)
return serializeContents(self.contents)
end,
on_punch = function(self, puncher, timeSinceLastPunch, toolCaps, dir)
local name = puncher:get_player_name()
if puncher:get_player_control().sneak then
if entityInv:is_empty(self.id) then
local playerInv = puncher:get_inventory()
if not name or not playerInv then return end
local contentData = serializeContents(self.contents)
local hp = self.object:get_hp()
local newItem =
ItemStack({ name = "backpack:backpack",
metadata = contentData,
wear = (2^16) * (BAG_MAX_HP - hp) / BAG_MAX_HP })
if not playerInv:room_for_item("main", newItem) then return end
self.object:remove()
playerInv:add_item("main", newItem)
end
else
if player_backpack[name] == nil then
self.object:setpos(puncher:getpos())
self.object:set_attach(puncher, "", {x=0,y=0,z=-2.5}, {x=0,y=0,z=0})
player_backpack[name] = self.object
end
end
end,
on_rightclick = function(self, player)
local invLoc = "detached:"..self.id
local w = math.max(8, 2 + BAG_WIDTH)
local h = math.max(5 + BAG_HEIGHT)
local yImg = math.floor(BAG_HEIGHT/2)
local yPlay = BAG_HEIGHT + 1
if not self.contents or #self.contents <= 0 then return end
entityInv:set_size(self.id, #self.contents)
for i, stack in ipairs(self.contents) do
entityInv:set_stack(self.id, i, stack)
end
local formspec =
"size["..w..","..h.."]"..
"image[1,"..yImg..";1,1;inventory_plus_backpack.png]"..
"list[detached:backpack:bags;"..self.id..";2,0;"..
BAG_WIDTH..","..BAG_HEIGHT..";]"..
"list[current_player;main;0,"..yPlay..";8,4;]"
minetest.show_formspec(
player:get_player_name(), "backpack:backpack", formspec)
minetest.sound_play(
OPEN_BAG_SOUND,
{
object = self.object,
gain = OPEN_BAG_SOUND_GAIN,
max_hear_distance = OPEN_BAG_SOUND_DIST,
loop = false
})
end,
--[[on_step = function(self, dt)
self.timer = self.timer - dt
if self.timer > 0.0 then return end
self.timer = ENV_CHECK_PERIOD__S
local haveFlame = minetest.registered_nodes["fire:basic_flame"]
local pos = self.object:getpos()
local node = minetest.env:get_node(pos)
local nodeType = node and minetest.registered_nodes[node.name]
if nodeType and nodeType.walkable and not nodeType.buildable_to then
--return self:remove()
end
if minetest.get_item_group(node.name, "lava") > 0 then
if haveFlame then
local flamePos = minetest.env:find_node_near(pos, 1.0, "air")
if flamePos then
minetest.env:add_node(flamePos,
{ name = "fire:basic_flame" })
end
end
return self:burn()
end
if minetest.env:find_node_near(pos, 1.0, "group:puts_out_fire") then
return
end
local minPos = { x = pos.x - MAX_IGNITE_DIST,
y = pos.y - MAX_IGNITE_DIST,
z = pos.z - MAX_IGNITE_DIST }
local maxPos = { x = pos.x + MAX_IGNITE_DIST,
y = pos.y + MAX_IGNITE_DIST,
z = pos.z + MAX_IGNITE_DIST }
local wasIgnited = false
local burnLevels = 0.0
local igniterPosList =
minetest.env:find_nodes_in_area(minPos, maxPos, "group:igniter")
for i, igniterPos in ipairs(igniterPosList) do
local distSq = (igniterPos.x - pos.x)^2 +
(igniterPos.y - pos.y)^2 +
(igniterPos.z - pos.z)^2
if distSq <= MAX_IGNITE_DIST^2 + EPSILON then
local igniterNode = minetest.env:get_node(igniterPos)
local igniterLevel =
minetest.get_item_group(igniterNode.name, "igniter")
- math.max(1.0, math.sqrt(distSq) - EPSILON)
if igniterLevel >= 0.0 then
if distSq <= 1.0 then
wasIgnited = true
end
burnLevels = burnLevels + 1.0 + igniterLevel
end
end
end
if burnLevels >= 1.0 then
if haveFlame and (not wasIgnited) and
math.random() >= (1.0 - IGNITE_PROB)^burnLevels
then
local flamePos =
(node.name == "air")
and pos
or minetest.env:find_node_near(pos, 1.0, "air")
if flamePos then
minetest.env:add_node(flamePos,
{ name = "fire:basic_flame" })
end
end
if math.random() >= (1.0 - BURN_DAMAGE_PROB)^burnLevels then
self:burn()
end
end
end,
remove = function(self)
entityInv:set_size(self.id, 0)
idSet[self.id] = nil
self.object:remove()
end,
burn = function(self)
local hp = self.object:get_hp() - BURN_DAMAGE__HP
self.object:set_hp(hp)
print("DEBUG - bag HP = "..hp)
if hp <= 0 then
return self:remove()
end
end--]]
})
local function rezEntity(stack, pos, player)
local x = pos.x
local y = math.floor(pos.y)
local z = pos.z
while true do
local node = minetest.env:get_node({ x = x, y = y-1, z = z})
local nodeType = node and minetest.registered_nodes[node.name]
if not nodeType or nodeType.walkable then
break
end
y = y - 1
end
local obj = minetest.env:add_entity(pos, "backpack:bag_entity")
if not obj then return stack end
local contentData = stack:get_metadata()
local contents = deserializeContents(contentData)
if contents then
obj:get_luaentity().contents = contents
end
obj:set_hp(BAG_MAX_HP - BAG_MAX_HP * stack:get_wear() / 2^16)
minetest.sound_play(
DROP_BAG_SOUND,
{
object = obj,
gain = DROP_BAG_SOUND_GAIN,
max_hear_distance = DROP_BAG_SOUND_DIST,
loop = false
})
return ItemStack(nil)
end
-- DEBUG minetest.register_craftitem(
minetest.register_tool(
"backpack:backpack",
{
description = "Backpack",
groups = { bag = BAG_WIDTH*BAG_HEIGHT, flammable = 1 },
inventory_image = "inventory_plus_backpack.png",
wield_image = "inventory_plus_backpack.png",
stack_max = 1,
on_place = function(stack, player, pointedThing)
local pos = pointedThing and pointedThing.under
local node = pos and minetest.env:get_node(pos)
local nodeType = node and minetest.registered_nodes[node.name]
if not nodeType or not nodeType.buildable_to then
pos = pointedThing and pointedThing.above
node = pos and minetest.env:get_node(pos)
nodeType = node and minetest.registered_nodes[node.name]
end
if not pos then pos = player:getpos() end
return rezEntity(stack, pos, player)
end,
on_drop = function(stack, player, pos)
return rezEntity(stack, pos, player)
end
-- Eventually add on_use(stack, player, pointedThing) which actually
-- opens the bag from player inventory; trick is, has to track whether
-- bag is still in inventory OR replace "player inventory" with a
-- detached proxy that doesn't allow the bag's stack to be changed
-- while open!
})
--[[
minetest.register_craft(
{
output = "backpack:backpack",
recipe =
{
{ "", "group:wool", "" },
{ "group:wool", "", "group:wool" },
{ "group:wool", "group:wool", "group:wool" },
}
})
--]]

BIN
models/backpack.blend Normal file

Binary file not shown.

BIN
models/backpack.blend1 Normal file

Binary file not shown.

13
models/backpack.mtl Normal file
View File

@ -0,0 +1,13 @@
# Blender MTL File: 'backpack.blend'
# Material Count: 1
newmtl Material
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd C:\Users\Elkien3\Documents\minetest-0.4.16\mods\backpack\textures\backpack.png

50
models/backpack.obj Normal file
View File

@ -0,0 +1,50 @@
# Blender v2.78 (sub 0) OBJ File: 'backpack.blend'
# www.blender.org
mtllib backpack.mtl
o Cube_Cube.001
v 2.000000 -3.000000 -1.500000
v 2.000000 3.000000 -1.500000
v 2.000000 -3.000000 1.500000
v 2.000000 3.000000 1.500000
v -2.000000 -3.000000 -1.500000
v -2.000000 3.000000 -1.500000
v -2.000000 -3.000000 1.500000
v -2.000000 3.000000 1.500000
vt 0.5333 0.0000
vt 0.5333 1.0000
vt 0.7333 1.0000
vt 0.7333 0.0000
vt 0.2667 0.0011
vt 0.2667 1.0011
vt -0.0000 0.9968
vt -0.0000 -0.0032
vt 0.7333 0.0000
vt 0.7333 1.0000
vt 0.5333 1.0000
vt 0.5333 0.0000
vt 0.5333 -0.0042
vt 0.5333 0.9958
vt 0.2667 0.9947
vt 0.2667 -0.0053
vt 1.0000 0.5000
vt 0.7333 0.5000
vt 0.7333 0.0000
vt 1.0000 0.0000
vt 0.7333 0.5000
vt 1.0000 0.5000
vt 1.0000 1.0000
vt 0.7333 1.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
usemtl Material
s off
f 1/1/1 2/2/1 4/3/1 3/4/1
f 3/5/2 4/6/2 8/7/2 7/8/2
f 7/9/3 8/10/3 6/11/3 5/12/3
f 5/13/4 6/14/4 2/15/4 1/16/4
f 3/17/5 7/18/5 5/19/5 1/20/5
f 8/21/6 4/22/6 2/23/6 6/24/6

BIN
models/prestibags_bag.blend Normal file

Binary file not shown.

17463
models/prestibags_bag.obj Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
textures/backpack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

BIN
textures/backpack.xcf Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

BIN
textures/prestibags_bag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB