nodes_water.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. -- TODO: play sound while working
  2. -- TODO: play sound when emptying a bucket
  3. -- TODO: store correct bucket texture when loading the world anew
  4. -- TODO: show particles when running? distinguish between running/idle state? (with punch?)
  5. -- well for getting water
  6. -- * has some storage space for buckets (filled with water, river water or empty)
  7. -- * only the owner can use the bucket store and the well
  8. -- * the bucket will be added as an entity and slowly rotate;
  9. -- once filled, the texture of the bucket is changed
  10. -- * full (water or river water) buckets can be emptied
  11. -- * by default public; but can also be made private
  12. -- how many seconds does it take to fill a bucket?
  13. cottages.water_fill_time = 10
  14. local S = cottages.S
  15. -- code taken from the itemframes mod in homedecor
  16. -- (the relevant functions are sadly private there and thus cannot be reused)
  17. local tmp = {}
  18. minetest.register_entity("cottages:bucket_entity",{
  19. hp_max = 1,
  20. visual="wielditem",
  21. visual_size={x = 0.33, y = 0.33},
  22. collisionbox = {0, 0, 0, 0, 0, 0},
  23. physical = false,
  24. textures = {"air"},
  25. on_activate = function(self, staticdata)
  26. if tmp.nodename ~= nil and tmp.texture ~= nil then
  27. self.nodename = tmp.nodename
  28. tmp.nodename = nil
  29. self.texture = tmp.texture
  30. tmp.texture = nil
  31. else
  32. if staticdata ~= nil and staticdata ~= "" then
  33. local data = staticdata:split(';')
  34. if data and data[1] and data[2] then
  35. self.nodename = data[1]
  36. self.texture = data[2]
  37. end
  38. end
  39. end
  40. if self.texture ~= nil then
  41. self.object:set_properties({textures = {self.texture}})
  42. end
  43. self.object:set_properties({automatic_rotate = 1})
  44. if self.texture ~= nil and self.nodename ~= nil then
  45. local entity_pos = vector.round(self.object:get_pos())
  46. local objs = minetest.get_objects_inside_radius(entity_pos, 0.5)
  47. for _, obj in ipairs(objs) do
  48. if obj ~= self.object and
  49. obj:get_luaentity() and
  50. obj:get_luaentity().name == "cottages:bucket_entity" and
  51. obj:get_luaentity().nodename == self.nodename and
  52. obj:get_properties() and
  53. obj:get_properties().textures and
  54. obj:get_properties().textures[1] == self.texture then
  55. minetest.log("action","[cottages] Removing extra " ..
  56. self.texture .. " found in " .. self.nodename .. " at " ..
  57. minetest.pos_to_string(entity_pos))
  58. self.object:remove()
  59. break
  60. end
  61. end
  62. end
  63. end,
  64. get_staticdata = function(self)
  65. if self.nodename ~= nil and self.texture ~= nil then
  66. return self.nodename .. ';' .. self.texture
  67. end
  68. return ""
  69. end,
  70. })
  71. cottages.water_gen_fill_bucket = function(pos)
  72. if( not(pos)) then
  73. return
  74. end
  75. local meta = minetest.get_meta(pos)
  76. local bucket = meta:get_string("bucket")
  77. -- nothing to do
  78. if( not(bucket) or bucket ~= "bucket:bucket_empty") then
  79. return
  80. end
  81. -- abort if the water has not been running long enough
  82. -- (the player may have removed a bucket before it was full)
  83. start = meta:get_string("fillstarttime")
  84. if( (minetest.get_us_time()/1000000) - tonumber(start) < cottages.water_fill_time -2) then
  85. return
  86. end
  87. -- the bucket has been filled
  88. meta:set_string("bucket", "bucket:bucket_river_water")
  89. -- change the texture of the bucket to that of one filled with river water
  90. local objs = nil
  91. objs = minetest.get_objects_inside_radius(pos, .5)
  92. if objs then
  93. for _, obj in ipairs(objs) do
  94. if obj and obj:get_luaentity() and obj:get_luaentity().name == "cottages:bucket_entity" then
  95. obj:set_properties( { textures = { "bucket:bucket_river_water" }})
  96. obj:get_luaentity().nodename = "bucket:bucket_river_water"
  97. obj:get_luaentity().texture = "bucket:bucket_river_water"
  98. end
  99. end
  100. end
  101. end
  102. minetest.register_node("cottages:water_gen", {
  103. description = "Tree Trunk Well",
  104. tiles = {"default_tree_top.png", "default_tree.png^[transformR90", "default_tree.png^[transformR90"},
  105. drawtype = "nodebox",
  106. paramtype = "light",
  107. paramtype2 = "facedir",
  108. is_ground_content = false,
  109. groups = {tree = 1, choppy = 2, cracky = 1, flammable = 2},
  110. sounds = cottages.sounds.wood,
  111. node_box = {
  112. type = "fixed",
  113. fixed = {
  114. -- floor of water bassin
  115. {-0.5, -0.5+(3/16), -0.5, 0.5, -0.5+(4/16), 0.5},
  116. -- walls
  117. {-0.5, -0.5+(3/16), -0.5, 0.5, (4/16), -0.5+(2/16)},
  118. {-0.5, -0.5+(3/16), -0.5, -0.5+(2/16), (4/16), 0.5},
  119. { 0.5, -0.5+(3/16), 0.5, 0.5-(2/16), (4/16), -0.5},
  120. { 0.5, -0.5+(3/16), 0.5, -0.5+(2/16), (4/16), 0.5-(2/16)},
  121. -- feet
  122. {-0.5+(3/16), -0.5, -0.5+(3/16), -0.5+(6/16), -0.5+(3/16), 0.5-(3/16)},
  123. { 0.5-(3/16), -0.5, -0.5+(3/16), 0.5-(6/16), -0.5+(3/16), 0.5-(3/16)},
  124. -- real pump
  125. { 0.5-(4/16), -0.5, -(2/16), 0.5, 0.5+(4/16), (2/16)},
  126. -- water pipe inside wooden stem
  127. { 0.5-(8/16), 0.5+(1/16), -(1/16), 0.5, 0.5+(3/16), (1/16)},
  128. -- where the water comes out
  129. { 0.5-(15/32), 0.5, -(1/32), 0.5-(12/32), 0.5+(1/16), (1/32)},
  130. },
  131. },
  132. selection_box = {
  133. type = "fixed",
  134. fixed = { -0.5, -0.5, -0.5, 0.5, 0.5+(4/16), 0.5 }
  135. },
  136. on_construct = function(pos)
  137. local meta = minetest.get_meta(pos)
  138. local spos = pos.x .. "," .. pos.y .. "," .. pos.z
  139. meta:set_string("formspec",
  140. "size[8,9]" ..
  141. "label[3.0,0.0;Tree trunk well]"..
  142. "label[1.5,0.7;Punch the well while wielding an empty bucket.]"..
  143. "label[1.5,1.0;Your bucket will slowly be filled with river water.]"..
  144. "label[1.5,1.3;Punch again to get the bucket back when it is full.]"..
  145. "label[1.0,2.9;Internal bucket storage (passive storage only):]"..
  146. "item_image[0.2,0.7;1.0,1.0;bucket:bucket_empty]"..
  147. "item_image[0.2,1.7;1.0,1.0;bucket:bucket_river_water]"..
  148. "label[1.5,1.9;Punch well with full water bucket in order to empty bucket.]"..
  149. "button_exit[6.0,0.0;2,0.5;public;"..S("Public?").."]"..
  150. "list[nodemeta:" .. spos .. ";main;1,3.3;8,1;]" ..
  151. "list[current_player;main;0,4.85;8,1;]" ..
  152. "list[current_player;main;0,6.08;8,3;8]" ..
  153. "listring[nodemeta:" .. spos .. ";main]" ..
  154. "listring[current_player;main]")
  155. local inv = meta:get_inventory()
  156. inv:set_size('main', 6)
  157. meta:set_string("infotext", S("Public tree trunk well")) -- (punch with empty bucket to fill bucket)")
  158. end,
  159. after_place_node = function(pos, placer)
  160. local meta = minetest.get_meta(pos)
  161. meta:set_string("owner", placer:get_player_name() or "")
  162. meta:set_string("infotext", S("Public tree trunk well (owned by %s)"):format(meta:get_string("owner")))
  163. -- no bucket loaded
  164. meta:set_string("bucket", "")
  165. meta:set_string("public", "public")
  166. end,
  167. can_dig = function(pos,player)
  168. local meta = minetest.get_meta(pos);
  169. local inv = meta:get_inventory()
  170. local bucket = meta:get_string("bucket")
  171. local start = meta:get_string("fillstarttime")
  172. return inv:is_empty("main")
  173. and default.can_interact_with_node(player, pos)
  174. and (not(bucket) or bucket == "")
  175. and ((not(start) or start == "" or
  176. (minetest.get_us_time()/1000000) - tonumber(start)
  177. >= cottages.water_fill_time -2))
  178. end,
  179. -- no inventory move allowed
  180. allow_metadata_inventory_move = function(pos, from_list, from_index,
  181. to_list, to_index, count, player)
  182. return 0
  183. end,
  184. allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  185. local meta = minetest.get_meta(pos)
  186. if not(stack) or not cottages.player_can_use(meta, player) then
  187. return 0
  188. end
  189. local inv = meta:get_inventory()
  190. -- only for buckets
  191. local sname = stack:get_name()
  192. if( sname ~= "bucket:bucket_empty"
  193. and sname ~= "bucket:bucket_water"
  194. and sname ~= "bucket:bucket_river_water") then
  195. return 0
  196. end
  197. return stack:get_count()
  198. end,
  199. allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  200. local meta = minetest.get_meta(pos)
  201. if not(cottages.player_can_use(meta, player)) then
  202. return 0
  203. end
  204. return stack:get_count()
  205. end,
  206. on_blast = function() end,
  207. on_receive_fields = function(pos, formname, fields, sender)
  208. cottages.switch_public(pos, formname, fields, sender, 'tree trunk well')
  209. end,
  210. -- punch to place and retrieve bucket
  211. on_punch = function(pos, node, puncher, pointed_thing)
  212. if( not( pos ) or not( node ) or not( puncher )) then
  213. return
  214. end
  215. -- only the owner can use the well
  216. local name = puncher:get_player_name()
  217. local meta = minetest.get_meta(pos)
  218. local owner = meta:get_string("owner")
  219. local public = meta:get_string("public")
  220. if( name ~= owner and public~="public") then
  221. minetest.chat_send_player( name,
  222. S("This tree trunk well is owned by %s. You can't use it."):format(owner))
  223. return
  224. end
  225. -- we will either add or take from the players inventory
  226. local pinv = puncher:get_inventory()
  227. -- is the well working on something? (either empty or full bucket)
  228. local bucket = meta:get_string("bucket")
  229. -- there is a bucket loaded - either empty or full
  230. if( bucket and bucket~="" and bucket ~= "bucket:bucket_empty") then
  231. if( not(pinv:room_for_item("main", bucket))) then
  232. minetest.chat_send_player( puncher:get_player_name(),
  233. S("Sorry. You have no room for the bucket. Please free some "..
  234. "space in your inventory first!"))
  235. return
  236. end
  237. elseif( bucket and bucket == "bucket:bucket_empty") then
  238. minetest.chat_send_player( puncher:get_player_name(),
  239. S("Please wait until your bucket has been filled."))
  240. -- do not give the empty bucket back immediately
  241. return
  242. end
  243. -- remove the old entity (either a bucket will be placed now or a bucket taken)
  244. local objs = nil
  245. objs = minetest.get_objects_inside_radius(pos, .5)
  246. if objs then
  247. for _, obj in ipairs(objs) do
  248. if obj and obj:get_luaentity() and obj:get_luaentity().name == "cottages:bucket_entity" then
  249. obj:remove()
  250. end
  251. end
  252. end
  253. -- the player gets the bucket (either empty or full) into his inventory
  254. if( bucket and bucket ~= "") then
  255. pinv:add_item("main", bucket )
  256. meta:set_string("bucket", "")
  257. -- we are done
  258. return
  259. end
  260. -- punching with empty bucket will put that bucket into the well (as an entity)
  261. -- and will slowly fill it
  262. local wielded = puncher:get_wielded_item()
  263. if( wielded
  264. and wielded:get_name()
  265. and wielded:get_name() == "bucket:bucket_empty") then
  266. -- remember that we got a bucket loaded
  267. meta:set_string("bucket", "bucket:bucket_empty")
  268. -- create the entity
  269. tmp.nodename = "bucket:bucket_empty"
  270. -- TODO: add a special texture with a handle for the bucket here
  271. tmp.texture = "bucket:bucket_empty"
  272. local e = minetest.add_entity({x=pos.x,y=pos.y+(4/16),z=pos.z},"cottages:bucket_entity")
  273. -- fill the bucket with water
  274. minetest.after(cottages.water_fill_time, cottages.water_gen_fill_bucket, pos)
  275. -- the bucket will only be filled if the water ran long enough
  276. meta:set_string("fillstarttime", tostring(minetest.get_us_time()/1000000))
  277. -- remove the bucket from the players inventory
  278. pinv:remove_item( "main", "bucket:bucket_empty")
  279. return;
  280. end
  281. -- buckets can also be emptied here
  282. if( wielded
  283. and wielded:get_name()
  284. and (wielded:get_name() == "bucket:bucket_water"
  285. or wielded:get_name() == "bucket:bucket_river_water")
  286. and (pinv:room_for_item("main", "bucket:bucket_empty"))) then
  287. -- remove the full bucket from the players inventory
  288. pinv:remove_item( "main", wielded:get_name())
  289. -- add empty bucket
  290. pinv:add_item("main", "bucket:bucket_empty")
  291. -- TODO: play diffrent sound when pouring a bucket
  292. return;
  293. end
  294. -- else check if there is a bucket that can be retrieved
  295. meta:set_string("bucket","")
  296. end,
  297. })
  298. -- a well (will fill water buckets) crafted from wooden materials
  299. minetest.register_craft({
  300. output = 'cottages:water_gen',
  301. recipe = {
  302. {'default:stick', '', ''},
  303. {'default:tree', 'bucket:bucket_empty', 'bucket:bucket_empty'},
  304. {'default:tree', 'default:tree', 'default:tree'},
  305. }
  306. })