init.lua 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. -- compass configuration interface - adjustable from other mods or minetest.conf settings
  2. ccompass = {}
  3. -- default target to static_spawnpoint or 0/0/0
  4. ccompass.default_target = minetest.setting_get_pos("static_spawnpoint") or {x=0, y=0, z=0}
  5. -- Re-calibration allowed
  6. ccompass.recalibrate = minetest.settings:get_bool("ccompass_recalibrate")
  7. if ccompass.recalibrate == nil then
  8. ccompass.recalibrate = false
  9. end
  10. -- Target restriction
  11. ccompass.restrict_target = minetest.settings:get_bool("ccompass_restrict_target")
  12. ccompass.restrict_target_nodes = {}
  13. local nodes_setting = minetest.settings:get("ccompass_restrict_target_nodes")
  14. if nodes_setting then
  15. nodes_setting:gsub("[^,]+", function(z)
  16. ccompass.restrict_target_nodes[z] = true
  17. end)
  18. end
  19. -- Teleport targets
  20. ccompass.teleport_nodes = {}
  21. local teleport_nodes_setting = minetest.settings:get("ccompass_teleport_nodes")
  22. if teleport_nodes_setting then
  23. teleport_nodes_setting:gsub("[^,]+", function(z)
  24. ccompass.teleport_nodes[z] = false
  25. end)
  26. else
  27. ccompass.teleport_nodes["default:mese"] = false
  28. end
  29. if minetest.settings:get_bool("ccompass_aliasses") then
  30. minetest.register_alias("compass:0", "ccompass:0")
  31. minetest.register_alias("compass:1", "ccompass:1")
  32. minetest.register_alias("compass:2", "ccompass:2")
  33. minetest.register_alias("compass:3", "ccompass:3")
  34. minetest.register_alias("compass:4", "ccompass:4")
  35. minetest.register_alias("compass:5", "ccompass:5")
  36. minetest.register_alias("compass:6", "ccompass:6")
  37. minetest.register_alias("compass:7", "ccompass:7")
  38. minetest.register_alias("compass:8", "ccompass:8")
  39. minetest.register_alias("compass:9", "ccompass:9")
  40. minetest.register_alias("compass:10", "ccompass:10")
  41. minetest.register_alias("compass:11", "ccompass:11")
  42. end
  43. -- set a position to the compass stack
  44. function ccompass.set_target(stack, param)
  45. param = param or {}
  46. -- param.target_pos_string
  47. -- param.target_name
  48. -- param.playername
  49. local meta=stack:get_meta()
  50. meta:set_string("target_pos", param.target_pos_string)
  51. if param.target_name == "" then
  52. meta:set_string("description", "Magic Compass to "..param.target_pos_string)
  53. else
  54. meta:set_string("description", "Magic Compass to "..param.target_name)
  55. end
  56. if param.playername then
  57. local player = minetest.get_player_by_name(param.playername)
  58. minetest.chat_send_player(param.playername, "Calibration done to "..param.target_name.." "..param.target_pos_string)
  59. minetest.sound_play({ name = "ccompass_calibrate", gain = 1 }, { pos = player:getpos(), max_hear_distance = 3 })
  60. end
  61. end
  62. -- Get compass target
  63. local function get_destination(player, stack)
  64. local posstring = stack:get_meta():get_string("target_pos")
  65. if posstring ~= "" then
  66. return minetest.string_to_pos(posstring)
  67. else
  68. return ccompass.default_target
  69. end
  70. end
  71. local function teleport_above(playername, target, counter)
  72. local player = minetest.get_player_by_name(playername)
  73. if not player then
  74. return
  75. end
  76. for i = (counter or 1), 160 do
  77. local nodename = minetest.get_node(target).name
  78. if nodename == "ignore" then
  79. minetest.emerge_area(target, target)
  80. minetest.after(0.1, teleport_above, playername, target, i)
  81. return
  82. end
  83. if nodename ~= 'air' then
  84. target.y = target.y + 1
  85. else
  86. break
  87. end
  88. end
  89. player:setpos(target)
  90. return
  91. end
  92. -- get right image number for players compas
  93. local function get_compass_stack(player, stack)
  94. local target = get_destination(player, stack)
  95. local pos = player:getpos()
  96. local dir = player:get_look_horizontal()
  97. local angle_north = math.deg(math.atan2(target.x - pos.x, target.z - pos.z))
  98. if angle_north < 0 then
  99. angle_north = angle_north + 360
  100. end
  101. local angle_dir = math.deg(dir)
  102. local angle_relative = (angle_north + angle_dir) % 360
  103. local compass_image = math.floor((angle_relative/22.5) + 0.5)%16
  104. -- create new stack with metadata copied
  105. local metadata = stack:get_meta():to_table()
  106. local newstack = ItemStack("ccompass:"..compass_image)
  107. if metadata then
  108. newstack:get_meta():from_table(metadata)
  109. end
  110. if ccompass.usage_hook then
  111. newstack = ccompass.usage_hook(newstack, player) or newstack
  112. end
  113. return newstack
  114. end
  115. -- Calibrate compass on pointed_thing
  116. local function on_use_function(itemstack, player, pointed_thing)
  117. -- possible only on nodes
  118. if pointed_thing.type ~= "node" then --support nodes only for destination
  119. minetest.chat_send_player(player:get_player_name(), "Calibration can be done on nodes only")
  120. return
  121. end
  122. local nodepos = minetest.get_pointed_thing_position(pointed_thing)
  123. local node = minetest.get_node(nodepos)
  124. -- Do teleport to target
  125. if ccompass.teleport_nodes[node.name] then
  126. teleport_above(player:get_player_name(), get_destination(player, itemstack))
  127. return
  128. end
  129. -- recalibration allowed?
  130. if not ccompass.recalibrate then
  131. local destination = itemstack:get_meta():get_string("target_pos")
  132. if destination ~= "" then
  133. minetest.chat_send_player(player:get_player_name(), "Compass already calibrated")
  134. return
  135. end
  136. end
  137. -- target nodes restricted?
  138. if ccompass.restrict_target then
  139. if not ccompass.restrict_target_nodes[node.name] then
  140. minetest.chat_send_player(player:get_player_name(), "Calibration on this node not possible")
  141. return
  142. end
  143. end
  144. -- check if waypoint name set in target node
  145. local nodepos_string = minetest.pos_to_string(nodepos)
  146. local nodemeta = minetest.get_meta(nodepos)
  147. local waypoint_name = nodemeta:get_string("waypoint_name")
  148. local waypoint_pos = nodemeta:get_string("waypoint_pos")
  149. local skip_namechange = nodemeta:get_string("waypoint_skip_namechange")
  150. local itemmeta=itemstack:get_meta()
  151. if waypoint_pos and waypoint_pos ~= "" then
  152. nodepos_string = waypoint_pos
  153. end
  154. if skip_namechange ~= "" then
  155. ccompass.set_target(itemstack, {
  156. target_pos_string = nodepos_string,
  157. target_name = waypoint_name,
  158. playername = player:get_player_name()
  159. })
  160. else
  161. -- show the formspec to player
  162. itemmeta:set_string("tmp_target_pos", nodepos_string) --just save temporary
  163. minetest.show_formspec(player:get_player_name(), "ccompass",
  164. "size[10,2.5]" ..
  165. "field[1,1;8,1;name;Destination name:;"..waypoint_name.."]"..
  166. "button_exit[0.7,2;3,1;cancel;Cancel]"..
  167. "button_exit[3.7,2;5,1;ok;Calibrate]" )
  168. end
  169. return itemstack
  170. end
  171. -- Process the calibration using entered data
  172. minetest.register_on_player_receive_fields(function(player, formname, fields)
  173. if formname == "ccompass" and fields.name and (fields.ok or fields.key_enter) then
  174. local stack=player:get_wielded_item()
  175. local meta=stack:get_meta()
  176. ccompass.set_target(stack, {
  177. target_pos_string = meta:get_string("tmp_target_pos"),
  178. target_name = fields.name,
  179. playername = player:get_player_name()
  180. })
  181. meta:set_string("tmp_target_pos", "")
  182. player:set_wielded_item(stack)
  183. end
  184. end)
  185. -- update inventory
  186. minetest.register_globalstep(function(dtime)
  187. for i,player in ipairs(minetest.get_connected_players()) do
  188. if player:get_inventory() then
  189. for i,stack in ipairs(player:get_inventory():get_list("main")) do
  190. if i > 8 then
  191. break
  192. end
  193. if string.sub(stack:get_name(), 0, 9) == "ccompass:" then
  194. player:get_inventory():set_stack("main", i, get_compass_stack(player, stack))
  195. end
  196. end
  197. end
  198. end
  199. end)
  200. -- register items
  201. for i = 0, 15 do
  202. local image = "ccompass_16_"..i..".png"
  203. local groups = {}
  204. if i > 0 then
  205. groups.not_in_creative_inventory = 1
  206. end
  207. minetest.register_tool("ccompass:"..i, {
  208. description = "Magic Compass",
  209. inventory_image = image,
  210. wield_image = image,
  211. groups = groups,
  212. on_use = on_use_function,
  213. })
  214. end
  215. minetest.register_craft({
  216. output = 'ccompass:0',
  217. recipe = {
  218. {'', 'default:steel_ingot', ''},
  219. {'default:steel_ingot', 'default:mese', 'default:steel_ingot'},
  220. {'', 'default:steel_ingot', ''}
  221. }
  222. })