Version 1.6
[minetest_orienteering.git] / init.lua
blob2a2c7fb4d5407016196467b7c0f58d59ecc6e2e7
1 local S = minetest.get_translator("orienteering")
2 local mod_map = minetest.get_modpath("map") -- map mod from Minetest Game
4 local orienteering = {}
5 orienteering.playerhuds = {}
6 orienteering.settings = {}
7 orienteering.settings.speed_unit = S("m/s")
8 orienteering.settings.length_unit = S("m")
9 orienteering.settings.hud_pos = { x = 0.5, y = 0 }
10 orienteering.settings.hud_offset = { x = 0, y = 15 }
11 orienteering.settings.hud_alignment = { x = 0, y = 0 }
13 local set = tonumber(minetest.settings:get("orienteering_hud_pos_x"))
14 if set then orienteering.settings.hud_pos.x = set end
15 set = tonumber(minetest.settings:get("orienteering_hud_pos_y"))
16 if set then orienteering.settings.hud_pos.y = set end
17 set = tonumber(minetest.settings:get("orienteering_hud_offset_x"))
18 if set then orienteering.settings.hud_offset.x = set end
19 set = tonumber(minetest.settings:get("orienteering_hud_offset_y"))
20 if set then orienteering.settings.hud_offset.y = set end
21 set = minetest.settings:get("orienteering_hud_alignment")
22 if set == "left" then
23 orienteering.settings.hud_alignment.x = 1
24 elseif set == "center" then
25 orienteering.settings.hud_alignment.x = 0
26 elseif set == "right" then
27 orienteering.settings.hud_alignment.x = -1
28 end
30 local o_lines = 4 -- Number of lines in HUD
32 -- Helper function to switch between 12h and 24 mode for the time
33 function orienteering.toggle_time_mode(itemstack, user, pointed_thing)
34 --[[ Player attribute “orienteering:twelve”:
35 * "true": Use 12h mode for time
36 * "false" or unset: Use 24h mode for time ]]
37 if user:get_meta():get_string("orienteering:twelve") == "true" then
38 user:get_meta():set_string("orienteering:twelve", "false")
39 else
40 user:get_meta():set_string("orienteering:twelve", "true")
41 end
42 orienteering.update_hud_displays(user)
43 end
45 local use = S("Put this tool in your hotbar to see the data it provides.")
46 local use_time = S("Put this tool in your hotbar to make use of its functionality. Punch to toggle between 24-hour and 12-hour display for the time feature.")
48 -- Displays height (Y)
49 minetest.register_tool("orienteering:altimeter", {
50 description = S("Altimeter"),
51 _tt_help = S("Shows your elevation"),
52 _doc_items_longdesc = S("It shows you your current elevation (Y)."),
53 _doc_items_usagehelp = use,
54 wield_image = "orienteering_altimeter.png",
55 inventory_image = "orienteering_altimeter.png",
56 groups = { disable_repair = 1 },
59 -- Displays X and Z coordinates
60 minetest.register_tool("orienteering:triangulator", {
61 description = S("Triangulator"),
62 _tt_help = S("Shows your horizontal coordinates"),
63 _doc_items_longdesc = S("It shows you the coordinates of your current position in the horizontal plane (X and Z)."),
64 _doc_items_usagehelp = use,
65 wield_image = "orienteering_triangulator.png",
66 inventory_image = "orienteering_triangulator.png",
67 groups = { disable_repair = 1 },
70 -- Displays player yaw
71 minetest.register_tool("orienteering:compass", {
72 description = S("Compass"),
73 _tt_help = S("Shows your yaw"),
74 _doc_items_longdesc = S("It shows you your yaw (horizontal viewing angle) in degrees."),
75 _doc_items_usagehelp = use,
76 wield_image = "orienteering_compass_wield.png",
77 inventory_image = "orienteering_compass_inv.png",
78 groups = { disable_repair = 1 },
81 -- Displays player pitch
82 minetest.register_tool("orienteering:sextant", {
83 description = S("Sextant"),
84 _tt_help = S("Shows your pitch"),
85 _doc_items_longdesc = S("It shows you your pitch (vertical viewing angle) in degrees."),
86 _doc_items_usagehelp = use,
87 wield_image = "orienteering_sextant_wield.png",
88 inventory_image = "orienteering_sextant_inv.png",
89 groups = { disable_repair = 1 },
92 -- Ultimate orienteering tool: Displays X,Y,Z, yaw, pitch, time, speed and enables the minimap
93 minetest.register_tool("orienteering:quadcorder", {
94 description = S("Quadcorder"),
95 _tt_help = S("Shows your coordinates, yaw, pitch, time, speed and enables minimap"),
96 _doc_items_longdesc = S("This is the ultimate orientieering tool. It shows you your coordinates (X, Y and Z), shows your yaw and pitch (horizontal and vertical viewing angles), the current time, your current speed and it enables you to access the minimap."),
97 wield_image = "orienteering_quadcorder.png",
98 _doc_items_usagehelp = use_time,
99 wield_scale = { x=1, y=1, z=3.5 },
100 inventory_image = "orienteering_quadcorder.png",
101 groups = { disable_repair = 1 },
102 on_use = orienteering.toggle_time_mode,
105 -- Displays game time
106 minetest.register_tool("orienteering:watch", {
107 description = S("Watch"),
108 _tt_help = S("Shows the time"),
109 _doc_items_longdesc = S("It shows you the current time."),
110 _doc_items_usagehelp = S("Put the watch in your hotbar to see the time. Punch to toggle between the 24-hour and 12-hour display."),
111 wield_image = "orienteering_watch.png",
112 inventory_image = "orienteering_watch.png",
113 groups = { disable_repair = 1 },
114 on_use = orienteering.toggle_time_mode,
117 -- Displays speed
118 minetest.register_tool("orienteering:speedometer", {
119 description = S("Speedometer"),
120 _tt_help = S("Shows your speed"),
121 _doc_items_longdesc = S("It shows you your current horizontal (“hor.”) and vertical (“ver.”) speed in meters per second, where one meter is the side length of a single cube."),
122 _doc_items_usagehelp = use,
123 wield_image = "orienteering_speedometer_wield.png",
124 inventory_image = "orienteering_speedometer_inv.png",
125 groups = { disable_repair = 1 },
128 if not mod_map then
129 -- Enables minimap (surface)
130 minetest.register_tool("orienteering:map", {
131 description = S("Map"),
132 _tt_help = S("Allows using the minimap"),
133 _doc_items_longdesc = S("The map allows you to view a minimap of the area around you."),
134 _doc_items_usagehelp = S("If you put a map in your hotbar, you will be able to access the minimap (only surface mode). Press the “minimap” key to view the minimap."),
135 wield_image = "orienteering_map.png",
136 wield_scale = { x=1.5, y=1.5, z=0.15 },
137 inventory_image = "orienteering_map.png",
138 groups = { disable_repair = 1 },
142 -- Enables minimap (radar)
143 minetest.register_tool("orienteering:automapper", {
144 description = S("Radar Mapper"),
145 _tt_help = S("Allows using the minimap and radar"),
146 _doc_items_longdesc = S("The radar mapper is a device that combines a map with a radar. It unlocks both the surface mode and radar mode of the minimap."),
147 _doc_items_usagehelp = S("If you put a radar mapper in your hotbar, you will be able to access the minimap. Press the “minimap” key to view the minimap."),
148 wield_image = "orienteering_automapper_wield.png",
149 wield_scale = { x=1, y=1, z=2 },
150 inventory_image = "orienteering_automapper_inv.png",
151 groups = { disable_repair = 1 },
154 -- Displays X,Y,Z coordinates, yaw and game time
155 minetest.register_tool("orienteering:gps", {
156 description = S("GPS device"),
157 _tt_help = S("Shows your coordinates, yaw and the time"),
158 _doc_items_longdesc = S("The GPS device shows you your coordinates (X, Y and Z), your yaw (horizontal viewing angle) and the time."),
159 _doc_items_usagehelp = use_time,
160 wield_image = "orienteering_gps_wield.png",
161 wield_scale = { x=1, y=1, z=2 },
162 inventory_image = "orienteering_gps_inv.png",
163 groups = { disable_repair = 1 },
164 on_use = orienteering.toggle_time_mode,
167 if minetest.get_modpath("default") ~= nil then
168 -- Register crafts
169 minetest.register_craft({
170 output = "orienteering:altimeter",
171 recipe = {
172 {"default:glass"},
173 {"default:steel_ingot"},
174 {"default:steel_ingot"},
177 minetest.register_craft({
178 output = "orienteering:triangulator",
179 recipe = {
180 {"", "default:bronze_ingot", ""},
181 {"default:bronze_ingot", "", "default:bronze_ingot"},
184 minetest.register_craft({
185 output = "orienteering:sextant",
186 recipe = {
187 {"", "default:gold_ingot", ""},
188 {"default:gold_ingot", "default:gold_ingot", "default:gold_ingot"},
191 minetest.register_craft({
192 output = "orienteering:compass",
193 recipe = {
194 {"", "default:tin_ingot", ""},
195 {"default:tin_ingot", "group:stick", "default:tin_ingot"},
196 {"", "default:tin_ingot", ""},
199 minetest.register_craft({
200 output = "orienteering:speedometer",
201 recipe = {
202 {"", "default:gold_ingot", ""},
203 {"default:steel_ingot", "group:stick", "default:steel_ingot"},
204 {"", "default:steel_ingot", ""},
207 minetest.register_craft({
208 output = "orienteering:automapper",
209 recipe = {
210 {"default:gold_ingot", "default:gold_ingot", "default:gold_ingot"},
211 {"default:mese_crystal", "default:obsidian_shard", "default:mese_crystal"},
212 {"default:gold_ingot", "default:gold_ingot", "default:gold_ingot"}
215 minetest.register_craft({
216 output = "orienteering:gps",
217 recipe = {
218 { "default:gold_ingot", "orienteering:triangulator", "default:gold_ingot" },
219 { "orienteering:compass", "default:bronze_ingot", "orienteering:watch" },
220 { "default:tin_ingot", "orienteering:altimeter", "default:tin_ingot" }
223 minetest.register_craft({
224 output = "orienteering:quadcorder",
225 recipe = {
226 { "default:gold_ingot", "default:gold_ingot", "default:gold_ingot" },
227 { "orienteering:speedometer", "default:diamond", "orienteering:automapper", },
228 { "orienteering:sextant", "default:diamond", "orienteering:gps" }
231 minetest.register_craft({
232 output = "orienteering:watch",
233 recipe = {
234 { "default:copper_ingot" },
235 { "default:glass" },
236 { "default:copper_ingot" }
240 if (not mod_map) and minetest.get_modpath("dye") then
241 minetest.register_craft({
242 output = "orienteering:map",
243 recipe = {
244 { "default:paper", "default:paper", "default:paper" },
245 { "default:paper", "dye:black", "default:paper" },
246 { "default:paper", "default:paper", "default:paper" },
253 function orienteering.update_automapper(player)
254 if orienteering.tool_active(player, "orienteering:automapper") or orienteering.tool_active(player, "orienteering:quadcorder") or minetest.is_creative_enabled(player:get_player_name()) then
255 player:hud_set_flags({minimap = true, minimap_radar = true})
256 elseif ((not mod_map) and orienteering.tool_active(player, "orienteering:map")) or ((mod_map) and orienteering.tool_active(player, "map:mapping_kit")) then
257 player:hud_set_flags({minimap = true, minimap_radar = false})
258 else
259 player:hud_set_flags({minimap = false, minimap_radar = false})
263 -- Checks whether a certain orienteering tool is “active” and ready for use
264 function orienteering.tool_active(player, item)
265 -- Requirement: player carries the tool in the hotbar
266 local inv = player:get_inventory()
267 -- Exception: MTG's Mapping Kit can be anywhere
268 if item == "map:mapping_kit" then
269 return inv:contains_item("main", item)
271 local hotbar = player:hud_get_hotbar_itemcount()
272 for i=1, hotbar do
273 if inv:get_stack("main", i):get_name() == item then
274 return true
277 return false
280 function orienteering.init_hud(player)
281 orienteering.update_automapper(player)
282 local name = player:get_player_name()
283 orienteering.playerhuds[name] = {}
284 for i=1, o_lines do
285 orienteering.playerhuds[name]["o_line"..i] = player:hud_add({
286 hud_elem_type = "text",
287 text = "",
288 position = orienteering.settings.hud_pos,
289 offset = { x = orienteering.settings.hud_offset.x, y = orienteering.settings.hud_offset.y + 20*(i-1) },
290 alignment = orienteering.settings.hud_alignment,
291 number = 0xFFFFFF,
292 scale= { x = 100, y = 20 },
293 z_index = 0,
298 function orienteering.update_hud_displays(player)
299 local toDegrees=180/math.pi
300 local name = player:get_player_name()
301 local gps, altimeter, triangulator, compass, sextant, watch, speedometer, quadcorder
303 if orienteering.tool_active(player, "orienteering:gps") then
304 gps = true
306 if orienteering.tool_active(player, "orienteering:altimeter") then
307 altimeter = true
309 if orienteering.tool_active(player, "orienteering:triangulator") then
310 triangulator = true
312 if orienteering.tool_active(player, "orienteering:compass") then
313 compass = true
315 if orienteering.tool_active(player, "orienteering:sextant") then
316 sextant = true
318 if orienteering.tool_active(player, "orienteering:watch") then
319 watch = true
321 if orienteering.tool_active(player, "orienteering:speedometer") then
322 speedometer = true
324 if orienteering.tool_active(player, "orienteering:quadcorder") then
325 quadcorder = true
328 local str_pos, str_angles, str_time, str_speed
329 local pos = vector.round(player:get_pos())
330 if (altimeter and triangulator) or gps or quadcorder then
331 str_pos = S("Coordinates: X=@1, Y=@2, Z=@3", pos.x, pos.y, pos.z)
332 elseif altimeter then
333 str_pos = S("Height: Y=@1", pos.y)
334 elseif triangulator then
335 str_pos = S("Coordinates: X=@1, Z=@2", pos.x, pos.z)
336 else
337 str_pos = ""
340 -- Yaw in Minetest goes counter-clockwise, which is opposite of how compasses work
341 local yaw = 360-player:get_look_horizontal()*toDegrees
342 local pitch = player:get_look_vertical()*toDegrees
343 if ((compass or gps) and sextant) or quadcorder then
344 str_angles = S("Yaw: @1°, pitch: @2°", string.format("%.1f", yaw), string.format("%.1f", pitch))
345 elseif compass or gps then
346 str_angles = S("Yaw: @1°", string.format("%.1f", yaw))
347 elseif sextant then
348 str_angles = S("Pitch: @1°", string.format("%.1f", pitch))
349 else
350 str_angles = ""
353 local time = minetest.get_timeofday()
354 if watch or gps or quadcorder then
355 local totalminutes = time * 1440
356 local minutes = totalminutes % 60
357 local hours = math.floor((totalminutes - minutes) / 60)
358 minutes = math.floor(minutes)
359 local twelve = player:get_meta():get_string("orienteering:twelve") == "true"
360 if twelve then
361 if hours == 12 and minutes == 0 then
362 str_time = S("Time: noon")
363 elseif hours == 0 and minutes == 0 then
364 str_time = S("Time: midnight")
365 else
366 local hours12 = math.fmod(hours, 12)
367 if hours12 == 0 then hours12 = 12 end
368 if hours >= 12 then
369 str_time = S("Time: @1:@2 p.m.", string.format("%i", hours12), string.format("%02i", minutes))
370 else
371 str_time = S("Time: @1:@2 a.m.", string.format("%i", hours12), string.format("%02i", minutes))
374 else
375 str_time = S("Time: @1:@2", string.format("%02i", hours), string.format("%02i", minutes))
377 else
378 str_time = ""
381 if speedometer or quadcorder then
382 local speed_hor, speed_ver
383 local v
384 local attach = player:get_attach()
385 if attach == nil then
386 v = player:get_player_velocity()
387 else
388 v = attach:get_velocity()
389 if not v then
390 v = player:get_player_velocity()
393 speed_ver = v.y
394 v.y = 0
395 speed_hor = vector.length(v)
397 local u = orienteering.settings.speed_unit
398 str_speed = S("Speed: hor.: @1 @2, vert.: @3 @4", string.format("%.1f", speed_hor), u, string.format("%.1f", speed_ver), u)
399 else
400 str_speed = ""
403 local strs = { str_pos, str_angles, str_time, str_speed }
404 local line = 1
405 for i=1, o_lines do
406 if strs[i] ~= "" then
407 player:hud_change(orienteering.playerhuds[name]["o_line"..line], "text", strs[i])
408 line = line + 1
411 for l=line, o_lines do
412 player:hud_change(orienteering.playerhuds[name]["o_line"..l], "text", "")
416 if mod_map then
417 -- Disable all HUD flag handling in map mod because we already handle it
418 -- ourselves.
419 map.update_hud_flags = function() end
422 minetest.register_on_newplayer(orienteering.init_hud)
423 minetest.register_on_joinplayer(orienteering.init_hud)
425 minetest.register_on_leaveplayer(function(player)
426 orienteering.playerhuds[player:get_player_name()] = nil
427 end)
429 local updatetimer = 0
430 minetest.register_globalstep(function(dtime)
431 updatetimer = updatetimer + dtime
432 if updatetimer > 0.1 then
433 local players = minetest.get_connected_players()
434 for i=1, #players do
435 orienteering.update_automapper(players[i])
436 orienteering.update_hud_displays(players[i])
438 updatetimer = updatetimer - dtime
440 end)
442 if minetest.get_modpath("awards") ~= nil and minetest.get_modpath("default") ~= nil then
443 awards.register_achievement("orienteering_quadcorder", {
444 title = S("Master of Orienteering"),
445 description = S("Craft a quadcorder."),
446 icon = "orienteering_quadcorder.png",
447 trigger = {
448 type = "craft",
449 item = "orienteering:quadcorder",
450 target = 1