Default/functions: Reduce lavacooling ABM/sound overload
[oweals/minetest_game.git] / mods / bones / init.lua
1 -- Minetest 0.4 mod: bones
2 -- See README.txt for licensing and other information. 
3
4 bones = {}
5
6 local function is_owner(pos, name)
7         local owner = minetest.get_meta(pos):get_string("owner")
8         if owner == "" or owner == name then
9                 return true
10         end
11         return false
12 end
13
14 bones.bones_formspec =
15         "size[8,9]"..
16         default.gui_bg..
17         default.gui_bg_img..
18         default.gui_slots..
19         "list[current_name;main;0,0.3;8,4;]"..
20         "list[current_player;main;0,4.85;8,1;]"..
21         "list[current_player;main;0,6.08;8,3;8]"..
22         default.get_hotbar_bg(0,4.85)
23
24 local share_bones_time = tonumber(minetest.setting_get("share_bones_time") or 1200)
25 local share_bones_time_early = tonumber(minetest.setting_get("share_bones_time_early") or (share_bones_time/4))
26
27 minetest.register_node("bones:bones", {
28         description = "Bones",
29         tiles = {
30                 "bones_top.png",
31                 "bones_bottom.png",
32                 "bones_side.png",
33                 "bones_side.png",
34                 "bones_rear.png",
35                 "bones_front.png"
36         },
37         paramtype2 = "facedir",
38         groups = {dig_immediate=2},
39         sounds = default.node_sound_dirt_defaults({
40                 footstep = {name="default_gravel_footstep", gain=0.5},
41                 dug = {name="default_gravel_footstep", gain=1.0},
42         }),
43         
44         can_dig = function(pos, player)
45                 local inv = minetest.get_meta(pos):get_inventory()
46                 return is_owner(pos, player:get_player_name()) and inv:is_empty("main")
47         end,
48         
49         allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
50                 if is_owner(pos, player:get_player_name()) then
51                         return count
52                 end
53                 return 0
54         end,
55         
56         allow_metadata_inventory_put = function(pos, listname, index, stack, player)
57                 return 0
58         end,
59         
60         allow_metadata_inventory_take = function(pos, listname, index, stack, player)
61                 if is_owner(pos, player:get_player_name()) then
62                         return stack:get_count()
63                 end
64                 return 0
65         end,
66         
67         on_metadata_inventory_take = function(pos, listname, index, stack, player)
68                 local meta = minetest.get_meta(pos)
69                 if meta:get_inventory():is_empty("main") then
70                         minetest.remove_node(pos)
71                 end
72         end,
73         
74         on_punch = function(pos, node, player)
75                 if(not is_owner(pos, player:get_player_name())) then
76                         return
77                 end
78                 
79                 local inv = minetest.get_meta(pos):get_inventory()
80                 local player_inv = player:get_inventory()
81                 local has_space = true
82                 
83                 for i=1,inv:get_size("main") do
84                         local stk = inv:get_stack("main", i)
85                         if player_inv:room_for_item("main", stk) then
86                                 inv:set_stack("main", i, nil)
87                                 player_inv:add_item("main", stk)
88                         else
89                                 has_space = false
90                                 break
91                         end
92                 end
93                 
94                 -- remove bones if player emptied them
95                 if has_space then
96                         minetest.remove_node(pos)
97                 end
98         end,
99         
100         on_timer = function(pos, elapsed)
101                 local meta = minetest.get_meta(pos)
102                 local time = meta:get_int("time") + elapsed
103                 if time >= share_bones_time then
104                         meta:set_string("infotext", meta:get_string("owner").."'s old bones")
105                         meta:set_string("owner", "")
106                 else
107                         meta:set_int("time", time)
108                         return true
109                 end
110         end,
111 })
112
113 local function may_replace(pos, player)
114         local node_name = minetest.get_node(pos).name
115         local node_definition = minetest.registered_nodes[node_name]
116
117         -- if the node is unknown, we let the protection mod decide
118         -- this is consistent with when a player could dig or not dig it
119         -- unknown decoration would often be removed
120         -- while unknown building materials in use would usually be left
121         if not node_definition then
122                 -- only replace nodes that are not protected
123                 return not minetest.is_protected(pos, player:get_player_name())
124         end
125
126         -- allow replacing air and liquids
127         if node_name == "air" or node_definition.liquidtype ~= "none" then
128                 return true
129         end
130
131         -- don't replace filled chests and other nodes that don't allow it
132         local can_dig_func = node_definition.can_dig
133         if can_dig_func and not can_dig_func(pos, player) then
134                 return false
135         end
136
137         -- default to each nodes buildable_to; if a placed block would replace it, why shouldn't bones?
138         -- flowers being squished by bones are more realistical than a squished stone, too
139         -- exception are of course any protected buildable_to
140         return node_definition.buildable_to and not minetest.is_protected(pos, player:get_player_name())
141 end
142
143 minetest.register_on_dieplayer(function(player)
144         if minetest.setting_getbool("creative_mode") then
145                 return
146         end
147         
148         local player_inv = player:get_inventory()
149         if player_inv:is_empty("main") and
150                 player_inv:is_empty("craft") then
151                 return
152         end
153
154         local pos = player:getpos()
155         pos.x = math.floor(pos.x+0.5)
156         pos.y = math.floor(pos.y+0.5)
157         pos.z = math.floor(pos.z+0.5)
158         local param2 = minetest.dir_to_facedir(player:get_look_dir())
159         local player_name = player:get_player_name()
160         local player_inv = player:get_inventory()
161
162         if (not may_replace(pos, player)) then
163                 if (may_replace({x=pos.x, y=pos.y+1, z=pos.z}, player)) then
164                         -- drop one node above if there's space
165                         -- this should solve most cases of protection related deaths in which players dig straight down
166                         -- yet keeps the bones reachable
167                         pos.y = pos.y+1
168                 else
169                         -- drop items instead of delete
170                         for i=1,player_inv:get_size("main") do
171                                 minetest.add_item(pos, player_inv:get_stack("main", i))
172                         end
173                         for i=1,player_inv:get_size("craft") do
174                                 minetest.add_item(pos, player_inv:get_stack("craft", i))
175                         end
176                         -- empty lists main and craft
177                         player_inv:set_list("main", {})
178                         player_inv:set_list("craft", {})
179                         return
180                 end
181         end
182         
183         minetest.set_node(pos, {name="bones:bones", param2=param2})
184         
185         local meta = minetest.get_meta(pos)
186         local inv = meta:get_inventory()
187         inv:set_size("main", 8*4)
188         inv:set_list("main", player_inv:get_list("main"))
189         
190         for i=1,player_inv:get_size("craft") do
191                 local stack = player_inv:get_stack("craft", i)
192                 if inv:room_for_item("main", stack) then
193                         inv:add_item("main", stack)
194                 else
195                         --drop if no space left
196                         minetest.add_item(pos, stack)
197                 end
198         end
199         
200         player_inv:set_list("main", {})
201         player_inv:set_list("craft", {})
202         
203         meta:set_string("formspec", bones.bones_formspec)
204         meta:set_string("owner", player_name)
205         
206         if share_bones_time ~= 0 then
207                 meta:set_string("infotext", player_name.."'s fresh bones")
208
209                 if share_bones_time_early == 0 or not minetest.is_protected(pos, player_name) then
210                         meta:set_int("time", 0)
211                 else
212                         meta:set_int("time", (share_bones_time - share_bones_time_early))
213                 end
214
215                 minetest.get_node_timer(pos):start(10)
216         else
217                 meta:set_string("infotext", player_name.."'s bones")
218         end
219 end)